diff options
author | Nadrieril Feneanar | 2019-04-06 00:43:09 +0200 |
---|---|---|
committer | GitHub | 2019-04-06 00:43:09 +0200 |
commit | 5eccde86fc3ccdeb34c9f8bb44de33d25e77f30c (patch) | |
tree | 76d0f0fc848887d2945d586b58847575ca31d0da /dhall_core/src | |
parent | f78af6d1e7f6c1dc39bde6cf97138327004ddb06 (diff) | |
parent | 6a675a13fcfafa057c44db84c3b0ca3b344cfdab (diff) |
Merge pull request #48 from Nadrieril/exprf
Move recursion out of Expr for enhanced genericity
Diffstat (limited to 'dhall_core/src')
-rw-r--r-- | dhall_core/src/core.rs | 502 | ||||
-rw-r--r-- | dhall_core/src/parser.rs | 152 | ||||
-rw-r--r-- | dhall_core/src/printer.rs | 26 | ||||
-rw-r--r-- | dhall_core/src/text.rs | 56 |
4 files changed, 469 insertions, 267 deletions
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index afa3d3f..3d1b9f3 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -100,7 +100,7 @@ pub enum Const { /// appear as a numeric suffix. /// #[derive(Debug, Clone, PartialEq, Eq)] -pub struct V(pub Label, pub usize); +pub struct V<Label>(pub Label, pub usize); // Definition order must match precedence order for // pretty-printing to work correctly @@ -170,45 +170,42 @@ pub type ParsedExpr = SubExpr<X, Import>; pub type ResolvedExpr = SubExpr<X, X>; pub type DhallExpr = ResolvedExpr; -pub type SubExpr<Note, Embed> = Rc<Expr<Note, Embed>>; +#[derive(Debug, PartialEq, Eq)] +pub struct SubExpr<Note, Embed>(pub Rc<Expr<Note, Embed>>); + +pub type Expr<Note, Embed> = ExprF<SubExpr<Note, Embed>, Label, Note, 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)] -pub enum Expr<Note, Embed> { +pub enum ExprF<SubExpr, Label, Note, Embed> { /// `Const c ~ c` Const(Const), /// `Var (V x 0) ~ x`<br> /// `Var (V x n) ~ x@n` - Var(V), + Var(V<Label>), /// `Lam x A b ~ λ(x : A) -> b` - Lam(Label, SubExpr<Note, Embed>, SubExpr<Note, Embed>), + Lam(Label, SubExpr, SubExpr), /// `Pi "_" A B ~ A -> B` /// `Pi x A B ~ ∀(x : A) -> B` - Pi(Label, SubExpr<Note, Embed>, SubExpr<Note, Embed>), + Pi(Label, SubExpr, SubExpr), /// `App f A ~ f A` - App(SubExpr<Note, Embed>, Vec<SubExpr<Note, Embed>>), + App(SubExpr, Vec<SubExpr>), /// `Let x Nothing r e ~ let x = r in e` /// `Let x (Just t) r e ~ let x : t = r in e` - Let( - Label, - Option<SubExpr<Note, Embed>>, - SubExpr<Note, Embed>, - SubExpr<Note, Embed>, - ), + Let(Label, Option<SubExpr>, SubExpr, SubExpr), /// `Annot x t ~ x : t` - Annot(SubExpr<Note, Embed>, SubExpr<Note, Embed>), + Annot(SubExpr, SubExpr), /// Built-in values Builtin(Builtin), // Binary operations - BinOp(BinOp, SubExpr<Note, Embed>, SubExpr<Note, Embed>), + BinOp(BinOp, SubExpr, SubExpr), /// `BoolLit b ~ b` BoolLit(bool), /// `BoolIf x y z ~ if x then y else z` - BoolIf( - SubExpr<Note, Embed>, - SubExpr<Note, Embed>, - SubExpr<Note, Embed>, - ), + BoolIf(SubExpr, SubExpr, SubExpr), /// `NaturalLit n ~ +n` NaturalLit(Natural), /// `IntegerLit n ~ n` @@ -216,39 +213,31 @@ pub enum Expr<Note, Embed> { /// `DoubleLit n ~ n` DoubleLit(Double), /// `TextLit t ~ t` - TextLit(InterpolatedText<Note, Embed>), + TextLit(InterpolatedText<SubExpr>), /// [] : List t` - EmptyListLit(SubExpr<Note, Embed>), + EmptyListLit(SubExpr), /// [x, y, z] - NEListLit(Vec<SubExpr<Note, Embed>>), + NEListLit(Vec<SubExpr>), /// None t - EmptyOptionalLit(SubExpr<Note, Embed>), + EmptyOptionalLit(SubExpr), /// Some e - NEOptionalLit(SubExpr<Note, Embed>), + NEOptionalLit(SubExpr), /// `Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 }` - RecordType(BTreeMap<Label, SubExpr<Note, Embed>>), + RecordType(BTreeMap<Label, SubExpr>), /// `RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 }` - RecordLit(BTreeMap<Label, SubExpr<Note, Embed>>), + RecordLit(BTreeMap<Label, SubExpr>), /// `Union [(k1, t1), (k2, t2)] ~ < k1 : t1, k2 : t2 >` - UnionType(BTreeMap<Label, SubExpr<Note, Embed>>), + UnionType(BTreeMap<Label, SubExpr>), /// `UnionLit (k1, v1) [(k2, t2), (k3, t3)] ~ < k1 = t1, k2 : t2, k3 : t3 >` - UnionLit( - Label, - SubExpr<Note, Embed>, - BTreeMap<Label, SubExpr<Note, Embed>>, - ), + UnionLit(Label, SubExpr, BTreeMap<Label, SubExpr>), /// `Merge x y t ~ merge x y : t` - Merge( - SubExpr<Note, Embed>, - SubExpr<Note, Embed>, - Option<SubExpr<Note, Embed>>, - ), + Merge(SubExpr, SubExpr, Option<SubExpr>), /// e.x - Field(SubExpr<Note, Embed>, Label), + Field(SubExpr, Label), /// e.{ x, y, z } - Projection(SubExpr<Note, Embed>, Vec<Label>), + Projection(SubExpr, Vec<Label>), /// Annotation on the AST. Unused for now but could hold e.g. file location information - Note(Note, SubExpr<Note, Embed>), + Note(Note, SubExpr), /// Embeds an import or the result of resolving the import Embed(Embed), } @@ -270,13 +259,12 @@ impl<S, A> Expr<S, A> { F3: FnOnce(&A) -> B, F4: Fn(&Label) -> Label, { - map_subexpr( - self, + self.map_ref( |x| rc(map_expr(x.as_ref())), + |_, x| rc(map_expr(x.as_ref())), map_note, map_embed, map_label, - |_, x| rc(map_expr(x.as_ref())), ) } @@ -299,12 +287,21 @@ impl<S, A> Expr<S, A> { let recurse = |e: &Self| -> Self { e.map_label(map_label) }; self.map_shallow(recurse, |x| x.clone(), |x| x.clone(), map_label) } + + #[inline(always)] + pub fn roll(&self) -> SubExpr<S, A> + where + S: Clone, + A: Clone, + { + rc(ExprF::clone(self)) + } } impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> { pub fn squash_embed(&self) -> Expr<S, A> { match self { - Expr::Embed(e) => e.clone(), + ExprF::Embed(e) => e.clone(), e => e.map_shallow( |e| e.squash_embed(), |x| x.clone(), @@ -315,20 +312,297 @@ impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> { } } +impl<SE, L, N, E> ExprF<SE, L, N, E> { + #[inline(always)] + pub fn as_ref(&self) -> ExprF<&SE, &L, &N, &E> + where + L: Ord, + { + fn opt<T>(x: &Option<T>) -> Option<&T> { + x.as_ref() + } + fn vec<T>(x: &Vec<T>) -> Vec<&T> { + x.iter().collect() + } + fn btmap<L: Ord, SE>(x: &BTreeMap<L, SE>) -> BTreeMap<&L, &SE> { + x.iter().collect() + } + + use crate::ExprF::*; + match self { + Var(V(l, n)) => Var(V(l, *n)), + Lam(l, t, b) => Lam(l, t, b), + Pi(l, t, b) => Pi(l, t, b), + Let(l, t, a, b) => Let(l, opt(t), a, b), + App(f, args) => App(f, vec(args)), + Annot(x, t) => Annot(x, t), + Const(k) => Const(*k), + Builtin(v) => Builtin(*v), + BoolLit(b) => BoolLit(*b), + NaturalLit(n) => NaturalLit(*n), + IntegerLit(n) => IntegerLit(*n), + DoubleLit(n) => DoubleLit(*n), + TextLit(t) => TextLit(t.as_ref()), + BinOp(o, x, y) => BinOp(*o, x, y), + BoolIf(b, t, f) => BoolIf(b, t, f), + EmptyListLit(t) => EmptyListLit(t), + NEListLit(es) => NEListLit(vec(es)), + EmptyOptionalLit(t) => EmptyOptionalLit(t), + NEOptionalLit(e) => NEOptionalLit(e), + RecordType(kts) => RecordType(btmap(kts)), + RecordLit(kvs) => RecordLit(btmap(kvs)), + UnionType(kts) => UnionType(btmap(kts)), + UnionLit(k, v, kvs) => UnionLit(k, v, btmap(kvs)), + Merge(x, y, t) => Merge(x, y, opt(t)), + Field(e, l) => Field(e, l), + Projection(e, ls) => Projection(e, vec(ls)), + Note(n, e) => Note(n, e), + Embed(a) => Embed(a), + } + } + + #[inline(always)] + pub fn map<SE2, L2, N2, E2, F1, F2, F3, F4, F5>( + self, + map_subexpr: F1, + map_under_binder: F2, + map_note: F3, + map_embed: F4, + mut map_label: F5, + ) -> ExprF<SE2, L2, N2, E2> + where + L: Ord, + L2: Ord, + F1: FnMut(SE) -> SE2, + F2: FnOnce(&L, SE) -> SE2, + F3: FnOnce(N) -> N2, + F4: FnOnce(E) -> E2, + F5: FnMut(L) -> L2, + { + let mut map = map_subexpr; + fn vec<T, U, F: FnMut(T) -> U>(x: Vec<T>, f: F) -> Vec<U> { + x.into_iter().map(f).collect() + } + fn btmap<K, L, T, U, FK, FV>( + x: BTreeMap<K, T>, + mut fk: FK, + mut fv: FV, + ) -> BTreeMap<L, U> + where + K: Ord, + L: Ord, + FK: FnMut(K) -> L, + FV: FnMut(T) -> U, + { + x.into_iter().map(|(k, v)| (fk(k), fv(v))).collect() + } + + use crate::ExprF::*; + match self { + Var(V(l, n)) => Var(V(map_label(l), n)), + Lam(l, t, b) => { + let b = map_under_binder(&l, b); + Lam(map_label(l), map(t), b) + } + Pi(l, t, b) => { + let b = map_under_binder(&l, b); + Pi(map_label(l), map(t), b) + } + Let(l, t, a, b) => { + let b = map_under_binder(&l, b); + Let(map_label(l), t.map(&mut map), map(a), b) + } + App(f, args) => App(map(f), vec(args, map)), + Annot(x, t) => Annot(map(x), map(t)), + Const(k) => Const(k), + Builtin(v) => Builtin(v), + BoolLit(b) => BoolLit(b), + NaturalLit(n) => NaturalLit(n), + IntegerLit(n) => IntegerLit(n), + DoubleLit(n) => DoubleLit(n), + TextLit(t) => TextLit(t.map(map)), + BinOp(o, x, y) => BinOp(o, map(x), map(y)), + BoolIf(b, t, f) => BoolIf(map(b), map(t), map(f)), + EmptyListLit(t) => EmptyListLit(map(t)), + NEListLit(es) => NEListLit(vec(es, map)), + EmptyOptionalLit(t) => EmptyOptionalLit(map(t)), + NEOptionalLit(e) => NEOptionalLit(map(e)), + RecordType(kts) => RecordType(btmap(kts, map_label, map)), + RecordLit(kvs) => RecordLit(btmap(kvs, map_label, map)), + UnionType(kts) => UnionType(btmap(kts, map_label, map)), + UnionLit(k, v, kvs) => { + UnionLit(map_label(k), map(v), btmap(kvs, map_label, map)) + } + Merge(x, y, t) => Merge(map(x), map(y), t.map(map)), + Field(e, l) => Field(map(e), map_label(l)), + Projection(e, ls) => Projection(map(e), vec(ls, map_label)), + Note(n, e) => Note(map_note(n), map(e)), + Embed(a) => Embed(map_embed(a)), + } + } + + #[inline(always)] + pub fn map_ref<'a, SE2, L2, N2, E2, F1, F2, F3, F4, F5>( + &'a self, + map_subexpr: F1, + map_under_binder: F2, + map_note: F3, + map_embed: F4, + map_label: F5, + ) -> ExprF<SE2, L2, N2, E2> + where + L: Ord, + L2: Ord, + F1: FnMut(&'a SE) -> SE2, + F2: FnOnce(&'a L, &'a SE) -> SE2, + F3: FnOnce(&'a N) -> N2, + F4: FnOnce(&'a E) -> E2, + F5: FnMut(&'a L) -> L2, + { + // Not optimal: reallocates all the Vecs and BTreeMaps for nothing. + self.as_ref().map( + map_subexpr, + |l, e| map_under_binder(*l, e), + map_note, + map_embed, + map_label, + ) + } + + #[inline(always)] + pub fn map_ref_simple<'a, SE2, F1>( + &'a self, + map_subexpr: F1, + ) -> ExprF<SE2, L, N, E> + where + L: Ord, + L: Clone, + N: Clone, + E: Clone, + F1: Fn(&'a SE) -> SE2, + { + self.map_ref( + &map_subexpr, + |_, e| map_subexpr(e), + N::clone, + E::clone, + L::clone, + ) + } + + // #[inline(always)] + // pub fn zip<SE2, L2, N2, E2>( + // self, + // other: ExprF<SE2, L2, N2, E2> + // ) -> Option<ExprF<(SE, SE2), (L, L2), (N, N2), (E, E2)>> + // where + // L: Ord, + // L2: Ord, + // { + // // What to do with Var ? + // use crate::ExprF::*; + // match (self, other) { + // // Var(V(l, n)) => Var(V(map_label(l), n)), + // // Lam(l, t, b) => { + // // Pi(l, t, b) => { + // // Let(l, t, a, b) => { + // // App(f, args) => App(map(f), vec(args, map)), + // // Annot(x, t) => Annot(map(x), map(t)), + // (Const(x), Const(y)) if x == y => Some(Const(x)), + // (Builtin(x), Builtin(y)) if x == y => Some(Builtin(x)), + // (BoolLit(x), BoolLit(y)) if x == y => Some(BoolLit(x)), + // (NaturalLit(x), NaturalLit(y)) if x == y => Some(NaturalLit(x)), + // (IntegerLit(x), IntegerLit(y)) if x == y => Some(IntegerLit(x)), + // (DoubleLit(x), DoubleLit(y)) if x == y => Some(DoubleLit(x)), + // // TextLit(t) => TextLit(t.map(map)), + // // BinOp(o, x, y) => BinOp(o, map(x), map(y)), + // // BoolIf(b, t, f) => BoolIf(map(b), map(t), map(f)), + // // EmptyListLit(t) => EmptyListLit(map(t)), + // // NEListLit(es) => NEListLit(vec(es, map)), + // // EmptyOptionalLit(t) => EmptyOptionalLit(map(t)), + // // NEOptionalLit(e) => NEOptionalLit(map(e)), + // // RecordType(kts) => RecordType(btmap(kts, map_label, map)), + // // RecordLit(kvs) => RecordLit(btmap(kvs, map_label, map)), + // // UnionType(kts) => UnionType(btmap(kts, map_label, map)), + // // UnionLit(k, v, kvs) => { + // // Merge(x, y, t) => Merge(map(x), map(y), t.map(map)), + // // Field(e, l) => Field(map(e), map_label(l)), + // // Projection(e, ls) => Projection(map(e), vec(ls, map_label)), + // // Note(n, e) => Note(map_note(n), map(e)), + // // Embed(a) => Embed(map_embed(a)), + // } + // } +} + +impl<N, E> SubExpr<N, E> { + #[inline(always)] + pub fn as_ref(&self) -> &Expr<N, E> { + self.0.as_ref() + } + + pub fn map_ref<'a, F1, F2>( + &'a self, + map_expr: F1, + map_under_binder: F2, + ) -> Self + where + F1: FnMut(&'a Self) -> Self, + F2: FnOnce(&'a Label, &'a Self) -> Self, + { + match self.as_ref() { + ExprF::Embed(_) => SubExpr::clone(self), + // Recursive call + ExprF::Note(_, e) => e.map_ref(map_expr, map_under_binder), + // Call ExprF::map_ref + e => rc(e.map_ref( + map_expr, + map_under_binder, + |_| unreachable!(), + |_| unreachable!(), + Label::clone, + )), + } + } + + pub fn map_ref_simple<F1>(&self, map_expr: F1) -> Self + where + F1: Fn(&Self) -> Self, + { + self.map_ref(&map_expr, |_, e| map_expr(e)) + } + + #[inline(always)] + pub fn unroll(&self) -> Expr<N, E> + where + N: Clone, + E: Clone, + { + ExprF::clone(self.as_ref()) + } +} + +impl<N, E> Clone for SubExpr<N, E> { + #[inline(always)] + fn clone(&self) -> Self { + SubExpr(Rc::clone(&self.0)) + } +} + // Remains of a previous life, where everything was in Boxes -pub fn bx<T>(x: T) -> Rc<T> { - Rc::new(x) +pub fn bx<N, E>(x: Expr<N, E>) -> SubExpr<N, E> { + SubExpr(Rc::new(x)) } -pub fn rc<T>(x: T) -> Rc<T> { - Rc::new(x) +// Should probably rename this too +pub fn rc<N, E>(x: Expr<N, E>) -> SubExpr<N, E> { + SubExpr(Rc::new(x)) } pub fn app<N, E>(f: Expr<N, E>, args: Vec<SubExpr<N, E>>) -> Expr<N, E> { if args.is_empty() { f } else { - Expr::App(rc(f), args) + ExprF::App(rc(f), args) } } @@ -339,7 +613,7 @@ pub fn app_rc<N, E>( if args.is_empty() { f } else { - rc(Expr::App(f, args)) + rc(ExprF::App(f, args)) } } @@ -351,100 +625,6 @@ fn add_ui(u: usize, i: isize) -> usize { } } -/// Map over the immediate children of the passed Expr -pub fn map_subexpr<S, T, A, B, F1, F2, F3, F4, F5>( - e: &Expr<S, A>, - map: F1, - map_note: F2, - map_embed: F3, - map_label: F4, - map_under_binder: F5, -) -> Expr<T, B> -where - F1: Fn(&SubExpr<S, A>) -> SubExpr<T, B>, - F2: FnOnce(&S) -> T, - F3: FnOnce(&A) -> B, - F4: Fn(&Label) -> Label, - F5: FnOnce(&Label, &SubExpr<S, A>) -> SubExpr<T, B>, -{ - use crate::Expr::*; - let map = ↦ - let opt = |x: &Option<_>| x.as_ref().map(&map); - let vec = |x: &Vec<_>| x.iter().map(&map).collect(); - let btmap = |x: &BTreeMap<_, _>| { - x.into_iter().map(|(k, v)| (map_label(k), map(v))).collect() - }; - match e { - Const(k) => Const(*k), - Var(V(l, n)) => Var(V(map_label(l), *n)), - Lam(l, t, b) => Lam(map_label(l), map(t), map_under_binder(l, b)), - Pi(l, t, b) => Pi(map_label(l), map(t), map_under_binder(l, b)), - App(f, args) => App(map(f), vec(args)), - Let(l, t, a, b) => { - Let(map_label(l), opt(t), map(a), map_under_binder(l, b)) - } - Annot(x, t) => Annot(map(x), map(t)), - Builtin(v) => Builtin(*v), - BoolLit(b) => BoolLit(*b), - BoolIf(b, t, f) => BoolIf(map(b), map(t), map(f)), - NaturalLit(n) => NaturalLit(*n), - IntegerLit(n) => IntegerLit(*n), - DoubleLit(n) => DoubleLit(*n), - TextLit(t) => TextLit(t.map(&map)), - BinOp(o, x, y) => BinOp(*o, map(x), map(y)), - EmptyListLit(t) => EmptyListLit(map(t)), - NEListLit(es) => NEListLit(vec(es)), - EmptyOptionalLit(t) => EmptyOptionalLit(map(t)), - NEOptionalLit(e) => NEOptionalLit(map(e)), - RecordType(kts) => RecordType(btmap(kts)), - RecordLit(kvs) => RecordLit(btmap(kvs)), - UnionType(kts) => UnionType(btmap(kts)), - UnionLit(k, v, kvs) => UnionLit(map_label(k), map(v), btmap(kvs)), - Merge(x, y, t) => Merge(map(x), map(y), opt(t)), - Field(e, l) => Field(map(e), map_label(l)), - Projection(e, ls) => { - Projection(map(e), ls.iter().map(&map_label).collect()) - } - Note(n, e) => Note(map_note(n), map(e)), - Embed(a) => Embed(map_embed(a)), - } -} - -pub fn map_subexpr_rc_binder<S, A, F1, F2>( - e: &SubExpr<S, A>, - map_expr: F1, - map_under_binder: F2, -) -> SubExpr<S, A> -where - F1: Fn(&SubExpr<S, A>) -> SubExpr<S, A>, - F2: FnOnce(&Label, &SubExpr<S, A>) -> SubExpr<S, A>, -{ - match e.as_ref() { - Expr::Embed(_) => Rc::clone(e), - Expr::Note(_, e) => { - map_subexpr_rc_binder(e, map_expr, map_under_binder) - } - _ => rc(map_subexpr( - e, - map_expr, - |_| unreachable!(), - |_| unreachable!(), - Label::clone, - map_under_binder, - )), - } -} - -pub fn map_subexpr_rc<S, A, F1>( - e: &SubExpr<S, A>, - map_expr: F1, -) -> SubExpr<S, A> -where - F1: Fn(&SubExpr<S, A>) -> SubExpr<S, A>, -{ - map_subexpr_rc_binder(e, &map_expr, |_, e| map_expr(e)) -} - /// `shift` is used by both normalization and type-checking to avoid variable /// capture by shifting variable indices /// @@ -518,10 +698,10 @@ where /// pub fn shift<S, A>( delta: isize, - var: &V, - in_expr: &Rc<Expr<S, A>>, -) -> Rc<Expr<S, A>> { - use crate::Expr::*; + var: &V<Label>, + in_expr: &SubExpr<S, A>, +) -> SubExpr<S, A> { + use crate::ExprF::*; let V(x, n) = var; let under_binder = |y: &Label, e: &SubExpr<_, _>| { let n = if x == y { n + 1 } else { *n }; @@ -532,11 +712,7 @@ pub fn shift<S, A>( Var(V(y, m)) if x == y && n <= m => { rc(Var(V(y.clone(), add_ui(*m, delta)))) } - _ => map_subexpr_rc_binder( - in_expr, - |e| shift(delta, var, e), - under_binder, - ), + _ => in_expr.map_ref(|e| shift(delta, var, e), under_binder), } } @@ -547,11 +723,11 @@ pub fn shift<S, A>( /// ``` /// pub fn subst<S, A>( - var: &V, - value: &Rc<Expr<S, A>>, - in_expr: &Rc<Expr<S, A>>, -) -> Rc<Expr<S, A>> { - use crate::Expr::*; + var: &V<Label>, + value: &SubExpr<S, A>, + in_expr: &SubExpr<S, A>, +) -> SubExpr<S, A> { + use crate::ExprF::*; let under_binder = |y: &Label, e: &SubExpr<_, _>| { let V(x, n) = var; let n = if x == y { n + 1 } else { *n }; @@ -559,11 +735,7 @@ pub fn subst<S, A>( subst(newvar, &shift(1, &V(y.clone(), 0), value), e) }; match in_expr.as_ref() { - Var(v) if var == v => Rc::clone(value), - _ => map_subexpr_rc_binder( - in_expr, - |e| subst(var, value, e), - under_binder, - ), + Var(v) if var == v => SubExpr::clone(value), + _ => in_expr.map_ref(|e| subst(var, value, e), under_binder), } } diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index b0d80c0..e18a709 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -13,10 +13,12 @@ use crate::*; // their own crate because they are quite general and useful. For now they // are here and hopefully you can figure out how they work. +use crate::ExprF::*; + type ParsedExpr = Expr<X, Import>; type ParsedSubExpr = SubExpr<X, Import>; -type ParsedText = InterpolatedText<X, Import>; -type ParsedTextContents = InterpolatedTextContents<X, Import>; +type ParsedText = InterpolatedText<SubExpr<X, Import>>; +type ParsedTextContents = InterpolatedTextContents<SubExpr<X, Import>>; pub type ParseError = pest::error::Error<Rule>; @@ -28,9 +30,9 @@ enum Either<A, B> { Right(B), } -impl Builtin { +impl crate::Builtin { pub fn parse(s: &str) -> Option<Self> { - use self::Builtin::*; + use crate::Builtin::*; match s { "Bool" => Some(Bool), "Natural" => Some(Natural), @@ -279,7 +281,7 @@ make_parser! { )); rule!(nonreserved_label<Label>; children!( [label(l)] => { - if Builtin::parse(&String::from(&l)).is_some() { + if crate::Builtin::parse(&String::from(&l)).is_some() { Err( format!("Builtin names are not allowed as bound variables") )? @@ -541,13 +543,13 @@ make_parser! { rule!(import<ParsedExpr> as expression; children!( [import_hashed(location_hashed)] => { - Expr::Embed(Import { + Embed(Import { mode: ImportMode::Code, location_hashed }) }, [import_hashed(location_hashed), Text(_)] => { - Expr::Embed(Import { + Embed(Import { mode: ImportMode::RawText, location_hashed }) @@ -563,28 +565,28 @@ make_parser! { rule!(expression<ParsedExpr> as expression; children!( [lambda(()), nonreserved_label(l), expression(typ), arrow(()), expression(body)] => { - Expr::Lam(l, rc(typ), rc(body)) + Lam(l, rc(typ), rc(body)) }, [if_(()), expression(cond), expression(left), expression(right)] => { - Expr::BoolIf(rc(cond), rc(left), rc(right)) + BoolIf(rc(cond), rc(left), rc(right)) }, [let_binding(bindings).., in_(()), expression(final_expr)] => { bindings.fold( final_expr, - |acc, x| Expr::Let(x.0, x.1, x.2, rc(acc)) + |acc, x| Let(x.0, x.1, x.2, rc(acc)) ) }, [forall(()), nonreserved_label(l), expression(typ), arrow(()), expression(body)] => { - Expr::Pi(l, rc(typ), rc(body)) + Pi(l, rc(typ), rc(body)) }, [expression(typ), arrow(()), expression(body)] => { - Expr::Pi("_".into(), rc(typ), rc(body)) + Pi("_".into(), rc(typ), rc(body)) }, [merge(()), expression(x), expression(y), expression(z)] => { - Expr::Merge(rc(x), rc(y), Option::Some(rc(z))) + Merge(rc(x), rc(y), Option::Some(rc(z))) }, [merge(()), expression(x), expression(y)] => { - Expr::Merge(rc(x), rc(y), Option::None) + Merge(rc(x), rc(y), Option::None) }, [expression(e)] => e, )); @@ -601,108 +603,108 @@ make_parser! { rule!(empty_collection<ParsedExpr> as expression; children!( [List(_), expression(t)] => { - Expr::EmptyListLit(rc(t)) + EmptyListLit(rc(t)) }, [Optional(_), expression(t)] => { - Expr::EmptyOptionalLit(rc(t)) + EmptyOptionalLit(rc(t)) }, )); rule!(non_empty_optional<ParsedExpr> as expression; children!( [expression(x), Optional(_), expression(t)] => { - Expr::Annot(rc(Expr::NEOptionalLit(rc(x))), rc(t)) + Annot(rc(NEOptionalLit(rc(x))), rc(t)) } )); rule!(import_alt_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::ImportAlt; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::ImportAlt; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(or_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::BoolOr; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::BoolOr; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(plus_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::NaturalPlus; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::NaturalPlus; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(text_append_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::TextAppend; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::TextAppend; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(list_append_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::ListAppend; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::ListAppend; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(and_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::BoolAnd; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::BoolAnd; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(combine_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::Combine; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::Combine; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(prefer_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::Prefer; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::Prefer; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(combine_types_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::CombineTypes; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::CombineTypes; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(times_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::NaturalTimes; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::NaturalTimes; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(equal_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::BoolEQ; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::BoolEQ; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(not_equal_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), expression(rest)..] => { - let o = BinOp::BoolNE; - rest.fold(first, |acc, e| Expr::BinOp(o, rc(acc), rc(e))) + let o = crate::BinOp::BoolNE; + rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) }, )); rule!(annotated_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(e), expression(annot)] => { - Expr::Annot(rc(e), rc(annot)) + Annot(rc(e), rc(annot)) }, )); @@ -710,12 +712,12 @@ make_parser! { rule!(application_expression<ParsedExpr> as expression; children!( [expression(e)] => e, - [expression(Expr::Builtin(Builtin::OptionalNone)), + [expression(Builtin(crate::Builtin::OptionalNone)), expression(e), expression(rest)..] => { - app(Expr::EmptyOptionalLit(rc(e)), rest.map(rc).collect()) + app(EmptyOptionalLit(rc(e)), rest.map(rc).collect()) }, [Some(()), expression(e), expression(rest)..] => { - app(Expr::NEOptionalLit(rc(e)), rest.map(rc).collect()) + app(NEOptionalLit(rc(e)), rest.map(rc).collect()) }, [expression(first), expression(rest)..] => { app(first, rest.map(rc).collect()) @@ -726,8 +728,8 @@ make_parser! { [expression(e)] => e, [expression(first), selector(rest)..] => { rest.fold(first, |acc, e| match e { - Either::Left(l) => Expr::Field(rc(acc), l), - Either::Right(ls) => Expr::Projection(rc(acc), ls), + Either::Left(l) => Field(rc(acc), l), + Either::Right(ls) => Projection(rc(acc), ls), }) } )); @@ -742,61 +744,61 @@ make_parser! { )); rule!(primitive_expression<ParsedExpr> as expression; children!( - [double_literal(n)] => Expr::DoubleLit(n), - [natural_literal(n)] => Expr::NaturalLit(n), - [integer_literal(n)] => Expr::IntegerLit(n), - [double_quote_literal(s)] => Expr::TextLit(s), - [single_quote_literal(s)] => Expr::TextLit(s), + [double_literal(n)] => DoubleLit(n), + [natural_literal(n)] => NaturalLit(n), + [integer_literal(n)] => IntegerLit(n), + [double_quote_literal(s)] => TextLit(s), + [single_quote_literal(s)] => TextLit(s), [expression(e)] => e, )); rule!(identifier<ParsedExpr> as expression; children!( [label(l), natural_literal(idx)] => { let name = String::from(&l); - match Builtin::parse(name.as_str()) { - Option::Some(b) => Expr::Builtin(b), + match crate::Builtin::parse(name.as_str()) { + Option::Some(b) => Builtin(b), Option::None => match name.as_str() { - "True" => Expr::BoolLit(true), - "False" => Expr::BoolLit(false), - "Type" => Expr::Const(Const::Type), - "Kind" => Expr::Const(Const::Kind), - _ => Expr::Var(V(l, idx)), + "True" => BoolLit(true), + "False" => BoolLit(false), + "Type" => Const(crate::Const::Type), + "Kind" => Const(crate::Const::Kind), + _ => Var(V(l, idx)), } } }, [label(l)] => { let name = String::from(&l); - match Builtin::parse(name.as_str()) { - Option::Some(b) => Expr::Builtin(b), + match crate::Builtin::parse(name.as_str()) { + Option::Some(b) => Builtin(b), Option::None => match name.as_str() { - "True" => Expr::BoolLit(true), - "False" => Expr::BoolLit(false), - "Type" => Expr::Const(Const::Type), - "Kind" => Expr::Const(Const::Kind), - _ => Expr::Var(V(l, 0)), + "True" => BoolLit(true), + "False" => BoolLit(false), + "Type" => Const(crate::Const::Type), + "Kind" => Const(crate::Const::Kind), + _ => Var(V(l, 0)), } } }, )); rule!(empty_record_literal<ParsedExpr> as expression; - captured_str!(_) => Expr::RecordLit(BTreeMap::new()) + captured_str!(_) => RecordLit(BTreeMap::new()) ); rule!(empty_record_type<ParsedExpr> as expression; - captured_str!(_) => Expr::RecordType(BTreeMap::new()) + captured_str!(_) => RecordType(BTreeMap::new()) ); rule!(non_empty_record_type_or_literal<ParsedExpr> as expression; children!( [label(first_label), non_empty_record_type(rest)] => { let (first_expr, mut map) = rest; map.insert(first_label, rc(first_expr)); - Expr::RecordType(map) + RecordType(map) }, [label(first_label), non_empty_record_literal(rest)] => { let (first_expr, mut map) = rest; map.insert(first_label, rc(first_expr)); - Expr::RecordLit(map) + RecordLit(map) }, )); @@ -824,13 +826,13 @@ make_parser! { rule!(union_type_or_literal<ParsedExpr> as expression; children!( [empty_union_type(_)] => { - Expr::UnionType(BTreeMap::new()) + UnionType(BTreeMap::new()) }, [non_empty_union_type_or_literal((Option::Some((l, e)), entries))] => { - Expr::UnionLit(l, e, entries) + UnionLit(l, e, entries) }, [non_empty_union_type_or_literal((Option::None, entries))] => { - Expr::UnionType(entries) + UnionType(entries) }, )); @@ -875,7 +877,7 @@ make_parser! { )); rule!(non_empty_list_literal<ParsedExpr> as expression; children!( - [expression(items)..] => Expr::NEListLit(items.map(rc).collect()) + [expression(items)..] => NEListLit(items.map(rc).collect()) )); rule!(final_expression<ParsedExpr> as expression; children!( @@ -891,7 +893,7 @@ pub fn parse_expr(s: &str) -> ParseResult<ParsedSubExpr> { ParsedValue::expression(e) => Ok(rc(e)), _ => unreachable!(), } - // Ok(rc(Expr::BoolLit(false))) + // Ok(rc(BoolLit(false))) } #[test] diff --git a/dhall_core/src/printer.rs b/dhall_core/src/printer.rs index 1d1b063..746b863 100644 --- a/dhall_core/src/printer.rs +++ b/dhall_core/src/printer.rs @@ -8,6 +8,12 @@ impl<S, A: Display> Display for Expr<S, A> { } } +impl<S, A: Display> Display for SubExpr<S, A> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.as_ref().fmt(f) + } +} + // 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 @@ -29,7 +35,7 @@ impl<S, A: Display> Expr<S, A> { f: &mut fmt::Formatter, phase: PrintPhase, ) -> Result<(), fmt::Error> { - use crate::Expr::*; + use crate::ExprF::*; use PrintPhase::*; match self { _ if phase == Paren => { @@ -137,7 +143,7 @@ impl<S, A: Display> Expr<S, A> { write!(f, " : ")?; b.fmt(f)?; } - Expr::BinOp(op, a, b) => { + ExprF::BinOp(op, a, b) => { // Precedence is magically handled by the ordering of BinOps. if phase > PrintPhase::BinOp(*op) { return self.fmt_phase(f, Paren); @@ -146,7 +152,7 @@ impl<S, A: Display> Expr<S, A> { write!(f, " {} ", op)?; b.fmt_phase(f, PrintPhase::BinOp(*op))?; } - Expr::App(a, args) => { + ExprF::App(a, args) => { if phase > PrintPhase::App { return self.fmt_phase(f, Paren); } @@ -211,6 +217,16 @@ impl<S, A: Display> Expr<S, A> { } } +impl<S, A: Display> SubExpr<S, A> { + fn fmt_phase( + &self, + f: &mut fmt::Formatter, + phase: PrintPhase, + ) -> Result<(), fmt::Error> { + self.0.as_ref().fmt_phase(f, phase) + } +} + fn fmt_list<T, I, F>( open: &str, sep: &str, @@ -233,7 +249,7 @@ where f.write_str(close) } -impl<S, A: Display> Display for InterpolatedText<S, A> { +impl<SubExpr: Display + Clone> Display for InterpolatedText<SubExpr> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str("\"")?; for x in self.iter() { @@ -446,7 +462,7 @@ impl Display for Scheme { } } -impl Display for V { +impl<Label: Display> Display for V<Label> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { let V(x, n) = self; x.fmt(f)?; diff --git a/dhall_core/src/text.rs b/dhall_core/src/text.rs index d377877..9500f32 100644 --- a/dhall_core/src/text.rs +++ b/dhall_core/src/text.rs @@ -1,18 +1,16 @@ -use crate::*; use std::iter::FromIterator; use std::ops::Add; -use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct InterpolatedText<Note, Embed> { +pub struct InterpolatedText<SubExpr> { head: String, - tail: Vec<(Rc<Expr<Note, Embed>>, String)>, + tail: Vec<(SubExpr, String)>, } -impl<N, E> From<(String, Vec<(Rc<Expr<N, E>>, String)>)> - for InterpolatedText<N, E> +impl<SubExpr> From<(String, Vec<(SubExpr, String)>)> + for InterpolatedText<SubExpr> { - fn from(x: (String, Vec<(Rc<Expr<N, E>>, String)>)) -> Self { + fn from(x: (String, Vec<(SubExpr, String)>)) -> Self { InterpolatedText { head: x.0, tail: x.1, @@ -20,7 +18,7 @@ impl<N, E> From<(String, Vec<(Rc<Expr<N, E>>, String)>)> } } -impl<N, E> From<String> for InterpolatedText<N, E> { +impl<SubExpr> From<String> for InterpolatedText<SubExpr> { fn from(s: String) -> Self { InterpolatedText { head: s, @@ -30,41 +28,55 @@ impl<N, E> From<String> for InterpolatedText<N, E> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum InterpolatedTextContents<Note, Embed> { +pub enum InterpolatedTextContents<SubExpr> { Text(String), - Expr(SubExpr<Note, Embed>), + Expr(SubExpr), } -impl<N, E> InterpolatedText<N, E> { - pub fn map<N2, E2, F>(&self, mut f: F) -> InterpolatedText<N2, E2> +impl<SubExpr> InterpolatedText<SubExpr> { + pub fn map<SubExpr2, F>(self, mut f: F) -> InterpolatedText<SubExpr2> where - F: FnMut(&Rc<Expr<N, E>>) -> Rc<Expr<N2, E2>>, + F: FnMut(SubExpr) -> SubExpr2, { InterpolatedText { head: self.head.clone(), - tail: self.tail.iter().map(|(e, s)| (f(e), s.clone())).collect(), + tail: self + .tail + .into_iter() + .map(|(e, s)| (f(e), s.clone())) + .collect(), + } + } + + pub fn as_ref(&self) -> InterpolatedText<&SubExpr> { + InterpolatedText { + head: self.head.clone(), + tail: self.tail.iter().map(|(e, s)| (e, s.clone())).collect(), } } pub fn iter<'a>( &'a self, - ) -> impl Iterator<Item = InterpolatedTextContents<N, E>> + 'a { + ) -> impl Iterator<Item = InterpolatedTextContents<SubExpr>> + 'a + where + SubExpr: Clone, + { use std::iter::once; once(InterpolatedTextContents::Text(self.head.clone())).chain( self.tail.iter().flat_map(|(e, s)| { - once(InterpolatedTextContents::Expr(Rc::clone(e))) + once(InterpolatedTextContents::Expr(SubExpr::clone(e))) .chain(once(InterpolatedTextContents::Text(s.clone()))) }), ) } } -impl<'a, N: 'a, E: 'a> FromIterator<InterpolatedTextContents<N, E>> - for InterpolatedText<N, E> +impl<'a, SubExpr: Clone + 'a> FromIterator<InterpolatedTextContents<SubExpr>> + for InterpolatedText<SubExpr> { fn from_iter<T>(iter: T) -> Self where - T: IntoIterator<Item = InterpolatedTextContents<N, E>>, + T: IntoIterator<Item = InterpolatedTextContents<SubExpr>>, { let mut res = InterpolatedText { head: "".to_owned(), @@ -84,9 +96,9 @@ impl<'a, N: 'a, E: 'a> FromIterator<InterpolatedTextContents<N, E>> } } -impl<N, E> Add for &InterpolatedText<N, E> { - type Output = InterpolatedText<N, E>; - fn add(self, rhs: &InterpolatedText<N, E>) -> Self::Output { +impl<SubExpr: Clone> Add for &InterpolatedText<SubExpr> { + type Output = InterpolatedText<SubExpr>; + fn add(self, rhs: &InterpolatedText<SubExpr>) -> Self::Output { self.iter().chain(rhs.iter()).collect() } } |