From 5a835d9db35bf76858e178e1bd66e60128879629 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 27 Jan 2020 18:45:09 +0000 Subject: Fix a bunch of bugs and more tck --- dhall/src/semantics/phase/resolve.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'dhall/src/semantics/phase/resolve.rs') diff --git a/dhall/src/semantics/phase/resolve.rs b/dhall/src/semantics/phase/resolve.rs index cc4a024..64106aa 100644 --- a/dhall/src/semantics/phase/resolve.rs +++ b/dhall/src/semantics/phase/resolve.rs @@ -52,10 +52,14 @@ fn load_import( import_cache: &mut ImportCache, import_stack: &ImportStack, ) -> Result { + // Ok( + // do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? + // .typecheck()? + // .normalize(), + // ) Ok( do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? - .typecheck()? - .normalize(), + .tck_and_normalize_new_flow()?, ) } -- cgit v1.3.1 From 7743647137d1914c280e03d6aaee81e507cff97d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 30 Jan 2020 11:17:49 +0000 Subject: Remove old typecheck module --- dhall/src/semantics/phase/mod.rs | 17 +++-------------- dhall/src/semantics/phase/resolve.rs | 8 ++------ dhall/src/semantics/phase/typecheck.rs | 1 - 3 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 dhall/src/semantics/phase/typecheck.rs (limited to 'dhall/src/semantics/phase/resolve.rs') diff --git a/dhall/src/semantics/phase/mod.rs b/dhall/src/semantics/phase/mod.rs index 2727a61..f24a668 100644 --- a/dhall/src/semantics/phase/mod.rs +++ b/dhall/src/semantics/phase/mod.rs @@ -2,9 +2,7 @@ use std::fmt::Display; use std::path::Path; use crate::error::{EncodeError, Error, ImportError, TypeError}; -use crate::semantics::core::value::Value; -use crate::semantics::core::value::ValueKind; -use crate::semantics::tck::tyexpr::TyExpr; +use crate::semantics::{typecheck, typecheck_with, TyExpr, Value, ValueKind}; use crate::syntax::binary; use crate::syntax::{Builtin, Const, Expr}; use resolve::ImportRoot; @@ -12,7 +10,6 @@ use resolve::ImportRoot; pub(crate) mod normalize; pub(crate) mod parse; pub(crate) mod resolve; -pub(crate) mod typecheck; pub type ParsedExpr = Expr; pub type DecodedExpr = Expr; @@ -80,23 +77,15 @@ impl Parsed { impl Resolved { pub fn typecheck(&self) -> Result { - Ok(Typed(crate::semantics::tck::typecheck::typecheck(&self.0)?)) + Ok(Typed(typecheck(&self.0)?)) } pub fn typecheck_with(self, ty: &Normalized) -> Result { - Ok(Typed(crate::semantics::tck::typecheck::typecheck_with( - &self.0, - ty.to_expr(), - )?)) + Ok(Typed(typecheck_with(&self.0, ty.to_expr())?)) } /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self) -> ResolvedExpr { self.0.clone() } - pub fn tck_and_normalize_new_flow(&self) -> Result { - let val = crate::semantics::tck::typecheck::typecheck(&self.0)? - .normalize_whnf_noenv(); - Ok(Normalized(val)) - } } impl Typed { diff --git a/dhall/src/semantics/phase/resolve.rs b/dhall/src/semantics/phase/resolve.rs index 64106aa..cc4a024 100644 --- a/dhall/src/semantics/phase/resolve.rs +++ b/dhall/src/semantics/phase/resolve.rs @@ -52,14 +52,10 @@ fn load_import( import_cache: &mut ImportCache, import_stack: &ImportStack, ) -> Result { - // Ok( - // do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? - // .typecheck()? - // .normalize(), - // ) Ok( do_resolve_expr(Parsed::parse_file(f)?, import_cache, import_stack)? - .tck_and_normalize_new_flow()?, + .typecheck()? + .normalize(), ) } diff --git a/dhall/src/semantics/phase/typecheck.rs b/dhall/src/semantics/phase/typecheck.rs deleted file mode 100644 index 8b13789..0000000 --- a/dhall/src/semantics/phase/typecheck.rs +++ /dev/null @@ -1 +0,0 @@ - -- cgit v1.3.1 From 5197c26c23edd6c499f8e0f8a239fe4393b2e3d2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 30 Jan 2020 17:09:16 +0000 Subject: Move main API to lib.rs --- dhall/src/error/mod.rs | 2 +- dhall/src/lib.rs | 244 +++++++++++++++++++++++++++++++++++ dhall/src/semantics/builtins.rs | 2 +- dhall/src/semantics/nze/normalize.rs | 2 +- dhall/src/semantics/nze/value.rs | 2 +- dhall/src/semantics/phase/mod.rs | 242 ---------------------------------- dhall/src/semantics/phase/parse.rs | 2 +- dhall/src/semantics/phase/resolve.rs | 2 +- dhall/src/semantics/tck/tyexpr.rs | 4 +- dhall/src/semantics/tck/typecheck.rs | 2 +- dhall/src/syntax/binary/decode.rs | 2 +- dhall/src/syntax/text/parser.rs | 2 +- dhall/src/tests.rs | 2 +- 13 files changed, 256 insertions(+), 254 deletions(-) (limited to 'dhall/src/semantics/phase/resolve.rs') diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs index 852e795..8991758 100644 --- a/dhall/src/error/mod.rs +++ b/dhall/src/error/mod.rs @@ -1,9 +1,9 @@ use std::io::Error as IOError; use crate::semantics::phase::resolve::ImportStack; -use crate::semantics::phase::NormalizedExpr; use crate::semantics::Value; use crate::syntax::{Import, ParseError}; +use crate::NormalizedExpr; pub type Result = std::result::Result; diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 62a1b27..cbf3ceb 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -16,3 +16,247 @@ mod tests; pub mod error; pub mod semantics; pub mod syntax; + +use std::fmt::Display; +use std::path::Path; + +use crate::error::{EncodeError, Error, ImportError, TypeError}; +use crate::semantics::phase::parse; +use crate::semantics::phase::resolve; +use crate::semantics::phase::resolve::ImportRoot; +use crate::semantics::{typecheck, typecheck_with, TyExpr, Value, ValueKind}; +use crate::syntax::binary; +use crate::syntax::{Builtin, Const, Expr}; + +pub type ParsedExpr = Expr; +pub type DecodedExpr = Expr; +pub type ResolvedExpr = Expr; +pub type NormalizedExpr = Expr; + +#[derive(Debug, Clone)] +pub struct Parsed(ParsedExpr, ImportRoot); + +/// An expression where all imports have been resolved +/// +/// Invariant: there must be no `Import` nodes or `ImportAlt` operations left. +#[derive(Debug, Clone)] +pub struct Resolved(ResolvedExpr); + +/// A typed expression +#[derive(Debug, Clone)] +pub struct Typed(TyExpr); + +/// A normalized expression. +/// +/// Invariant: the contained Typed expression must be in normal form, +#[derive(Debug, Clone)] +pub struct Normalized(Value); + +/// Controls conversion from `Value` to `Expr` +#[derive(Copy, Clone)] +pub(crate) struct ToExprOptions { + /// Whether to convert all variables to `_` + pub(crate) alpha: bool, + /// Whether to normalize before converting + pub(crate) normalize: bool, +} + +impl Parsed { + pub fn parse_file(f: &Path) -> Result { + parse::parse_file(f) + } + pub fn parse_str(s: &str) -> Result { + parse::parse_str(s) + } + pub fn parse_binary_file(f: &Path) -> Result { + parse::parse_binary_file(f) + } + pub fn parse_binary(data: &[u8]) -> Result { + parse::parse_binary(data) + } + + pub fn resolve(self) -> Result { + resolve::resolve(self) + } + pub fn skip_resolve(self) -> Result { + resolve::skip_resolve_expr(self) + } + + pub fn encode(&self) -> Result, EncodeError> { + binary::encode(&self.0) + } + + /// Converts a value back to the corresponding AST expression. + pub fn to_expr(&self) -> ParsedExpr { + self.0.clone() + } +} + +impl Resolved { + pub fn typecheck(&self) -> Result { + Ok(Typed(typecheck(&self.0)?)) + } + pub fn typecheck_with(self, ty: &Normalized) -> Result { + Ok(Typed(typecheck_with(&self.0, ty.to_expr())?)) + } + /// Converts a value back to the corresponding AST expression. + pub fn to_expr(&self) -> ResolvedExpr { + self.0.clone() + } +} + +impl Typed { + /// Reduce an expression to its normal form, performing beta reduction + pub fn normalize(&self) -> Normalized { + Normalized(self.0.rec_eval_closed_expr()) + } + + /// Converts a value back to the corresponding AST expression. + fn to_expr(&self) -> ResolvedExpr { + self.0.to_expr(ToExprOptions { + alpha: false, + normalize: false, + }) + } + + pub(crate) fn get_type(&self) -> Result { + Ok(Normalized(self.0.get_type()?)) + } +} + +impl Normalized { + pub fn encode(&self) -> Result, EncodeError> { + binary::encode(&self.to_expr()) + } + + /// Converts a value back to the corresponding AST expression. + pub fn to_expr(&self) -> NormalizedExpr { + self.0.to_expr(ToExprOptions { + alpha: false, + normalize: false, + }) + } + /// Converts a value back to the corresponding AST expression, alpha-normalizing in the process. + pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { + self.0.to_expr(ToExprOptions { + alpha: true, + normalize: false, + }) + } + pub(crate) fn to_value(&self) -> Value { + self.0.clone() + } + pub(crate) fn into_value(self) -> Value { + self.0 + } + + pub(crate) fn from_const(c: Const) -> Self { + Normalized(Value::from_const(c)) + } + pub(crate) fn from_kind_and_type( + v: ValueKind, + t: Normalized, + ) -> Self { + Normalized(Value::from_kind_and_type(v, t.into_value())) + } + pub(crate) fn from_value(th: Value) -> Self { + Normalized(th) + } + pub(crate) fn const_type() -> Self { + Normalized::from_const(Const::Type) + } + + pub fn make_builtin_type(b: Builtin) -> Self { + Normalized::from_value(Value::from_builtin(b)) + } + pub fn make_optional_type(t: Normalized) -> Self { + Normalized::from_value( + Value::from_builtin(Builtin::Optional).app(t.to_value()), + ) + } + pub fn make_list_type(t: Normalized) -> Self { + Normalized::from_value( + Value::from_builtin(Builtin::List).app(t.to_value()), + ) + } + pub fn make_record_type( + kts: impl Iterator, + ) -> Self { + Normalized::from_kind_and_type( + ValueKind::RecordType( + kts.map(|(k, t)| (k.into(), t.into_value())).collect(), + ), + Normalized::const_type(), + ) + } + pub fn make_union_type( + kts: impl Iterator)>, + ) -> Self { + Normalized::from_kind_and_type( + ValueKind::UnionType( + kts.map(|(k, t)| (k.into(), t.map(|t| t.into_value()))) + .collect(), + ), + Normalized::const_type(), + ) + } +} + +macro_rules! derive_traits_for_wrapper_struct { + ($ty:ident) => { + impl std::cmp::PartialEq for $ty { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl std::cmp::Eq for $ty {} + + impl std::fmt::Display for $ty { + fn fmt( + &self, + f: &mut std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + self.0.fmt(f) + } + } + }; +} + +derive_traits_for_wrapper_struct!(Parsed); +derive_traits_for_wrapper_struct!(Resolved); + +impl std::hash::Hash for Normalized { + fn hash(&self, state: &mut H) + where + H: std::hash::Hasher, + { + if let Ok(vec) = self.encode() { + vec.hash(state) + } + } +} + +impl Eq for Typed {} +impl PartialEq for Typed { + fn eq(&self, other: &Self) -> bool { + self.normalize() == other.normalize() + } +} +impl Display for Typed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} + +impl Eq for Normalized {} +impl PartialEq for Normalized { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} +impl Display for Normalized { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 9d10d89..2211579 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -1,4 +1,3 @@ -use crate::semantics::phase::Normalized; use crate::semantics::{ typecheck, NzEnv, TyExpr, TyExprKind, Value, ValueKind, VarEnv, }; @@ -8,6 +7,7 @@ use crate::syntax::{ BinOp, Builtin, Const, Expr, ExprKind, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, Span, UnspannedExpr, V, }; +use crate::Normalized; use std::collections::HashMap; use std::convert::TryInto; diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index ea1a25b..6564018 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use crate::semantics::phase::Normalized; use crate::semantics::NzEnv; use crate::semantics::{ Binder, BuiltinClosure, Closure, TyExpr, TyExprKind, Value, ValueKind, @@ -8,6 +7,7 @@ use crate::semantics::{ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, }; +use crate::Normalized; pub(crate) fn apply_any(f: Value, a: Value, ty: &Value) -> ValueKind { let f_borrow = f.kind(); diff --git a/dhall/src/semantics/nze/value.rs b/dhall/src/semantics/nze/value.rs index 215c342..0a9de6a 100644 --- a/dhall/src/semantics/nze/value.rs +++ b/dhall/src/semantics/nze/value.rs @@ -4,7 +4,6 @@ use std::rc::Rc; use crate::error::{TypeError, TypeMessage}; use crate::semantics::nze::visitor; -use crate::semantics::phase::{Normalized, NormalizedExpr, ToExprOptions}; use crate::semantics::Binder; use crate::semantics::{apply_any, normalize_tyexpr_whnf, normalize_whnf}; use crate::semantics::{type_of_builtin, typecheck, TyExpr, TyExprKind}; @@ -13,6 +12,7 @@ use crate::syntax::{ BinOp, Builtin, Const, ExprKind, Integer, InterpolatedTextContents, Label, NaiveDouble, Natural, Span, }; +use crate::{Normalized, NormalizedExpr, ToExprOptions}; use self::Form::{Unevaled, WHNF}; diff --git a/dhall/src/semantics/phase/mod.rs b/dhall/src/semantics/phase/mod.rs index ff4b859..02e2b18 100644 --- a/dhall/src/semantics/phase/mod.rs +++ b/dhall/src/semantics/phase/mod.rs @@ -1,244 +1,2 @@ -use std::fmt::Display; -use std::path::Path; - -use crate::error::{EncodeError, Error, ImportError, TypeError}; -use crate::semantics::{typecheck, typecheck_with, TyExpr, Value, ValueKind}; -use crate::syntax::binary; -use crate::syntax::{Builtin, Const, Expr}; -use resolve::ImportRoot; - pub(crate) mod parse; pub(crate) mod resolve; - -pub type ParsedExpr = Expr; -pub type DecodedExpr = Expr; -pub type ResolvedExpr = Expr; -pub type NormalizedExpr = Expr; - -#[derive(Debug, Clone)] -pub struct Parsed(ParsedExpr, ImportRoot); - -/// An expression where all imports have been resolved -/// -/// Invariant: there must be no `Import` nodes or `ImportAlt` operations left. -#[derive(Debug, Clone)] -pub struct Resolved(ResolvedExpr); - -/// A typed expression -#[derive(Debug, Clone)] -pub struct Typed(TyExpr); - -/// A normalized expression. -/// -/// Invariant: the contained Typed expression must be in normal form, -#[derive(Debug, Clone)] -pub struct Normalized(Value); - -/// Controls conversion from `Value` to `Expr` -#[derive(Copy, Clone)] -pub(crate) struct ToExprOptions { - /// Whether to convert all variables to `_` - pub(crate) alpha: bool, - /// Whether to normalize before converting - pub(crate) normalize: bool, -} - -impl Parsed { - pub fn parse_file(f: &Path) -> Result { - parse::parse_file(f) - } - pub fn parse_str(s: &str) -> Result { - parse::parse_str(s) - } - pub fn parse_binary_file(f: &Path) -> Result { - parse::parse_binary_file(f) - } - pub fn parse_binary(data: &[u8]) -> Result { - parse::parse_binary(data) - } - - pub fn resolve(self) -> Result { - resolve::resolve(self) - } - pub fn skip_resolve(self) -> Result { - resolve::skip_resolve_expr(self) - } - - pub fn encode(&self) -> Result, EncodeError> { - binary::encode(&self.0) - } - - /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> ParsedExpr { - self.0.clone() - } -} - -impl Resolved { - pub fn typecheck(&self) -> Result { - Ok(Typed(typecheck(&self.0)?)) - } - pub fn typecheck_with(self, ty: &Normalized) -> Result { - Ok(Typed(typecheck_with(&self.0, ty.to_expr())?)) - } - /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> ResolvedExpr { - self.0.clone() - } -} - -impl Typed { - /// Reduce an expression to its normal form, performing beta reduction - pub fn normalize(&self) -> Normalized { - Normalized(self.0.rec_eval_closed_expr()) - } - - /// Converts a value back to the corresponding AST expression. - fn to_expr(&self) -> ResolvedExpr { - self.0.to_expr(ToExprOptions { - alpha: false, - normalize: false, - }) - } - - pub(crate) fn get_type(&self) -> Result { - Ok(Normalized(self.0.get_type()?)) - } -} - -impl Normalized { - pub fn encode(&self) -> Result, EncodeError> { - binary::encode(&self.to_expr()) - } - - /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> NormalizedExpr { - self.0.to_expr(ToExprOptions { - alpha: false, - normalize: false, - }) - } - /// Converts a value back to the corresponding AST expression, alpha-normalizing in the process. - pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr { - self.0.to_expr(ToExprOptions { - alpha: true, - normalize: false, - }) - } - pub(crate) fn to_value(&self) -> Value { - self.0.clone() - } - pub(crate) fn into_value(self) -> Value { - self.0 - } - - pub(crate) fn from_const(c: Const) -> Self { - Normalized(Value::from_const(c)) - } - pub(crate) fn from_kind_and_type( - v: ValueKind, - t: Normalized, - ) -> Self { - Normalized(Value::from_kind_and_type(v, t.into_value())) - } - pub(crate) fn from_value(th: Value) -> Self { - Normalized(th) - } - pub(crate) fn const_type() -> Self { - Normalized::from_const(Const::Type) - } - - pub fn make_builtin_type(b: Builtin) -> Self { - Normalized::from_value(Value::from_builtin(b)) - } - pub fn make_optional_type(t: Normalized) -> Self { - Normalized::from_value( - Value::from_builtin(Builtin::Optional).app(t.to_value()), - ) - } - pub fn make_list_type(t: Normalized) -> Self { - Normalized::from_value( - Value::from_builtin(Builtin::List).app(t.to_value()), - ) - } - pub fn make_record_type( - kts: impl Iterator, - ) -> Self { - Normalized::from_kind_and_type( - ValueKind::RecordType( - kts.map(|(k, t)| (k.into(), t.into_value())).collect(), - ), - Normalized::const_type(), - ) - } - pub fn make_union_type( - kts: impl Iterator)>, - ) -> Self { - Normalized::from_kind_and_type( - ValueKind::UnionType( - kts.map(|(k, t)| (k.into(), t.map(|t| t.into_value()))) - .collect(), - ), - Normalized::const_type(), - ) - } -} - -macro_rules! derive_traits_for_wrapper_struct { - ($ty:ident) => { - impl std::cmp::PartialEq for $ty { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl std::cmp::Eq for $ty {} - - impl std::fmt::Display for $ty { - fn fmt( - &self, - f: &mut std::fmt::Formatter, - ) -> Result<(), std::fmt::Error> { - self.0.fmt(f) - } - } - }; -} - -derive_traits_for_wrapper_struct!(Parsed); -derive_traits_for_wrapper_struct!(Resolved); - -impl std::hash::Hash for Normalized { - fn hash(&self, state: &mut H) - where - H: std::hash::Hasher, - { - if let Ok(vec) = self.encode() { - vec.hash(state) - } - } -} - -impl Eq for Typed {} -impl PartialEq for Typed { - fn eq(&self, other: &Self) -> bool { - self.normalize() == other.normalize() - } -} -impl Display for Typed { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.to_expr().fmt(f) - } -} - -impl Eq for Normalized {} -impl PartialEq for Normalized { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} -impl Display for Normalized { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.to_expr().fmt(f) - } -} diff --git a/dhall/src/semantics/phase/parse.rs b/dhall/src/semantics/phase/parse.rs index 00db422..b72fe7f 100644 --- a/dhall/src/semantics/phase/parse.rs +++ b/dhall/src/semantics/phase/parse.rs @@ -4,9 +4,9 @@ use std::path::Path; use crate::error::Error; use crate::semantics::phase::resolve::ImportRoot; -use crate::semantics::phase::Parsed; use crate::syntax::binary; use crate::syntax::parse_expr; +use crate::Parsed; pub(crate) fn parse_file(f: &Path) -> Result { let mut buffer = String::new(); diff --git a/dhall/src/semantics/phase/resolve.rs b/dhall/src/semantics/phase/resolve.rs index cc4a024..3acf114 100644 --- a/dhall/src/semantics/phase/resolve.rs +++ b/dhall/src/semantics/phase/resolve.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; -use crate::semantics::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; use crate::syntax; use crate::syntax::{FilePath, ImportLocation, URL}; +use crate::{Normalized, NormalizedExpr, Parsed, Resolved}; type Import = syntax::Import; diff --git a/dhall/src/semantics/tck/tyexpr.rs b/dhall/src/semantics/tck/tyexpr.rs index 98dc3f9..4b88048 100644 --- a/dhall/src/semantics/tck/tyexpr.rs +++ b/dhall/src/semantics/tck/tyexpr.rs @@ -1,9 +1,9 @@ use crate::error::{TypeError, TypeMessage}; use crate::semantics::normalize_tyexpr_whnf; -use crate::semantics::phase::Normalized; -use crate::semantics::phase::{NormalizedExpr, ToExprOptions}; use crate::semantics::{rc, NameEnv, NzEnv, TyEnv, Value}; use crate::syntax::{ExprKind, Span, V}; +use crate::Normalized; +use crate::{NormalizedExpr, ToExprOptions}; pub(crate) type Type = Value; diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 348471f..212e6e7 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -4,7 +4,6 @@ use std::collections::HashMap; use crate::error::{TypeError, TypeMessage}; use crate::semantics::merge_maps; -use crate::semantics::phase::Normalized; use crate::semantics::{ type_of_builtin, Binder, BuiltinClosure, Closure, TyEnv, TyExpr, TyExprKind, Type, Value, ValueKind, @@ -12,6 +11,7 @@ use crate::semantics::{ use crate::syntax::{ BinOp, Builtin, Const, Expr, ExprKind, InterpolatedTextContents, Span, }; +use crate::Normalized; fn type_of_recordtype<'a>( tys: impl Iterator>, diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs index c18deb5..52b699c 100644 --- a/dhall/src/syntax/binary/decode.rs +++ b/dhall/src/syntax/binary/decode.rs @@ -3,13 +3,13 @@ use serde_cbor::value::value as cbor; use std::iter::FromIterator; use crate::error::DecodeError; -use crate::semantics::phase::DecodedExpr; use crate::syntax; use crate::syntax::{ Expr, ExprKind, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, Integer, InterpolatedText, Label, Natural, Scheme, Span, UnspannedExpr, URL, V, }; +use crate::DecodedExpr; pub(crate) fn decode(data: &[u8]) -> Result { match serde_cbor::de::from_slice(data) { diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index 681d6dd..2ec63e2 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -5,7 +5,6 @@ use std::rc::Rc; use pest_consume::{match_nodes, Parser}; -use crate::semantics::phase::Normalized; use crate::syntax; use crate::syntax::map::{DupTreeMap, DupTreeSet}; use crate::syntax::ExprKind::*; @@ -14,6 +13,7 @@ use crate::syntax::{ InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, Natural, Scheme, Span, UnspannedExpr, URL, V, }; +use crate::Normalized; // This file consumes the parse tree generated by pest and turns it into // our own AST. All those custom macros should eventually moved into diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs index 08feadf..8216243 100644 --- a/dhall/src/tests.rs +++ b/dhall/src/tests.rs @@ -48,7 +48,7 @@ use std::io::{Read, Write}; use std::path::PathBuf; use crate::error::{Error, Result}; -use crate::semantics::phase::Parsed; +use crate::Parsed; #[allow(dead_code)] #[derive(Clone)] -- cgit v1.3.1 From 8ff022fa2cec34bc1d46ac3655d0c3d228ef893c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 30 Jan 2020 17:16:25 +0000 Subject: Move parse and resolve up a level --- dhall/src/error/mod.rs | 2 +- dhall/src/lib.rs | 6 +- dhall/src/semantics/mod.rs | 3 +- dhall/src/semantics/parse.rs | 37 +++++++ dhall/src/semantics/phase/mod.rs | 2 - dhall/src/semantics/phase/parse.rs | 37 ------- dhall/src/semantics/phase/resolve.rs | 181 ----------------------------------- dhall/src/semantics/resolve.rs | 181 +++++++++++++++++++++++++++++++++++ 8 files changed, 224 insertions(+), 225 deletions(-) create mode 100644 dhall/src/semantics/parse.rs delete mode 100644 dhall/src/semantics/phase/mod.rs delete mode 100644 dhall/src/semantics/phase/parse.rs delete mode 100644 dhall/src/semantics/phase/resolve.rs create mode 100644 dhall/src/semantics/resolve.rs (limited to 'dhall/src/semantics/phase/resolve.rs') diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs index 8991758..4df018d 100644 --- a/dhall/src/error/mod.rs +++ b/dhall/src/error/mod.rs @@ -1,6 +1,6 @@ use std::io::Error as IOError; -use crate::semantics::phase::resolve::ImportStack; +use crate::semantics::resolve::ImportStack; use crate::semantics::Value; use crate::syntax::{Import, ParseError}; use crate::NormalizedExpr; diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index cbf3ceb..e9f8aa3 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -21,9 +21,9 @@ use std::fmt::Display; use std::path::Path; use crate::error::{EncodeError, Error, ImportError, TypeError}; -use crate::semantics::phase::parse; -use crate::semantics::phase::resolve; -use crate::semantics::phase::resolve::ImportRoot; +use crate::semantics::parse; +use crate::semantics::resolve; +use crate::semantics::resolve::ImportRoot; use crate::semantics::{typecheck, typecheck_with, TyExpr, Value, ValueKind}; use crate::syntax::binary; use crate::syntax::{Builtin, Const, Expr}; diff --git a/dhall/src/semantics/mod.rs b/dhall/src/semantics/mod.rs index 92e5912..98fdf5a 100644 --- a/dhall/src/semantics/mod.rs +++ b/dhall/src/semantics/mod.rs @@ -1,6 +1,7 @@ pub mod builtins; pub mod nze; -pub mod phase; +pub mod parse; +pub mod resolve; pub mod tck; pub(crate) use self::builtins::*; pub(crate) use self::nze::*; diff --git a/dhall/src/semantics/parse.rs b/dhall/src/semantics/parse.rs new file mode 100644 index 0000000..ee35536 --- /dev/null +++ b/dhall/src/semantics/parse.rs @@ -0,0 +1,37 @@ +use std::fs::File; +use std::io::Read; +use std::path::Path; + +use crate::error::Error; +use crate::semantics::resolve::ImportRoot; +use crate::syntax::binary; +use crate::syntax::parse_expr; +use crate::Parsed; + +pub(crate) fn parse_file(f: &Path) -> Result { + let mut buffer = String::new(); + File::open(f)?.read_to_string(&mut buffer)?; + let expr = parse_expr(&*buffer)?; + let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); + Ok(Parsed(expr, root)) +} + +pub(crate) fn parse_str(s: &str) -> Result { + let expr = parse_expr(s)?; + let root = ImportRoot::LocalDir(std::env::current_dir()?); + Ok(Parsed(expr, root)) +} + +pub(crate) fn parse_binary(data: &[u8]) -> Result { + let expr = binary::decode(data)?; + let root = ImportRoot::LocalDir(std::env::current_dir()?); + Ok(Parsed(expr, root)) +} + +pub(crate) fn parse_binary_file(f: &Path) -> Result { + let mut buffer = Vec::new(); + File::open(f)?.read_to_end(&mut buffer)?; + let expr = binary::decode(&buffer)?; + let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); + Ok(Parsed(expr, root)) +} diff --git a/dhall/src/semantics/phase/mod.rs b/dhall/src/semantics/phase/mod.rs deleted file mode 100644 index 02e2b18..0000000 --- a/dhall/src/semantics/phase/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod parse; -pub(crate) mod resolve; diff --git a/dhall/src/semantics/phase/parse.rs b/dhall/src/semantics/phase/parse.rs deleted file mode 100644 index b72fe7f..0000000 --- a/dhall/src/semantics/phase/parse.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::fs::File; -use std::io::Read; -use std::path::Path; - -use crate::error::Error; -use crate::semantics::phase::resolve::ImportRoot; -use crate::syntax::binary; -use crate::syntax::parse_expr; -use crate::Parsed; - -pub(crate) fn parse_file(f: &Path) -> Result { - let mut buffer = String::new(); - File::open(f)?.read_to_string(&mut buffer)?; - let expr = parse_expr(&*buffer)?; - let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); - Ok(Parsed(expr, root)) -} - -pub(crate) fn parse_str(s: &str) -> Result { - let expr = parse_expr(s)?; - let root = ImportRoot::LocalDir(std::env::current_dir()?); - Ok(Parsed(expr, root)) -} - -pub(crate) fn parse_binary(data: &[u8]) -> Result { - let expr = binary::decode(data)?; - let root = ImportRoot::LocalDir(std::env::current_dir()?); - Ok(Parsed(expr, root)) -} - -pub(crate) fn parse_binary_file(f: &Path) -> Result { - let mut buffer = Vec::new(); - File::open(f)?.read_to_end(&mut buffer)?; - let expr = binary::decode(&buffer)?; - let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); - Ok(Parsed(expr, root)) -} diff --git a/dhall/src/semantics/phase/resolve.rs b/dhall/src/semantics/phase/resolve.rs deleted file mode 100644 index 3acf114..0000000 --- a/dhall/src/semantics/phase/resolve.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -use crate::error::{Error, ImportError}; -use crate::syntax; -use crate::syntax::{FilePath, ImportLocation, URL}; -use crate::{Normalized, NormalizedExpr, Parsed, 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; - -fn resolve_import( - import: &Import, - root: &ImportRoot, - import_cache: &mut ImportCache, - import_stack: &ImportStack, -) -> 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(&path_buf, import_cache, import_stack).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 do_resolve_expr( - 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)); - } - match import_cache.get(&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()); - - // Resolve the import recursively - let expr = resolve_import( - &import, - &root, - import_cache, - &import_stack, - )?; - - // Add the import to the cache - import_cache.insert(import, expr.clone()); - Ok(expr) - } - } - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) -} - -pub(crate) fn resolve(e: Parsed) -> Result { - do_resolve_expr(e, &mut HashMap::new(), &Vec::new()) -} - -pub(crate) fn skip_resolve_expr( - parsed: Parsed, -) -> Result { - let mut expr = parsed.0; - let mut resolve = |import: Import| -> Result { - Err(ImportError::UnexpectedImport(import)) - }; - expr.traverse_resolve_mut(&mut resolve)?; - Ok(Resolved(expr)) -} - -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, - } - } -} diff --git a/dhall/src/semantics/resolve.rs b/dhall/src/semantics/resolve.rs new file mode 100644 index 0000000..3acf114 --- /dev/null +++ b/dhall/src/semantics/resolve.rs @@ -0,0 +1,181 @@ +use std::collections::HashMap; +use std::path::{Path, PathBuf}; + +use crate::error::{Error, ImportError}; +use crate::syntax; +use crate::syntax::{FilePath, ImportLocation, URL}; +use crate::{Normalized, NormalizedExpr, Parsed, 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; + +fn resolve_import( + import: &Import, + root: &ImportRoot, + import_cache: &mut ImportCache, + import_stack: &ImportStack, +) -> 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(&path_buf, import_cache, import_stack).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 do_resolve_expr( + 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)); + } + match import_cache.get(&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()); + + // Resolve the import recursively + let expr = resolve_import( + &import, + &root, + import_cache, + &import_stack, + )?; + + // Add the import to the cache + import_cache.insert(import, expr.clone()); + Ok(expr) + } + } + }; + expr.traverse_resolve_mut(&mut resolve)?; + Ok(Resolved(expr)) +} + +pub(crate) fn resolve(e: Parsed) -> Result { + do_resolve_expr(e, &mut HashMap::new(), &Vec::new()) +} + +pub(crate) fn skip_resolve_expr( + parsed: Parsed, +) -> Result { + let mut expr = parsed.0; + let mut resolve = |import: Import| -> Result { + Err(ImportError::UnexpectedImport(import)) + }; + expr.traverse_resolve_mut(&mut resolve)?; + Ok(Resolved(expr)) +} + +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.3.1