diff options
author | Nadrieril | 2020-12-06 17:26:50 +0000 |
---|---|---|
committer | Nadrieril | 2020-12-06 17:57:08 +0000 |
commit | 66dcbc5a6142693e79f89a837a3145ac6f810d3c (patch) | |
tree | cb9318ef89b1cd32e41279aa4fdda2cfc336bddc | |
parent | 980349dff0aaaa6ed34ae78d53ff57b67d7629d5 (diff) |
Prepare `ImportLocation` for more fields
-rw-r--r-- | dhall/src/semantics/parse.rs | 19 | ||||
-rw-r--r-- | dhall/src/semantics/resolve/resolve.rs | 101 | ||||
-rw-r--r-- | dhall/tests/import/failure/cycle.txt | 2 |
3 files changed, 83 insertions, 39 deletions
diff --git a/dhall/src/semantics/parse.rs b/dhall/src/semantics/parse.rs index a770c15..fa7ba18 100644 --- a/dhall/src/semantics/parse.rs +++ b/dhall/src/semantics/parse.rs @@ -2,7 +2,9 @@ use std::path::Path; use url::Url; use crate::error::Error; -use crate::semantics::resolve::{download_http_text, ImportLocation}; +use crate::semantics::resolve::{ + download_http_text, ImportLocation, ImportLocationKind, +}; use crate::syntax::binary; use crate::syntax::parse_expr; use crate::Parsed; @@ -10,32 +12,37 @@ use crate::Parsed; pub fn parse_file(f: &Path) -> Result<Parsed, Error> { let text = std::fs::read_to_string(f)?; let expr = parse_expr(&text)?; - let root = ImportLocation::Local(f.to_owned()); + let root_kind = ImportLocationKind::Local(f.to_owned()); + let root = ImportLocation { kind: root_kind }; Ok(Parsed(expr, root)) } pub fn parse_remote(url: Url) -> Result<Parsed, Error> { let body = download_http_text(url.clone())?; let expr = parse_expr(&body)?; - let root = ImportLocation::Remote(url); + let root_kind = ImportLocationKind::Remote(url); + let root = ImportLocation { kind: root_kind }; Ok(Parsed(expr, root)) } pub fn parse_str(s: &str) -> Result<Parsed, Error> { let expr = parse_expr(s)?; - let root = ImportLocation::Missing; + let root_kind = ImportLocationKind::Missing; + let root = ImportLocation { kind: root_kind }; Ok(Parsed(expr, root)) } pub fn parse_binary(data: &[u8]) -> Result<Parsed, Error> { let expr = binary::decode(data)?; - let root = ImportLocation::Missing; + let root_kind = ImportLocationKind::Missing; + let root = ImportLocation { kind: root_kind }; Ok(Parsed(expr, root)) } pub fn parse_binary_file(f: &Path) -> Result<Parsed, Error> { let data = crate::utils::read_binary_file(f)?; let expr = binary::decode(&data)?; - let root = ImportLocation::Local(f.to_owned()); + let root_kind = ImportLocationKind::Local(f.to_owned()); + let root = ImportLocation { kind: root_kind }; Ok(Parsed(expr, root)) } diff --git a/dhall/src/semantics/resolve/resolve.rs b/dhall/src/semantics/resolve/resolve.rs index dc1951e..7838eb9 100644 --- a/dhall/src/semantics/resolve/resolve.rs +++ b/dhall/src/semantics/resolve/resolve.rs @@ -20,9 +20,8 @@ use crate::{Parsed, Resolved, Typed}; // TODO: evaluate import headers pub type Import = syntax::Import<()>; -/// The location of some data, usually some dhall code. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ImportLocation { +pub enum ImportLocationKind { /// Local file Local(PathBuf), /// Remote file @@ -33,7 +32,13 @@ pub enum ImportLocation { Missing, } -impl ImportLocation { +/// The location of some data, usually some dhall code. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ImportLocation { + pub kind: ImportLocationKind, +} + +impl ImportLocationKind { /// Given an import pointing to `target` found in the current location, compute the next /// location, or error if not allowed. /// `sanity_check` indicates whether to check if that location is allowed to be referenced, @@ -42,14 +47,14 @@ impl ImportLocation { &self, target: &ImportTarget<()>, sanity_check: bool, - ) -> Result<ImportLocation, Error> { + ) -> Result<Self, Error> { Ok(match target { ImportTarget::Local(prefix, path) => { self.chain_local(*prefix, path)? } ImportTarget::Remote(remote) => { if sanity_check { - if let ImportLocation::Remote(..) = self { + if let ImportLocationKind::Remote(..) = self { // TODO: allow if CORS check passes return Err(ImportError::SanityCheck.into()); } @@ -60,17 +65,17 @@ impl ImportLocation { ))?; url.set_path(&remote.path.file_path.iter().join("/")); url.set_query(remote.query.as_ref().map(String::as_ref)); - ImportLocation::Remote(url) + ImportLocationKind::Remote(url) } ImportTarget::Env(var_name) => { if sanity_check { - if let ImportLocation::Remote(..) = self { + if let ImportLocationKind::Remote(..) = self { return Err(ImportError::SanityCheck.into()); } } - ImportLocation::Env(var_name.clone()) + ImportLocationKind::Env(var_name.clone()) } - ImportTarget::Missing => ImportLocation::Missing, + ImportTarget::Missing => ImportLocationKind::Missing, }) } @@ -78,18 +83,17 @@ impl ImportLocation { &self, prefix: FilePrefix, path: &FilePath, - ) -> Result<ImportLocation, Error> { + ) -> Result<Self, Error> { Ok(match self { - ImportLocation::Local(..) - | ImportLocation::Env(..) - | ImportLocation::Missing => { + ImportLocationKind::Local(..) + | ImportLocationKind::Env(..) + | ImportLocationKind::Missing => { let dir = match self { - ImportLocation::Local(path) => { + ImportLocationKind::Local(path) => { path.parent().unwrap().to_owned() } - ImportLocation::Env(..) | ImportLocation::Missing => { - std::env::current_dir()? - } + ImportLocationKind::Env(..) + | ImportLocationKind::Missing => std::env::current_dir()?, _ => unreachable!(), }; let mut dir: Vec<String> = dir @@ -120,9 +124,9 @@ impl ImportLocation { }; let path = Some(prefix.to_string()).into_iter().chain(path).collect(); - ImportLocation::Local(path) + ImportLocationKind::Local(path) } - ImportLocation::Remote(url) => { + ImportLocationKind::Remote(url) => { let mut url = url.clone(); match prefix { FilePrefix::Here => {} @@ -133,46 +137,52 @@ impl ImportLocation { FilePrefix::Home => panic!("error"), } url = url.join(&path.file_path.join("/"))?; - ImportLocation::Remote(url) + ImportLocationKind::Remote(url) } }) } fn fetch_dhall(self) -> Result<Parsed, Error> { Ok(match self { - ImportLocation::Local(path) => Parsed::parse_file(&path)?, - ImportLocation::Remote(url) => Parsed::parse_remote(url)?, - ImportLocation::Env(var_name) => { + ImportLocationKind::Local(path) => Parsed::parse_file(&path)?, + ImportLocationKind::Remote(url) => Parsed::parse_remote(url)?, + ImportLocationKind::Env(var_name) => { let val = match env::var(var_name) { Ok(val) => val, Err(_) => return Err(ImportError::MissingEnvVar.into()), }; Parsed::parse_str(&val)? } - ImportLocation::Missing => return Err(ImportError::Missing.into()), + ImportLocationKind::Missing => { + return Err(ImportError::Missing.into()) + } }) } fn fetch_text(self) -> Result<String, Error> { Ok(match self { - ImportLocation::Local(path) => std::fs::read_to_string(&path)?, - ImportLocation::Remote(url) => download_http_text(url)?, - ImportLocation::Env(var_name) => match env::var(var_name) { + ImportLocationKind::Local(path) => std::fs::read_to_string(&path)?, + ImportLocationKind::Remote(url) => download_http_text(url)?, + ImportLocationKind::Env(var_name) => match env::var(var_name) { Ok(val) => val, Err(_) => return Err(ImportError::MissingEnvVar.into()), }, - ImportLocation::Missing => return Err(ImportError::Missing.into()), + ImportLocationKind::Missing => { + return Err(ImportError::Missing.into()) + } }) } fn into_location(self) -> Expr { let (field_name, arg) = match self { - ImportLocation::Local(path) => { + ImportLocationKind::Local(path) => { ("Local", Some(path.to_string_lossy().into_owned())) } - ImportLocation::Remote(url) => ("Remote", Some(url.into_string())), - ImportLocation::Env(name) => ("Environment", Some(name)), - ImportLocation::Missing => ("Missing", None), + ImportLocationKind::Remote(url) => { + ("Remote", Some(url.into_string())) + } + ImportLocationKind::Env(name) => ("Environment", Some(name)), + ImportLocationKind::Missing => ("Missing", None), }; let asloc_ty = make_aslocation_uniontype(); @@ -188,6 +198,33 @@ impl ImportLocation { } } +impl ImportLocation { + /// Given an import pointing to `target` found in the current location, compute the next + /// location, or error if not allowed. + /// `sanity_check` indicates whether to check if that location is allowed to be referenced, + /// for example to prevent a remote file from reading an environment variable. + fn chain( + &self, + target: &ImportTarget<()>, + sanity_check: bool, + ) -> Result<ImportLocation, Error> { + let kind = self.kind.chain(target, sanity_check)?; + Ok(ImportLocation { kind }) + } + + fn fetch_dhall(self) -> Result<Parsed, Error> { + self.kind.fetch_dhall() + } + + fn fetch_text(self) -> Result<String, Error> { + self.kind.fetch_text() + } + + fn into_location(self) -> Expr { + self.kind.into_location() + } +} + fn mkexpr(kind: UnspannedExpr) -> Expr { Expr::new(kind, Span::Artificial) } diff --git a/dhall/tests/import/failure/cycle.txt b/dhall/tests/import/failure/cycle.txt index 899484b..a103312 100644 --- a/dhall/tests/import/failure/cycle.txt +++ b/dhall/tests/import/failure/cycle.txt @@ -10,7 +10,7 @@ Type error: error: error --> <current file>:1:1 | 1 | ../data/cycle.dhall - | ^^^^^^^^^^^^^^^^^^^ ImportCycle([Local("./dhall-lang/tests/import/data/cycle.dhall"), Local("./dhall-lang/tests/import/failure/cycle.dhall")], Local("./dhall-lang/tests/import/data/cycle.dhall")) + | ^^^^^^^^^^^^^^^^^^^ ImportCycle([ImportLocation { kind: Local("./dhall-lang/tests/import/data/cycle.dhall") }, ImportLocation { kind: Local("./dhall-lang/tests/import/failure/cycle.dhall") }], ImportLocation { kind: Local("./dhall-lang/tests/import/data/cycle.dhall") }) | | | |