From e95c0ffe952c504839f924b504fa7c235375cb3b Mon Sep 17 00:00:00 2001
From: Basile Henry
Date: Fri, 12 Apr 2019 09:32:56 +0200
Subject: Cache imports

---
 dhall/src/imports.rs | 46 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 12 deletions(-)

(limited to 'dhall')

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)
     }
 }
-- 
cgit v1.2.3