summaryrefslogtreecommitdiff
path: root/dhall_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'dhall_syntax')
-rw-r--r--dhall_syntax/src/core/import.rs78
-rw-r--r--dhall_syntax/src/parser.rs22
-rw-r--r--dhall_syntax/src/printer.rs4
3 files changed, 85 insertions, 19 deletions
diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs
index d1f3fca..ef696b9 100644
--- a/dhall_syntax/src/core/import.rs
+++ b/dhall_syntax/src/core/import.rs
@@ -11,10 +11,15 @@ pub enum FilePrefix {
Home,
}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct File {
+ pub file_path: Vec<String>,
+}
+
/// The location of import (i.e. local vs. remote vs. environment)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ImportLocation<SubExpr> {
- Local(FilePrefix, Vec<String>),
+ Local(FilePrefix, File),
Remote(URL<SubExpr>),
Env(String),
Missing,
@@ -24,7 +29,7 @@ pub enum ImportLocation<SubExpr> {
pub struct URL<SubExpr> {
pub scheme: Scheme,
pub authority: String,
- pub path: Vec<String>,
+ pub path: File,
pub query: Option<String>,
pub headers: Option<SubExpr>,
}
@@ -99,3 +104,72 @@ impl<SE> Import<SE> {
})
}
}
+
+pub trait Canonicalize {
+ fn canonicalize(&self) -> Self;
+}
+
+impl Canonicalize for File {
+ fn canonicalize(&self) -> File {
+ let mut file_path = Vec::new();
+ let mut file_path_components = self.file_path.clone().into_iter();
+
+ loop {
+ let component = file_path_components.next();
+ match component.as_ref() {
+ // ───────────────────
+ // canonicalize(ε) = ε
+ None => break,
+
+ // canonicalize(directory₀) = directory₁
+ // ───────────────────────────────────────
+ // canonicalize(directory₀/.) = directory₁
+ Some(c) if c == "." => continue,
+
+ Some(c) if c == ".." => match file_path_components.next() {
+ // canonicalize(directory₀) = ε
+ // ────────────────────────────
+ // canonicalize(directory₀/..) = /..
+ None => file_path.push("..".to_string()),
+
+ // canonicalize(directory₀) = directory₁/..
+ // ──────────────────────────────────────────────
+ // canonicalize(directory₀/..) = directory₁/../..
+ Some(ref c) if c == ".." => {
+ file_path.push("..".to_string());
+ file_path.push("..".to_string());
+ },
+
+ // canonicalize(directory₀) = directory₁/component
+ // ─────────────────────────────────────────────── ; If "component" is not
+ // canonicalize(directory₀/..) = directory₁ ; ".."
+ Some(_) => continue,
+ },
+
+ // canonicalize(directory₀) = directory₁
+ // ───────────────────────────────────────────────────────── ; If no other
+ // canonicalize(directory₀/component) = directory₁/component ; rule matches
+ Some(c) => file_path.push(c.clone()),
+ }
+ }
+
+ File { file_path }
+ }
+}
+
+impl<SubExpr: Copy> Canonicalize for ImportLocation<SubExpr> {
+ fn canonicalize(&self) -> ImportLocation<SubExpr> {
+ match self {
+ ImportLocation::Local(prefix, file) => ImportLocation::Local(*prefix, file.canonicalize()),
+ ImportLocation::Remote(url) => ImportLocation::Remote(URL {
+ scheme: url.scheme,
+ authority: url.authority.clone(),
+ path: url.path.canonicalize(),
+ query: url.query.clone(),
+ headers: url.headers.clone(),
+ }),
+ ImportLocation::Env(name) => ImportLocation::Env(name.to_string()),
+ ImportLocation::Missing => ImportLocation::Missing,
+ }
+ }
+}
diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs
index c2ba19a..40784ec 100644
--- a/dhall_syntax/src/parser.rs
+++ b/dhall_syntax/src/parser.rs
@@ -564,17 +564,15 @@ impl Parsers {
},
))
}
- fn path(input: ParseInput<Rule>) -> ParseResult<Vec<String>> {
+ fn path(input: ParseInput<Rule>) -> ParseResult<File> {
Ok(parse_children!(input;
[path_component(components)..] => {
- components.collect()
+ File { file_path: components.collect() }
}
))
}
- fn local(
- input: ParseInput<Rule>,
- ) -> ParseResult<(FilePrefix, Vec<String>)> {
+ fn local(input: ParseInput<Rule>) -> ParseResult<(FilePrefix, File)> {
Ok(parse_children!(input;
[parent_path(l)] => l,
[here_path(l)] => l,
@@ -583,30 +581,24 @@ impl Parsers {
))
}
- fn parent_path(
- input: ParseInput<Rule>,
- ) -> ParseResult<(FilePrefix, Vec<String>)> {
+ fn parent_path(input: ParseInput<Rule>) -> ParseResult<(FilePrefix, File)> {
Ok(parse_children!(input;
[path(p)] => (FilePrefix::Parent, p)
))
}
- fn here_path(
- input: ParseInput<Rule>,
- ) -> ParseResult<(FilePrefix, Vec<String>)> {
+ fn here_path(input: ParseInput<Rule>) -> ParseResult<(FilePrefix, File)> {
Ok(parse_children!(input;
[path(p)] => (FilePrefix::Here, p)
))
}
- fn home_path(
- input: ParseInput<Rule>,
- ) -> ParseResult<(FilePrefix, Vec<String>)> {
+ fn home_path(input: ParseInput<Rule>) -> ParseResult<(FilePrefix, File)> {
Ok(parse_children!(input;
[path(p)] => (FilePrefix::Home, p)
))
}
fn absolute_path(
input: ParseInput<Rule>,
- ) -> ParseResult<(FilePrefix, Vec<String>)> {
+ ) -> ParseResult<(FilePrefix, File)> {
Ok(parse_children!(input;
[path(p)] => (FilePrefix::Absolute, p)
))
diff --git a/dhall_syntax/src/printer.rs b/dhall_syntax/src/printer.rs
index f3dc648..1e3b7f2 100644
--- a/dhall_syntax/src/printer.rs
+++ b/dhall_syntax/src/printer.rs
@@ -378,12 +378,12 @@ impl<SubExpr: Display> Display for Import<SubExpr> {
};
write!(f, "{}/", prefix)?;
let path: String =
- path.iter().map(|c| quote_if_needed(&*c)).join("/");
+ path.file_path.iter().map(|c| quote_if_needed(&*c)).join("/");
f.write_str(&path)?;
}
Remote(url) => {
write!(f, "{}://{}/", url.scheme, url.authority,)?;
- let path: String = url.path.iter().join("/");
+ let path: String = url.path.file_path.iter().join("/");
f.write_str(&path)?;
if let Some(q) = &url.query {
write!(f, "?{}", q)?