summaryrefslogtreecommitdiff
path: root/dhall/src/semantics
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dhall/src/semantics/resolve/env.rs37
-rw-r--r--dhall/src/semantics/resolve/resolve.rs113
2 files changed, 88 insertions, 62 deletions
diff --git a/dhall/src/semantics/resolve/env.rs b/dhall/src/semantics/resolve/env.rs
index 29dd16b..82f21e8 100644
--- a/dhall/src/semantics/resolve/env.rs
+++ b/dhall/src/semantics/resolve/env.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::error::{Error, ImportError};
use crate::semantics::{AlphaVar, Cache, ImportLocation, VarEnv};
use crate::syntax::{Hash, Label, V};
-use crate::Typed;
+use crate::{Ctxt, ImportResultId, Typed};
/// Environment for resolving names.
#[derive(Debug, Clone, Default)]
@@ -11,14 +11,13 @@ pub struct NameEnv {
names: Vec<Label>,
}
-pub type MemCache = HashMap<ImportLocation, Typed>;
pub type CyclesStack = Vec<ImportLocation>;
/// Environment for resolving imports
-#[derive(Debug)]
-pub struct ImportEnv {
- disk_cache: Option<Cache>, // Missing if it failed to initialize
- mem_cache: MemCache,
+pub struct ImportEnv<'cx> {
+ cx: Ctxt<'cx>,
+ disk_cache: Option<Cache>, // `None` if it failed to initialize
+ mem_cache: HashMap<ImportLocation, ImportResultId>,
stack: CyclesStack,
}
@@ -66,26 +65,28 @@ impl NameEnv {
}
}
-impl ImportEnv {
- pub fn new() -> Self {
+impl<'cx> ImportEnv<'cx> {
+ pub fn new(cx: Ctxt<'cx>) -> Self {
ImportEnv {
+ cx,
disk_cache: Cache::new().ok(),
mem_cache: Default::default(),
stack: Default::default(),
}
}
+ pub fn cx(&self) -> Ctxt<'cx> {
+ self.cx
+ }
+
pub fn get_from_mem_cache(
- &mut self,
+ &self,
location: &ImportLocation,
- ) -> Option<Typed> {
- Some(self.mem_cache.get(location)?.clone())
+ ) -> Option<ImportResultId> {
+ Some(*self.mem_cache.get(location)?)
}
- pub fn get_from_disk_cache(
- &mut self,
- hash: &Option<Hash>,
- ) -> Option<Typed> {
+ pub fn get_from_disk_cache(&self, hash: &Option<Hash>) -> Option<Typed> {
let hash = hash.as_ref()?;
let expr = self.disk_cache.as_ref()?.get(hash).ok()?;
Some(expr)
@@ -94,12 +95,12 @@ impl ImportEnv {
pub fn write_to_mem_cache(
&mut self,
location: ImportLocation,
- expr: Typed,
+ result: ImportResultId,
) {
- self.mem_cache.insert(location, expr);
+ self.mem_cache.insert(location, result);
}
- pub fn write_to_disk_cache(&mut self, hash: &Option<Hash>, expr: &Typed) {
+ pub fn write_to_disk_cache(&self, hash: &Option<Hash>, expr: &Typed) {
if let Some(disk_cache) = self.disk_cache.as_ref() {
if let Some(hash) = hash {
let _ = disk_cache.insert(hash, &expr);
diff --git a/dhall/src/semantics/resolve/resolve.rs b/dhall/src/semantics/resolve/resolve.rs
index 16987de..da17c0a 100644
--- a/dhall/src/semantics/resolve/resolve.rs
+++ b/dhall/src/semantics/resolve/resolve.rs
@@ -15,7 +15,7 @@ use crate::syntax::{
Expr, ExprKind, FilePath, FilePrefix, Hash, ImportMode, ImportTarget, Span,
UnspannedExpr, URL,
};
-use crate::{Parsed, Resolved, Typed};
+use crate::{Ctxt, ImportId, Parsed, Resolved, Typed};
// TODO: evaluate import headers
pub type Import = syntax::Import<()>;
@@ -227,7 +227,11 @@ impl ImportLocation {
}
/// Fetches the expression corresponding to this location.
- fn fetch(&self, env: &mut ImportEnv, span: Span) -> Result<Typed, Error> {
+ fn fetch<'cx>(
+ &self,
+ env: &mut ImportEnv<'cx>,
+ span: Span,
+ ) -> Result<Typed, Error> {
let (hir, ty) = match self.mode {
ImportMode::Code => {
let parsed = self.kind.fetch_dhall()?;
@@ -386,8 +390,63 @@ fn traverse_resolve_expr(
})
}
-fn resolve_with_env(
- env: &mut ImportEnv,
+/// Fetch the import and store the result in the global context.
+fn fetch_import<'cx>(
+ env: &mut ImportEnv<'cx>,
+ import_id: ImportId,
+) -> Result<(), Error> {
+ let base_location = env.cx().get_import_base_location(import_id);
+ let import = env.cx().get_import(import_id);
+ let span = env.cx().get_import_span(import_id);
+ let location = base_location.chain(&import)?;
+
+ // If the import is in the in-memory cache, or the hash is in the on-disk cache, return
+ // the cached contents.
+ if let Some(res_id) = env.get_from_mem_cache(&location) {
+ env.cx().set_resultid_of_import(import_id, res_id);
+ // The same location may be used with different or no hashes. Thus we need to check
+ // the hashes every time.
+ let typed = env.cx().get_import_result(res_id);
+ check_hash(import, typed, span)?;
+ env.write_to_disk_cache(&import.hash, typed);
+ return Ok(());
+ }
+ if let Some(typed) = env.get_from_disk_cache(&import.hash) {
+ // No need to check the hash, it was checked before reading the file. We also don't
+ // write to the in-memory cache, because the location might be completely unrelated
+ // to the cached file (e.g. `missing sha256:...` is valid).
+ // This actually means that importing many times a same hashed import will take
+ // longer than importing many times a same non-hashed import.
+ env.cx().set_result_of_import(import_id, typed);
+ return Ok(());
+ }
+
+ // Resolve this import, making sure that recursive imports don't cycle back to the
+ // current one.
+ let res = env.with_cycle_detection(location.clone(), |env| {
+ location.fetch(env, span.clone())
+ });
+ let typed = match res {
+ Ok(typed) => typed,
+ Err(e) => mkerr(
+ ErrorBuilder::new("error")
+ .span_err(span.clone(), e.to_string())
+ .format(),
+ )?,
+ };
+
+ // Add the resolved import to the caches
+ let import = env.cx().get_import(import_id);
+ check_hash(import, &typed, span)?;
+ env.write_to_disk_cache(&import.hash, &typed);
+ let res_id = env.cx().set_result_of_import(import_id, typed);
+ env.write_to_mem_cache(location, res_id);
+
+ Ok(())
+}
+
+fn resolve_with_env<'cx>(
+ env: &mut ImportEnv<'cx>,
parsed: Parsed,
) -> Result<Resolved, Error> {
let Parsed(expr, base_location) = parsed;
@@ -395,52 +454,18 @@ fn resolve_with_env(
&mut NameEnv::new(),
&expr,
&mut |import, span| {
- let location = base_location.chain(&import)?;
-
- // If the import is in the in-memory cache, or the hash is in the on-disk cache, return
- // the cached contents.
- if let Some(typed) = env.get_from_mem_cache(&location) {
- // The same location may be used with different or no hashes. Thus we need to check
- // the hashes every time.
- check_hash(&import, &typed, span)?;
- env.write_to_disk_cache(&import.hash, &typed);
- return Ok(typed);
- }
- if let Some(typed) = env.get_from_disk_cache(&import.hash) {
- // No need to check the hash, it was checked before reading the file. We also don't
- // write to the in-memory cache, because the location might be completely unrelated
- // to the cached file (e.g. `missing sha256:...` is valid).
- // This actually means that importing many times a same hashed import will take
- // longer than importing many times a same non-hashed import.
- return Ok(typed);
- }
-
- // Resolve this import, making sure that recursive imports don't cycle back to the
- // current one.
- let res = env.with_cycle_detection(location.clone(), |env| {
- location.fetch(env, span.clone())
- });
- let typed = match res {
- Ok(typed) => typed,
- Err(e) => mkerr(
- ErrorBuilder::new("error")
- .span_err(span.clone(), e.to_string())
- .format(),
- )?,
- };
-
- // Add the resolved import to the caches
- check_hash(&import, &typed, span)?;
- env.write_to_disk_cache(&import.hash, &typed);
- env.write_to_mem_cache(location, typed.clone());
- Ok(typed)
+ let import_id =
+ env.cx().push_import(base_location.clone(), import, span);
+ fetch_import(env, import_id)?;
+ // TODO: store import id in Hir
+ Ok(env.cx().get_result_of_import(import_id).unwrap().clone())
},
)?;
Ok(Resolved(resolved))
}
pub fn resolve(parsed: Parsed) -> Result<Resolved, Error> {
- resolve_with_env(&mut ImportEnv::new(), parsed)
+ Ctxt::with_new(|cx| resolve_with_env(&mut ImportEnv::new(cx), parsed))
}
pub fn skip_resolve_expr(expr: &Expr) -> Result<Hir, Error> {