diff options
author | Nadrieril Feneanar | 2019-12-20 19:39:16 +0000 |
---|---|---|
committer | GitHub | 2019-12-20 19:39:16 +0000 |
commit | de0dd59204e979e29445d634a0739394110261ef (patch) | |
tree | a75ce010c7ea771a03cb51cc2b828dad6ea1a9f7 /dhall/src/syntax | |
parent | 91ef0cf697d56c91a8d15937aa4669dc221cd6c1 (diff) | |
parent | 64cca1837cc97b7679c4e2ffd54a22ad50f05cfd (diff) |
Merge pull request #118 from Nadrieril/clarify-types
Clarify naming and file organization
Diffstat (limited to '')
-rw-r--r-- | dhall/src/syntax/ast/expr.rs (renamed from dhall/src/syntax/core/expr.rs) | 203 | ||||
-rw-r--r-- | dhall/src/syntax/ast/import.rs (renamed from dhall/src/syntax/core/import.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/ast/label.rs (renamed from dhall/src/syntax/core/label.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/ast/map.rs (renamed from dhall/src/syntax/core/map.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/ast/mod.rs (renamed from dhall/src/syntax/core/mod.rs) | 1 | ||||
-rw-r--r-- | dhall/src/syntax/ast/span.rs (renamed from dhall/src/syntax/core/span.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/ast/text.rs (renamed from dhall/src/syntax/core/text.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/ast/visitor.rs (renamed from dhall/src/syntax/core/visitor.rs) | 47 | ||||
-rw-r--r-- | dhall/src/syntax/binary/decode.rs | 19 | ||||
-rw-r--r-- | dhall/src/syntax/binary/encode.rs | 16 | ||||
-rw-r--r-- | dhall/src/syntax/core/context.rs | 80 | ||||
-rw-r--r-- | dhall/src/syntax/mod.rs | 7 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 29 | ||||
-rw-r--r-- | dhall/src/syntax/text/printer.rs | 275 |
14 files changed, 300 insertions, 377 deletions
diff --git a/dhall/src/syntax/core/expr.rs b/dhall/src/syntax/ast/expr.rs index 5b9f401..48c48d8 100644 --- a/dhall/src/syntax/core/expr.rs +++ b/dhall/src/syntax/ast/expr.rs @@ -1,51 +1,15 @@ use crate::syntax::map::{DupTreeMap, DupTreeSet}; -use crate::syntax::visitor::{self, ExprFMutVisitor, ExprFVisitor}; +use crate::syntax::visitor::{self, ExprKindMutVisitor, ExprKindVisitor}; use crate::syntax::*; pub type Integer = isize; pub type Natural = usize; pub type Double = NaiveDouble; -pub fn trivial_result<T>(x: Result<T, !>) -> T { - match x { - Ok(x) => x, - Err(e) => e, - } -} - /// Double with bitwise equality #[derive(Debug, Copy, Clone)] pub struct NaiveDouble(f64); -impl PartialEq for NaiveDouble { - fn eq(&self, other: &Self) -> bool { - self.0.to_bits() == other.0.to_bits() - } -} - -impl Eq for NaiveDouble {} - -impl std::hash::Hash for NaiveDouble { - fn hash<H>(&self, state: &mut H) - where - H: std::hash::Hasher, - { - self.0.to_bits().hash(state) - } -} - -impl From<f64> for NaiveDouble { - fn from(x: f64) -> Self { - NaiveDouble(x) - } -} - -impl From<NaiveDouble> for f64 { - fn from(x: NaiveDouble) -> f64 { - x.0 - } -} - /// Constants for a pure type system #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Const { @@ -62,18 +26,6 @@ pub enum Const { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct V<Label>(pub Label, pub usize); -// This is only for the specific `Label` type, not generic -impl From<Label> for V<Label> { - fn from(x: Label) -> V<Label> { - V(x, 0) - } -} -impl<'a> From<&'a Label> for V<Label> { - fn from(x: &'a Label) -> V<Label> { - V(x.clone(), 0) - } -} - // Definition order must match precedence order for // pretty-printing to work correctly #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -142,33 +94,19 @@ pub enum Builtin { // Each node carries an annotation. #[derive(Debug, Clone)] -pub struct Expr<Embed>(Box<(RawExpr<Embed>, Span)>); - -pub type RawExpr<Embed> = ExprF<Expr<Embed>, Embed>; - -impl<Embed: PartialEq> std::cmp::PartialEq for Expr<Embed> { - fn eq(&self, other: &Self) -> bool { - self.0.as_ref().0 == other.0.as_ref().0 - } +pub struct Expr<Embed> { + kind: Box<ExprKind<Expr<Embed>, Embed>>, + span: Span, } -impl<Embed: Eq> std::cmp::Eq for Expr<Embed> {} - -impl<Embed: std::hash::Hash> std::hash::Hash for Expr<Embed> { - fn hash<H>(&self, state: &mut H) - where - H: std::hash::Hasher, - { - (self.0).0.hash(state) - } -} +pub type UnspannedExpr<Embed> = ExprKind<Expr<Embed>, Embed>; /// Syntax tree for expressions // Having the recursion out of the enum definition enables writing // much more generic code and improves pattern-matching behind // smart pointers. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ExprF<SubExpr, Embed> { +pub enum ExprKind<SubExpr, Embed> { Const(Const), /// `x` /// `x@n` @@ -231,12 +169,12 @@ pub enum ExprF<SubExpr, Embed> { Embed(Embed), } -impl<SE, E> ExprF<SE, E> { +impl<SE, E> ExprKind<SE, E> { pub fn traverse_ref_with_special_handling_of_binders<'a, SE2, Err>( &'a self, visit_subexpr: impl FnMut(&'a SE) -> Result<SE2, Err>, visit_under_binder: impl FnOnce(&'a Label, &'a SE) -> Result<SE2, Err>, - ) -> Result<ExprF<SE2, E>, Err> + ) -> Result<ExprKind<SE2, E>, Err> where E: Clone, { @@ -250,7 +188,7 @@ impl<SE, E> ExprF<SE, E> { fn traverse_ref<'a, SE2, Err>( &'a self, visit_subexpr: impl FnMut(&'a SE) -> Result<SE2, Err>, - ) -> Result<ExprF<SE2, E>, Err> + ) -> Result<ExprKind<SE2, E>, Err> where E: Clone, { @@ -268,7 +206,7 @@ impl<SE, E> ExprF<SE, E> { &'a self, mut map_subexpr: impl FnMut(&'a SE) -> SE2, mut map_under_binder: impl FnMut(&'a Label, &'a SE) -> SE2, - ) -> ExprF<SE2, E> + ) -> ExprKind<SE2, E> where E: Clone, { @@ -281,7 +219,7 @@ impl<SE, E> ExprF<SE, E> { pub fn map_ref<'a, SE2>( &'a self, mut map_subexpr: impl FnMut(&'a SE) -> SE2, - ) -> ExprF<SE2, E> + ) -> ExprKind<SE2, E> where E: Clone, { @@ -294,22 +232,25 @@ impl<SE, E> ExprF<SE, E> { } impl<E> Expr<E> { - pub fn as_ref(&self) -> &RawExpr<E> { - &self.0.as_ref().0 - } - pub fn as_mut(&mut self) -> &mut RawExpr<E> { - &mut self.0.as_mut().0 + pub fn as_ref(&self) -> &UnspannedExpr<E> { + &self.kind } pub fn span(&self) -> Span { - self.0.as_ref().1.clone() + self.span.clone() } - pub fn new(x: RawExpr<E>, n: Span) -> Self { - Expr(Box::new((x, n))) + pub fn new(kind: UnspannedExpr<E>, span: Span) -> Self { + Expr { + kind: Box::new(kind), + span, + } } - pub fn rewrap<E2>(&self, x: RawExpr<E2>) -> Expr<E2> { - Expr(Box::new((x, (self.0).1.clone()))) + pub fn rewrap<E2>(&self, kind: UnspannedExpr<E2>) -> Expr<E2> { + Expr { + kind: Box::new(kind), + span: self.span.clone(), + } } pub fn traverse_resolve_mut<Err, F1>( @@ -320,21 +261,21 @@ impl<E> Expr<E> { E: Clone, F1: FnMut(Import<Expr<E>>) -> Result<E, Err>, { - match self.as_mut() { - ExprF::BinOp(BinOp::ImportAlt, l, r) => { - let garbage_expr = ExprF::BoolLit(false); + match self.kind.as_mut() { + ExprKind::BinOp(BinOp::ImportAlt, l, r) => { + let garbage_expr = ExprKind::BoolLit(false); let new_self = if l.traverse_resolve_mut(f).is_ok() { l } else { r.traverse_resolve_mut(f)?; r }; - *self.as_mut() = - std::mem::replace(new_self.as_mut(), garbage_expr); + *self.kind = + std::mem::replace(new_self.kind.as_mut(), garbage_expr); } _ => { - self.as_mut().traverse_mut(|e| e.traverse_resolve_mut(f))?; - if let ExprF::Import(import) = self.as_mut() { + self.kind.traverse_mut(|e| e.traverse_resolve_mut(f))?; + if let ExprKind::Import(import) = self.kind.as_mut() { let garbage_import = Import { mode: ImportMode::Code, location: ImportLocation::Missing, @@ -342,7 +283,7 @@ impl<E> Expr<E> { }; // Move out of &mut import let import = std::mem::replace(import, garbage_import); - *self.as_mut() = ExprF::Embed(f(import)?); + *self.kind = ExprKind::Embed(f(import)?); } } } @@ -350,16 +291,6 @@ impl<E> Expr<E> { } } -/// Add an isize to an usize -/// Returns `None` on over/underflow -fn add_ui(u: usize, i: isize) -> Option<usize> { - Some(if i < 0 { - u.checked_sub(i.checked_neg()? as usize)? - } else { - u.checked_add(i as usize)? - }) -} - impl<Label: PartialEq + Clone> V<Label> { pub fn shift(&self, delta: isize, var: &V<Label>) -> Option<Self> { let V(x, n) = var; @@ -375,3 +306,73 @@ impl<Label: PartialEq + Clone> V<Label> { self.shift(-1, &V(x.clone(), 0)) } } + +pub fn trivial_result<T>(x: Result<T, !>) -> T { + match x { + Ok(x) => x, + Err(e) => e, + } +} + +/// Add an isize to an usize +/// Returns `None` on over/underflow +fn add_ui(u: usize, i: isize) -> Option<usize> { + Some(if i < 0 { + u.checked_sub(i.checked_neg()? as usize)? + } else { + u.checked_add(i as usize)? + }) +} + +impl PartialEq for NaiveDouble { + fn eq(&self, other: &Self) -> bool { + self.0.to_bits() == other.0.to_bits() + } +} + +impl Eq for NaiveDouble {} + +impl std::hash::Hash for NaiveDouble { + fn hash<H>(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.0.to_bits().hash(state) + } +} + +impl From<f64> for NaiveDouble { + fn from(x: f64) -> Self { + NaiveDouble(x) + } +} + +impl From<NaiveDouble> for f64 { + fn from(x: NaiveDouble) -> f64 { + x.0 + } +} + +/// This is only for the specific `Label` type, not generic +impl From<Label> for V<Label> { + fn from(x: Label) -> V<Label> { + V(x, 0) + } +} + +impl<Embed: PartialEq> std::cmp::PartialEq for Expr<Embed> { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} + +impl<Embed: Eq> std::cmp::Eq for Expr<Embed> {} + +impl<Embed: std::hash::Hash> std::hash::Hash for Expr<Embed> { + fn hash<H>(&self, state: &mut H) + where + H: std::hash::Hasher, + { + self.kind.hash(state) + } +} diff --git a/dhall/src/syntax/core/import.rs b/dhall/src/syntax/ast/import.rs index da3e99b..da3e99b 100644 --- a/dhall/src/syntax/core/import.rs +++ b/dhall/src/syntax/ast/import.rs diff --git a/dhall/src/syntax/core/label.rs b/dhall/src/syntax/ast/label.rs index 43c3f53..43c3f53 100644 --- a/dhall/src/syntax/core/label.rs +++ b/dhall/src/syntax/ast/label.rs diff --git a/dhall/src/syntax/core/map.rs b/dhall/src/syntax/ast/map.rs index c4c6126..c4c6126 100644 --- a/dhall/src/syntax/core/map.rs +++ b/dhall/src/syntax/ast/map.rs diff --git a/dhall/src/syntax/core/mod.rs b/dhall/src/syntax/ast/mod.rs index 66bf229..1950154 100644 --- a/dhall/src/syntax/core/mod.rs +++ b/dhall/src/syntax/ast/mod.rs @@ -8,6 +8,5 @@ mod span; pub use span::*; mod text; pub use text::*; -pub mod context; pub mod map; pub mod visitor; diff --git a/dhall/src/syntax/core/span.rs b/dhall/src/syntax/ast/span.rs index f9c7008..f9c7008 100644 --- a/dhall/src/syntax/core/span.rs +++ b/dhall/src/syntax/ast/span.rs diff --git a/dhall/src/syntax/core/text.rs b/dhall/src/syntax/ast/text.rs index fb390ee..fb390ee 100644 --- a/dhall/src/syntax/core/text.rs +++ b/dhall/src/syntax/ast/text.rs diff --git a/dhall/src/syntax/core/visitor.rs b/dhall/src/syntax/ast/visitor.rs index b76d037..b557995 100644 --- a/dhall/src/syntax/core/visitor.rs +++ b/dhall/src/syntax/ast/visitor.rs @@ -1,7 +1,7 @@ use crate::syntax::*; use std::iter::FromIterator; -/// A visitor trait that can be used to traverse `ExprF`s. We need this pattern so that Rust lets +/// A visitor trait that can be used to traverse `ExprKind`s. We need this pattern so that Rust lets /// us have as much mutability as we can. /// For example, `traverse_ref_with_special_handling_of_binders` cannot be made using only /// `traverse_ref`, because `traverse_ref` takes a `FnMut` so we would need to pass multiple @@ -9,7 +9,7 @@ use std::iter::FromIterator; /// preventing exactly this ! So we have to be more clever. The visitor pattern allows us to have /// only one mutable thing the whole time: the visitor itself. The visitor can then carry around /// multiple closures or just one, and Rust is ok with either. See for example TraverseRefVisitor. -pub trait ExprFVisitor<'a, SE1, SE2, E1, E2>: Sized { +pub trait ExprKindVisitor<'a, SE1, SE2, E1, E2>: Sized { type Error; fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result<SE2, Self::Error>; @@ -25,14 +25,14 @@ pub trait ExprFVisitor<'a, SE1, SE2, E1, E2>: Sized { fn visit( self, - input: &'a ExprF<SE1, E1>, - ) -> Result<ExprF<SE2, E2>, Self::Error> { + input: &'a ExprKind<SE1, E1>, + ) -> Result<ExprKind<SE2, E2>, Self::Error> { visit_ref(self, input) } } -/// Like `ExprFVisitor`, but by mutable reference -pub trait ExprFMutVisitor<'a, SE, E>: Sized { +/// Like `ExprKindVisitor`, but by mutable reference +pub trait ExprKindMutVisitor<'a, SE, E>: Sized { type Error; fn visit_subexpr(&mut self, subexpr: &'a mut SE) @@ -49,17 +49,17 @@ pub trait ExprFMutVisitor<'a, SE, E>: Sized { self.visit_subexpr(subexpr) } - fn visit(self, input: &'a mut ExprF<SE, E>) -> Result<(), Self::Error> { + fn visit(self, input: &'a mut ExprKind<SE, E>) -> Result<(), Self::Error> { visit_mut(self, input) } } fn visit_ref<'a, V, SE1, SE2, E1, E2>( mut v: V, - input: &'a ExprF<SE1, E1>, -) -> Result<ExprF<SE2, E2>, V::Error> + input: &'a ExprKind<SE1, E1>, +) -> Result<ExprKind<SE2, E2>, V::Error> where - V: ExprFVisitor<'a, SE1, SE2, E1, E2>, + V: ExprKindVisitor<'a, SE1, SE2, E1, E2>, { fn vec<'a, T, U, Err, F: FnMut(&'a T) -> Result<U, Err>>( x: &'a [T], @@ -83,7 +83,7 @@ where where SE1: 'a, T: FromIterator<(Label, SE2)>, - V: ExprFVisitor<'a, SE1, SE2, E1, E2>, + V: ExprKindVisitor<'a, SE1, SE2, E1, E2>, { x.into_iter() .map(|(k, x)| Ok((k.clone(), v.visit_subexpr(x)?))) @@ -96,7 +96,7 @@ where where SE1: 'a, T: FromIterator<(Label, Option<SE2>)>, - V: ExprFVisitor<'a, SE1, SE2, E1, E2>, + V: ExprKindVisitor<'a, SE1, SE2, E1, E2>, { x.into_iter() .map(|(k, x)| { @@ -111,7 +111,7 @@ where .collect() } - use crate::syntax::ExprF::*; + use crate::syntax::ExprKind::*; Ok(match input { Var(v) => Var(v.clone()), Lam(l, t, e) => { @@ -172,14 +172,14 @@ where fn visit_mut<'a, V, SE, E>( mut v: V, - input: &'a mut ExprF<SE, E>, + input: &'a mut ExprKind<SE, E>, ) -> Result<(), V::Error> where - V: ExprFMutVisitor<'a, SE, E>, + V: ExprKindMutVisitor<'a, SE, E>, { fn vec<'a, V, SE, E>(v: &mut V, x: &'a mut Vec<SE>) -> Result<(), V::Error> where - V: ExprFMutVisitor<'a, SE, E>, + V: ExprKindMutVisitor<'a, SE, E>, { for x in x { v.visit_subexpr(x)?; @@ -191,7 +191,7 @@ where x: &'a mut Option<SE>, ) -> Result<(), V::Error> where - V: ExprFMutVisitor<'a, SE, E>, + V: ExprKindMutVisitor<'a, SE, E>, { if let Some(x) = x { v.visit_subexpr(x)?; @@ -204,7 +204,7 @@ where ) -> Result<(), V::Error> where SE: 'a, - V: ExprFMutVisitor<'a, SE, E>, + V: ExprKindMutVisitor<'a, SE, E>, { for (_, x) in x { v.visit_subexpr(x)?; @@ -217,7 +217,7 @@ where ) -> Result<(), V::Error> where SE: 'a, - V: ExprFMutVisitor<'a, SE, E>, + V: ExprKindMutVisitor<'a, SE, E>, { for (_, x) in x { opt(&mut v, x)?; @@ -225,7 +225,7 @@ where Ok(()) } - use crate::syntax::ExprF::*; + use crate::syntax::ExprKind::*; match input { Var(_) | Const(_) | Builtin(_) | BoolLit(_) | NaturalLit(_) | IntegerLit(_) | DoubleLit(_) => {} @@ -293,7 +293,7 @@ pub struct TraverseRefWithBindersVisitor<F1, F2> { pub visit_under_binder: F2, } -impl<'a, SE, E, SE2, Err, F1, F2> ExprFVisitor<'a, SE, SE2, E, E> +impl<'a, SE, E, SE2, Err, F1, F2> ExprKindVisitor<'a, SE, SE2, E, E> for TraverseRefWithBindersVisitor<F1, F2> where SE: 'a, @@ -322,7 +322,7 @@ pub struct TraverseRefVisitor<F1> { pub visit_subexpr: F1, } -impl<'a, SE, E, SE2, Err, F1> ExprFVisitor<'a, SE, SE2, E, E> +impl<'a, SE, E, SE2, Err, F1> ExprKindVisitor<'a, SE, SE2, E, E> for TraverseRefVisitor<F1> where SE: 'a, @@ -343,7 +343,8 @@ pub struct TraverseMutVisitor<F1> { pub visit_subexpr: F1, } -impl<'a, SE, E, Err, F1> ExprFMutVisitor<'a, SE, E> for TraverseMutVisitor<F1> +impl<'a, SE, E, Err, F1> ExprKindMutVisitor<'a, SE, E> + for TraverseMutVisitor<F1> where SE: 'a, E: 'a, diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs index 46c9921..254ab07 100644 --- a/dhall/src/syntax/binary/decode.rs +++ b/dhall/src/syntax/binary/decode.rs @@ -2,12 +2,13 @@ use itertools::Itertools; use serde_cbor::value::value as cbor; use std::iter::FromIterator; -use crate::semantics::error::DecodeError; +use crate::error::DecodeError; use crate::semantics::phase::DecodedExpr; use crate::syntax; use crate::syntax::{ - Expr, ExprF, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, - Integer, InterpolatedText, Label, Natural, RawExpr, Scheme, Span, URL, V, + Expr, ExprKind, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, + Integer, InterpolatedText, Label, Natural, Scheme, Span, UnspannedExpr, + URL, V, }; pub(crate) fn decode(data: &[u8]) -> Result<DecodedExpr, DecodeError> { @@ -18,17 +19,17 @@ pub(crate) fn decode(data: &[u8]) -> Result<DecodedExpr, DecodeError> { } // Should probably rename this -fn rc<E>(x: RawExpr<E>) -> Expr<E> { +fn rc<E>(x: UnspannedExpr<E>) -> Expr<E> { Expr::new(x, Span::Decoded) } fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { use cbor::Value::*; use syntax::{BinOp, Builtin, Const}; - use ExprF::*; + use ExprKind::*; Ok(rc(match data { String(s) => match Builtin::parse(s) { - Some(b) => ExprF::Builtin(b), + Some(b) => ExprKind::Builtin(b), None => match s.as_str() { "True" => BoolLit(true), "False" => BoolLit(false), @@ -123,7 +124,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { } [U64(4), t] => { let t = cbor_value_to_dhall(&t)?; - EmptyListLit(rc(App(rc(ExprF::Builtin(Builtin::List)), t))) + EmptyListLit(rc(App(rc(ExprKind::Builtin(Builtin::List)), t))) } [U64(4), Null, rest @ ..] => { let rest = rest @@ -139,14 +140,14 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { // Old-style optional literals [U64(5), t] => { let t = cbor_value_to_dhall(&t)?; - App(rc(ExprF::Builtin(Builtin::OptionalNone)), t) + App(rc(ExprKind::Builtin(Builtin::OptionalNone)), t) } [U64(5), t, x] => { let x = cbor_value_to_dhall(&x)?; let t = cbor_value_to_dhall(&t)?; Annot( rc(SomeLit(x)), - rc(App(rc(ExprF::Builtin(Builtin::Optional)), t)), + rc(App(rc(ExprKind::Builtin(Builtin::Optional)), t)), ) } [U64(6), x, y] => { diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs index 8e13efd..25a545c 100644 --- a/dhall/src/syntax/binary/encode.rs +++ b/dhall/src/syntax/binary/encode.rs @@ -1,12 +1,12 @@ use serde_cbor::value::value as cbor; use std::vec; -use crate::semantics::error::EncodeError; +use crate::error::EncodeError; use crate::syntax; use crate::syntax::map::DupTreeMap; use crate::syntax::{ - Expr, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, Label, - Scheme, V, + Expr, ExprKind, FilePrefix, Hash, Import, ImportLocation, ImportMode, + Label, Scheme, V, }; /// Warning: will fail if `expr` contains an `Embed` node. @@ -46,7 +46,7 @@ where use cbor::Value::{String, I64, U64}; use std::iter::once; use syntax::Builtin; - use syntax::ExprF::*; + use syntax::ExprKind::*; use self::Serialize::{RecordMap, UnionMap}; fn expr<E>(x: &Expr<E>) -> self::Serialize<'_, E> { @@ -110,7 +110,9 @@ where SomeLit(x) => ser_seq!(ser; tag(5), null(), expr(x)), EmptyListLit(x) => match x.as_ref() { App(f, a) => match f.as_ref() { - ExprF::Builtin(Builtin::List) => ser_seq!(ser; tag(4), expr(a)), + ExprKind::Builtin(Builtin::List) => { + ser_seq!(ser; tag(4), expr(a)) + } _ => ser_seq!(ser; tag(28), expr(x)), }, _ => ser_seq!(ser; tag(28), expr(x)), @@ -284,7 +286,7 @@ fn collect_nested_applications<'a, E>( ) -> (&'a Expr<E>, Vec<&'a Expr<E>>) { fn go<'a, E>(e: &'a Expr<E>, vec: &mut Vec<&'a Expr<E>>) -> &'a Expr<E> { match e.as_ref() { - ExprF::App(f, a) => { + ExprKind::App(f, a) => { vec.push(a); go(f, vec) } @@ -306,7 +308,7 @@ fn collect_nested_lets<'a, E>( vec: &mut Vec<LetBinding<'a, E>>, ) -> &'a Expr<E> { match e.as_ref() { - ExprF::Let(l, t, v, e) => { + ExprKind::Let(l, t, v, e) => { vec.push((l, t, v)); go(e, vec) } diff --git a/dhall/src/syntax/core/context.rs b/dhall/src/syntax/core/context.rs deleted file mode 100644 index 6844baa..0000000 --- a/dhall/src/syntax/core/context.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::cmp::Eq; -use std::collections::HashMap; -use std::hash::Hash; - -/// A `(Context a)` associates `Text` labels with values of type `a` -/// -/// The `Context` is used for type-checking when `(a = Expr)` -/// -/// * You create a `Context` using `empty` and `insert` -/// * You transform a `Context` using `fmap` -/// * You consume a `Context` using `lookup` and `toList` -/// -/// The difference between a `Context` and a `Map` is that a `Context` lets you -/// have multiple ordered occurrences of the same key and you can query for the -/// `n`th occurrence of a given key. -/// -#[derive(Debug, Clone)] -pub struct Context<K: Eq + Hash, T>(HashMap<K, Vec<T>>); - -impl<K: Hash + Eq + Clone, T> Context<K, T> { - /// An empty context with no key-value pairs - pub fn new() -> Self { - Context(HashMap::new()) - } - - /// Look up a key by name and index - /// - /// ```c - /// lookup _ _ empty = Nothing - /// lookup k 0 (insert k v c) = Just v - /// lookup k n (insert k v c) = lookup k (n - 1) c -- 1 <= n - /// lookup k n (insert j v c) = lookup k n c -- k /= j - /// ``` - pub fn lookup<'a>(&'a self, k: &K, n: usize) -> Option<&'a T> { - self.0.get(k).and_then(|v| { - if n < v.len() { - v.get(v.len() - 1 - n) - } else { - None - } - }) - } - - pub fn map<U, F: Fn(&K, &T) -> U>(&self, f: F) -> Context<K, U> { - Context( - self.0 - .iter() - .map(|(k, vs)| { - ((*k).clone(), vs.iter().map(|v| f(k, v)).collect()) - }) - .collect(), - ) - } - - pub fn lookup_all<'a>(&'a self, k: &K) -> impl Iterator<Item = &T> { - self.0.get(k).into_iter().flat_map(|v| v.iter()) - } - - pub fn iter(&self) -> impl Iterator<Item = (&K, &T)> { - self.0 - .iter() - .flat_map(|(k, vs)| vs.iter().map(move |v| (k, v))) - } - - pub fn iter_keys(&self) -> impl Iterator<Item = (&K, &Vec<T>)> { - self.0.iter() - } -} - -impl<K: Hash + Eq + Clone, T: Clone> Context<K, T> { - /// Add a key-value pair to the `Context` - pub fn insert(&self, k: K, v: T) -> Self { - let mut ctx = (*self).clone(); - { - let m = ctx.0.entry(k).or_insert_with(Vec::new); - m.push(v); - } - ctx - } -} diff --git a/dhall/src/syntax/mod.rs b/dhall/src/syntax/mod.rs index a82e827..512a026 100644 --- a/dhall/src/syntax/mod.rs +++ b/dhall/src/syntax/mod.rs @@ -5,10 +5,9 @@ clippy::type_complexity )] -mod core; -pub use crate::syntax::core::context; -pub use crate::syntax::core::visitor; -pub use crate::syntax::core::*; +mod ast; +pub use crate::syntax::ast::visitor; +pub use crate::syntax::ast::*; pub use crate::syntax::text::parser::*; pub use crate::syntax::text::printer::*; pub mod binary; diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index f6b6577..90cb4b1 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -7,13 +7,12 @@ use pest_consume::{match_nodes, Parser}; use crate::semantics::phase::Normalized; use crate::syntax; -use crate::syntax::core; use crate::syntax::map::{DupTreeMap, DupTreeSet}; -use crate::syntax::ExprF::*; +use crate::syntax::ExprKind::*; use crate::syntax::{ - FilePath, FilePrefix, Hash, ImportLocation, ImportMode, InterpolatedText, - InterpolatedTextContents, Label, NaiveDouble, RawExpr, Scheme, Span, URL, - V, + Double, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, Integer, + InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, Natural, + Scheme, Span, UnspannedExpr, URL, V, }; // This file consumes the parse tree generated by pest and turns it into @@ -77,10 +76,14 @@ impl crate::syntax::Builtin { fn input_to_span(input: ParseInput) -> Span { Span::make(input.user_data().clone(), input.as_pair().as_span()) } -fn spanned(input: ParseInput, x: RawExpr<Normalized>) -> Expr { +fn spanned(input: ParseInput, x: UnspannedExpr<Normalized>) -> Expr { Expr::new(x, input_to_span(input)) } -fn spanned_union(span1: Span, span2: Span, x: RawExpr<Normalized>) -> Expr { +fn spanned_union( + span1: Span, + span2: Span, + x: UnspannedExpr<Normalized>, +) -> Expr { Expr::new(x, span1.union(&span2)) } @@ -349,20 +352,20 @@ impl DhallParser { } #[alias(double_literal)] - fn NaN(_input: ParseInput) -> ParseResult<core::Double> { + fn NaN(_input: ParseInput) -> ParseResult<Double> { Ok(std::f64::NAN.into()) } #[alias(double_literal)] - fn minus_infinity_literal(_input: ParseInput) -> ParseResult<core::Double> { + fn minus_infinity_literal(_input: ParseInput) -> ParseResult<Double> { Ok(std::f64::NEG_INFINITY.into()) } #[alias(double_literal)] - fn plus_infinity_literal(_input: ParseInput) -> ParseResult<core::Double> { + fn plus_infinity_literal(_input: ParseInput) -> ParseResult<Double> { Ok(std::f64::INFINITY.into()) } #[alias(double_literal)] - fn numeric_double_literal(input: ParseInput) -> ParseResult<core::Double> { + fn numeric_double_literal(input: ParseInput) -> ParseResult<Double> { let s = input.as_str().trim(); match s.parse::<f64>() { Ok(x) if x.is_infinite() => Err(input.error(format!( @@ -374,7 +377,7 @@ impl DhallParser { } } - fn natural_literal(input: ParseInput) -> ParseResult<core::Natural> { + fn natural_literal(input: ParseInput) -> ParseResult<Natural> { input .as_str() .trim() @@ -382,7 +385,7 @@ impl DhallParser { .map_err(|e| input.error(format!("{}", e))) } - fn integer_literal(input: ParseInput) -> ParseResult<core::Integer> { + fn integer_literal(input: ParseInput) -> ParseResult<Integer> { input .as_str() .trim() diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs index 8df456b..78942ed 100644 --- a/dhall/src/syntax/text/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -2,10 +2,137 @@ use crate::syntax::*; use itertools::Itertools; use std::fmt::{self, Display}; +// There is a one-to-one correspondence between the formatter and the grammar. Each phase is +// named after a corresponding grammar group, and the structure of the formatter reflects +// the relationship between the corresponding grammar rules. This leads to the nice property +// of automatically getting all the parentheses and precedences right. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +enum PrintPhase { + Base, + Operator, + BinOp(ast::BinOp), + App, + Import, + Primitive, +} + +// Wraps an Expr with a phase, so that phase selection can be done separate from the actual +// printing. +#[derive(Clone)] +struct PhasedExpr<'a, E>(&'a Expr<E>, PrintPhase); + +impl<'a, E: Display + Clone> PhasedExpr<'a, E> { + fn phase(self, phase: PrintPhase) -> PhasedExpr<'a, E> { + PhasedExpr(self.0, phase) + } +} + +impl<E: Display + Clone> UnspannedExpr<E> { + // Annotate subexpressions with the appropriate phase, defaulting to Base + fn annotate_with_phases<'a>(&'a self) -> ExprKind<PhasedExpr<'a, E>, E> { + use crate::syntax::ExprKind::*; + use PrintPhase::*; + let with_base = self.map_ref(|e| PhasedExpr(e, Base)); + match with_base { + Pi(a, b, c) => { + if &String::from(&a) == "_" { + Pi(a, b.phase(Operator), c) + } else { + Pi(a, b, c) + } + } + Merge(a, b, c) => Merge( + a.phase(PrintPhase::Import), + b.phase(PrintPhase::Import), + c.map(|x| x.phase(PrintPhase::App)), + ), + ToMap(a, b) => ToMap( + a.phase(PrintPhase::Import), + b.map(|x| x.phase(PrintPhase::App)), + ), + Annot(a, b) => Annot(a.phase(Operator), b), + ExprKind::BinOp(op, a, b) => ExprKind::BinOp( + op, + a.phase(PrintPhase::BinOp(op)), + b.phase(PrintPhase::BinOp(op)), + ), + SomeLit(e) => SomeLit(e.phase(PrintPhase::Import)), + ExprKind::App(f, a) => ExprKind::App( + f.phase(PrintPhase::Import), + a.phase(PrintPhase::Import), + ), + Field(a, b) => Field(a.phase(Primitive), b), + Projection(e, ls) => Projection(e.phase(Primitive), ls), + ProjectionByExpr(a, b) => ProjectionByExpr(a.phase(Primitive), b), + e => e, + } + } + + fn fmt_phase( + &self, + f: &mut fmt::Formatter, + phase: PrintPhase, + ) -> Result<(), fmt::Error> { + use crate::syntax::ExprKind::*; + + let needs_paren = match self { + Lam(_, _, _) + | BoolIf(_, _, _) + | Pi(_, _, _) + | Let(_, _, _, _) + | EmptyListLit(_) + | NEListLit(_) + | SomeLit(_) + | Merge(_, _, _) + | ToMap(_, _) + | Annot(_, _) => phase > PrintPhase::Base, + // Precedence is magically handled by the ordering of BinOps. + ExprKind::BinOp(op, _, _) => phase > PrintPhase::BinOp(*op), + ExprKind::App(_, _) => phase > PrintPhase::App, + Field(_, _) | Projection(_, _) | ProjectionByExpr(_, _) => { + phase > PrintPhase::Import + } + _ => false, + }; + + if needs_paren { + f.write_str("(")?; + } + self.annotate_with_phases().fmt(f)?; + if needs_paren { + f.write_str(")")?; + } + + Ok(()) + } +} + +fn fmt_list<T, I, F>( + open: &str, + sep: &str, + close: &str, + it: I, + f: &mut fmt::Formatter, + func: F, +) -> Result<(), fmt::Error> +where + I: IntoIterator<Item = T>, + F: Fn(T, &mut fmt::Formatter) -> Result<(), fmt::Error>, +{ + f.write_str(open)?; + for (i, x) in it.into_iter().enumerate() { + if i > 0 { + f.write_str(sep)?; + } + func(x, f)?; + } + f.write_str(close) +} + /// Generic instance that delegates to subexpressions -impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> { +impl<SE: Display + Clone, E: Display> Display for ExprKind<SE, E> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::syntax::ExprF::*; + use crate::syntax::ExprKind::*; match self { Lam(a, b, c) => { write!(f, "λ({} : {}) → {}", a, b, c)?; @@ -53,10 +180,10 @@ impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> { Assert(a) => { write!(f, "assert : {}", a)?; } - ExprF::BinOp(op, a, b) => { + ExprKind::BinOp(op, a, b) => { write!(f, "{} {} {}", a, op, b)?; } - ExprF::App(a, b) => { + ExprKind::App(a, b) => { write!(f, "{} {}", a, b)?; } Field(a, b) => { @@ -104,147 +231,16 @@ impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> { } } -// There is a one-to-one correspondence between the formatter and the grammar. Each phase is -// named after a corresponding grammar group, and the structure of the formatter reflects -// the relationship between the corresponding grammar rules. This leads to the nice property -// of automatically getting all the parentheses and precedences right. -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -enum PrintPhase { - Base, - Operator, - BinOp(core::BinOp), - App, - Import, - Primitive, -} - -// Wraps an Expr with a phase, so that phase selsction can be done -// separate from the actual printing -#[derive(Clone)] -struct PhasedExpr<'a, A>(&'a Expr<A>, PrintPhase); - -impl<'a, A: Display + Clone> Display for PhasedExpr<'a, A> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0.as_ref().fmt_phase(f, self.1) - } -} - -impl<'a, A: Display + Clone> PhasedExpr<'a, A> { - fn phase(self, phase: PrintPhase) -> PhasedExpr<'a, A> { - PhasedExpr(self.0, phase) - } -} - -impl<A: Display + Clone> RawExpr<A> { - fn fmt_phase( - &self, - f: &mut fmt::Formatter, - phase: PrintPhase, - ) -> Result<(), fmt::Error> { - use crate::syntax::ExprF::*; - use PrintPhase::*; - - let needs_paren = match self { - Lam(_, _, _) - | BoolIf(_, _, _) - | Pi(_, _, _) - | Let(_, _, _, _) - | EmptyListLit(_) - | NEListLit(_) - | SomeLit(_) - | Merge(_, _, _) - | ToMap(_, _) - | Annot(_, _) - if phase > Base => - { - true - } - // Precedence is magically handled by the ordering of BinOps. - ExprF::BinOp(op, _, _) if phase > PrintPhase::BinOp(*op) => true, - ExprF::App(_, _) if phase > PrintPhase::App => true, - Field(_, _) | Projection(_, _) | ProjectionByExpr(_, _) - if phase > PrintPhase::Import => - { - true - } - _ => false, - }; - - // Annotate subexpressions with the appropriate phase, defaulting to Base - let phased_self = match self.map_ref(|e| PhasedExpr(e, Base)) { - Pi(a, b, c) => { - if &String::from(&a) == "_" { - Pi(a, b.phase(Operator), c) - } else { - Pi(a, b, c) - } - } - Merge(a, b, c) => Merge( - a.phase(PrintPhase::Import), - b.phase(PrintPhase::Import), - c.map(|x| x.phase(PrintPhase::App)), - ), - ToMap(a, b) => ToMap( - a.phase(PrintPhase::Import), - b.map(|x| x.phase(PrintPhase::App)), - ), - Annot(a, b) => Annot(a.phase(Operator), b), - ExprF::BinOp(op, a, b) => ExprF::BinOp( - op, - a.phase(PrintPhase::BinOp(op)), - b.phase(PrintPhase::BinOp(op)), - ), - SomeLit(e) => SomeLit(e.phase(PrintPhase::Import)), - ExprF::App(f, a) => ExprF::App( - f.phase(PrintPhase::Import), - a.phase(PrintPhase::Import), - ), - Field(a, b) => Field(a.phase(Primitive), b), - Projection(e, ls) => Projection(e.phase(Primitive), ls), - ProjectionByExpr(a, b) => ProjectionByExpr(a.phase(Primitive), b), - e => e, - }; - - if needs_paren { - f.write_str("(")?; - } - - // Uses the ExprF<PhasedExpr<_>, _> instance - phased_self.fmt(f)?; - - if needs_paren { - f.write_str(")")?; - } - Ok(()) - } -} - -impl<A: Display + Clone> Display for Expr<A> { +impl<E: Display + Clone> Display for Expr<E> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.as_ref().fmt_phase(f, PrintPhase::Base) } } -fn fmt_list<T, I, F>( - open: &str, - sep: &str, - close: &str, - it: I, - f: &mut fmt::Formatter, - func: F, -) -> Result<(), fmt::Error> -where - I: IntoIterator<Item = T>, - F: Fn(T, &mut fmt::Formatter) -> Result<(), fmt::Error>, -{ - f.write_str(open)?; - for (i, x) in it.into_iter().enumerate() { - if i > 0 { - f.write_str(sep)?; - } - func(x, f)?; +impl<'a, E: Display + Clone> Display for PhasedExpr<'a, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.as_ref().fmt_phase(f, self.1) } - f.write_str(close) } impl<SubExpr: Display> Display for InterpolatedText<SubExpr> { @@ -361,6 +357,7 @@ impl Display for Hash { } } } + impl<SubExpr: Display> Display for Import<SubExpr> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { use FilePrefix::*; |