diff options
Diffstat (limited to 'dhall_syntax')
-rw-r--r-- | dhall_syntax/src/core/import.rs | 78 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 22 | ||||
-rw-r--r-- | dhall_syntax/src/printer.rs | 4 |
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)? |