diff options
author | Nadrieril | 2020-02-09 21:38:37 +0000 |
---|---|---|
committer | Nadrieril | 2020-02-09 21:38:37 +0000 |
commit | a709c65eb28f1b6a666f15bfc2255da7bc7105ab (patch) | |
tree | 547aa7da265a308c8e96954c5eb31602bf06ad9a /dhall/src/semantics | |
parent | 5c342a5688fe7a4bb337ce0622968226d524022e (diff) |
Resolve variables alongside import resolution
Diffstat (limited to '')
-rw-r--r-- | dhall/src/semantics/hir.rs | 36 | ||||
-rw-r--r-- | dhall/src/semantics/resolve.rs | 93 | ||||
-rw-r--r-- | dhall/src/semantics/tck/typecheck.rs | 2 |
3 files changed, 87 insertions, 44 deletions
diff --git a/dhall/src/semantics/hir.rs b/dhall/src/semantics/hir.rs index 683dbbb..80d17fb 100644 --- a/dhall/src/semantics/hir.rs +++ b/dhall/src/semantics/hir.rs @@ -1,15 +1,15 @@ #![allow(dead_code)] -use crate::semantics::{rc, NameEnv, NzEnv, TyEnv, Value}; +use crate::semantics::{NameEnv, NzEnv, TyEnv, Value}; use crate::syntax::{ExprKind, Span, V}; -use crate::{Normalized, NormalizedExpr, ToExprOptions}; +use crate::{Expr, Normalized, NormalizedExpr, ToExprOptions}; /// Stores an alpha-normalized variable. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AlphaVar { idx: usize, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) enum HirKind { Var(AlphaVar), // Forbidden ExprKind variants: Var, Import, Embed @@ -51,6 +51,14 @@ impl Hir { pub fn to_expr(&self, opts: ToExprOptions) -> NormalizedExpr { hir_to_expr(self, opts, &mut NameEnv::new()) } + /// Converts a HIR expr back to the corresponding AST expression. + pub fn to_expr_noopts(&self) -> NormalizedExpr { + let opts = ToExprOptions { + normalize: false, + alpha: false, + }; + self.to_expr(opts) + } pub fn to_expr_tyenv(&self, env: &TyEnv) -> NormalizedExpr { let opts = ToExprOptions { normalize: true, @@ -82,7 +90,7 @@ fn hir_to_expr( opts: ToExprOptions, env: &mut NameEnv, ) -> NormalizedExpr { - rc(match hir.kind() { + let kind = match hir.kind() { HirKind::Var(v) if opts.alpha => ExprKind::Var(V("_".into(), v.idx())), HirKind::Var(v) => ExprKind::Var(env.label_var(v)), HirKind::Expr(e) => { @@ -107,5 +115,21 @@ fn hir_to_expr( e => e, } } - }) + }; + Expr::new(kind, hir.span()) +} + +impl std::cmp::PartialEq for Hir { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} +impl std::cmp::Eq for Hir {} +impl std::hash::Hash for Hir { + fn hash<H>(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.kind.hash(state) + } } 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<NormalizedExpr>; +type Import = syntax::Import<Hir>; /// 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<Normalized, ImportError>, - ) -> Result<Normalized, ImportError> { + mut do_resolve: impl FnMut(&mut Self, &Import) -> Result<Normalized, Error>, + ) -> Result<Normalized, Error> { 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<Normalized, ImportError> { +) -> Result<Normalized, Error> { 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<Normalized, Error> { /// Traverse the expression, handling import alternatives and passing /// found imports to the provided function. fn traverse_resolve_expr( + name_env: &mut NameEnv, expr: &Expr<Normalized>, - f: &mut impl FnMut(Import) -> Result<Normalized, ImportError>, -) -> Result<Expr<Normalized>, ImportError> { - Ok(match expr.kind() { + f: &mut impl FnMut(Import) -> Result<Normalized, Error>, +) -> Result<Hir, Error> { + 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<Resolved, ImportError> { +) -> Result<Resolved, Error> { 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<Resolved, ImportError> { +pub(crate) fn resolve(parsed: Parsed) -> Result<Resolved, Error> { resolve_with_env(&mut ResolveEnv::new(), parsed) } -pub(crate) fn skip_resolve_expr( - parsed: Parsed, -) -> Result<Resolved, ImportError> { +pub(crate) fn skip_resolve_expr(parsed: Parsed) -> Result<Resolved, Error> { 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)) } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 5b233f8..eb6a58c 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -43,7 +43,7 @@ fn function_check(a: Const, b: Const) -> Const { } } -fn mkerr<T, S: ToString>(x: S) -> Result<T, TypeError> { +pub fn mkerr<T, S: ToString>(x: S) -> Result<T, TypeError> { Err(TypeError::new(TypeMessage::Custom(x.to_string()))) } |