summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-05-06 22:09:55 +0200
committerNadrieril2019-05-06 22:09:55 +0200
commit423fdeebe9247b16744fae4b50df415bbd08be04 (patch)
treef2f16407d7e365e6fecee400a1959ca08b2a5156
parent2075cba6d883278a534afd2d8fe8f0a5e9b2f0d0 (diff)
Reorganize dhall into a phase structure
-rw-r--r--dhall/src/error.rs38
-rw-r--r--dhall/src/expr.rs228
-rw-r--r--dhall/src/lib.rs11
-rw-r--r--dhall/src/parser.rs6
-rw-r--r--dhall/src/phase/binary.rs (renamed from dhall/src/binary.rs)0
-rw-r--r--dhall/src/phase/mod.rs389
-rw-r--r--dhall/src/phase/normalize.rs (renamed from dhall/src/normalize.rs)37
-rw-r--r--dhall/src/phase/parse.rs38
-rw-r--r--dhall/src/phase/resolve.rs (renamed from dhall/src/imports.rs)53
-rw-r--r--dhall/src/phase/typecheck.rs (renamed from dhall/src/typecheck.rs)157
-rw-r--r--dhall/src/serde.rs2
-rw-r--r--dhall/src/tests.rs2
-rw-r--r--dhall/src/traits/deserialize.rs2
-rw-r--r--dhall/src/traits/dynamic_type.rs7
-rw-r--r--dhall/src/traits/static_type.rs6
15 files changed, 499 insertions, 477 deletions
diff --git a/dhall/src/error.rs b/dhall/src/error.rs
index 6ed0bfb..8497a91 100644
--- a/dhall/src/error.rs
+++ b/dhall/src/error.rs
@@ -1,13 +1,21 @@
+use std::io::Error as IOError;
+
+use dhall_syntax::ParseError;
+
+use crate::phase::binary::DecodeError;
+use crate::phase::resolve::ImportError;
+use crate::phase::typecheck::TypeError;
+
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
- IO(std::io::Error),
- Parse(dhall_syntax::ParseError),
- Decode(crate::binary::DecodeError),
- Resolve(crate::imports::ImportError),
- Typecheck(crate::typecheck::TypeError),
+ IO(IOError),
+ Parse(ParseError),
+ Decode(DecodeError),
+ Resolve(ImportError),
+ Typecheck(TypeError),
Deserialize(String),
}
@@ -25,28 +33,28 @@ impl std::fmt::Display for Error {
}
impl std::error::Error for Error {}
-impl From<std::io::Error> for Error {
- fn from(err: std::io::Error) -> Error {
+impl From<IOError> for Error {
+ fn from(err: IOError) -> Error {
Error::IO(err)
}
}
-impl From<dhall_syntax::ParseError> for Error {
- fn from(err: dhall_syntax::ParseError) -> Error {
+impl From<ParseError> for Error {
+ fn from(err: ParseError) -> Error {
Error::Parse(err)
}
}
-impl From<crate::binary::DecodeError> for Error {
- fn from(err: crate::binary::DecodeError) -> Error {
+impl From<DecodeError> for Error {
+ fn from(err: DecodeError) -> Error {
Error::Decode(err)
}
}
-impl From<crate::imports::ImportError> for Error {
- fn from(err: crate::imports::ImportError) -> Error {
+impl From<ImportError> for Error {
+ fn from(err: ImportError) -> Error {
Error::Resolve(err)
}
}
-impl From<crate::typecheck::TypeError> for Error {
- fn from(err: crate::typecheck::TypeError) -> Error {
+impl From<TypeError> for Error {
+ fn from(err: TypeError) -> Error {
Error::Typecheck(err)
}
}
diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs
deleted file mode 100644
index 896753c..0000000
--- a/dhall/src/expr.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use crate::imports::ImportRoot;
-use crate::normalize::{Thunk, Value};
-use dhall_syntax::*;
-
-macro_rules! derive_other_traits {
- ($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(Debug, Clone)]
-pub(crate) struct Parsed(
- pub(crate) SubExpr<Span, Import>,
- pub(crate) ImportRoot,
-);
-derive_other_traits!(Parsed);
-
-#[derive(Debug, Clone)]
-pub(crate) struct Resolved(pub(crate) SubExpr<Span, Normalized>);
-derive_other_traits!(Resolved);
-
-pub(crate) use self::typed::Typed;
-
-#[derive(Debug, Clone)]
-pub(crate) struct Normalized(pub(crate) Typed);
-
-impl std::cmp::PartialEq for Normalized {
- fn eq(&self, other: &Self) -> bool {
- self.0 == other.0
- }
-}
-
-impl std::cmp::Eq for Normalized {}
-
-impl std::fmt::Display for Normalized {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
- self.to_expr().fmt(f)
- }
-}
-
-mod typed {
- use super::Type;
- use crate::normalize::{AlphaVar, Thunk, Value};
- use crate::typecheck::{
- TypeError, TypeInternal, TypeMessage, TypecheckContext,
- };
- use dhall_syntax::{Const, SubExpr, X};
- use std::borrow::Cow;
-
- #[derive(Debug, Clone)]
- pub(crate) enum Typed {
- // The `Sort` higher-kinded type doesn't have a type
- Sort,
- // Any other value, along with its type
- Value(Thunk, Option<Type>),
- }
-
- impl Typed {
- pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self {
- Typed::Value(th, Some(t))
- }
-
- pub(crate) fn from_thunk_untyped(th: Thunk) -> Self {
- Typed::Value(th, None)
- }
-
- // TODO: Avoid cloning if possible
- pub(crate) fn to_value(&self) -> Value {
- match self {
- Typed::Value(th, _) => th.to_value(),
- Typed::Sort => Value::Const(Const::Sort),
- }
- }
-
- pub(crate) fn to_expr(&self) -> SubExpr<X, X> {
- self.to_value().normalize_to_expr()
- }
-
- pub(crate) fn to_expr_alpha(&self) -> SubExpr<X, X> {
- self.to_value().normalize_to_expr_maybe_alpha(true)
- }
-
- pub(crate) fn to_thunk(&self) -> Thunk {
- match self {
- Typed::Value(th, _) => th.clone(),
- Typed::Sort => Thunk::from_value(Value::Const(Const::Sort)),
- }
- }
-
- pub(crate) fn to_type(&self) -> Type {
- match self {
- Typed::Sort => Type(TypeInternal::Const(Const::Sort)),
- Typed::Value(th, _) => match &*th.as_value() {
- Value::Const(c) => Type(TypeInternal::Const(*c)),
- _ => Type(TypeInternal::Typed(Box::new(self.clone()))),
- },
- }
- }
-
- pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- match self {
- Typed::Value(_, Some(t)) => Ok(Cow::Borrowed(t)),
- Typed::Value(_, None) => Err(TypeError::new(
- &TypecheckContext::new(),
- TypeMessage::Untyped,
- )),
- Typed::Sort => Err(TypeError::new(
- &TypecheckContext::new(),
- TypeMessage::Sort,
- )),
- }
- }
-
- pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- match self {
- Typed::Value(th, t) => Typed::Value(
- th.shift(delta, var),
- t.as_ref().map(|x| x.shift(delta, var)),
- ),
- Typed::Sort => Typed::Sort,
- }
- }
-
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- match self {
- Typed::Value(th, t) => Typed::Value(
- th.subst_shift(var, val),
- t.as_ref().map(|x| x.subst_shift(var, val)),
- ),
- Typed::Sort => Typed::Sort,
- }
- }
- pub(crate) fn const_sort() -> Self {
- Typed::Sort
- }
- }
-
- impl std::cmp::PartialEq for Typed {
- fn eq(&self, other: &Self) -> bool {
- self.to_value() == other.to_value()
- }
- }
-
- impl std::cmp::Eq for Typed {}
-}
-
-/// A Dhall expression representing a simple type.
-///
-/// This captures what is usually simply called a "type", like
-/// `Bool`, `{ x: Integer }` or `Natural -> Text`.
-///
-/// For a more general notion of "type", see [Type].
-#[derive(Debug, Clone)]
-pub struct SimpleType(pub(crate) SubExpr<X, X>);
-derive_other_traits!(SimpleType);
-
-pub(crate) use crate::typecheck::TypeInternal;
-
-/// A Dhall expression representing a (possibly higher-kinded) type.
-///
-/// This includes [SimpleType]s but also higher-kinded expressions like
-/// `Type`, `Kind` and `{ x: Type }`.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Type(pub(crate) TypeInternal);
-
-impl std::fmt::Display for Type {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
- self.to_normalized().fmt(f)
- }
-}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<SimpleType> for SubExpr<X, X> {
- fn from(x: SimpleType) -> SubExpr<X, X> {
- x.0
- }
-}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<SubExpr<X, X>> for SimpleType {
- fn from(x: SubExpr<X, X>) -> SimpleType {
- SimpleType(x)
- }
-}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<Normalized> for Typed {
- fn from(x: Normalized) -> Typed {
- x.0
- }
-}
-
-impl Normalized {
- pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self {
- Normalized(Typed::from_thunk_and_type(th, t))
- }
- pub(crate) fn to_expr(&self) -> SubExpr<X, X> {
- self.0.to_expr()
- }
- #[allow(dead_code)]
- pub(crate) fn to_expr_alpha(&self) -> SubExpr<X, X> {
- self.0.to_expr_alpha()
- }
- pub(crate) fn to_value(&self) -> Value {
- self.0.to_value()
- }
- pub(crate) fn to_thunk(&self) -> Thunk {
- self.0.to_thunk()
- }
-}
diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs
index a531f64..ec110f7 100644
--- a/dhall/src/lib.rs
+++ b/dhall/src/lib.rs
@@ -123,18 +123,11 @@
#[macro_use]
mod tests;
-#[cfg(test)]
-mod parser;
-
-mod binary;
/// When manipulating Dhall expressions goes wrong.
pub mod error;
-pub mod expr;
-mod imports;
-mod normalize;
+mod phase;
mod serde;
mod traits;
-mod typecheck;
/// Deserialization of Dhall expressions into Rust
pub mod de {
@@ -153,7 +146,7 @@ pub mod de {
/// expression has that type.
pub fn from_str<'a, T: Deserialize<'a>>(
s: &'a str,
- ty: Option<&crate::expr::Type>,
+ ty: Option<&crate::phase::Type>,
) -> crate::error::Result<T> {
T::from_str(s, ty)
}
diff --git a/dhall/src/parser.rs b/dhall/src/parser.rs
deleted file mode 100644
index 3648c4f..0000000
--- a/dhall/src/parser.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[cfg(test)]
-mod spec_tests {
- #![rustfmt::skip]
- // See ../build.rs
- include!(concat!(env!("OUT_DIR"), "/parser_tests.rs"));
-}
diff --git a/dhall/src/binary.rs b/dhall/src/phase/binary.rs
index 9c31d4c..9c31d4c 100644
--- a/dhall/src/binary.rs
+++ b/dhall/src/phase/binary.rs
diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs
new file mode 100644
index 0000000..0b6eca6
--- /dev/null
+++ b/dhall/src/phase/mod.rs
@@ -0,0 +1,389 @@
+use std::borrow::Cow;
+use std::fmt::Display;
+use std::path::Path;
+
+use dhall_syntax::{Const, Import, Span, SubExpr, X};
+
+use crate::error::Error;
+
+use normalize::{AlphaVar, Thunk, Value};
+use resolve::{ImportError, ImportRoot};
+use typecheck::{
+ const_to_typed, type_of_const, TypeError, TypeMessage, TypecheckContext,
+};
+
+pub(crate) mod binary;
+pub(crate) mod normalize;
+pub(crate) mod parse;
+pub(crate) mod resolve;
+pub(crate) mod typecheck;
+
+pub(crate) type ParsedSubExpr = SubExpr<Span, Import>;
+pub(crate) type ResolvedSubExpr = SubExpr<Span, Normalized>;
+pub(crate) type NormalizedSubExpr = SubExpr<X, X>;
+
+#[derive(Debug, Clone)]
+pub(crate) struct Parsed(pub(crate) ParsedSubExpr, pub(crate) ImportRoot);
+
+/// An expression where all imports have been resolved
+#[derive(Debug, Clone)]
+pub(crate) struct Resolved(pub(crate) ResolvedSubExpr);
+
+/// A typed expression
+#[derive(Debug, Clone)]
+pub(crate) enum Typed {
+ // The `Sort` higher-kinded type; it doesn't have a type
+ Sort,
+ // Any other value, along with (optionally) its type
+ Value(Thunk, Option<Type>),
+}
+
+/// A normalized expression.
+///
+/// Invariant: the contained Typed expression must be in normal form,
+#[derive(Debug, Clone)]
+pub(crate) struct Normalized(pub(crate) Typed);
+
+/// A Dhall expression representing a simple type.
+///
+/// This captures what is usually simply called a "type", like
+/// `Bool`, `{ x: Integer }` or `Natural -> Text`.
+///
+/// For a more general notion of "type", see [Type].
+#[derive(Debug, Clone)]
+pub struct SimpleType(pub(crate) NormalizedSubExpr);
+
+/// A Dhall expression representing a (possibly higher-kinded) type.
+///
+/// This includes [SimpleType]s but also higher-kinded expressions like
+/// `Type`, `Kind` and `{ x: Type }`.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Type(pub(crate) TypeInternal);
+
+#[derive(Debug, Clone)]
+pub(crate) enum TypeInternal {
+ Const(Const),
+ /// This must not contain a Const value.
+ Typed(Box<Typed>),
+}
+
+impl Parsed {
+ pub fn parse_file(f: &Path) -> Result<Parsed, Error> {
+ parse::parse_file(f)
+ }
+
+ pub fn parse_str(s: &str) -> Result<Parsed, Error> {
+ parse::parse_str(s)
+ }
+
+ #[allow(dead_code)]
+ pub fn parse_binary_file(f: &Path) -> Result<Parsed, Error> {
+ parse::parse_binary_file(f)
+ }
+
+ pub fn resolve(self) -> Result<Resolved, ImportError> {
+ resolve::resolve(self)
+ }
+
+ #[allow(dead_code)]
+ pub fn skip_resolve(self) -> Result<Resolved, ImportError> {
+ resolve::skip_resolve_expr(self)
+ }
+}
+
+impl Resolved {
+ pub fn typecheck(self) -> Result<Typed, TypeError> {
+ typecheck::typecheck(self)
+ }
+ pub fn typecheck_with(self, ty: &Type) -> Result<Typed, TypeError> {
+ typecheck::typecheck_with(self, ty)
+ }
+ /// Pretends this expression has been typechecked. Use with care.
+ #[allow(dead_code)]
+ pub fn skip_typecheck(self) -> Typed {
+ typecheck::skip_typecheck(self)
+ }
+}
+
+impl Typed {
+ /// Reduce an expression to its normal form, performing beta reduction
+ ///
+ /// `normalize` does not type-check the expression. You may want to type-check
+ /// expressions before normalizing them since normalization can convert an
+ /// ill-typed expression into a well-typed expression.
+ ///
+ /// However, `normalize` will not fail if the expression is ill-typed and will
+ /// leave ill-typed sub-expressions unevaluated.
+ pub fn normalize(self) -> Normalized {
+ match &self {
+ Typed::Sort => {}
+ Typed::Value(thunk, _) => {
+ thunk.normalize_nf();
+ }
+ }
+ Normalized(self)
+ }
+
+ pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self {
+ Typed::Value(th, Some(t))
+ }
+ pub(crate) fn from_thunk_untyped(th: Thunk) -> Self {
+ Typed::Value(th, None)
+ }
+
+ // TODO: Avoid cloning if possible
+ pub(crate) fn to_value(&self) -> Value {
+ match self {
+ Typed::Value(th, _) => th.to_value(),
+ Typed::Sort => Value::Const(Const::Sort),
+ }
+ }
+ pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
+ self.to_value().normalize_to_expr()
+ }
+ pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr {
+ self.to_value().normalize_to_expr_maybe_alpha(true)
+ }
+ pub(crate) fn to_thunk(&self) -> Thunk {
+ match self {
+ Typed::Value(th, _) => th.clone(),
+ Typed::Sort => Thunk::from_value(Value::Const(Const::Sort)),
+ }
+ }
+ pub(crate) fn to_type(&self) -> Type {
+ match self {
+ Typed::Sort => Type(TypeInternal::Const(Const::Sort)),
+ Typed::Value(th, _) => match &*th.as_value() {
+ Value::Const(c) => Type(TypeInternal::Const(*c)),
+ _ => Type(TypeInternal::Typed(Box::new(self.clone()))),
+ },
+ }
+ }
+
+ pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
+ match self {
+ Typed::Value(_, Some(t)) => Ok(Cow::Borrowed(t)),
+ Typed::Value(_, None) => Err(TypeError::new(
+ &TypecheckContext::new(),
+ TypeMessage::Untyped,
+ )),
+ Typed::Sort => {
+ Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort))
+ }
+ }
+ }
+
+ pub(crate) fn const_sort() -> Self {
+ Typed::Sort
+ }
+
+ pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
+ match self {
+ Typed::Value(th, t) => Typed::Value(
+ th.shift(delta, var),
+ t.as_ref().map(|x| x.shift(delta, var)),
+ ),
+ Typed::Sort => Typed::Sort,
+ }
+ }
+
+ pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
+ match self {
+ Typed::Value(th, t) => Typed::Value(
+ th.subst_shift(var, val),
+ t.as_ref().map(|x| x.subst_shift(var, val)),
+ ),
+ Typed::Sort => Typed::Sort,
+ }
+ }
+}
+
+impl Type {
+ pub(crate) fn to_normalized(&self) -> Normalized {
+ self.0.to_normalized()
+ }
+ pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
+ self.0.to_expr()
+ }
+ pub(crate) fn to_value(&self) -> Value {
+ self.0.to_value()
+ }
+ pub(crate) fn as_const(&self) -> Option<Const> {
+ self.0.as_const()
+ }
+ pub(crate) fn internal_whnf(&self) -> Option<Value> {
+ self.0.whnf()
+ }
+ pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
+ self.0.get_type()
+ }
+
+ pub(crate) fn const_sort() -> Self {
+ Type(TypeInternal::Const(Const::Sort))
+ }
+ pub(crate) fn const_kind() -> Self {
+ Type(TypeInternal::Const(Const::Kind))
+ }
+ pub(crate) fn const_type() -> Self {
+ Type(TypeInternal::Const(Const::Type))
+ }
+
+ pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
+ Type(self.0.shift(delta, var))
+ }
+ pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
+ Type(self.0.subst_shift(var, val))
+ }
+}
+
+impl TypeInternal {
+ pub(crate) fn to_typed(&self) -> Typed {
+ match self {
+ TypeInternal::Typed(e) => e.as_ref().clone(),
+ TypeInternal::Const(c) => const_to_typed(*c),
+ }
+ }
+ pub(crate) fn to_normalized(&self) -> Normalized {
+ self.to_typed().normalize()
+ }
+ pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
+ self.to_normalized().to_expr()
+ }
+ pub(crate) fn to_value(&self) -> Value {
+ self.to_typed().to_value()
+ }
+ pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
+ Ok(match self {
+ TypeInternal::Typed(e) => e.get_type()?,
+ TypeInternal::Const(c) => Cow::Owned(type_of_const(*c)?),
+ })
+ }
+ pub(crate) fn as_const(&self) -> Option<Const> {
+ match self {
+ TypeInternal::Const(c) => Some(*c),
+ _ => None,
+ }
+ }
+ pub(crate) fn whnf(&self) -> Option<Value> {
+ match self {
+ TypeInternal::Typed(e) => Some(e.to_value()),
+ _ => None,
+ }
+ }
+ pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
+ use TypeInternal::*;
+ match self {
+ Typed(e) => Typed(Box::new(e.shift(delta, var))),
+ Const(c) => Const(*c),
+ }
+ }
+ pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
+ use TypeInternal::*;
+ match self {
+ Typed(e) => Typed(Box::new(e.subst_shift(var, val))),
+ Const(c) => Const(*c),
+ }
+ }
+}
+
+impl Normalized {
+ pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self {
+ Normalized(Typed::from_thunk_and_type(th, t))
+ }
+
+ pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
+ self.0.to_expr()
+ }
+ #[allow(dead_code)]
+ pub(crate) fn to_expr_alpha(&self) -> NormalizedSubExpr {
+ self.0.to_expr_alpha()
+ }
+ pub(crate) fn to_value(&self) -> Value {
+ self.0.to_value()
+ }
+ pub(crate) fn to_thunk(&self) -> Thunk {
+ self.0.to_thunk()
+ }
+ pub(crate) fn to_type(self) -> Type {
+ self.0.to_type()
+ }
+ pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
+ Normalized(self.0.shift(delta, var))
+ }
+}
+
+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);
+derive_traits_for_wrapper_struct!(Normalized);
+derive_traits_for_wrapper_struct!(SimpleType);
+
+impl Eq for Typed {}
+impl PartialEq for Typed {
+ fn eq(&self, other: &Self) -> bool {
+ self.to_value() == other.to_value()
+ }
+}
+
+impl Eq for TypeInternal {}
+impl PartialEq for TypeInternal {
+ fn eq(&self, other: &Self) -> bool {
+ self.to_normalized() == other.to_normalized()
+ }
+}
+
+impl Display for Typed {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ self.to_expr().fmt(f)
+ }
+}
+
+impl Display for Type {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ self.to_normalized().fmt(f)
+ }
+}
+
+// Exposed for the macros
+#[doc(hidden)]
+impl From<SimpleType> for NormalizedSubExpr {
+ fn from(x: SimpleType) -> NormalizedSubExpr {
+ x.0
+ }
+}
+
+// Exposed for the macros
+#[doc(hidden)]
+impl From<NormalizedSubExpr> for SimpleType {
+ fn from(x: NormalizedSubExpr) -> SimpleType {
+ SimpleType(x)
+ }
+}
+
+// Exposed for the macros
+#[doc(hidden)]
+impl From<Normalized> for Typed {
+ fn from(x: Normalized) -> Typed {
+ x.0
+ }
+}
diff --git a/dhall/src/normalize.rs b/dhall/src/phase/normalize.rs
index 1d306bc..2340bbd 100644
--- a/dhall/src/normalize.rs
+++ b/dhall/src/phase/normalize.rs
@@ -6,34 +6,13 @@ use dhall_proc_macros as dhall;
use dhall_syntax::context::Context;
use dhall_syntax::{
rc, BinOp, Builtin, Const, ExprF, Integer, InterpolatedTextContents, Label,
- Natural, Span, SubExpr, V, X,
+ Natural, V, X,
};
-use crate::expr::{Normalized, Type, Typed};
-
-type InputSubExpr = SubExpr<Span, Normalized>;
-type OutputSubExpr = SubExpr<X, X>;
-
-impl Typed {
- /// Reduce an expression to its normal form, performing beta reduction
- ///
- /// `normalize` does not type-check the expression. You may want to type-check
- /// expressions before normalizing them since normalization can convert an
- /// ill-typed expression into a well-typed expression.
- ///
- /// However, `normalize` will not fail if the expression is ill-typed and will
- /// leave ill-typed sub-expressions unevaluated.
- ///
- pub fn normalize(self) -> Normalized {
- match &self {
- Typed::Sort => {}
- Typed::Value(thunk, _) => {
- thunk.normalize_nf();
- }
- }
- Normalized(self)
- }
-}
+use crate::phase::{NormalizedSubExpr, ResolvedSubExpr, Type, Typed};
+
+type InputSubExpr = ResolvedSubExpr;
+type OutputSubExpr = NormalizedSubExpr;
/// Stores a pair of variables: a normal one and if relevant one
/// that corresponds to the alpha-normalized version of the first one.
@@ -186,9 +165,9 @@ impl NormalizationContext {
}
}
pub(crate) fn from_typecheck_ctx(
- tc_ctx: &crate::typecheck::TypecheckContext,
+ tc_ctx: &crate::phase::typecheck::TypecheckContext,
) -> Self {
- use crate::typecheck::EnvItem::*;
+ use crate::phase::typecheck::EnvItem::*;
let mut ctx = Context::new();
for (k, vs) in tc_ctx.0.iter_keys() {
for v in vs.iter() {
@@ -718,7 +697,7 @@ mod thunk {
apply_any, normalize_whnf, AlphaVar, InputSubExpr,
NormalizationContext, OutputSubExpr, Value,
};
- use crate::expr::Typed;
+ use crate::phase::Typed;
use std::cell::{Ref, RefCell};
use std::rc::Rc;
diff --git a/dhall/src/phase/parse.rs b/dhall/src/phase/parse.rs
new file mode 100644
index 0000000..809faf4
--- /dev/null
+++ b/dhall/src/phase/parse.rs
@@ -0,0 +1,38 @@
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+
+use dhall_syntax::parse_expr;
+
+use crate::error::Error;
+use crate::phase::resolve::ImportRoot;
+use crate::phase::Parsed;
+
+pub(crate) fn parse_file(f: &Path) -> Result<Parsed, Error> {
+ 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.unnote().note_absurd(), root))
+}
+
+pub(crate) fn parse_str(s: &str) -> Result<Parsed, Error> {
+ let expr = parse_expr(s)?;
+ let root = ImportRoot::LocalDir(std::env::current_dir()?);
+ Ok(Parsed(expr, root))
+}
+
+pub(crate) fn parse_binary_file(f: &Path) -> Result<Parsed, Error> {
+ let mut buffer = Vec::new();
+ File::open(f)?.read_to_end(&mut buffer)?;
+ let expr = crate::phase::binary::decode(&buffer)?;
+ let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned());
+ Ok(Parsed(expr.note_absurd(), root))
+}
+
+#[cfg(test)]
+mod spec_tests {
+ #![rustfmt::skip]
+ // See build.rs
+ include!(concat!(env!("OUT_DIR"), "/parser_tests.rs"));
+}
diff --git a/dhall/src/imports.rs b/dhall/src/phase/resolve.rs
index 87642a2..afb49cb 100644
--- a/dhall/src/imports.rs
+++ b/dhall/src/phase/resolve.rs
@@ -1,11 +1,10 @@
-use crate::error::Error;
-use crate::expr::*;
-use dhall_syntax::*;
use std::collections::HashMap;
-use std::fs::File;
-use std::io::Read;
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
+
+use dhall_syntax::Import;
+
+use crate::error::Error;
+use crate::phase::{Normalized, Parsed, Resolved};
#[derive(Debug)]
pub enum ImportError {
@@ -97,7 +96,11 @@ fn do_resolve_expr(
Ok(Resolved(expr))
}
-fn skip_resolve_expr(
+pub(crate) fn resolve(e: Parsed) -> Result<Resolved, ImportError> {
+ do_resolve_expr(e, &mut HashMap::new(), &Vec::new())
+}
+
+pub(crate) fn skip_resolve_expr(
Parsed(expr, _root): Parsed,
) -> Result<Resolved, ImportError> {
let resolve = |import: &Import| -> Result<Normalized, ImportError> {
@@ -107,40 +110,6 @@ fn skip_resolve_expr(
Ok(Resolved(expr))
}
-impl Parsed {
- pub fn parse_file(f: &Path) -> Result<Parsed, Error> {
- 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.unnote().note_absurd(), root))
- }
-
- pub fn parse_str(s: &str) -> Result<Parsed, Error> {
- let expr = parse_expr(s)?;
- let root = ImportRoot::LocalDir(std::env::current_dir()?);
- Ok(Parsed(expr, root))
- }
-
- #[allow(dead_code)]
- pub fn parse_binary_file(f: &Path) -> Result<Parsed, Error> {
- let mut buffer = Vec::new();
- File::open(f)?.read_to_end(&mut buffer)?;
- let expr = crate::binary::decode(&buffer)?;
- let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned());
- Ok(Parsed(expr.note_absurd(), root))
- }
-
- pub fn resolve(self) -> Result<Resolved, ImportError> {
- crate::imports::do_resolve_expr(self, &mut HashMap::new(), &Vec::new())
- }
-
- #[allow(dead_code)]
- pub fn skip_resolve(self) -> Result<Resolved, ImportError> {
- crate::imports::skip_resolve_expr(self)
- }
-}
-
#[cfg(test)]
mod spec_tests {
#![rustfmt::skip]
diff --git a/dhall/src/typecheck.rs b/dhall/src/phase/typecheck.rs
index 4dde883..6b12077 100644
--- a/dhall/src/typecheck.rs
+++ b/dhall/src/phase/typecheck.rs
@@ -4,10 +4,10 @@ use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt;
-use crate::expr::*;
-use crate::normalize::{
+use crate::phase::normalize::{
AlphaVar, NormalizationContext, Thunk, TypeThunk, Value,
};
+use crate::phase::*;
use crate::traits::DynamicType;
use dhall_proc_macros as dhall;
use dhall_syntax;
@@ -16,71 +16,6 @@ use dhall_syntax::*;
use self::TypeMessage::*;
-impl Resolved {
- pub fn typecheck(self) -> Result<Typed, TypeError> {
- type_of(self.0)
- }
- pub fn typecheck_with(self, ty: &Type) -> Result<Typed, TypeError> {
- let expr: SubExpr<_, _> = self.0;
- let ty: SubExpr<_, _> = ty.to_expr().embed_absurd().note_absurd();
- type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty)))
- }
- /// Pretends this expression has been typechecked. Use with care.
- #[allow(dead_code)]
- pub fn skip_typecheck(self) -> Typed {
- Typed::from_thunk_untyped(Thunk::new(
- NormalizationContext::new(),
- self.0,
- ))
- }
-}
-
-impl Normalized {
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- Normalized(self.0.shift(delta, var))
- }
- pub(crate) fn to_type(self) -> Type {
- self.0.to_type()
- }
-}
-
-impl Type {
- pub(crate) fn to_normalized(&self) -> Normalized {
- self.0.to_normalized()
- }
- pub(crate) fn to_expr(&self) -> SubExpr<X, X> {
- self.0.to_expr()
- }
- pub(crate) fn to_value(&self) -> Value {
- self.0.to_value()
- }
- pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- self.0.get_type()
- }
- fn as_const(&self) -> Option<Const> {
- self.0.as_const()
- }
- fn internal_whnf(&self) -> Option<Value> {
- self.0.whnf()
- }
- pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- Type(self.0.shift(delta, var))
- }
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- Type(self.0.subst_shift(var, val))
- }
-
- fn const_sort() -> Self {
- Type(TypeInternal::Const(Const::Sort))
- }
- fn const_kind() -> Self {
- Type(TypeInternal::Const(Const::Kind))
- }
- pub(crate) fn const_type() -> Self {
- Type(TypeInternal::Const(Const::Type))
- }
-}
-
impl TypeThunk {
fn to_type(&self, ctx: &TypecheckContext) -> Result<Type, TypeError> {
match self {
@@ -93,74 +28,6 @@ impl TypeThunk {
}
}
-/// A semantic type. This is partially redundant with `dhall_syntax::Expr`, on purpose. `TypeInternal` should
-/// be limited to syntactic expressions: either written by the user or meant to be printed.
-/// The rule is the following: we must _not_ construct values of type `Expr` while typechecking,
-/// but only construct `TypeInternal`s.
-#[derive(Debug, Clone)]
-pub(crate) enum TypeInternal {
- Const(Const),
- /// This must not contain a Const value.
- Typed(Box<Typed>),
-}
-
-impl TypeInternal {
- fn to_typed(&self) -> Typed {
- match self {
- TypeInternal::Typed(e) => e.as_ref().clone(),
- TypeInternal::Const(c) => const_to_typed(*c),
- }
- }
- fn to_normalized(&self) -> Normalized {
- self.to_typed().normalize()
- }
- fn to_expr(&self) -> SubExpr<X, X> {
- self.to_normalized().to_expr()
- }
- fn to_value(&self) -> Value {
- self.to_typed().to_value()
- }
- pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- Ok(match self {
- TypeInternal::Typed(e) => e.get_type()?,
- TypeInternal::Const(c) => Cow::Owned(type_of_const(*c)?),
- })
- }
- fn as_const(&self) -> Option<Const> {
- match self {
- TypeInternal::Const(c) => Some(*c),
- _ => None,
- }
- }
- fn whnf(&self) -> Option<Value> {
- match self {
- TypeInternal::Typed(e) => Some(e.to_value()),
- _ => None,
- }
- }
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- use TypeInternal::*;
- match self {
- Typed(e) => Typed(Box::new(e.shift(delta, var))),
- Const(c) => Const(*c),
- }
- }
- fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- use TypeInternal::*;
- match self {
- Typed(e) => Typed(Box::new(e.subst_shift(var, val))),
- Const(c) => Const(*c),
- }
- }
-}
-
-impl Eq for TypeInternal {}
-impl PartialEq for TypeInternal {
- fn eq(&self, other: &Self) -> bool {
- self.to_normalized() == other.to_normalized()
- }
-}
-
#[derive(Debug, Clone)]
pub(crate) enum EnvItem {
Type(AlphaVar, Type),
@@ -237,7 +104,7 @@ where
eL0.borrow().to_value() == eR0.borrow().to_value()
}
-fn const_to_typed(c: Const) -> Typed {
+pub(crate) fn const_to_typed(c: Const) -> Typed {
match c {
Const::Sort => Typed::const_sort(),
_ => Typed::from_thunk_and_type(
@@ -251,7 +118,7 @@ fn const_to_type(c: Const) -> Type {
Type(TypeInternal::Const(c))
}
-fn type_of_const(c: Const) -> Result<Type, TypeError> {
+pub(crate) fn type_of_const(c: Const) -> Result<Type, TypeError> {
match c {
Const::Type => Ok(Type::const_kind()),
Const::Kind => Ok(Type::const_sort()),
@@ -918,6 +785,22 @@ fn type_of(e: SubExpr<Span, Normalized>) -> Result<Typed, TypeError> {
Ok(e)
}
+pub(crate) fn typecheck(e: Resolved) -> Result<Typed, TypeError> {
+ type_of(e.0)
+}
+
+pub(crate) fn typecheck_with(
+ e: Resolved,
+ ty: &Type,
+) -> Result<Typed, TypeError> {
+ let expr: SubExpr<_, _> = e.0;
+ let ty: SubExpr<_, _> = ty.to_expr().embed_absurd().note_absurd();
+ type_of(expr.rewrap(ExprF::Annot(expr.clone(), ty)))
+}
+pub(crate) fn skip_typecheck(e: Resolved) -> Typed {
+ Typed::from_thunk_untyped(Thunk::new(NormalizationContext::new(), e.0))
+}
+
/// The specific type error
#[derive(Debug)]
pub(crate) enum TypeMessage {
diff --git a/dhall/src/serde.rs b/dhall/src/serde.rs
index 96bc765..93921ba 100644
--- a/dhall/src/serde.rs
+++ b/dhall/src/serde.rs
@@ -1,5 +1,5 @@
use crate::error::{Error, Result};
-use crate::expr::{Normalized, Type};
+use crate::phase::{Normalized, Type};
use crate::traits::Deserialize;
use dhall_syntax::*;
use std::borrow::Cow;
diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs
index 6b2ab60..18f6917 100644
--- a/dhall/src/tests.rs
+++ b/dhall/src/tests.rs
@@ -34,7 +34,7 @@ macro_rules! make_spec_test {
}
use crate::error::{Error, Result};
-use crate::expr::Parsed;
+use crate::phase::Parsed;
use crate::traits::DynamicType;
use std::path::PathBuf;
diff --git a/dhall/src/traits/deserialize.rs b/dhall/src/traits/deserialize.rs
index e3ff2d5..9673cf9 100644
--- a/dhall/src/traits/deserialize.rs
+++ b/dhall/src/traits/deserialize.rs
@@ -1,5 +1,5 @@
use crate::error::*;
-use crate::expr::*;
+use crate::phase::*;
/// A data structure that can be deserialized from a Dhall expression
///
diff --git a/dhall/src/traits/dynamic_type.rs b/dhall/src/traits/dynamic_type.rs
index 4c8e1fd..3f8d117 100644
--- a/dhall/src/traits/dynamic_type.rs
+++ b/dhall/src/traits/dynamic_type.rs
@@ -1,9 +1,6 @@
-use crate::expr::*;
+use crate::phase::typecheck::TypeError;
+use crate::phase::*;
use crate::traits::StaticType;
-#[allow(unused_imports)]
-use crate::typecheck::{TypeError, TypeMessage, TypecheckContext};
-#[allow(unused_imports)]
-use dhall_syntax::{Const, ExprF};
use std::borrow::Cow;
pub trait DynamicType {
diff --git a/dhall/src/traits/static_type.rs b/dhall/src/traits/static_type.rs
index f90b8df..8b141a0 100644
--- a/dhall/src/traits/static_type.rs
+++ b/dhall/src/traits/static_type.rs
@@ -1,4 +1,4 @@
-use crate::expr::*;
+use crate::phase::*;
use dhall_proc_macros as dhall;
use dhall_syntax::*;
@@ -38,8 +38,8 @@ fn mktype(x: SubExpr<X, X>) -> SimpleType {
impl<T: SimpleStaticType> StaticType for T {
fn get_static_type() -> Type {
- crate::expr::Normalized::from_thunk_and_type(
- crate::normalize::Thunk::from_normalized_expr(
+ crate::phase::Normalized::from_thunk_and_type(
+ crate::phase::normalize::Thunk::from_normalized_expr(
T::get_simple_static_type().into(),
),
Type::const_type(),