From 4edaf0814868e604eed5cfd594ea3f448ca90678 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Tue, 3 Sep 2019 14:42:30 +0100 Subject: Move Canonicalize into resolve. Rename File to FilePath and have more consistent naming. --- dhall/src/phase/binary.rs | 10 +++---- dhall/src/phase/resolve.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) (limited to 'dhall') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 16e7ce9..3c45e81 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -6,7 +6,7 @@ use std::vec; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ rc, Expr, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, - Integer, InterpolatedText, Label, Natural, Scheme, URL, V, File + Integer, InterpolatedText, Label, Natural, Scheme, URL, V, FilePath }; use crate::error::{DecodeError, EncodeError}; @@ -279,7 +279,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { "import/remote/query".to_owned(), ))?, }; - let file_path: Vec<_> = rest + let file_path = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -287,7 +287,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { )), }) .collect::>()?; - let path = File { file_path }; + let path = FilePath { file_path }; ImportLocation::Remote(URL { scheme, authority, @@ -306,7 +306,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { "import/local/prefix".to_owned(), ))?, }; - let file_path: Vec<_> = rest + let file_path = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -314,7 +314,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { )), }) .collect::>()?; - let path = File { file_path }; + let path = FilePath { file_path }; ImportLocation::Local(prefix, path) } 6 => { diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index 5bde68a..54a0f27 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; use crate::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; +use dhall_syntax::{FilePath, ImportLocation, URL}; type Import = dhall_syntax::Import; @@ -105,6 +106,75 @@ pub(crate) fn skip_resolve_expr( Ok(Resolved(expr)) } +pub trait Canonicalize { + fn canonicalize(&self) -> Self; +} + +impl Canonicalize for FilePath { + fn canonicalize(&self) -> FilePath { + 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()), + } + } + + FilePath { file_path } + } +} + +impl Canonicalize for ImportLocation { + fn canonicalize(&self) -> ImportLocation { + 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, + } + } +} + #[cfg(test)] #[rustfmt::skip] mod spec_tests { -- cgit v1.2.3