summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2020-12-06 17:26:50 +0000
committerNadrieril2020-12-06 17:57:08 +0000
commit66dcbc5a6142693e79f89a837a3145ac6f810d3c (patch)
treecb9318ef89b1cd32e41279aa4fdda2cfc336bddc
parent980349dff0aaaa6ed34ae78d53ff57b67d7629d5 (diff)
Prepare `ImportLocation` for more fields
-rw-r--r--dhall/src/semantics/parse.rs19
-rw-r--r--dhall/src/semantics/resolve/resolve.rs101
-rw-r--r--dhall/tests/import/failure/cycle.txt2
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") })
|
|
|