summaryrefslogtreecommitdiff
path: root/dhall/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dhall/src/semantics/builtins.rs28
-rw-r--r--dhall/src/semantics/nze/nir.rs46
-rw-r--r--dhall/src/semantics/nze/normalize.rs182
-rw-r--r--dhall/src/semantics/resolve/resolve.rs21
-rw-r--r--dhall/src/semantics/tck/typecheck.rs35
-rw-r--r--dhall/src/syntax/ast/expr.rs121
-rw-r--r--dhall/src/syntax/ast/visitor.rs100
-rw-r--r--dhall/src/syntax/binary/decode.rs34
-rw-r--r--dhall/src/syntax/binary/encode.rs33
-rw-r--r--dhall/src/syntax/text/parser.rs36
-rw-r--r--dhall/src/syntax/text/printer.rs141
11 files changed, 424 insertions, 353 deletions
diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs
index 6007a92..45be448 100644
--- a/dhall/src/semantics/builtins.rs
+++ b/dhall/src/semantics/builtins.rs
@@ -5,8 +5,8 @@ use crate::syntax::map::DupTreeMap;
use crate::syntax::Const::Type;
use crate::syntax::{
BinOp, Builtin, Const, Expr, ExprKind, InterpolatedText,
- InterpolatedTextContents, Label, NaiveDouble, NumKind, Span, UnspannedExpr,
- V,
+ InterpolatedTextContents, Label, NaiveDouble, NumKind, OpKind, Span,
+ UnspannedExpr, V,
};
use std::collections::HashMap;
use std::convert::TryInto;
@@ -34,10 +34,10 @@ impl BuiltinClosure {
HirKind::Expr(self.args.iter().fold(
ExprKind::Builtin(self.b),
|acc, v| {
- ExprKind::App(
+ ExprKind::Op(OpKind::App(
Hir::new(HirKind::Expr(acc), Span::Artificial),
v.to_hir(venv),
- )
+ ))
},
))
}
@@ -59,16 +59,16 @@ macro_rules! make_type {
rc(ExprKind::Var(V(stringify!($var).into(), 0)))
};
(Optional $ty:ident) => {
- rc(ExprKind::App(
+ rc(ExprKind::Op(OpKind::App(
rc(ExprKind::Builtin(Builtin::Optional)),
make_type!($ty)
- ))
+ )))
};
(List $($rest:tt)*) => {
- rc(ExprKind::App(
+ rc(ExprKind::Op(OpKind::App(
rc(ExprKind::Builtin(Builtin::List)),
make_type!($($rest)*)
- ))
+ )))
};
({ $($label:ident : $ty:ident),* }) => {{
let mut kts = DupTreeMap::new();
@@ -214,10 +214,10 @@ macro_rules! make_closure {
};
(List $($ty:tt)*) => {{
let ty = make_closure!($($ty)*);
- rc(ExprKind::App(
+ rc(ExprKind::Op(OpKind::App(
rc(ExprKind::Builtin(Builtin::List)),
ty
- ))
+ )))
}};
(Some($($v:tt)*)) => {
rc(ExprKind::SomeLit(
@@ -225,20 +225,20 @@ macro_rules! make_closure {
))
};
(1 + $($v:tt)*) => {
- rc(ExprKind::BinOp(
+ rc(ExprKind::Op(OpKind::BinOp(
BinOp::NaturalPlus,
make_closure!($($v)*),
rc(ExprKind::Num(NumKind::Natural(1)))
- ))
+ )))
};
([ $($head:tt)* ] # $($tail:tt)*) => {{
let head = make_closure!($($head)*);
let tail = make_closure!($($tail)*);
- rc(ExprKind::BinOp(
+ rc(ExprKind::Op(OpKind::BinOp(
BinOp::ListAppend,
rc(ExprKind::NEListLit(vec![head])),
tail,
- ))
+ )))
}};
}
diff --git a/dhall/src/semantics/nze/nir.rs b/dhall/src/semantics/nze/nir.rs
index e0d227e..73c3f30 100644
--- a/dhall/src/semantics/nze/nir.rs
+++ b/dhall/src/semantics/nze/nir.rs
@@ -8,7 +8,7 @@ use crate::semantics::{
};
use crate::syntax::{
BinOp, Builtin, Const, Expr, ExprKind, InterpolatedTextContents, Label,
- NumKind, Span,
+ NumKind, OpKind, Span,
};
use crate::ToExprOptions;
@@ -190,24 +190,24 @@ impl Nir {
NirKind::Const(c) => ExprKind::Const(*c),
NirKind::BuiltinType(b) => ExprKind::Builtin(*b),
NirKind::Num(l) => ExprKind::Num(l.clone()),
- NirKind::OptionalType(t) => ExprKind::App(
+ NirKind::OptionalType(t) => ExprKind::Op(OpKind::App(
Nir::from_builtin(Builtin::Optional).to_hir(venv),
t.to_hir(venv),
- ),
- NirKind::EmptyOptionalLit(n) => ExprKind::App(
+ )),
+ NirKind::EmptyOptionalLit(n) => ExprKind::Op(OpKind::App(
Nir::from_builtin(Builtin::OptionalNone).to_hir(venv),
n.to_hir(venv),
- ),
+ )),
NirKind::NEOptionalLit(n) => ExprKind::SomeLit(n.to_hir(venv)),
- NirKind::ListType(t) => ExprKind::App(
+ NirKind::ListType(t) => ExprKind::Op(OpKind::App(
Nir::from_builtin(Builtin::List).to_hir(venv),
t.to_hir(venv),
- ),
+ )),
NirKind::EmptyListLit(n) => ExprKind::EmptyListLit(Hir::new(
- HirKind::Expr(ExprKind::App(
+ HirKind::Expr(ExprKind::Op(OpKind::App(
Nir::from_builtin(Builtin::List).to_hir(venv),
n.to_hir(venv),
- )),
+ ))),
Span::Artificial,
)),
NirKind::NEListLit(elts) => ExprKind::NEListLit(
@@ -229,31 +229,33 @@ impl Nir {
.collect(),
),
NirKind::UnionType(kts) => map_uniontype(kts),
- NirKind::UnionConstructor(l, kts) => ExprKind::Field(
- Hir::new(
- HirKind::Expr(map_uniontype(kts)),
- Span::Artificial,
- ),
- l.clone(),
- ),
- NirKind::UnionLit(l, v, kts) => ExprKind::App(
+ NirKind::UnionConstructor(l, kts) => {
+ ExprKind::Op(OpKind::Field(
+ Hir::new(
+ HirKind::Expr(map_uniontype(kts)),
+ Span::Artificial,
+ ),
+ l.clone(),
+ ))
+ }
+ NirKind::UnionLit(l, v, kts) => ExprKind::Op(OpKind::App(
Hir::new(
- HirKind::Expr(ExprKind::Field(
+ HirKind::Expr(ExprKind::Op(OpKind::Field(
Hir::new(
HirKind::Expr(map_uniontype(kts)),
Span::Artificial,
),
l.clone(),
- )),
+ ))),
Span::Artificial,
),
v.to_hir(venv),
- ),
- NirKind::Equivalence(x, y) => ExprKind::BinOp(
+ )),
+ NirKind::Equivalence(x, y) => ExprKind::Op(OpKind::BinOp(
BinOp::Equivalence,
x.to_hir(venv),
y.to_hir(venv),
- ),
+ )),
NirKind::PartialExpr(e) => e.map_ref(|v| v.to_hir(venv)),
}),
};
diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs
index 570e106..ebf4ae1 100644
--- a/dhall/src/semantics/nze/normalize.rs
+++ b/dhall/src/semantics/nze/normalize.rs
@@ -3,7 +3,9 @@ use std::collections::HashMap;
use crate::semantics::NzEnv;
use crate::semantics::{Binder, Closure, Hir, HirKind, Nir, NirKind, TextLit};
-use crate::syntax::{BinOp, ExprKind, InterpolatedTextContents, NumKind};
+use crate::syntax::{
+ BinOp, ExprKind, InterpolatedTextContents, NumKind, OpKind,
+};
pub fn apply_any(f: Nir, a: Nir) -> NirKind {
match f.kind() {
@@ -12,7 +14,7 @@ pub fn apply_any(f: Nir, a: Nir) -> NirKind {
NirKind::UnionConstructor(l, kts) => {
NirKind::UnionLit(l.clone(), a, kts.clone())
}
- _ => NirKind::PartialExpr(ExprKind::App(f, a)),
+ _ => NirKind::PartialExpr(ExprKind::Op(OpKind::App(f, a))),
}
}
@@ -173,11 +175,11 @@ fn apply_binop<'a>(o: BinOp, x: &'a Nir, y: &'a Nir) -> Option<Ret<'a>> {
}
(RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => {
let kvs = merge_maps(kvs1, kvs2, |_, v1, v2| {
- Nir::from_partial_expr(ExprKind::BinOp(
+ Nir::from_partial_expr(ExprKind::Op(OpKind::BinOp(
RecursiveRecordMerge,
v1.clone(),
v2.clone(),
- ))
+ )))
});
Ret::NirKind(RecordLit(kvs))
}
@@ -188,11 +190,11 @@ fn apply_binop<'a>(o: BinOp, x: &'a Nir, y: &'a Nir) -> Option<Ret<'a>> {
kts_y,
// If the Label exists for both records, then we hit the recursive case.
|_, l: &Nir, r: &Nir| {
- Nir::from_partial_expr(ExprKind::BinOp(
+ Nir::from_partial_expr(ExprKind::Op(OpKind::BinOp(
RecursiveRecordTypeMerge,
l.clone(),
r.clone(),
- ))
+ )))
},
);
Ret::NirKind(RecordType(kts))
@@ -216,7 +218,7 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
use NumKind::Bool;
let ret = match expr {
- ExprKind::Import(..) | ExprKind::Completion(..) => {
+ ExprKind::Import(..) | ExprKind::Op(OpKind::Completion(..)) => {
unreachable!("This case should have been handled in resolution")
}
ExprKind::Var(..)
@@ -230,7 +232,7 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
ExprKind::Const(c) => Ret::Nir(Nir::from_const(c)),
ExprKind::Builtin(b) => Ret::Nir(Nir::from_builtin_env(b, env)),
ExprKind::Assert(_) => Ret::Expr(expr),
- ExprKind::App(v, a) => Ret::Nir(v.app(a)),
+ ExprKind::Op(OpKind::App(v, a)) => Ret::Nir(v.app(a)),
ExprKind::Num(l) => Ret::NirKind(Num(l)),
ExprKind::SomeLit(e) => Ret::NirKind(NEOptionalLit(e)),
ExprKind::EmptyListLit(t) => {
@@ -261,7 +263,7 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
Ret::NirKind(NirKind::TextLit(tlit))
}
}
- ExprKind::BoolIf(ref b, ref e1, ref e2) => {
+ ExprKind::Op(OpKind::BoolIf(ref b, ref e1, ref e2)) => {
match b.kind() {
Num(Bool(true)) => Ret::NirRef(e1),
Num(Bool(false)) => Ret::NirRef(e2),
@@ -275,12 +277,14 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
}
}
}
- ExprKind::BinOp(o, ref x, ref y) => match apply_binop(o, x, y) {
- Some(ret) => ret,
- None => Ret::Expr(expr),
- },
+ ExprKind::Op(OpKind::BinOp(o, ref x, ref y)) => {
+ match apply_binop(o, x, y) {
+ Some(ret) => ret,
+ None => Ret::Expr(expr),
+ }
+ }
- ExprKind::Field(ref v, ref field) => match v.kind() {
+ ExprKind::Op(OpKind::Field(ref v, ref field)) => match v.kind() {
RecordLit(kvs) => match kvs.get(field) {
Some(r) => Ret::Nir(r.clone()),
None => Ret::Expr(expr),
@@ -288,53 +292,65 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
UnionType(kts) => {
Ret::NirKind(UnionConstructor(field.clone(), kts.clone()))
}
- PartialExpr(ExprKind::Projection(x, _)) => {
+ PartialExpr(ExprKind::Op(OpKind::Projection(x, _))) => {
return normalize_one_layer(
- ExprKind::Field(x.clone(), field.clone()),
+ ExprKind::Op(OpKind::Field(x.clone(), field.clone())),
env,
)
}
- PartialExpr(ExprKind::BinOp(
+ PartialExpr(ExprKind::Op(OpKind::BinOp(
BinOp::RightBiasedRecordMerge,
x,
y,
- )) => match (x.kind(), y.kind()) {
+ ))) => match (x.kind(), y.kind()) {
(_, RecordLit(kvs)) => match kvs.get(field) {
Some(r) => Ret::Nir(r.clone()),
None => {
return normalize_one_layer(
- ExprKind::Field(x.clone(), field.clone()),
+ ExprKind::Op(OpKind::Field(
+ x.clone(),
+ field.clone(),
+ )),
env,
)
}
},
(RecordLit(kvs), _) => match kvs.get(field) {
- Some(r) => Ret::Expr(ExprKind::Field(
- Nir::from_kind(PartialExpr(ExprKind::BinOp(
- BinOp::RightBiasedRecordMerge,
- Nir::from_kind(RecordLit(
- Some((field.clone(), r.clone()))
- .into_iter()
- .collect(),
- )),
- y.clone(),
+ Some(r) => Ret::Expr(ExprKind::Op(OpKind::Field(
+ Nir::from_kind(PartialExpr(ExprKind::Op(
+ OpKind::BinOp(
+ BinOp::RightBiasedRecordMerge,
+ Nir::from_kind(RecordLit(
+ Some((field.clone(), r.clone()))
+ .into_iter()
+ .collect(),
+ )),
+ y.clone(),
+ ),
))),
field.clone(),
- )),
+ ))),
None => {
return normalize_one_layer(
- ExprKind::Field(y.clone(), field.clone()),
+ ExprKind::Op(OpKind::Field(
+ y.clone(),
+ field.clone(),
+ )),
env,
)
}
},
_ => Ret::Expr(expr),
},
- PartialExpr(ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y)) => {
- match (x.kind(), y.kind()) {
- (RecordLit(kvs), _) => match kvs.get(field) {
- Some(r) => Ret::Expr(ExprKind::Field(
- Nir::from_kind(PartialExpr(ExprKind::BinOp(
+ PartialExpr(ExprKind::Op(OpKind::BinOp(
+ BinOp::RecursiveRecordMerge,
+ x,
+ y,
+ ))) => match (x.kind(), y.kind()) {
+ (RecordLit(kvs), _) => match kvs.get(field) {
+ Some(r) => Ret::Expr(ExprKind::Op(OpKind::Field(
+ Nir::from_kind(PartialExpr(ExprKind::Op(
+ OpKind::BinOp(
BinOp::RecursiveRecordMerge,
Nir::from_kind(RecordLit(
Some((field.clone(), r.clone()))
@@ -342,19 +358,24 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
.collect(),
)),
y.clone(),
- ))),
- field.clone(),
- )),
- None => {
- return normalize_one_layer(
- ExprKind::Field(y.clone(), field.clone()),
- env,
- )
- }
- },
- (_, RecordLit(kvs)) => match kvs.get(field) {
- Some(r) => Ret::Expr(ExprKind::Field(
- Nir::from_kind(PartialExpr(ExprKind::BinOp(
+ ),
+ ))),
+ field.clone(),
+ ))),
+ None => {
+ return normalize_one_layer(
+ ExprKind::Op(OpKind::Field(
+ y.clone(),
+ field.clone(),
+ )),
+ env,
+ )
+ }
+ },
+ (_, RecordLit(kvs)) => match kvs.get(field) {
+ Some(r) => Ret::Expr(ExprKind::Op(OpKind::Field(
+ Nir::from_kind(PartialExpr(ExprKind::Op(
+ OpKind::BinOp(
BinOp::RecursiveRecordMerge,
x.clone(),
Nir::from_kind(RecordLit(
@@ -362,52 +383,57 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
.into_iter()
.collect(),
)),
- ))),
- field.clone(),
- )),
- None => {
- return normalize_one_layer(
- ExprKind::Field(x.clone(), field.clone()),
- env,
- )
- }
- },
- _ => Ret::Expr(expr),
- }
- }
+ ),
+ ))),
+ field.clone(),
+ ))),
+ None => {
+ return normalize_one_layer(
+ ExprKind::Op(OpKind::Field(
+ x.clone(),
+ field.clone(),
+ )),
+ env,
+ )
+ }
+ },
+ _ => Ret::Expr(expr),
+ },
_ => Ret::Expr(expr),
},
- ExprKind::Projection(_, ref ls) if ls.is_empty() => {
+ ExprKind::Op(OpKind::Projection(_, ref ls)) if ls.is_empty() => {
Ret::NirKind(RecordLit(HashMap::new()))
}
- ExprKind::Projection(ref v, ref ls) => match v.kind() {
+ ExprKind::Op(OpKind::Projection(ref v, ref ls)) => match v.kind() {
RecordLit(kvs) => Ret::NirKind(RecordLit(
ls.iter()
.filter_map(|l| kvs.get(l).map(|x| (l.clone(), x.clone())))
.collect(),
)),
- PartialExpr(ExprKind::Projection(v2, _)) => {
+ PartialExpr(ExprKind::Op(OpKind::Projection(v2, _))) => {
return normalize_one_layer(
- ExprKind::Projection(v2.clone(), ls.clone()),
+ ExprKind::Op(OpKind::Projection(v2.clone(), ls.clone())),
env,
)
}
_ => Ret::Expr(expr),
},
- ExprKind::ProjectionByExpr(ref v, ref t) => match t.kind() {
- RecordType(kts) => {
- return normalize_one_layer(
- ExprKind::Projection(
- v.clone(),
- kts.keys().cloned().collect(),
- ),
- env,
- )
+ ExprKind::Op(OpKind::ProjectionByExpr(ref v, ref t)) => {
+ match t.kind() {
+ RecordType(kts) => {
+ return normalize_one_layer(
+ ExprKind::Op(OpKind::Projection(
+ v.clone(),
+ kts.keys().cloned().collect(),
+ )),
+ env,
+ )
+ }
+ _ => Ret::Expr(expr),
}
- _ => Ret::Expr(expr),
- },
+ }
- ExprKind::Merge(ref handlers, ref variant, _) => {
+ ExprKind::Op(OpKind::Merge(ref handlers, ref variant, _)) => {
match handlers.kind() {
RecordLit(kvs) => match variant.kind() {
UnionConstructor(l, _) => match kvs.get(l) {
@@ -431,7 +457,7 @@ pub fn normalize_one_layer(expr: ExprKind<Nir>, env: &NzEnv) -> NirKind {
_ => Ret::Expr(expr),
}
}
- ExprKind::ToMap(ref v, ref annot) => match v.kind() {
+ ExprKind::Op(OpKind::ToMap(ref v, ref annot)) => match v.kind() {
RecordLit(kvs) if kvs.is_empty() => {
match annot.as_ref().map(|v| v.kind()) {
Some(NirKind::ListType(t)) => {
diff --git a/dhall/src/semantics/resolve/resolve.rs b/dhall/src/semantics/resolve/resolve.rs
index 6e50fa6..3e0022f 100644
--- a/dhall/src/semantics/resolve/resolve.rs
+++ b/dhall/src/semantics/resolve/resolve.rs
@@ -11,7 +11,7 @@ use crate::syntax;
use crate::syntax::map::DupTreeMap;
use crate::syntax::{
BinOp, Builtin, Expr, ExprKind, FilePath, FilePrefix, Hash, ImportMode,
- ImportTarget, Span, UnspannedExpr, URL,
+ ImportTarget, OpKind, Span, UnspannedExpr, URL,
};
use crate::{Parsed, Resolved};
@@ -179,12 +179,13 @@ impl ImportLocation {
};
let asloc_ty = make_aslocation_uniontype();
- let expr = mkexpr(ExprKind::Field(asloc_ty, field_name.into()));
+ let expr =
+ mkexpr(ExprKind::Op(OpKind::Field(asloc_ty, field_name.into())));
match arg {
- Some(arg) => mkexpr(ExprKind::App(
+ Some(arg) => mkexpr(ExprKind::Op(OpKind::App(
expr,
mkexpr(ExprKind::TextLit(arg.into())),
- )),
+ ))),
None => expr,
}
}
@@ -261,21 +262,21 @@ fn resolve_one_import(
/// Desugar the first level of the expression.
fn desugar(expr: &Expr) -> Cow<'_, Expr> {
match expr.kind() {
- ExprKind::Completion(ty, compl) => {
+ ExprKind::Op(OpKind::Completion(ty, compl)) => {
let ty_field_default = Expr::new(
- ExprKind::Field(ty.clone(), "default".into()),
+ ExprKind::Op(OpKind::Field(ty.clone(), "default".into())),
expr.span(),
);
let merged = Expr::new(
- ExprKind::BinOp(
+ ExprKind::Op(OpKind::BinOp(
BinOp::RightBiasedRecordMerge,
ty_field_default,
compl.clone(),
- ),
+ )),
expr.span(),
);
let ty_field_type = Expr::new(
- ExprKind::Field(ty.clone(), "Type".into()),
+ ExprKind::Op(OpKind::Field(ty.clone(), "Type".into())),
expr.span(),
);
Cow::Owned(Expr::new(
@@ -304,7 +305,7 @@ fn traverse_resolve_expr(
.format(),
)?,
},
- ExprKind::BinOp(BinOp::ImportAlt, l, r) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::ImportAlt, l, r)) => {
match traverse_resolve_expr(name_env, l, f) {
Ok(l) => l,
Err(_) => {
diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs
index c3334b5..8f3fcb2 100644
--- a/dhall/src/semantics/tck/typecheck.rs
+++ b/dhall/src/semantics/tck/typecheck.rs
@@ -9,7 +9,8 @@ use crate::semantics::{
Type,
};
use crate::syntax::{
- BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, NumKind, Span,
+ BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, NumKind, OpKind,
+ Span,
};
fn check_rectymerge(
@@ -75,7 +76,7 @@ fn type_one_layer(
let span_err = |msg: &str| mk_span_err(span.clone(), msg);
let ty = match &ekind {
- ExprKind::Import(..) | ExprKind::Completion(..) => {
+ ExprKind::Import(..) | ExprKind::Op(OpKind::Completion(..)) => {
unreachable!("This case should have been handled in resolution")
}
ExprKind::Var(..)
@@ -222,7 +223,7 @@ fn type_one_layer(
Type::from_const(k)
}
- ExprKind::Field(scrut, x) => {
+ ExprKind::Op(OpKind::Field(scrut, x)) => {
match scrut.ty().kind() {
NirKind::RecordType(kts) => match kts.get(&x) {
Some(val) => Type::new_infer_universe(env, val.clone())?,
@@ -261,7 +262,7 @@ fn type_one_layer(
}
t
}
- ExprKind::App(f, arg) => {
+ ExprKind::Op(OpKind::App(f, arg)) => {
match f.ty().kind() {
// TODO: store Type in closure
NirKind::PiClosure { annot, closure, .. } => {
@@ -309,7 +310,7 @@ fn type_one_layer(
),
}
}
- ExprKind::BoolIf(x, y, z) => {
+ ExprKind::Op(OpKind::BoolIf(x, y, z)) => {
if *x.ty().kind() != NirKind::from_builtin(Builtin::Bool) {
return span_err("InvalidPredicate");
}
@@ -322,7 +323,7 @@ fn type_one_layer(
y.ty().clone()
}
- ExprKind::BinOp(BinOp::RightBiasedRecordMerge, x, y) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::RightBiasedRecordMerge, x, y)) => {
let x_type = x.ty();
let y_type = y.ty();
@@ -344,22 +345,22 @@ fn type_one_layer(
let u = max(x.ty().ty(), y.ty().ty());
Nir::from_kind(NirKind::RecordType(kts)).to_type(u)
}
- ExprKind::BinOp(BinOp::RecursiveRecordMerge, x, y) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::RecursiveRecordMerge, x, y)) => {
check_rectymerge(&span, env, x.ty().to_nir(), y.ty().to_nir())?;
let hir = Hir::new(
- HirKind::Expr(ExprKind::BinOp(
+ HirKind::Expr(ExprKind::Op(OpKind::BinOp(
BinOp::RecursiveRecordTypeMerge,
x.ty().to_hir(env.as_varenv()),
y.ty().to_hir(env.as_varenv()),
- )),
+ ))),
span.clone(),
);
let x_u = x.ty().ty();
let y_u = y.ty().ty();
Type::new(hir.eval(env), max(x_u, y_u))
}
- ExprKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::RecursiveRecordTypeMerge, x, y)) => {
check_rectymerge(&span, env, x.eval(env), y.eval(env))?;
// A RecordType's type is always a const
@@ -367,7 +368,7 @@ fn type_one_layer(
let yk = y.ty().as_const().unwrap();
Type::from_const(max(xk, yk))
}
- ExprKind::BinOp(BinOp::ListAppend, l, r) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::ListAppend, l, r)) => {
match l.ty().kind() {
NirKind::ListType(..) => {}
_ => return span_err("BinOpTypeMismatch"),
@@ -379,7 +380,7 @@ fn type_one_layer(
l.ty().clone()
}
- ExprKind::BinOp(BinOp::Equivalence, l, r) => {
+ ExprKind::Op(OpKind::BinOp(BinOp::Equivalence, l, r)) => {
if l.ty() != r.ty() {
return span_err("EquivalenceTypeMismatch");
}
@@ -389,7 +390,7 @@ fn type_one_layer(
Type::from_const(Const::Type)
}
- ExprKind::BinOp(o, l, r) => {
+ ExprKind::Op(OpKind::BinOp(o, l, r)) => {
let t = Type::from_builtin(match o {
BinOp::BoolAnd
| BinOp::BoolOr
@@ -415,7 +416,7 @@ fn type_one_layer(
t
}
- ExprKind::Merge(record, union, type_annot) => {
+ ExprKind::Op(OpKind::Merge(record, union, type_annot)) => {
let record_type = record.ty();
let handlers = match record_type.kind() {
NirKind::RecordType(kts) => kts,
@@ -554,7 +555,7 @@ fn type_one_layer(
(None, None) => return span_err("MergeEmptyNeedsAnnotation"),
}
}
- ExprKind::ToMap(record, annot) => {
+ ExprKind::Op(OpKind::ToMap(record, annot)) => {
if record.ty().ty().as_const() != Some(Const::Type) {
return span_err("`toMap` only accepts records of type `Type`");
}
@@ -624,7 +625,7 @@ fn type_one_layer(
output_type
}
}
- ExprKind::Projection(record, labels) => {
+ ExprKind::Op(OpKind::Projection(record, labels)) => {
let record_type = record.ty();
let kts = match record_type.kind() {
NirKind::RecordType(kts) => kts,
@@ -652,7 +653,7 @@ fn type_one_layer(
Nir::from_kind(NirKind::RecordType(new_kts)),
)?
}
- ExprKind::ProjectionByExpr(record, selection) => {
+ ExprKind::Op(OpKind::ProjectionByExpr(record, selection)) => {
let record_type = record.ty();
let rec_kts = match record_type.kind() {
NirKind::RecordType(kts) => kts,
diff --git a/dhall/src/syntax/ast/expr.rs b/dhall/src/syntax/ast/expr.rs
index 9e935dc..51426ce 100644
--- a/dhall/src/syntax/ast/expr.rs
+++ b/dhall/src/syntax/ast/expr.rs
@@ -126,63 +126,73 @@ pub enum NumKind {
Double(Double),
}
+/// Operations
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum OpKind<SubExpr> {
+ /// `f a`
+ App(SubExpr, SubExpr),
+ /// Binary operations
+ BinOp(BinOp, SubExpr, SubExpr),
+ /// `if x then y else z`
+ BoolIf(SubExpr, SubExpr, SubExpr),
+ /// `merge x y : t`
+ Merge(SubExpr, SubExpr, Option<SubExpr>),
+ /// `toMap x : t`
+ ToMap(SubExpr, Option<SubExpr>),
+ /// `e.x`
+ Field(SubExpr, Label),
+ /// `e.{ x, y, z }`
+ Projection(SubExpr, DupTreeSet<Label>),
+ /// `e.(t)`
+ ProjectionByExpr(SubExpr, SubExpr),
+ /// `x::y`
+ Completion(SubExpr, SubExpr),
+}
+
/// 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 ExprKind<SubExpr> {
+ /// `Type`, `Kind` and `Sort`
Const(Const),
+ /// Numbers and booleans
Num(NumKind),
- /// `x`
- /// `x@n`
- Var(V),
- /// `λ(x : A) -> b`
- Lam(Label, SubExpr, SubExpr),
- /// `A -> B`
- /// `∀(x : A) -> B`
- Pi(Label, SubExpr, SubExpr),
- /// `f a`
- App(SubExpr, SubExpr),
- /// `let x = r in e`
- /// `let x : t = r in e`
- Let(Label, Option<SubExpr>, SubExpr, SubExpr),
- /// `x : t`
- Annot(SubExpr, SubExpr),
- /// `assert : t`
- Assert(SubExpr),
- /// Built-in values
+ /// Built-in functions and types
Builtin(Builtin),
- // Binary operations
- BinOp(BinOp, SubExpr, SubExpr),
- /// `if x then y else z`
- BoolIf(SubExpr, SubExpr, SubExpr),
+ /// `Some e`
+ SomeLit(SubExpr),
/// `"Some ${interpolated} text"`
TextLit(InterpolatedText<SubExpr>),
/// `[] : t`
EmptyListLit(SubExpr),
/// `[x, y, z]`
NEListLit(Vec<SubExpr>),
- /// `Some e`
- SomeLit(SubExpr),
/// `{ k1 : t1, k2 : t1 }`
RecordType(DupTreeMap<Label, SubExpr>),
/// `{ k1 = v1, k2 = v2 }`
RecordLit(BTreeMap<Label, SubExpr>),
/// `< k1 : t1, k2 >`
UnionType(DupTreeMap<Label, Option<SubExpr>>),
- /// `merge x y : t`
- Merge(SubExpr, SubExpr, Option<SubExpr>),
- /// `toMap x : t`
- ToMap(SubExpr, Option<SubExpr>),
- /// `e.x`
- Field(SubExpr, Label),
- /// `e.{ x, y, z }`
- Projection(SubExpr, DupTreeSet<Label>),
- /// `e.(t)`
- ProjectionByExpr(SubExpr, SubExpr),
- /// `x::y`
- Completion(SubExpr, SubExpr),
+
+ /// `x`, `x@n`
+ Var(V),
+ /// `λ(x : A) -> b`
+ Lam(Label, SubExpr, SubExpr),
+ /// `A -> B`, `∀(x : A) -> B`
+ Pi(Label, SubExpr, SubExpr),
+ /// `let x : t = r in e`
+ Let(Label, Option<SubExpr>, SubExpr, SubExpr),
+
+ /// Operations
+ Op(OpKind<SubExpr>),
+
+ /// `x : t`
+ Annot(SubExpr, SubExpr),
+ /// `assert : t`
+ Assert(SubExpr),
+
/// `./some/path`
Import(Import<SubExpr>),
}
@@ -239,6 +249,45 @@ impl<SE> ExprKind<SE> {
}
}
+impl<SE> OpKind<SE> {
+ pub fn traverse_ref<'a, SE2, Err>(
+ &'a self,
+ mut f: impl FnMut(&'a SE) -> Result<SE2, Err>,
+ ) -> Result<OpKind<SE2>, Err> {
+ // Can't use closures because of borrowing rules
+ macro_rules! expr {
+ ($e:expr) => {
+ f($e)?
+ };
+ }
+ macro_rules! opt {
+ ($e:expr) => {
+ $e.as_ref().map(|e| Ok(expr!(e))).transpose()?
+ };
+ }
+
+ use OpKind::*;
+ Ok(match self {
+ App(f, a) => App(expr!(f), expr!(a)),
+ BinOp(o, x, y) => BinOp(*o, expr!(x), expr!(y)),
+ BoolIf(b, t, f) => BoolIf(expr!(b), expr!(t), expr!(f)),
+ Merge(x, y, t) => Merge(expr!(x), expr!(y), opt!(t)),
+ ToMap(x, t) => ToMap(expr!(x), opt!(t)),
+ Field(e, l) => Field(expr!(e), l.clone()),
+ Projection(e, ls) => Projection(expr!(e), ls.clone()),
+ ProjectionByExpr(e, x) => ProjectionByExpr(expr!(e), expr!(x)),
+ Completion(e, x) => Completion(expr!(e), expr!(x)),
+ })
+ }
+
+ pub fn map_ref<'a, SE2>(
+ &'a self,
+ mut f: impl FnMut(&'a SE) -> SE2,
+ ) -> OpKind<SE2> {
+ trivial_result(self.traverse_ref(|x| Ok(f(x))))
+ }
+}
+
impl Expr {
pub fn as_ref(&self) -> &UnspannedExpr {
&self.kind
diff --git a/dhall/src/syntax/ast/visitor.rs b/dhall/src/syntax/ast/visitor.rs
index 0a0c5ef..7244d0a 100644
--- a/dhall/src/syntax/ast/visitor.rs
+++ b/dhall/src/syntax/ast/visitor.rs
@@ -1,22 +1,13 @@
+use itertools::Itertools;
use std::iter::FromIterator;
use crate::syntax::*;
-fn vec<'a, T, U, Err>(
- x: &'a [T],
- f: impl FnMut(&'a T) -> Result<U, Err>,
-) -> Result<Vec<U>, Err> {
- x.iter().map(f).collect()
-}
-
fn opt<'a, T, U, Err>(
x: &'a Option<T>,
f: impl FnOnce(&'a T) -> Result<U, Err>,
) -> Result<Option<U>, Err> {
- Ok(match x {
- Some(x) => Some(f(x)?),
- None => None,
- })
+ x.as_ref().map(f).transpose()
}
fn dupmap<'a, SE1, SE2, T, Err>(
@@ -30,27 +21,6 @@ where
x.into_iter().map(|(k, x)| Ok((k.clone(), f(x)?))).collect()
}
-fn optdupmap<'a, SE1, SE2, T, Err>(
- x: impl IntoIterator<Item = (&'a Label, &'a Option<SE1>)>,
- mut f: impl FnMut(&'a SE1) -> Result<SE2, Err>,
-) -> Result<T, Err>
-where
- SE1: 'a,
- T: FromIterator<(Label, Option<SE2>)>,
-{
- x.into_iter()
- .map(|(k, x)| {
- Ok((
- k.clone(),
- match x {
- Some(x) => Some(f(x)?),
- None => None,
- },
- ))
- })
- .collect()
-}
-
pub fn visit_ref<'a, F, SE1, SE2, Err>(
input: &'a ExprKind<SE1>,
mut f: F,
@@ -60,54 +30,44 @@ where
{
// Can't use closures because of borrowing rules
macro_rules! expr {
+ () => {
+ |e| Ok(expr!(e))
+ };
($e:expr) => {
- f(None, $e)
+ f(None, $e)?
};
($l:expr, $e:expr) => {
- f(Some($l), $e)
+ f(Some($l), $e)?
+ };
+ }
+ macro_rules! opt {
+ () => {
+ |e| Ok(opt!(e))
+ };
+ ($e:expr) => {
+ opt($e, |e| Ok(expr!(e)))?
};
}
use crate::syntax::ExprKind::*;
Ok(match input {
Var(v) => Var(v.clone()),
- Lam(l, t, e) => {
- let t = expr!(t)?;
- let e = expr!(l, e)?;
- Lam(l.clone(), t, e)
- }
- Pi(l, t, e) => {
- let t = expr!(t)?;
- let e = expr!(l, e)?;
- Pi(l.clone(), t, e)
- }
- Let(l, t, a, e) => {
- let t = opt(t, &mut |e| expr!(e))?;
- let a = expr!(a)?;
- let e = expr!(l, e)?;
- Let(l.clone(), t, a, e)
- }
- App(f, a) => App(expr!(f)?, expr!(a)?),
- Annot(x, t) => Annot(expr!(x)?, expr!(t)?),
+ Lam(l, t, e) => Lam(l.clone(), expr!(t), expr!(l, e)),
+ Pi(l, t, e) => Pi(l.clone(), expr!(t), expr!(l, e)),
+ Let(l, t, a, e) => Let(l.clone(), opt!(t), expr!(a), expr!(l, e)),
Const(k) => Const(*k),
- Builtin(v) => Builtin(*v),
Num(n) => Num(n.clone()),
- TextLit(t) => TextLit(t.traverse_ref(|e| expr!(e))?),
- BinOp(o, x, y) => BinOp(*o, expr!(x)?, expr!(y)?),
- BoolIf(b, t, f) => BoolIf(expr!(b)?, expr!(t)?, expr!(f)?),
- EmptyListLit(t) => EmptyListLit(expr!(t)?),
- NEListLit(es) => NEListLit(vec(es, |e| expr!(e))?),
- SomeLit(e) => SomeLit(expr!(e)?),
- RecordType(kts) => RecordType(dupmap(kts, |e| expr!(e))?),
- RecordLit(kvs) => RecordLit(dupmap(kvs, |e| expr!(e))?),
- UnionType(kts) => UnionType(optdupmap(kts, |e| expr!(e))?),
- Merge(x, y, t) => Merge(expr!(x)?, expr!(y)?, opt(t, |e| expr!(e))?),
- ToMap(x, t) => ToMap(expr!(x)?, opt(t, |e| expr!(e))?),
- Field(e, l) => Field(expr!(e)?, l.clone()),
- Projection(e, ls) => Projection(expr!(e)?, ls.clone()),
- ProjectionByExpr(e, x) => ProjectionByExpr(expr!(e)?, expr!(x)?),
- Completion(e, x) => Completion(expr!(e)?, expr!(x)?),
- Assert(e) => Assert(expr!(e)?),
- Import(i) => Import(i.traverse_ref(|e| expr!(e))?),
+ Builtin(v) => Builtin(*v),
+ TextLit(t) => TextLit(t.traverse_ref(expr!())?),
+ SomeLit(e) => SomeLit(expr!(e)),
+ EmptyListLit(t) => EmptyListLit(expr!(t)),
+ NEListLit(es) => NEListLit(es.iter().map(expr!()).try_collect()?),
+ RecordType(kts) => RecordType(dupmap(kts, expr!())?),
+ RecordLit(kvs) => RecordLit(dupmap(kvs, expr!())?),
+ UnionType(kts) => UnionType(dupmap(kts, opt!())?),
+ Op(op) => Op(op.traverse_ref(expr!())?),
+ Annot(x, t) => Annot(expr!(x), expr!(t)),
+ Assert(e) => Assert(expr!(e)),
+ Import(i) => Import(i.traverse_ref(expr!())?),
})
}
diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs
index 3c93419..b183f6c 100644
--- a/dhall/src/syntax/binary/decode.rs
+++ b/dhall/src/syntax/binary/decode.rs
@@ -6,7 +6,7 @@ use crate::error::DecodeError;
use crate::syntax;
use crate::syntax::{
Expr, ExprKind, FilePath, FilePrefix, Hash, ImportMode, ImportTarget,
- Integer, InterpolatedText, Label, Natural, NumKind, Scheme, Span,
+ Integer, InterpolatedText, Label, Natural, NumKind, OpKind, Scheme, Span,
UnspannedExpr, URL, V,
};
type DecodedExpr = Expr;
@@ -27,6 +27,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
use cbor::Value::*;
use syntax::{BinOp, Builtin, Const};
use ExprKind::*;
+ use OpKind::*;
Ok(rc(match data {
String(s) => match Builtin::parse(s) {
Some(b) => ExprKind::Builtin(b),
@@ -66,7 +67,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
let mut f = cbor_value_to_dhall(&f)?;
for a in args {
let a = cbor_value_to_dhall(&a)?;
- f = rc(App(f, a))
+ f = rc(Op(App(f, a)))
}
return Ok(f);
}
@@ -105,7 +106,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
[U64(3), U64(13), x, y] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
- Completion(x, y)
+ Op(Completion(x, y))
}
[U64(3), U64(n), x, y] => {
let x = cbor_value_to_dhall(&x)?;
@@ -131,11 +132,14 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
))
}
};
- BinOp(op, x, y)
+ Op(BinOp(op, x, y))
}
[U64(4), t] => {
let t = cbor_value_to_dhall(&t)?;
- EmptyListLit(rc(App(rc(ExprKind::Builtin(Builtin::List)), t)))
+ EmptyListLit(rc(Op(App(
+ rc(ExprKind::Builtin(Builtin::List)),
+ t,
+ ))))
}
[U64(4), Null, rest @ ..] => {
let rest = rest
@@ -151,26 +155,26 @@ 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(ExprKind::Builtin(Builtin::OptionalNone)), t)
+ Op(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(ExprKind::Builtin(Builtin::Optional)), t)),
+ rc(Op(App(rc(ExprKind::Builtin(Builtin::Optional)), t))),
)
}
[U64(6), x, y] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
- Merge(x, y, None)
+ Op(Merge(x, y, None))
}
[U64(6), x, y, z] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
let z = cbor_value_to_dhall(&z)?;
- Merge(x, y, Some(z))
+ Op(Merge(x, y, Some(z)))
}
[U64(7), Object(map)] => {
let map = cbor_map_to_dhall_map(map)?;
@@ -183,13 +187,13 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
[U64(9), x, String(l)] => {
let x = cbor_value_to_dhall(&x)?;
let l = Label::from(l.as_str());
- Field(x, l)
+ Op(Field(x, l))
}
[U64(10), x, Array(arr)] => {
let x = cbor_value_to_dhall(&x)?;
if let [y] = arr.as_slice() {
let y = cbor_value_to_dhall(&y)?;
- ProjectionByExpr(x, y)
+ Op(ProjectionByExpr(x, y))
} else {
return Err(DecodeError::WrongFormatError(
"projection-by-expr".to_owned(),
@@ -207,7 +211,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
)),
})
.collect::<Result<_, _>>()?;
- Projection(x, labels)
+ Op(Projection(x, labels))
}
[U64(11), Object(map)] => {
let map = cbor_map_to_dhall_opt_map(map)?;
@@ -222,7 +226,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
let z = cbor_value_to_dhall(&z)?;
- BoolIf(x, y, z)
+ Op(BoolIf(x, y, z))
}
[U64(15), U64(x)] => Num(NumKind::Natural(*x as Natural)),
[U64(16), U64(x)] => Num(NumKind::Integer(*x as Integer)),
@@ -416,12 +420,12 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
}
[U64(27), x] => {
let x = cbor_value_to_dhall(&x)?;
- ToMap(x, None)
+ Op(ToMap(x, None))
}
[U64(27), x, y] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
- ToMap(x, Some(y))
+ Op(ToMap(x, Some(y)))
}
[U64(28), x] => {
let x = cbor_value_to_dhall(&x)?;
diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs
index 8d22a9b..f2bc6f1 100644
--- a/dhall/src/syntax/binary/encode.rs
+++ b/dhall/src/syntax/binary/encode.rs
@@ -7,7 +7,7 @@ use crate::syntax;
use crate::syntax::map::DupTreeMap;
use crate::syntax::{
Expr, ExprKind, FilePrefix, Hash, Import, ImportMode, ImportTarget, Label,
- Scheme, V,
+ OpKind, Scheme, V,
};
pub fn encode(expr: &Expr) -> Result<Vec<u8>, EncodeError> {
@@ -49,6 +49,7 @@ where
use syntax::Builtin;
use syntax::ExprKind::*;
use syntax::NumKind::*;
+ use syntax::OpKind::*;
use self::Serialize::{RecordDupMap, RecordMap, UnionMap};
fn expr(x: &Expr) -> self::Serialize<'_> {
@@ -70,7 +71,9 @@ where
let n: f64 = (*n).into();
ser.serialize_f64(n)
}
- BoolIf(x, y, z) => ser_seq!(ser; tag(14), expr(x), expr(y), expr(z)),
+ Op(BoolIf(x, y, z)) => {
+ ser_seq!(ser; tag(14), expr(x), expr(y), expr(z))
+ }
Var(V(l, n)) if l == &"_".into() => ser.serialize_u64(*n as u64),
Var(V(l, n)) => ser_seq!(ser; label(l), U64(*n as u64)),
Lam(l, x, y) if l == &"_".into() => {
@@ -99,7 +102,7 @@ where
ser_seq.serialize_element(&expr(bound_e))?;
ser_seq.end()
}
- App(_, _) => {
+ Op(App(_, _)) => {
let (f, args) = collect_nested_applications(e);
ser.collect_seq(
once(tag(0))
@@ -111,7 +114,7 @@ where
Assert(x) => ser_seq!(ser; tag(19), expr(x)),
SomeLit(x) => ser_seq!(ser; tag(5), null(), expr(x)),
EmptyListLit(x) => match x.as_ref() {
- App(f, a) => match f.as_ref() {
+ Op(App(f, a)) => match f.as_ref() {
ExprKind::Builtin(Builtin::List) => {
ser_seq!(ser; tag(4), expr(a))
}
@@ -132,8 +135,8 @@ where
RecordType(map) => ser_seq!(ser; tag(7), RecordDupMap(map)),
RecordLit(map) => ser_seq!(ser; tag(8), RecordMap(map)),
UnionType(map) => ser_seq!(ser; tag(11), UnionMap(map)),
- Field(x, l) => ser_seq!(ser; tag(9), expr(x), label(l)),
- BinOp(op, x, y) => {
+ Op(Field(x, l)) => ser_seq!(ser; tag(9), expr(x), label(l)),
+ Op(BinOp(op, x, y)) => {
use syntax::BinOp::*;
let op = match op {
BoolOr => 0,
@@ -152,21 +155,23 @@ where
};
ser_seq!(ser; tag(3), U64(op), expr(x), expr(y))
}
- Merge(x, y, None) => ser_seq!(ser; tag(6), expr(x), expr(y)),
- Merge(x, y, Some(z)) => {
+ Op(Merge(x, y, None)) => ser_seq!(ser; tag(6), expr(x), expr(y)),
+ Op(Merge(x, y, Some(z))) => {
ser_seq!(ser; tag(6), expr(x), expr(y), expr(z))
}
- ToMap(x, None) => ser_seq!(ser; tag(27), expr(x)),
- ToMap(x, Some(y)) => ser_seq!(ser; tag(27), expr(x), expr(y)),
- Projection(x, ls) => ser.collect_seq(
+ Op(ToMap(x, None)) => ser_seq!(ser; tag(27), expr(x)),
+ Op(ToMap(x, Some(y))) => ser_seq!(ser; tag(27), expr(x), expr(y)),
+ Op(Projection(x, ls)) => ser.collect_seq(
once(tag(10))
.chain(once(expr(x)))
.chain(ls.iter().map(label)),
),
- ProjectionByExpr(x, y) => {
+ Op(ProjectionByExpr(x, y)) => {
ser_seq!(ser; tag(10), expr(x), vec![expr(y)])
}
- Completion(x, y) => ser_seq!(ser; tag(3), tag(13), expr(x), expr(y)),
+ Op(Completion(x, y)) => {
+ ser_seq!(ser; tag(3), tag(13), expr(x), expr(y))
+ }
Import(import) => serialize_import(ser, import),
}
}
@@ -286,7 +291,7 @@ impl<'a> serde::ser::Serialize for Serialize<'a> {
fn collect_nested_applications<'a>(e: &'a Expr) -> (&'a Expr, Vec<&'a Expr>) {
fn go<'a>(e: &'a Expr, vec: &mut Vec<&'a Expr>) -> &'a Expr {
match e.as_ref() {
- ExprKind::App(f, a) => {
+ ExprKind::Op(OpKind::App(f, a)) => {
vec.push(a);
go(f, vec)
}
diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs
index 6f5949f..ab9bc24 100644
--- a/dhall/src/syntax/text/parser.rs
+++ b/dhall/src/syntax/text/parser.rs
@@ -10,6 +10,7 @@ use pest_consume::{match_nodes, Parser};
use crate::syntax::map::{DupTreeMap, DupTreeSet};
use crate::syntax::ExprKind::*;
use crate::syntax::NumKind::*;
+use crate::syntax::OpKind::*;
use crate::syntax::{
Double, Expr, FilePath, FilePrefix, Hash, ImportMode, ImportTarget,
Integer, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble,
@@ -138,7 +139,7 @@ fn insert_recordlit_entry(map: &mut BTreeMap<Label, Expr>, l: Label, e: Expr) {
let dummy = Expr::new(Num(Bool(false)), Span::Artificial);
let other = entry.insert(dummy);
entry.insert(Expr::new(
- BinOp(RecursiveRecordMerge, other, e),
+ Op(BinOp(RecursiveRecordMerge, other, e)),
Span::DuplicateRecordFieldsSugar,
));
}
@@ -151,13 +152,16 @@ fn desugar_with_expr(x: Expr, labels: &[Label], y: Expr) -> Expr {
match labels {
[] => y,
[l, rest @ ..] => {
- let res =
- desugar_with_expr(expr(Field(x.clone(), l.clone())), rest, y);
- expr(BinOp(
+ let res = desugar_with_expr(
+ expr(Op(Field(x.clone(), l.clone()))),
+ rest,
+ y,
+ );
+ expr(Op(BinOp(
RightBiasedRecordMerge,
x,
expr(RecordLit(once((l.clone(), res)).collect())),
- ))
+ )))
}
}
}
@@ -725,7 +729,7 @@ impl DhallParser {
},
[if_(()), expression(cond), expression(left),
expression(right)] => {
- spanned(input, BoolIf(cond, left, right))
+ spanned(input, Op(BoolIf(cond, left, right)))
},
[let_binding(bindings).., expression(final_expr)] => {
bindings.rev().fold(
@@ -747,13 +751,13 @@ impl DhallParser {
spanned(input, Pi("_".into(), typ, body))
},
[merge(()), expression(x), expression(y), expression(z)] => {
- spanned(input, Merge(x, y, Some(z)))
+ spanned(input, Op(Merge(x, y, Some(z))))
},
[assert(()), expression(x)] => {
spanned(input, Assert(x))
},
[toMap(()), expression(x), expression(y)] => {
- spanned(input, ToMap(x, Some(y)))
+ spanned(input, Op(ToMap(x, Some(y))))
},
[expression(e), expression(annot)] => {
spanned(input, Annot(e, annot))
@@ -801,7 +805,7 @@ impl DhallParser {
}
};
- Ok(spanned_union(l.span(), r.span(), BinOp(op, l, r)))
+ Ok(spanned_union(l.span(), r.span(), Op(BinOp(op, l, r))))
}
fn Some_(_input: ParseInput) -> ParseResult<()> {
@@ -840,7 +844,7 @@ impl DhallParser {
spanned_union(
acc.span(),
e.span(),
- App(acc, e)
+ Op(App(acc, e))
)
}
)
@@ -855,10 +859,10 @@ impl DhallParser {
spanned(input, SomeLit(e))
},
[merge(()), expression(x), expression(y)] => {
- spanned(input, Merge(x, y, None))
+ spanned(input, Op(Merge(x, y, None)))
},
[toMap(()), expression(x)] => {
- spanned(input, ToMap(x, None))
+ spanned(input, Op(ToMap(x, None)))
},
[expression(e)] => e,
))
@@ -875,7 +879,7 @@ impl DhallParser {
spanned_union(
acc.span(),
e.span(),
- Completion(acc, e),
+ Op(Completion(acc, e)),
)
}
)
@@ -895,9 +899,9 @@ impl DhallParser {
acc.span(),
e.1,
match e.0 {
- Selector::Field(l) => Field(acc, l),
- Selector::Projection(ls) => Projection(acc, ls),
- Selector::ProjectionByExpr(e) => ProjectionByExpr(acc, e)
+ Selector::Field(l) => Op(Field(acc, l)),
+ Selector::Projection(ls) => Op(Projection(acc, ls)),
+ Selector::ProjectionByExpr(e) => Op(ProjectionByExpr(acc, e))
}
)
}
diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs
index 378f408..d655489 100644
--- a/dhall/src/syntax/text/printer.rs
+++ b/dhall/src/syntax/text/printer.rs
@@ -5,14 +5,15 @@ 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.
+// of automatically getting all the parentheses and precedences right (in a manner dual do Pratt
+// parsing).
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
enum PrintPhase {
// `expression`
Base,
// `operator-expression`
Operator,
- // All the operator `*-expression`s
+ // All the `<operator>-expression`s
BinOp(ast::BinOp),
// `application-expression`
App,
@@ -37,6 +38,7 @@ impl UnspannedExpr {
// Annotate subexpressions with the appropriate phase, defaulting to Base
fn annotate_with_phases(&self) -> ExprKind<PhasedExpr<'_>> {
use crate::syntax::ExprKind::*;
+ use crate::syntax::OpKind::*;
use PrintPhase::*;
let with_base = self.map_ref(|e| PhasedExpr(e, Base));
match with_base {
@@ -47,31 +49,33 @@ impl UnspannedExpr {
Pi(a, b, c)
}
}
- Merge(a, b, c) => Merge(
+ Op(Merge(a, b, c)) => Op(Merge(
a.phase(PrintPhase::Import),
b.phase(PrintPhase::Import),
c.map(|x| x.phase(PrintPhase::App)),
- ),
- ToMap(a, b) => ToMap(
+ )),
+ Op(ToMap(a, b)) => Op(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(OpKind::BinOp(op, a, b)) => Op(OpKind::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(
+ Op(OpKind::App(f, a)) => Op(OpKind::App(
f.phase(PrintPhase::App),
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),
- Completion(a, b) => {
- Completion(a.phase(Primitive), b.phase(Primitive))
+ )),
+ Op(Field(a, b)) => Op(Field(a.phase(Primitive), b)),
+ Op(Projection(e, ls)) => Op(Projection(e.phase(Primitive), ls)),
+ Op(ProjectionByExpr(a, b)) => {
+ Op(ProjectionByExpr(a.phase(Primitive), b))
+ }
+ Op(Completion(a, b)) => {
+ Op(Completion(a.phase(Primitive), b.phase(Primitive)))
}
ExprKind::Import(a) => {
ExprKind::Import(a.map_ref(|x| x.phase(PrintPhase::Import)))
@@ -86,21 +90,23 @@ impl UnspannedExpr {
phase: PrintPhase,
) -> Result<(), fmt::Error> {
use crate::syntax::ExprKind::*;
+ use crate::syntax::OpKind::*;
let needs_paren = match self {
Lam(_, _, _)
- | BoolIf(_, _, _)
| Pi(_, _, _)
| Let(_, _, _, _)
- | EmptyListLit(_)
| SomeLit(_)
- | Merge(_, _, _)
- | ToMap(_, _)
+ | EmptyListLit(_)
+ | Op(BoolIf(_, _, _))
+ | Op(Merge(_, _, _))
+ | Op(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,
- Completion(_, _) => phase > PrintPhase::Import,
+ // Precedence is magically handled by the ordering of BinOps. This is reverse Pratt
+ // parsing.
+ Op(BinOp(op, _, _)) => phase > PrintPhase::BinOp(*op),
+ Op(App(_, _)) => phase > PrintPhase::App,
+ Op(Completion(_, _)) => phase > PrintPhase::Import,
_ => false,
};
@@ -143,12 +149,10 @@ impl<SE: Display + Clone> Display for ExprKind<SE> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
use crate::syntax::ExprKind::*;
match self {
+ Var(a) => a.fmt(f)?,
Lam(a, b, c) => {
write!(f, "λ({} : {}) → {}", a, b, c)?;
}
- BoolIf(a, b, c) => {
- write!(f, "if {} then {} else {}", a, b, c)?;
- }
Pi(a, b, c) if &String::from(a) == "_" => {
write!(f, "{} → {}", b, c)?;
}
@@ -162,14 +166,62 @@ impl<SE: Display + Clone> Display for ExprKind<SE> {
}
write!(f, " = {} in {}", c, d)?;
}
+ Const(k) => k.fmt(f)?,
+ Builtin(v) => v.fmt(f)?,
+ Num(a) => a.fmt(f)?,
+ TextLit(a) => a.fmt(f)?,
+ SomeLit(e) => {
+ write!(f, "Some {}", e)?;
+ }
EmptyListLit(t) => {
write!(f, "[] : {}", t)?;
}
NEListLit(es) => {
fmt_list("[", ", ", "]", es, f, Display::fmt)?;
}
- SomeLit(e) => {
- write!(f, "Some {}", e)?;
+ RecordLit(a) if a.is_empty() => f.write_str("{=}")?,
+ RecordLit(a) => fmt_list("{ ", ", ", " }", a, f, |(k, v), f| {
+ write!(f, "{} = {}", k, v)
+ })?,
+ RecordType(a) if a.is_empty() => f.write_str("{}")?,
+ RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| {
+ write!(f, "{} : {}", k, t)
+ })?,
+ UnionType(a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| {
+ write!(f, "{}", k)?;
+ if let Some(v) = v {
+ write!(f, ": {}", v)?;
+ }
+ Ok(())
+ })?,
+ Op(op) => {
+ op.fmt(f)?;
+ }
+ Annot(a, b) => {
+ write!(f, "{} : {}", a, b)?;
+ }
+ Assert(a) => {
+ write!(f, "assert : {}", a)?;
+ }
+ Import(a) => a.fmt(f)?,
+ }
+ Ok(())
+ }
+}
+
+/// Generic instance that delegates to subexpressions
+impl<SE: Display + Clone> Display for OpKind<SE> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ use crate::syntax::OpKind::*;
+ match self {
+ App(a, b) => {
+ write!(f, "{} {}", a, b)?;
+ }
+ BinOp(op, a, b) => {
+ write!(f, "{} {} {}", a, op, b)?;
+ }
+ BoolIf(a, b, c) => {
+ write!(f, "if {} then {} else {}", a, b, c)?;
}
Merge(a, b, c) => {
write!(f, "merge {} {}", a, b)?;
@@ -183,41 +235,9 @@ impl<SE: Display + Clone> Display for ExprKind<SE> {
write!(f, " : {}", b)?;
}
}
- Annot(a, b) => {
- write!(f, "{} : {}", a, b)?;
- }
- Assert(a) => {
- write!(f, "assert : {}", a)?;
- }
- ExprKind::BinOp(op, a, b) => {
- write!(f, "{} {} {}", a, op, b)?;
- }
- ExprKind::App(a, b) => {
- write!(f, "{} {}", a, b)?;
- }
Field(a, b) => {
write!(f, "{}.{}", a, b)?;
}
- Var(a) => a.fmt(f)?,
- Const(k) => k.fmt(f)?,
- Builtin(v) => v.fmt(f)?,
- Num(a) => a.fmt(f)?,
- TextLit(a) => a.fmt(f)?,
- RecordType(a) if a.is_empty() => f.write_str("{}")?,
- RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| {
- write!(f, "{} : {}", k, t)
- })?,
- RecordLit(a) if a.is_empty() => f.write_str("{=}")?,
- RecordLit(a) => fmt_list("{ ", ", ", " }", a, f, |(k, v), f| {
- write!(f, "{} = {}", k, v)
- })?,
- UnionType(a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| {
- write!(f, "{}", k)?;
- if let Some(v) = v {
- write!(f, ": {}", v)?;
- }
- Ok(())
- })?,
Projection(e, ls) => {
write!(f, "{}.", e)?;
fmt_list("{ ", ", ", " }", ls, f, Display::fmt)?;
@@ -228,7 +248,6 @@ impl<SE: Display + Clone> Display for ExprKind<SE> {
Completion(a, b) => {
write!(f, "{}::{}", a, b)?;
}
- Import(a) => a.fmt(f)?,
}
Ok(())
}