summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dhall/src/expr.rs30
-rw-r--r--dhall/src/imports.rs95
-rw-r--r--dhall/tests/common/mod.rs9
-rw-r--r--dhall_core/src/core.rs39
4 files changed, 122 insertions, 51 deletions
diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs
index 0d093cb..72633ea 100644
--- a/dhall/src/expr.rs
+++ b/dhall/src/expr.rs
@@ -1,17 +1,27 @@
+use crate::imports::ImportError;
+use crate::imports::ImportRoot;
use crate::typecheck::TypeError;
use dhall_core::*;
-pub struct Parsed(SubExpr<X, Import>);
-pub struct Resolved(SubExpr<X, X>);
-pub struct Typed(SubExpr<X, X>, Type);
-pub struct Type(Box<Normalized>);
-pub struct Normalized(SubExpr<X, X>);
+#[derive(Debug, Clone)]
+pub struct Parsed(pub(crate) SubExpr<X, Import>, pub(crate) ImportRoot);
+#[derive(Debug, Clone)]
+pub struct Resolved(pub(crate) SubExpr<X, X>);
+#[derive(Debug, Clone)]
+pub struct Typed(pub(crate) SubExpr<X, X>, Type);
+#[derive(Debug, Clone)]
+pub struct Type(pub(crate) Box<Normalized>);
+#[derive(Debug, Clone)]
+pub struct Normalized(pub(crate) SubExpr<X, X>);
-// impl Parsed {
-// pub fn resolve(self) -> Result<Resolved, ImportError> {
-// Ok(Resolved(crate::imports::resolve(self.0)?))
-// }
-// }
+impl Parsed {
+ pub fn resolve(self) -> Result<Resolved, ImportError> {
+ crate::imports::resolve_expr(self, true)
+ }
+ pub fn resolve_no_imports(self) -> Result<Resolved, ImportError> {
+ crate::imports::resolve_expr(self, false)
+ }
+}
impl Resolved {
pub fn typecheck(self) -> Result<Typed, TypeError<X>> {
let typ = Type(Box::new(Normalized(crate::typecheck::type_of(
diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs
index 95cf6fa..bc38bb6 100644
--- a/dhall/src/imports.rs
+++ b/dhall/src/imports.rs
@@ -1,6 +1,7 @@
// use dhall_core::{Expr, FilePrefix, Import, ImportLocation, ImportMode, X};
use dhall_core::{Expr, Import, X};
// use std::path::Path;
+use crate::expr::*;
use dhall_core::*;
use std::fmt;
use std::fs::File;
@@ -8,6 +9,34 @@ use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
+#[derive(Debug)]
+pub enum ImportError {
+ ParseError(ParseError),
+ IOError(std::io::Error),
+ UnexpectedImportError(Import),
+}
+impl From<ParseError> for ImportError {
+ fn from(e: ParseError) -> Self {
+ ImportError::ParseError(e)
+ }
+}
+impl From<std::io::Error> for ImportError {
+ fn from(e: std::io::Error) -> Self {
+ ImportError::IOError(e)
+ }
+}
+impl fmt::Display for ImportError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ use self::ImportError::*;
+ match self {
+ ParseError(e) => e.fmt(f),
+ IOError(e) => e.fmt(f),
+ UnexpectedImportError(e) => e.fmt(f),
+ }
+ }
+}
+
+// Deprecated
pub fn panic_imports<S: Clone>(expr: &Expr<S, Import>) -> Expr<S, X> {
let no_import = |i: &Import| -> X { panic!("ahhh import: {:?}", i) };
expr.map_embed(&no_import)
@@ -42,55 +71,43 @@ fn resolve_import(
}
}
-#[derive(Debug)]
-pub enum ImportError {
- ParseError(ParseError),
- IOError(std::io::Error),
-}
-impl From<ParseError> for ImportError {
- fn from(e: ParseError) -> Self {
- ImportError::ParseError(e)
- }
-}
-impl From<std::io::Error> for ImportError {
- fn from(e: std::io::Error) -> Self {
- ImportError::IOError(e)
- }
-}
-impl fmt::Display for ImportError {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- use self::ImportError::*;
- match self {
- ParseError(e) => e.fmt(f),
- IOError(e) => e.fmt(f),
+pub(crate) fn resolve_expr(
+ Parsed(expr, root): Parsed,
+ allow_imports: bool,
+) -> Result<Resolved, ImportError> {
+ let resolve = |import: &Import| -> Result<SubExpr<X, X>, ImportError> {
+ if allow_imports {
+ let expr = resolve_import(import, &root)?;
+ Ok(expr.roll())
+ } else {
+ Err(ImportError::UnexpectedImportError(import.clone()))
}
- }
+ };
+ let expr = expr.as_ref().traverse_embed(&resolve)?;
+ Ok(Resolved(expr.squash_embed()))
+}
+
+pub fn load_from_file(f: &Path) -> Result<Parsed, ImportError> {
+ let mut buffer = String::new();
+ File::open(f)?.read_to_string(&mut buffer)?;
+ let expr = parse_expr(&*buffer)?;
+ let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned());
+ Ok(Parsed(expr, root))
}
+// Deprecated
pub fn load_dhall_file(
f: &Path,
resolve_imports: bool,
) -> Result<Expr<X, X>, ImportError> {
- let mut buffer = String::new();
- File::open(f)?.read_to_string(&mut buffer)?;
- let expr = parse_expr(&*buffer)?;
- let expr = if resolve_imports {
- let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned());
- let resolve = |import: &Import| -> Expr<X, X> {
- resolve_import(import, &root).unwrap()
- };
- expr.as_ref().map_embed(&resolve).squash_embed()
- } else {
- panic_imports(expr.as_ref())
- };
- Ok(expr)
+ let expr = load_from_file(f)?;
+ let expr = resolve_expr(expr, resolve_imports)?;
+ Ok(expr.0.unroll())
}
+// Deprecated
pub fn load_dhall_file_no_resolve_imports(
f: &Path,
) -> Result<ParsedExpr, ImportError> {
- let mut buffer = String::new();
- File::open(f)?.read_to_string(&mut buffer)?;
- let expr = parse_expr(&*buffer)?;
- Ok(expr)
+ Ok(load_from_file(f)?.0)
}
diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs
index e748cf0..70b7d81 100644
--- a/dhall/tests/common/mod.rs
+++ b/dhall/tests/common/mod.rs
@@ -54,6 +54,12 @@ pub fn read_dhall_file_no_resolve_imports<'i>(
load_dhall_file_no_resolve_imports(&PathBuf::from(file_path))
}
+pub fn load_from_file_str<'i>(
+ file_path: &str,
+) -> Result<dhall::Parsed, ImportError> {
+ load_from_file(&PathBuf::from(file_path))
+}
+
pub fn run_test(base_path: &str, feature: Feature) {
use self::Feature::*;
let base_path_prefix = match feature {
@@ -90,8 +96,7 @@ pub fn run_test(base_path: &str, feature: Feature) {
}
ParserFailure => {
let file_path = base_path + ".dhall";
- let err =
- read_dhall_file_no_resolve_imports(&file_path).unwrap_err();
+ let err = load_from_file_str(&file_path).unwrap_err();
match err {
ImportError::ParseError(_) => {}
e => panic!("Expected parse error, got: {:?}", e),
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs
index a56c5a3..d832cd5 100644
--- a/dhall_core/src/core.rs
+++ b/dhall_core/src/core.rs
@@ -285,6 +285,28 @@ impl<S, A> Expr<S, A> {
self.map_shallow(recurse, |x| x.clone(), map_embed, |x| x.clone())
}
+ #[inline(always)]
+ pub fn traverse_embed<B, Err, F>(
+ &self,
+ map_embed: &F,
+ ) -> Result<Expr<S, B>, Err>
+ where
+ S: Clone,
+ B: Clone,
+ F: Fn(&A) -> Result<B, Err>,
+ {
+ let recurse = |e: &SubExpr<S, A>| -> Result<SubExpr<S, B>, Err> {
+ Ok(e.as_ref().traverse_embed(map_embed)?.roll())
+ };
+ self.as_ref().traverse(
+ |e| recurse(e),
+ |_, e| recurse(e),
+ |x| Ok(S::clone(x)),
+ map_embed,
+ |x| Ok(Label::clone(x)),
+ )
+ }
+
pub fn map_label<F>(&self, map_label: &F) -> Self
where
A: Clone,
@@ -319,6 +341,23 @@ impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> {
}
}
+impl<S: Clone, A: Clone> Expr<S, SubExpr<S, A>> {
+ pub fn squash_embed(&self) -> SubExpr<S, A> {
+ match self.as_ref() {
+ ExprF::Embed(e) => e.clone(),
+ e => e
+ .map(
+ |e| e.as_ref().squash_embed(),
+ |_, e| e.as_ref().squash_embed(),
+ S::clone,
+ |_| unreachable!(),
+ Label::clone,
+ )
+ .roll(),
+ }
+ }
+}
+
impl<SE, L, N, E> ExprF<SE, L, N, E> {
#[inline(always)]
pub fn as_ref(&self) -> ExprF<&SE, &L, &N, &E>