From bbcb0c497dcf922d19bd529ceb936aff9d71a732 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 12:29:05 +0000 Subject: Introduce environment for import resolution --- dhall/src/semantics/resolve.rs | 87 +++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 31 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 3acf114..5ec6192 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -18,11 +18,42 @@ type ImportCache = HashMap; pub(crate) type ImportStack = Vec; +struct ResolveEnv { + cache: ImportCache, + stack: ImportStack, +} + +impl ResolveEnv { + pub fn new() -> Self { + ResolveEnv { + cache: HashMap::new(), + stack: Vec::new(), + } + } + pub fn to_import_stack(&self) -> ImportStack { + self.stack.clone() + } + pub fn check_cyclic_import(&self, import: &Import) -> bool { + self.stack.contains(import) + } + pub fn get_from_cache(&self, import: &Import) -> Option<&Normalized> { + self.cache.get(import) + } + pub fn push_on_stack(&mut self, import: Import) { + self.stack.push(import) + } + pub fn pop_from_stack(&mut self) { + self.stack.pop(); + } + pub fn insert_cache(&mut self, import: Import, expr: Normalized) { + self.cache.insert(import, expr); + } +} + fn resolve_import( + env: &mut ResolveEnv, import: &Import, root: &ImportRoot, - import_cache: &mut ImportCache, - import_stack: &ImportStack, ) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; @@ -39,53 +70,47 @@ fn resolve_import( Here => cwd.join(path_buf), _ => unimplemented!("{:?}", import), }; - Ok(load_import(&path_buf, import_cache, import_stack).map_err( - |e| ImportError::Recursive(import.clone(), Box::new(e)), - )?) + Ok(load_import(env, &path_buf).map_err(|e| { + ImportError::Recursive(import.clone(), Box::new(e)) + })?) } _ => unimplemented!("{:?}", import), } } -fn load_import( - f: &Path, - import_cache: &mut ImportCache, - import_stack: &ImportStack, -) -> Result { - Ok( - do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? - .typecheck()? - .normalize(), - ) +fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { + Ok(do_resolve_expr(env, Parsed::parse_file(f)?)? + .typecheck()? + .normalize()) } fn do_resolve_expr( + env: &mut ResolveEnv, parsed: Parsed, - import_cache: &mut ImportCache, - import_stack: &ImportStack, ) -> Result { let Parsed(mut expr, root) = parsed; let mut resolve = |import: Import| -> Result { - if import_stack.contains(&import) { - return Err(ImportError::ImportCycle(import_stack.clone(), import)); + if env.check_cyclic_import(&import) { + return Err(ImportError::ImportCycle( + env.to_import_stack(), + import, + )); } - match import_cache.get(&import) { + match env.get_from_cache(&import) { Some(expr) => Ok(expr.clone()), None => { - // Copy the import stack and push the current import - let mut import_stack = import_stack.clone(); - import_stack.push(import.clone()); + // Push the current import on the stack + env.push_on_stack(import.clone()); // Resolve the import recursively - let expr = resolve_import( - &import, - &root, - import_cache, - &import_stack, - )?; + let expr = resolve_import(env, &import, &root)?; + + // Remove import from the stack. + env.pop_from_stack(); // Add the import to the cache - import_cache.insert(import, expr.clone()); + env.insert_cache(import, expr.clone()); + Ok(expr) } } @@ -95,7 +120,7 @@ fn do_resolve_expr( } pub(crate) fn resolve(e: Parsed) -> Result { - do_resolve_expr(e, &mut HashMap::new(), &Vec::new()) + do_resolve_expr(&mut ResolveEnv::new(), e) } pub(crate) fn skip_resolve_expr( -- cgit v1.2.3 From 5c342a5688fe7a4bb337ce0622968226d524022e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 15:32:27 +0000 Subject: Resolve by ref instead of by mut --- dhall/src/semantics/resolve.rs | 136 +++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 59 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 5ec6192..223cfa4 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; use crate::syntax; -use crate::syntax::{FilePath, ImportLocation, URL}; +use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; use crate::{Normalized, NormalizedExpr, Parsed, Resolved}; type Import = syntax::Import; @@ -30,27 +30,40 @@ impl ResolveEnv { stack: Vec::new(), } } - pub fn to_import_stack(&self) -> ImportStack { - self.stack.clone() - } - pub fn check_cyclic_import(&self, import: &Import) -> bool { - self.stack.contains(import) - } - pub fn get_from_cache(&self, import: &Import) -> Option<&Normalized> { - self.cache.get(import) - } - pub fn push_on_stack(&mut self, import: Import) { - self.stack.push(import) - } - pub fn pop_from_stack(&mut self) { - self.stack.pop(); - } - pub fn insert_cache(&mut self, import: Import, expr: Normalized) { - self.cache.insert(import, expr); + + pub fn handle_import( + &mut self, + import: Import, + mut do_resolve: impl FnMut( + &mut Self, + &Import, + ) -> Result, + ) -> Result { + if self.stack.contains(&import) { + return Err(ImportError::ImportCycle(self.stack.clone(), import)); + } + Ok(match self.cache.get(&import) { + Some(expr) => expr.clone(), + None => { + // Push the current import on the stack + self.stack.push(import.clone()); + + // Resolve the import recursively + let expr = do_resolve(self, &import)?; + + // Remove import from the stack. + self.stack.pop(); + + // Add the import to the cache + self.cache.insert(import, expr.clone()); + + expr + } + }) } } -fn resolve_import( +fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, @@ -79,59 +92,64 @@ fn resolve_import( } fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { - Ok(do_resolve_expr(env, Parsed::parse_file(f)?)? - .typecheck()? - .normalize()) + let parsed = Parsed::parse_file(f)?; + Ok(resolve_with_env(env, parsed)?.typecheck()?.normalize()) } -fn do_resolve_expr( +/// Traverse the expression, handling import alternatives and passing +/// found imports to the provided function. +fn traverse_resolve_expr( + expr: &Expr, + f: &mut impl FnMut(Import) -> Result, +) -> Result, ImportError> { + Ok(match expr.kind() { + ExprKind::BinOp(BinOp::ImportAlt, l, r) => { + match traverse_resolve_expr(l, f) { + Ok(l) => l, + Err(_) => { + match traverse_resolve_expr(r, f) { + Ok(r) => r, + // TODO: keep track of the other error too + Err(e) => return Err(e), + } + } + } + } + kind => { + let kind = kind.traverse_ref(|e| traverse_resolve_expr(e, f))?; + expr.rewrap(match kind { + ExprKind::Import(import) => ExprKind::Embed(f(import)?), + kind => kind, + }) + } + }) +} + +fn resolve_with_env( env: &mut ResolveEnv, parsed: Parsed, ) -> Result { - let Parsed(mut expr, root) = parsed; - let mut resolve = |import: Import| -> Result { - if env.check_cyclic_import(&import) { - return Err(ImportError::ImportCycle( - env.to_import_stack(), - import, - )); - } - match env.get_from_cache(&import) { - Some(expr) => Ok(expr.clone()), - None => { - // Push the current import on the stack - env.push_on_stack(import.clone()); - - // Resolve the import recursively - let expr = resolve_import(env, &import, &root)?; - - // Remove import from the stack. - env.pop_from_stack(); - - // Add the import to the cache - env.insert_cache(import, expr.clone()); - - Ok(expr) - } - } - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) + let Parsed(expr, root) = parsed; + let resolved = traverse_resolve_expr(&expr, &mut |import| { + env.handle_import(import, |env, import| { + resolve_one_import(env, import, &root) + }) + })?; + Ok(Resolved(resolved)) } -pub(crate) fn resolve(e: Parsed) -> Result { - do_resolve_expr(&mut ResolveEnv::new(), e) +pub(crate) fn resolve(parsed: Parsed) -> Result { + resolve_with_env(&mut ResolveEnv::new(), parsed) } pub(crate) fn skip_resolve_expr( parsed: Parsed, ) -> Result { - let mut expr = parsed.0; - let mut resolve = |import: Import| -> Result { + let Parsed(expr, _) = parsed; + let resolved = traverse_resolve_expr(&expr, &mut |import| { Err(ImportError::UnexpectedImport(import)) - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) + })?; + Ok(Resolved(resolved)) } pub trait Canonicalize { -- cgit v1.2.3 From a709c65eb28f1b6a666f15bfc2255da7bc7105ab Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 21:38:37 +0000 Subject: Resolve variables alongside import resolution --- dhall/src/semantics/resolve.rs | 93 +++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 37 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 223cfa4..e12e892 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -1,12 +1,14 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use crate::error::ErrorBuilder; use crate::error::{Error, ImportError}; +use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, NormalizedExpr, Parsed, Resolved}; +use crate::{Normalized, Parsed, Resolved}; -type Import = syntax::Import; +type Import = syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] @@ -34,13 +36,12 @@ impl ResolveEnv { pub fn handle_import( &mut self, import: Import, - mut do_resolve: impl FnMut( - &mut Self, - &Import, - ) -> Result, - ) -> Result { + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, + ) -> Result { if self.stack.contains(&import) { - return Err(ImportError::ImportCycle(self.stack.clone(), import)); + return Err( + ImportError::ImportCycle(self.stack.clone(), import).into() + ); } Ok(match self.cache.get(&import) { Some(expr) => expr.clone(), @@ -67,7 +68,7 @@ fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, -) -> Result { +) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; use syntax::ImportLocation::*; @@ -83,9 +84,7 @@ fn resolve_one_import( Here => cwd.join(path_buf), _ => unimplemented!("{:?}", import), }; - Ok(load_import(env, &path_buf).map_err(|e| { - ImportError::Recursive(import.clone(), Box::new(e)) - })?) + Ok(load_import(env, &path_buf)?) } _ => unimplemented!("{:?}", import), } @@ -99,56 +98,76 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { /// Traverse the expression, handling import alternatives and passing /// found imports to the provided function. fn traverse_resolve_expr( + name_env: &mut NameEnv, expr: &Expr, - f: &mut impl FnMut(Import) -> Result, -) -> Result, ImportError> { - Ok(match expr.kind() { + f: &mut impl FnMut(Import) -> Result, +) -> Result { + let kind = match expr.kind() { + ExprKind::Var(var) => match name_env.unlabel_var(&var) { + Some(v) => HirKind::Var(v), + None => mkerr( + ErrorBuilder::new(format!("unbound variable `{}`", var)) + .span_err(expr.span(), "not found in this scope") + .format(), + )?, + }, ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - match traverse_resolve_expr(l, f) { - Ok(l) => l, + return match traverse_resolve_expr(name_env, l, f) { + Ok(l) => Ok(l), Err(_) => { - match traverse_resolve_expr(r, f) { - Ok(r) => r, + match traverse_resolve_expr(name_env, r, f) { + Ok(r) => Ok(r), // TODO: keep track of the other error too - Err(e) => return Err(e), + Err(e) => Err(e), } } - } + }; } kind => { - let kind = kind.traverse_ref(|e| traverse_resolve_expr(e, f))?; - expr.rewrap(match kind { + let kind = kind.traverse_ref_maybe_binder(|l, e| { + if let Some(l) = l { + name_env.insert_mut(l); + } + let hir = traverse_resolve_expr(name_env, e, f)?; + if let Some(_) = l { + name_env.remove_mut(); + } + Ok::<_, Error>(hir) + })?; + HirKind::Expr(match kind { ExprKind::Import(import) => ExprKind::Embed(f(import)?), kind => kind, }) } - }) + }; + + Ok(Hir::new(kind, expr.span())) } fn resolve_with_env( env: &mut ResolveEnv, parsed: Parsed, -) -> Result { +) -> Result { let Parsed(expr, root) = parsed; - let resolved = traverse_resolve_expr(&expr, &mut |import| { - env.handle_import(import, |env, import| { - resolve_one_import(env, import, &root) - }) - })?; + let resolved = + traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { + env.handle_import(import, |env, import| { + resolve_one_import(env, import, &root) + }) + })?; Ok(Resolved(resolved)) } -pub(crate) fn resolve(parsed: Parsed) -> Result { +pub(crate) fn resolve(parsed: Parsed) -> Result { resolve_with_env(&mut ResolveEnv::new(), parsed) } -pub(crate) fn skip_resolve_expr( - parsed: Parsed, -) -> Result { +pub(crate) fn skip_resolve_expr(parsed: Parsed) -> Result { let Parsed(expr, _) = parsed; - let resolved = traverse_resolve_expr(&expr, &mut |import| { - Err(ImportError::UnexpectedImport(import)) - })?; + let resolved = + traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { + Err(ImportError::UnexpectedImport(import).into()) + })?; Ok(Resolved(resolved)) } -- cgit v1.2.3 From 21db63d3e614554f258526182c7ed89a2c244b65 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 9 Feb 2020 21:58:28 +0000 Subject: Take Hir for typecheck --- dhall/src/semantics/resolve.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index e12e892..8c9bb05 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -6,7 +6,7 @@ use crate::error::{Error, ImportError}; use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, Parsed, Resolved}; +use crate::{Normalized, Parsed, ParsedExpr, Resolved}; type Import = syntax::Import; @@ -162,13 +162,10 @@ pub(crate) fn resolve(parsed: Parsed) -> Result { resolve_with_env(&mut ResolveEnv::new(), parsed) } -pub(crate) fn skip_resolve_expr(parsed: Parsed) -> Result { - let Parsed(expr, _) = parsed; - let resolved = - traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { - Err(ImportError::UnexpectedImport(import).into()) - })?; - Ok(Resolved(resolved)) +pub(crate) fn skip_resolve(expr: &ParsedExpr) -> Result { + traverse_resolve_expr(&mut NameEnv::new(), expr, &mut |import| { + Err(ImportError::UnexpectedImport(import).into()) + }) } pub trait Canonicalize { -- cgit v1.2.3 From c3ed75dc4b354becac0821e4288105dc2a300c4c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 10 Feb 2020 19:14:07 +0000 Subject: Remove need for Embed This was an archaic leftover from copying the Haskell datatypes anyway --- dhall/src/semantics/resolve.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 8c9bb05..80e5132 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -16,7 +16,7 @@ pub(crate) enum ImportRoot { LocalDir(PathBuf), } -type ImportCache = HashMap; +type ImportCache = HashMap; pub(crate) type ImportStack = Vec; @@ -36,8 +36,8 @@ impl ResolveEnv { pub fn handle_import( &mut self, import: Import, - mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, - ) -> Result { + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, + ) -> Result { if self.stack.contains(&import) { return Err( ImportError::ImportCycle(self.stack.clone(), import).into() @@ -68,7 +68,7 @@ fn resolve_one_import( env: &mut ResolveEnv, import: &Import, root: &ImportRoot, -) -> Result { +) -> Result { use self::ImportRoot::*; use syntax::FilePrefix::*; use syntax::ImportLocation::*; @@ -90,9 +90,12 @@ fn resolve_one_import( } } -fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { +fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { let parsed = Parsed::parse_file(f)?; - Ok(resolve_with_env(env, parsed)?.typecheck()?.normalize()) + Ok(resolve_with_env(env, parsed)? + .typecheck()? + .normalize() + .to_hir()) } /// Traverse the expression, handling import alternatives and passing @@ -100,7 +103,7 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { fn traverse_resolve_expr( name_env: &mut NameEnv, expr: &Expr, - f: &mut impl FnMut(Import) -> Result, + f: &mut impl FnMut(Import) -> Result, ) -> Result { let kind = match expr.kind() { ExprKind::Var(var) => match name_env.unlabel_var(&var) { @@ -134,10 +137,10 @@ fn traverse_resolve_expr( } Ok::<_, Error>(hir) })?; - HirKind::Expr(match kind { - ExprKind::Import(import) => ExprKind::Embed(f(import)?), - kind => kind, - }) + match kind { + ExprKind::Import(import) => f(import)?.kind().clone(), + kind => HirKind::Expr(kind), + } } }; -- cgit v1.2.3 From 5a2538d174fd36a8ed7f4fa344b9583fc48bd977 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 11 Feb 2020 13:12:13 +0000 Subject: Remove the Embed variant from ExprKind --- dhall/src/semantics/resolve.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index 80e5132..fac88d2 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -6,7 +6,7 @@ use crate::error::{Error, ImportError}; use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; use crate::syntax; use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Normalized, Parsed, ParsedExpr, Resolved}; +use crate::{Parsed, ParsedExpr, Resolved}; type Import = syntax::Import; @@ -102,7 +102,7 @@ fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { /// found imports to the provided function. fn traverse_resolve_expr( name_env: &mut NameEnv, - expr: &Expr, + expr: &Expr, f: &mut impl FnMut(Import) -> Result, ) -> Result { let kind = match expr.kind() { -- cgit v1.2.3 From 5057144ed99bc4e1a76a0840dd39fc1bd862665c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 15 Feb 2020 19:10:52 +0000 Subject: Desugar Completion during resolution --- dhall/src/semantics/resolve.rs | 45 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs index fac88d2..3038597 100644 --- a/dhall/src/semantics/resolve.rs +++ b/dhall/src/semantics/resolve.rs @@ -105,9 +105,9 @@ fn traverse_resolve_expr( expr: &Expr, f: &mut impl FnMut(Import) -> Result, ) -> Result { - let kind = match expr.kind() { + Ok(match expr.kind() { ExprKind::Var(var) => match name_env.unlabel_var(&var) { - Some(v) => HirKind::Var(v), + Some(v) => Hir::new(HirKind::Var(v), expr.span()), None => mkerr( ErrorBuilder::new(format!("unbound variable `{}`", var)) .span_err(expr.span(), "not found in this scope") @@ -115,16 +115,38 @@ fn traverse_resolve_expr( )?, }, ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - return match traverse_resolve_expr(name_env, l, f) { - Ok(l) => Ok(l), + match traverse_resolve_expr(name_env, l, f) { + Ok(l) => l, Err(_) => { match traverse_resolve_expr(name_env, r, f) { - Ok(r) => Ok(r), + Ok(r) => r, // TODO: keep track of the other error too - Err(e) => Err(e), + Err(e) => return Err(e), } } - }; + } + } + // Desugar + ExprKind::Completion(ty, compl) => { + let ty_field_default = Expr::new( + ExprKind::Field(ty.clone(), "default".into()), + expr.span(), + ); + let merged = Expr::new( + ExprKind::BinOp( + BinOp::RightBiasedRecordMerge, + ty_field_default, + compl.clone(), + ), + expr.span(), + ); + let ty_field_type = Expr::new( + ExprKind::Field(ty.clone(), "Type".into()), + expr.span(), + ); + let desugared = + Expr::new(ExprKind::Annot(merged, ty_field_type), expr.span()); + traverse_resolve_expr(name_env, &desugared, f)? } kind => { let kind = kind.traverse_ref_maybe_binder(|l, e| { @@ -137,14 +159,13 @@ fn traverse_resolve_expr( } Ok::<_, Error>(hir) })?; - match kind { + let kind = match kind { ExprKind::Import(import) => f(import)?.kind().clone(), kind => HirKind::Expr(kind), - } + }; + Hir::new(kind, expr.span()) } - }; - - Ok(Hir::new(kind, expr.span())) + }) } fn resolve_with_env( -- cgit v1.2.3 From 8264df65c21b5ad508c5faf96c4a1f9d732449cc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 17 Feb 2020 17:50:22 +0000 Subject: Move hir and resolve into a module --- dhall/src/semantics/resolve.rs | 264 ----------------------------------------- 1 file changed, 264 deletions(-) delete mode 100644 dhall/src/semantics/resolve.rs (limited to 'dhall/src/semantics/resolve.rs') diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs deleted file mode 100644 index 3038597..0000000 --- a/dhall/src/semantics/resolve.rs +++ /dev/null @@ -1,264 +0,0 @@ -use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -use crate::error::ErrorBuilder; -use crate::error::{Error, ImportError}; -use crate::semantics::{mkerr, Hir, HirKind, NameEnv}; -use crate::syntax; -use crate::syntax::{BinOp, Expr, ExprKind, FilePath, ImportLocation, URL}; -use crate::{Parsed, ParsedExpr, Resolved}; - -type Import = syntax::Import; - -/// A root from which to resolve relative imports. -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ImportRoot { - LocalDir(PathBuf), -} - -type ImportCache = HashMap; - -pub(crate) type ImportStack = Vec; - -struct ResolveEnv { - cache: ImportCache, - stack: ImportStack, -} - -impl ResolveEnv { - pub fn new() -> Self { - ResolveEnv { - cache: HashMap::new(), - stack: Vec::new(), - } - } - - pub fn handle_import( - &mut self, - import: Import, - mut do_resolve: impl FnMut(&mut Self, &Import) -> Result, - ) -> Result { - if self.stack.contains(&import) { - return Err( - ImportError::ImportCycle(self.stack.clone(), import).into() - ); - } - Ok(match self.cache.get(&import) { - Some(expr) => expr.clone(), - None => { - // Push the current import on the stack - self.stack.push(import.clone()); - - // Resolve the import recursively - let expr = do_resolve(self, &import)?; - - // Remove import from the stack. - self.stack.pop(); - - // Add the import to the cache - self.cache.insert(import, expr.clone()); - - expr - } - }) - } -} - -fn resolve_one_import( - env: &mut ResolveEnv, - import: &Import, - root: &ImportRoot, -) -> Result { - use self::ImportRoot::*; - use syntax::FilePrefix::*; - use syntax::ImportLocation::*; - let cwd = match root { - LocalDir(cwd) => cwd, - }; - match &import.location { - Local(prefix, path) => { - let path_buf: PathBuf = path.file_path.iter().collect(); - let path_buf = match prefix { - // TODO: fail gracefully - Parent => cwd.parent().unwrap().join(path_buf), - Here => cwd.join(path_buf), - _ => unimplemented!("{:?}", import), - }; - Ok(load_import(env, &path_buf)?) - } - _ => unimplemented!("{:?}", import), - } -} - -fn load_import(env: &mut ResolveEnv, f: &Path) -> Result { - let parsed = Parsed::parse_file(f)?; - Ok(resolve_with_env(env, parsed)? - .typecheck()? - .normalize() - .to_hir()) -} - -/// Traverse the expression, handling import alternatives and passing -/// found imports to the provided function. -fn traverse_resolve_expr( - name_env: &mut NameEnv, - expr: &Expr, - f: &mut impl FnMut(Import) -> Result, -) -> Result { - Ok(match expr.kind() { - ExprKind::Var(var) => match name_env.unlabel_var(&var) { - Some(v) => Hir::new(HirKind::Var(v), expr.span()), - None => mkerr( - ErrorBuilder::new(format!("unbound variable `{}`", var)) - .span_err(expr.span(), "not found in this scope") - .format(), - )?, - }, - ExprKind::BinOp(BinOp::ImportAlt, l, r) => { - match traverse_resolve_expr(name_env, l, f) { - Ok(l) => l, - Err(_) => { - match traverse_resolve_expr(name_env, r, f) { - Ok(r) => r, - // TODO: keep track of the other error too - Err(e) => return Err(e), - } - } - } - } - // Desugar - ExprKind::Completion(ty, compl) => { - let ty_field_default = Expr::new( - ExprKind::Field(ty.clone(), "default".into()), - expr.span(), - ); - let merged = Expr::new( - ExprKind::BinOp( - BinOp::RightBiasedRecordMerge, - ty_field_default, - compl.clone(), - ), - expr.span(), - ); - let ty_field_type = Expr::new( - ExprKind::Field(ty.clone(), "Type".into()), - expr.span(), - ); - let desugared = - Expr::new(ExprKind::Annot(merged, ty_field_type), expr.span()); - traverse_resolve_expr(name_env, &desugared, f)? - } - kind => { - let kind = kind.traverse_ref_maybe_binder(|l, e| { - if let Some(l) = l { - name_env.insert_mut(l); - } - let hir = traverse_resolve_expr(name_env, e, f)?; - if let Some(_) = l { - name_env.remove_mut(); - } - Ok::<_, Error>(hir) - })?; - let kind = match kind { - ExprKind::Import(import) => f(import)?.kind().clone(), - kind => HirKind::Expr(kind), - }; - Hir::new(kind, expr.span()) - } - }) -} - -fn resolve_with_env( - env: &mut ResolveEnv, - parsed: Parsed, -) -> Result { - let Parsed(expr, root) = parsed; - let resolved = - traverse_resolve_expr(&mut NameEnv::new(), &expr, &mut |import| { - env.handle_import(import, |env, import| { - resolve_one_import(env, import, &root) - }) - })?; - Ok(Resolved(resolved)) -} - -pub(crate) fn resolve(parsed: Parsed) -> Result { - resolve_with_env(&mut ResolveEnv::new(), parsed) -} - -pub(crate) fn skip_resolve(expr: &ParsedExpr) -> Result { - traverse_resolve_expr(&mut NameEnv::new(), expr, &mut |import| { - Err(ImportError::UnexpectedImport(import).into()) - }) -} - -pub trait Canonicalize { - fn canonicalize(&self) -> Self; -} - -impl Canonicalize for FilePath { - fn canonicalize(&self) -> FilePath { - let mut file_path = Vec::new(); - let mut file_path_components = self.file_path.clone().into_iter(); - - loop { - let component = file_path_components.next(); - match component.as_ref() { - // ─────────────────── - // canonicalize(ε) = ε - None => break, - - // canonicalize(directory₀) = directory₁ - // ─────────────────────────────────────── - // canonicalize(directory₀/.) = directory₁ - Some(c) if c == "." => continue, - - Some(c) if c == ".." => match file_path_components.next() { - // canonicalize(directory₀) = ε - // ──────────────────────────── - // canonicalize(directory₀/..) = /.. - None => file_path.push("..".to_string()), - - // canonicalize(directory₀) = directory₁/.. - // ────────────────────────────────────────────── - // canonicalize(directory₀/..) = directory₁/../.. - Some(ref c) if c == ".." => { - file_path.push("..".to_string()); - file_path.push("..".to_string()); - } - - // canonicalize(directory₀) = directory₁/component - // ─────────────────────────────────────────────── ; If "component" is not - // canonicalize(directory₀/..) = directory₁ ; ".." - Some(_) => continue, - }, - - // canonicalize(directory₀) = directory₁ - // ───────────────────────────────────────────────────────── ; If no other - // canonicalize(directory₀/component) = directory₁/component ; rule matches - Some(c) => file_path.push(c.clone()), - } - } - - FilePath { file_path } - } -} - -impl Canonicalize for ImportLocation { - fn canonicalize(&self) -> ImportLocation { - match self { - ImportLocation::Local(prefix, file) => { - ImportLocation::Local(*prefix, file.canonicalize()) - } - ImportLocation::Remote(url) => ImportLocation::Remote(URL { - scheme: url.scheme, - authority: url.authority.clone(), - path: url.path.canonicalize(), - query: url.query.clone(), - headers: url.headers.clone(), - }), - ImportLocation::Env(name) => ImportLocation::Env(name.to_string()), - ImportLocation::Missing => ImportLocation::Missing, - } - } -} -- cgit v1.2.3