summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall/src/imports.rs46
-rw-r--r--dhall_core/src/import.rs16
2 files changed, 42 insertions, 20 deletions
diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs
index ff28ab2..0078040 100644
--- a/dhall/src/imports.rs
+++ b/dhall/src/imports.rs
@@ -1,6 +1,7 @@
use crate::error::Error;
use crate::expr::*;
use dhall_core::*;
+use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::Path;
@@ -18,9 +19,12 @@ pub enum ImportRoot {
LocalDir(PathBuf),
}
+type ImportCache = HashMap<Import, Normalized<'static>>;
+
fn resolve_import(
import: &Import,
root: &ImportRoot,
+ import_cache: &mut ImportCache,
) -> Result<Normalized<'static>, ImportError> {
use self::ImportRoot::*;
use dhall_core::FilePrefix::*;
@@ -36,7 +40,7 @@ fn resolve_import(
Here => cwd.join(path),
_ => unimplemented!("{:?}", import),
};
- Ok(load_import(&path).map_err(|e| {
+ Ok(load_import(&path, import_cache).map_err(|e| {
ImportError::Recursive(import.clone(), Box::new(e))
})?)
}
@@ -44,23 +48,41 @@ fn resolve_import(
}
}
-fn load_import(f: &Path) -> Result<Normalized<'static>, Error> {
- Ok(Parsed::parse_file(f)?.resolve()?.typecheck()?.normalize())
+fn load_import(
+ f: &Path,
+ import_cache: &mut ImportCache,
+) -> Result<Normalized<'static>, Error> {
+ Ok(resolve_expr_imports(Parsed::parse_file(f)?, import_cache)?
+ .typecheck()?
+ .normalize())
}
-fn resolve_expr<'a>(
+fn resolve_expr_imports<'a>(
Parsed(expr, root): Parsed<'a>,
- allow_imports: bool,
+ import_cache: &mut ImportCache,
) -> Result<Resolved<'a>, ImportError> {
let resolve =
|import: &Import| -> Result<Normalized<'static>, ImportError> {
- if allow_imports {
- let expr = resolve_import(import, &root)?;
- Ok(expr)
- } else {
- Err(ImportError::UnexpectedImport(import.clone()))
+ match import_cache.get(import) {
+ Some(expr) => Ok(expr.clone()),
+ None => {
+ let expr = resolve_import(import, &root, import_cache)?;
+ import_cache.insert(import.clone(), expr.clone());
+ Ok(expr)
+ }
}
};
+ let expr = expr.as_ref().traverse_embed(resolve)?;
+ Ok(Resolved(rc(expr)))
+}
+
+fn resolve_expr<'a>(
+ Parsed(expr, _root): Parsed<'a>,
+) -> Result<Resolved<'a>, ImportError> {
+ let resolve =
+ |import: &Import| -> Result<Normalized<'static>, ImportError> {
+ Err(ImportError::UnexpectedImport(import.clone()))
+ };
let expr = expr.as_ref().traverse_embed(&resolve)?;
Ok(Resolved(rc(expr)))
}
@@ -90,11 +112,11 @@ impl<'a> Parsed<'a> {
}
pub fn resolve(self) -> Result<Resolved<'a>, ImportError> {
- crate::imports::resolve_expr(self, true)
+ crate::imports::resolve_expr_imports(self, &mut HashMap::new())
}
#[allow(dead_code)]
pub fn skip_resolve(self) -> Result<Resolved<'a>, ImportError> {
- crate::imports::resolve_expr(self, false)
+ crate::imports::resolve_expr(self)
}
}
diff --git a/dhall_core/src/import.rs b/dhall_core/src/import.rs
index f039953..00f293c 100644
--- a/dhall_core/src/import.rs
+++ b/dhall_core/src/import.rs
@@ -1,7 +1,7 @@
use std::path::PathBuf;
/// The beginning of a file path which anchors subsequent path components
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FilePrefix {
/// Absolute path
Absolute,
@@ -14,7 +14,7 @@ pub enum FilePrefix {
}
/// The location of import (i.e. local vs. remote vs. environment)
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ImportLocation {
Local(FilePrefix, PathBuf),
Remote(URL),
@@ -22,7 +22,7 @@ pub enum ImportLocation {
Missing,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct URL {
pub scheme: Scheme,
pub authority: String,
@@ -31,33 +31,33 @@ pub struct URL {
pub headers: Option<Box<ImportHashed>>,
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Scheme {
HTTP,
HTTPS,
}
/// How to interpret the import's contents (i.e. as Dhall code or raw text)
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ImportMode {
Code,
RawText,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Hash {
pub protocol: String,
pub hash: String,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ImportHashed {
pub location: ImportLocation,
pub hash: Option<Hash>,
}
/// Reference to an external resource
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Import {
pub mode: ImportMode,
pub location_hashed: ImportHashed,