summaryrefslogtreecommitdiff
path: root/dhall/src/semantics
diff options
context:
space:
mode:
authorNadrieril2020-02-09 21:38:37 +0000
committerNadrieril2020-02-09 21:38:37 +0000
commita709c65eb28f1b6a666f15bfc2255da7bc7105ab (patch)
tree547aa7da265a308c8e96954c5eb31602bf06ad9a /dhall/src/semantics
parent5c342a5688fe7a4bb337ce0622968226d524022e (diff)
Resolve variables alongside import resolution
Diffstat (limited to 'dhall/src/semantics')
-rw-r--r--dhall/src/semantics/hir.rs36
-rw-r--r--dhall/src/semantics/resolve.rs93
-rw-r--r--dhall/src/semantics/tck/typecheck.rs2
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())))
}