From 405bc3d80c0e169ea74dd12422b9504b7383dab3 Mon Sep 17 00:00:00 2001 From: FintanH Date: Mon, 12 Aug 2019 22:22:24 +0100 Subject: Refactor of File to be the combination of Directory and the file name, where Directory is the Vector of component paths. The refactor meant changing some sections of the code where we were parsing and manipulating Files/Directories. This also includes a new trait Canonicalization which is needed for import logic. --- dhall_syntax/src/core/import.rs | 122 +++++++++++++++++++++++++++++++++++++++- dhall_syntax/src/parser.rs | 41 +++++++++----- dhall_syntax/src/printer.rs | 10 ++-- 3 files changed, 154 insertions(+), 19 deletions(-) (limited to 'dhall_syntax') diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs index c328e34..ea42dbc 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall_syntax/src/core/import.rs @@ -11,10 +11,41 @@ pub enum FilePrefix { Home, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Directory { + pub components: Vec, +} + +impl IntoIterator for Directory { + type Item = String; + type IntoIter = ::std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.components.into_iter() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct File { + pub directory: Directory, + pub file: String, +} + +impl IntoIterator for File { + type Item = String; + type IntoIter = ::std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let mut paths = self.directory.components; + paths.push(self.file); + paths.into_iter() + } +} + /// The location of import (i.e. local vs. remote vs. environment) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ImportLocation { - Local(FilePrefix, Vec), + Local(FilePrefix, File), Remote(URL), Env(String), Missing, @@ -24,7 +55,7 @@ pub enum ImportLocation { pub struct URL { pub scheme: Scheme, pub authority: String, - pub path: Vec, + pub path: File, pub query: Option, pub headers: Option>, } @@ -59,3 +90,90 @@ pub struct Import { pub mode: ImportMode, pub location_hashed: ImportHashed, } + +pub trait Canonicalize { + fn canonicalize(&self) -> Self; +} + +impl Canonicalize for Directory { + fn canonicalize(&self) -> Directory { + let mut components = Vec::new(); + let mut dir_components = self.clone().into_iter(); + + loop { + let component = dir_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 dir_components.next() { + // canonicalize(directory₀) = ε + // ──────────────────────────── + // canonicalize(directory₀/..) = /.. + None => components.push("..".to_string()), + + // canonicalize(directory₀) = directory₁/.. + // ────────────────────────────────────────────── + // canonicalize(directory₀/..) = directory₁/../.. + Some(ref c) if c == ".." => { + components.push("..".to_string()); + components.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) => components.push(c.clone()), + } + } + + Directory { components: components } + } +} + +impl Canonicalize for File { + fn canonicalize(&self) -> File { + File { directory: self.directory.canonicalize(), file: self.file.clone() } + } +} + +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().map(|boxed_hash| Box::new(boxed_hash.canonicalize())), + }), + ImportLocation::Env(name) => ImportLocation::Env(name.to_string()), + ImportLocation::Missing => ImportLocation::Missing, + } + } +} + +impl Canonicalize for ImportHashed { + fn canonicalize(&self) -> ImportHashed { + ImportHashed { hash: self.hash.clone(), location: self.location.canonicalize() } + } +} + +impl Canonicalize for Import { + fn canonicalize(&self) -> Import { + Import { mode: self.mode, location_hashed: self.location_hashed.canonicalize() } + } +} diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 9d9a374..7675622 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -146,6 +146,14 @@ fn debug_pair(pair: Pair) -> String { s } +fn to_file(path: Vec) -> Result { + let mut path = path; + let file_name: Option = path.pop(); + let file = file_name.ok_or("Empty file path was provided")?; + let directory = Directory { components: path }; + Ok(File { directory: directory, file: file }) +} + macro_rules! make_parser { (@pattern, rule, $name:ident) => (Rule::$name); (@pattern, token_rule, $name:ident) => (Rule::$name); @@ -589,19 +597,25 @@ make_parser! { }); rule!(http_raw; children!( - [scheme(sch), authority(auth), path(p)] => URL { - scheme: sch, - authority: auth, - path: p, - query: None, - headers: None, + [scheme(sch), authority(auth), path(p)] => { + let file = to_file(p)?; + URL { + scheme: sch, + authority: auth, + path: file, + query: None, + headers: None, + } }, - [scheme(sch), authority(auth), path(p), query(q)] => URL { - scheme: sch, - authority: auth, - path: p, - query: Some(q), - headers: None, + [scheme(sch), authority(auth), path(p), query(q)] => { + let file = to_file(p)?; + URL { + scheme: sch, + authority: auth, + path: file, + query: Some(q), + headers: None, + } }, )); @@ -655,7 +669,8 @@ make_parser! { ImportLocation::Remote(url) }, [local((prefix, p))] => { - ImportLocation::Local(prefix, p) + let file = to_file(p)?; + ImportLocation::Local(prefix, file) }, )); diff --git a/dhall_syntax/src/printer.rs b/dhall_syntax/src/printer.rs index dbed55d..8503a1e 100644 --- a/dhall_syntax/src/printer.rs +++ b/dhall_syntax/src/printer.rs @@ -380,17 +380,19 @@ impl Display for ImportHashed { Absolute => "", }; write!(f, "{}/", prefix)?; - let path: String = path - .iter() + let full_path: String = path + .clone() + .into_iter() .map(|c| fmt_local_path_component(c.as_ref())) .join("/"); - f.write_str(&path)?; + f.write_str(&full_path)?; } Remote(url) => { write!(f, "{}://{}/", url.scheme, url.authority,)?; let path: String = url .path - .iter() + .clone() + .into_iter() .map(|c| fmt_remote_path_component(c.as_ref())) .join("/"); f.write_str(&path)?; -- cgit v1.2.3 From e73f822b6972e8fa2e72b56ff5378b91bea1a5e6 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Mon, 2 Sep 2019 21:17:00 +0100 Subject: Remove the notion of Directory and have File be the vector of components --- dhall_syntax/src/core/import.rs | 49 +++++++++++------------------------------ dhall_syntax/src/parser.rs | 23 +++++-------------- 2 files changed, 19 insertions(+), 53 deletions(-) (limited to 'dhall_syntax') diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs index 82bb7ff..4aad70d 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall_syntax/src/core/import.rs @@ -11,24 +11,9 @@ pub enum FilePrefix { Home, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Directory { - pub components: Vec, -} - -impl IntoIterator for Directory { - type Item = String; - type IntoIter = ::std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.components.into_iter() - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct File { - pub directory: Directory, - pub file: String, + pub file_path: Vec, } impl IntoIterator for File { @@ -36,9 +21,7 @@ impl IntoIterator for File { type IntoIter = ::std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - let mut paths = self.directory.components; - paths.push(self.file); - paths.into_iter() + self.file_path.into_iter() } } @@ -97,13 +80,13 @@ pub trait Canonicalize { fn canonicalize(&self) -> Self; } -impl Canonicalize for Directory { - fn canonicalize(&self) -> Directory { - let mut components = Vec::new(); - let mut dir_components = self.clone().into_iter(); +impl Canonicalize for File { + fn canonicalize(&self) -> File { + let mut file_path = Vec::new(); + let mut file_path_components = self.clone().into_iter(); loop { - let component = dir_components.next(); + let component = file_path_components.next(); match component.as_ref() { // ─────────────────── // canonicalize(ε) = ε @@ -114,18 +97,18 @@ impl Canonicalize for Directory { // canonicalize(directory₀/.) = directory₁ Some(c) if c == "." => continue, - Some(c) if c == ".." => match dir_components.next() { + Some(c) if c == ".." => match file_path_components.next() { // canonicalize(directory₀) = ε // ──────────────────────────── // canonicalize(directory₀/..) = /.. - None => components.push("..".to_string()), + None => file_path.push("..".to_string()), // canonicalize(directory₀) = directory₁/.. // ────────────────────────────────────────────── // canonicalize(directory₀/..) = directory₁/../.. Some(ref c) if c == ".." => { - components.push("..".to_string()); - components.push("..".to_string()); + file_path.push("..".to_string()); + file_path.push("..".to_string()); }, // canonicalize(directory₀) = directory₁/component @@ -137,17 +120,11 @@ impl Canonicalize for Directory { // canonicalize(directory₀) = directory₁ // ───────────────────────────────────────────────────────── ; If no other // canonicalize(directory₀/component) = directory₁/component ; rule matches - Some(c) => components.push(c.clone()), + Some(c) => file_path.push(c.clone()), } } - Directory { components: components } - } -} - -impl Canonicalize for File { - fn canonicalize(&self) -> File { - File { directory: self.directory.canonicalize(), file: self.file.clone() } + File { file_path } } } diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index a2495ee..71d0936 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -147,14 +147,6 @@ fn debug_pair(pair: Pair) -> String { s } -fn to_file(path: Vec) -> Result { - let mut path = path; - let file_name: Option = path.pop(); - let file = file_name.ok_or("Empty file path was provided")?; - let directory = Directory { components: path }; - Ok(File { directory: directory, file: file }) -} - macro_rules! make_parser { (@pattern, rule, $name:ident) => (Rule::$name); (@pattern, token_rule, $name:ident) => (Rule::$name); @@ -638,22 +630,20 @@ make_parser! { }); rule!(http_raw; children!( - [scheme(sch), authority(auth), path(p)] => { - let file = to_file(p)?; + [scheme(sch), authority(auth), path(file_path)] => { URL { scheme: sch, authority: auth, - path: file, + path: File { file_path }, query: None, headers: None, } }, - [scheme(sch), authority(auth), path(p), query(q)] => { - let file = to_file(p)?; + [scheme(sch), authority(auth), path(file_path), query(q)] => { URL { scheme: sch, authority: auth, - path: file, + path: File { file_path }, query: Some(q), headers: None, } @@ -709,9 +699,8 @@ make_parser! { [http(url)] => { ImportLocation::Remote(url) }, - [local((prefix, p))] => { - let file = to_file(p)?; - ImportLocation::Local(prefix, file) + [local((prefix, file_path))] => { + ImportLocation::Local(prefix, File { file_path }) }, )); -- cgit v1.2.3 From eae1eac7048cd87d2775cdc470a295b9d2ee7346 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Tue, 3 Sep 2019 13:56:55 +0100 Subject: No need for as_ref call --- dhall_syntax/src/core/import.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dhall_syntax') diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs index ef696b9..5e0ff6c 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall_syntax/src/core/import.rs @@ -116,7 +116,7 @@ impl Canonicalize for File { loop { let component = file_path_components.next(); - match component.as_ref() { + match component { // ─────────────────── // canonicalize(ε) = ε None => break, -- cgit v1.2.3 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_syntax/src/core/import.rs | 75 ++--------------------------------------- dhall_syntax/src/parser.rs | 6 ++-- 2 files changed, 6 insertions(+), 75 deletions(-) (limited to 'dhall_syntax') diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs index 5e0ff6c..cc38bb0 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall_syntax/src/core/import.rs @@ -12,14 +12,14 @@ pub enum FilePrefix { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct File { +pub struct FilePath { pub file_path: Vec, } /// The location of import (i.e. local vs. remote vs. environment) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ImportLocation { - Local(FilePrefix, File), + Local(FilePrefix, FilePath), Remote(URL), Env(String), Missing, @@ -29,7 +29,7 @@ pub enum ImportLocation { pub struct URL { pub scheme: Scheme, pub authority: String, - pub path: File, + pub path: FilePath, pub query: Option, pub headers: Option, } @@ -104,72 +104,3 @@ impl Import { }) } } - -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 { - // ─────────────────── - // 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 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, - } - } -} diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index b70a236..52b3760 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -729,7 +729,7 @@ make_parser! { [scheme(sch), authority(auth), path(file_path)] => URL { scheme: sch, authority: auth, - path: File { file_path }, + path: FilePath { file_path }, query: None, headers: None, }, @@ -737,7 +737,7 @@ make_parser! { URL { scheme: sch, authority: auth, - path: File { file_path }, + path: FilePath { file_path }, query: Some(q), headers: None, } @@ -794,7 +794,7 @@ make_parser! { ImportLocation::Remote(url) }, [local((prefix, file_path))] => { - ImportLocation::Local(prefix, File { file_path }) + ImportLocation::Local(prefix, FilePath { file_path }) }, )); -- cgit v1.2.3