summaryrefslogtreecommitdiff
path: root/dhall_core
diff options
context:
space:
mode:
Diffstat (limited to 'dhall_core')
-rw-r--r--dhall_core/src/core.rs502
-rw-r--r--dhall_core/src/parser.rs152
-rw-r--r--dhall_core/src/printer.rs26
-rw-r--r--dhall_core/src/text.rs56
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 = &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()
}
}