summaryrefslogtreecommitdiff
path: root/dhall/src/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'dhall/src/syntax')
-rw-r--r--dhall/src/syntax/ast/expr.rs134
-rw-r--r--dhall/src/syntax/ast/map.rs282
-rw-r--r--dhall/src/syntax/ast/mod.rs1
-rw-r--r--dhall/src/syntax/ast/visitor.rs100
-rw-r--r--dhall/src/syntax/binary/decode.rs37
-rw-r--r--dhall/src/syntax/binary/encode.rs51
-rw-r--r--dhall/src/syntax/text/parser.rs148
-rw-r--r--dhall/src/syntax/text/printer.rs192
8 files changed, 269 insertions, 676 deletions
diff --git a/dhall/src/syntax/ast/expr.rs b/dhall/src/syntax/ast/expr.rs
index 9e935dc..9d216a7 100644
--- a/dhall/src/syntax/ast/expr.rs
+++ b/dhall/src/syntax/ast/expr.rs
@@ -1,8 +1,9 @@
use std::collections::BTreeMap;
+use crate::builtins::Builtin;
use crate::error::Error;
+use crate::operations::OpKind;
use crate::semantics::Universe;
-use crate::syntax::map::{DupTreeMap, DupTreeSet};
use crate::syntax::visitor;
use crate::syntax::*;
@@ -36,74 +37,6 @@ impl Const {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct V(pub Label, pub usize);
-// Definition order must match precedence order for
-// pretty-printing to work correctly
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum BinOp {
- /// `x ? y`
- ImportAlt,
- /// `x || y`
- BoolOr,
- /// `x + y`
- NaturalPlus,
- /// `x ++ y`
- TextAppend,
- /// `x # y`
- ListAppend,
- /// `x && y`
- BoolAnd,
- /// `x ∧ y`
- RecursiveRecordMerge,
- /// `x ⫽ y`
- RightBiasedRecordMerge,
- /// `x ⩓ y`
- RecursiveRecordTypeMerge,
- /// `x * y`
- NaturalTimes,
- /// `x == y`
- BoolEQ,
- /// `x != y`
- BoolNE,
- /// x === y
- Equivalence,
-}
-
-/// Built-ins
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum Builtin {
- Bool,
- Natural,
- Integer,
- Double,
- Text,
- List,
- Optional,
- OptionalNone,
- NaturalBuild,
- NaturalFold,
- NaturalIsZero,
- NaturalEven,
- NaturalOdd,
- NaturalToInteger,
- NaturalShow,
- NaturalSubtract,
- IntegerToDouble,
- IntegerShow,
- IntegerNegate,
- IntegerClamp,
- DoubleShow,
- ListBuild,
- ListFold,
- ListLength,
- ListHead,
- ListLast,
- ListIndexed,
- ListReverse,
- OptionalFold,
- OptionalBuild,
- TextShow,
-}
-
// Each node carries an annotation.
#[derive(Debug, Clone)]
pub struct Expr {
@@ -132,57 +65,44 @@ pub enum NumKind {
// 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 ${interpolated} text"`
TextLit(InterpolatedText<SubExpr>),
+ /// `Some e`
+ SomeLit(SubExpr),
/// `[] : t`
EmptyListLit(SubExpr),
/// `[x, y, z]`
NEListLit(Vec<SubExpr>),
- /// `Some e`
- SomeLit(SubExpr),
/// `{ k1 : t1, k2 : t1 }`
- RecordType(DupTreeMap<Label, SubExpr>),
+ RecordType(BTreeMap<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),
+ UnionType(BTreeMap<Label, Option<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>),
}
diff --git a/dhall/src/syntax/ast/map.rs b/dhall/src/syntax/ast/map.rs
deleted file mode 100644
index 7a88204..0000000
--- a/dhall/src/syntax/ast/map.rs
+++ /dev/null
@@ -1,282 +0,0 @@
-/// A sorted map that allows multiple values for each key.
-pub use dup_tree_map::DupTreeMap;
-pub use dup_tree_set::DupTreeSet;
-
-mod known_size_iter {
- pub struct KnownSizeIterator<I> {
- pub iter: I,
- pub size: usize,
- }
-
- impl<I: Iterator> Iterator for KnownSizeIterator<I> {
- type Item = I::Item;
-
- fn next(&mut self) -> Option<Self::Item> {
- let next = self.iter.next();
- if next.is_some() {
- self.size -= 1;
- }
- next
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.size, Some(self.size))
- }
- }
-
- // unsafe impl<I: Iterator> iter::TrustedLen for KnownSizeIterator<I> {}
-}
-
-mod tuple {
- mod sealed {
- pub trait Sealed {}
- }
- pub trait Tuple: sealed::Sealed {
- type First;
- type Second;
- }
- impl<A, B> sealed::Sealed for (A, B) {}
- impl<A, B> Tuple for (A, B) {
- type First = A;
- type Second = B;
- }
-}
-
-mod dup_tree_map {
- use super::known_size_iter::KnownSizeIterator;
- use super::tuple::Tuple;
- use smallvec::SmallVec;
- use std::collections::BTreeMap;
- use std::iter;
-
- type OneOrMore<V> = SmallVec<[V; 1]>;
- type DupTreeMapInternal<K, V> = BTreeMap<K, OneOrMore<V>>;
-
- #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
- pub struct DupTreeMap<K, V> {
- map: DupTreeMapInternal<K, V>,
- size: usize,
- }
-
- // Generic types and functions to construct the iterators for this struct.
- type ZipRepeatIter<T> = iter::Zip<
- iter::Repeat<<T as Tuple>::First>,
- <<T as Tuple>::Second as IntoIterator>::IntoIter,
- >;
- type DupTreeMapIter<M> = KnownSizeIterator<
- iter::FlatMap<
- <M as IntoIterator>::IntoIter,
- ZipRepeatIter<<M as IntoIterator>::Item>,
- fn(
- <M as IntoIterator>::Item,
- ) -> ZipRepeatIter<<M as IntoIterator>::Item>,
- >,
- >;
-
- fn zip_repeat<K, I>((k, iter): (K, I)) -> ZipRepeatIter<(K, I)>
- where
- K: Clone,
- I: IntoIterator,
- {
- iter::repeat(k).zip(iter.into_iter())
- }
-
- fn make_map_iter<M, K, I>(map: M, size: usize) -> DupTreeMapIter<M>
- where
- M: IntoIterator<Item = (K, I)>,
- K: Clone,
- I: IntoIterator,
- {
- KnownSizeIterator {
- iter: map.into_iter().flat_map(zip_repeat),
- size,
- }
- }
-
- pub type IterMut<'a, K, V> =
- DupTreeMapIter<&'a mut DupTreeMapInternal<K, V>>;
- pub type Iter<'a, K, V> = DupTreeMapIter<&'a DupTreeMapInternal<K, V>>;
- pub type IntoIter<K, V> = DupTreeMapIter<DupTreeMapInternal<K, V>>;
-
- impl<K: Ord, V> DupTreeMap<K, V> {
- pub fn new() -> Self {
- DupTreeMap {
- map: BTreeMap::new(),
- size: 0,
- }
- }
-
- pub fn insert(&mut self, key: K, value: V) {
- self.map.entry(key).or_default().push(value);
- self.size += 1;
- }
-
- pub fn len(&self) -> usize {
- self.size
- }
- pub fn is_empty(&self) -> bool {
- self.size == 0
- }
-
- pub fn iter(&self) -> Iter<'_, K, V> {
- make_map_iter(&self.map, self.size)
- }
-
- pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
- make_map_iter(&mut self.map, self.size)
- }
- }
-
- impl<K, V> Default for DupTreeMap<K, V>
- where
- K: Ord,
- {
- fn default() -> Self {
- Self::new()
- }
- }
-
- impl<K, V> IntoIterator for DupTreeMap<K, V>
- where
- K: Ord + Clone,
- {
- type Item = (K, V);
- type IntoIter = IntoIter<K, V>;
-
- fn into_iter(self) -> Self::IntoIter {
- make_map_iter(self.map, self.size)
- }
- }
-
- impl<'a, K, V> IntoIterator for &'a DupTreeMap<K, V>
- where
- K: Ord + 'a,
- V: 'a,
- {
- type Item = (&'a K, &'a V);
- type IntoIter = Iter<'a, K, V>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.iter()
- }
- }
-
- impl<'a, K, V> IntoIterator for &'a mut DupTreeMap<K, V>
- where
- K: Ord + 'a,
- V: 'a,
- {
- type Item = (&'a K, &'a mut V);
- type IntoIter = IterMut<'a, K, V>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.iter_mut()
- }
- }
-
- impl<K, V> iter::FromIterator<(K, V)> for DupTreeMap<K, V>
- where
- K: Ord,
- {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = (K, V)>,
- {
- let mut map = DupTreeMap::new();
- for (k, v) in iter {
- map.insert(k, v);
- }
- map
- }
- }
-}
-
-mod dup_tree_set {
- use super::tuple::Tuple;
- use super::DupTreeMap;
- use std::iter;
-
- #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
- pub struct DupTreeSet<K> {
- map: DupTreeMap<K, ()>,
- }
-
- type DupTreeSetIter<M> = iter::Map<
- <M as IntoIterator>::IntoIter,
- fn(
- <M as IntoIterator>::Item,
- ) -> <<M as IntoIterator>::Item as Tuple>::First,
- >;
-
- pub type Iter<'a, K> = DupTreeSetIter<&'a DupTreeMap<K, ()>>;
- pub type IntoIter<K> = DupTreeSetIter<DupTreeMap<K, ()>>;
-
- fn drop_second<A, B>((a, _): (A, B)) -> A {
- a
- }
-
- impl<K: Ord> DupTreeSet<K> {
- pub fn new() -> Self {
- DupTreeSet {
- map: DupTreeMap::new(),
- }
- }
-
- pub fn len(&self) -> usize {
- self.map.len()
- }
- pub fn is_empty(&self) -> bool {
- self.map.is_empty()
- }
-
- pub fn iter(&self) -> Iter<'_, K> {
- self.map.iter().map(drop_second)
- }
- }
-
- impl<K> Default for DupTreeSet<K>
- where
- K: Ord,
- {
- fn default() -> Self {
- Self::new()
- }
- }
-
- impl<K> IntoIterator for DupTreeSet<K>
- where
- K: Ord + Clone,
- {
- type Item = K;
- type IntoIter = IntoIter<K>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.map.into_iter().map(drop_second)
- }
- }
-
- impl<'a, K> IntoIterator for &'a DupTreeSet<K>
- where
- K: Ord + 'a,
- {
- type Item = &'a K;
- type IntoIter = Iter<'a, K>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.iter()
- }
- }
-
- impl<K> iter::FromIterator<K> for DupTreeSet<K>
- where
- K: Ord,
- {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = K>,
- {
- let map = iter.into_iter().map(|k| (k, ())).collect();
- DupTreeSet { map }
- }
- }
-}
diff --git a/dhall/src/syntax/ast/mod.rs b/dhall/src/syntax/ast/mod.rs
index 1950154..c341af7 100644
--- a/dhall/src/syntax/ast/mod.rs
+++ b/dhall/src/syntax/ast/mod.rs
@@ -8,5 +8,4 @@ mod span;
pub use span::*;
mod text;
pub use text::*;
-pub mod map;
pub mod visitor;
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..195bd0a 100644
--- a/dhall/src/syntax/binary/decode.rs
+++ b/dhall/src/syntax/binary/decode.rs
@@ -3,6 +3,7 @@ use serde_cbor::value::value as cbor;
use std::iter::FromIterator;
use crate::error::DecodeError;
+use crate::operations::OpKind;
use crate::syntax;
use crate::syntax::{
Expr, ExprKind, FilePath, FilePrefix, Hash, ImportMode, ImportTarget,
@@ -24,9 +25,12 @@ fn rc(x: UnspannedExpr) -> Expr {
}
fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
+ use crate::builtins::Builtin;
+ use crate::operations::BinOp;
use cbor::Value::*;
- use syntax::{BinOp, Builtin, Const};
+ use syntax::Const;
use ExprKind::*;
+ use OpKind::*;
Ok(rc(match data {
String(s) => match Builtin::parse(s) {
Some(b) => ExprKind::Builtin(b),
@@ -66,7 +70,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 +109,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 +135,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 +158,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 +190,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 +214,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 +229,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 +423,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..b6bbabe 100644
--- a/dhall/src/syntax/binary/encode.rs
+++ b/dhall/src/syntax/binary/encode.rs
@@ -2,9 +2,10 @@ use serde_cbor::value::value as cbor;
use std::collections::BTreeMap;
use std::vec;
+use crate::builtins::Builtin;
use crate::error::EncodeError;
+use crate::operations::{BinOp, OpKind};
use crate::syntax;
-use crate::syntax::map::DupTreeMap;
use crate::syntax::{
Expr, ExprKind, FilePrefix, Hash, Import, ImportMode, ImportTarget, Label,
Scheme, V,
@@ -19,8 +20,7 @@ enum Serialize<'a> {
Expr(&'a Expr),
CBOR(cbor::Value),
RecordMap(&'a BTreeMap<Label, Expr>),
- RecordDupMap(&'a DupTreeMap<Label, Expr>),
- UnionMap(&'a DupTreeMap<Label, Option<Expr>>),
+ UnionMap(&'a BTreeMap<Label, Option<Expr>>),
}
macro_rules! count {
@@ -46,11 +46,11 @@ where
{
use cbor::Value::{String, I64, U64};
use std::iter::once;
- use syntax::Builtin;
use syntax::ExprKind::*;
use syntax::NumKind::*;
+ use OpKind::*;
- use self::Serialize::{RecordDupMap, RecordMap, UnionMap};
+ use self::Serialize::{RecordMap, UnionMap};
fn expr(x: &Expr) -> self::Serialize<'_> {
self::Serialize::Expr(x)
}
@@ -70,7 +70,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 +101,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,8 +113,8 @@ 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() {
- ExprKind::Builtin(Builtin::List) => {
+ Op(App(f, a)) => match f.as_ref() {
+ ExprKind::Builtin(self::Builtin::List) => {
ser_seq!(ser; tag(4), expr(a))
}
_ => ser_seq!(ser; tag(28), expr(x)),
@@ -129,12 +131,12 @@ where
Text(x) => cbor(String(x)),
})))
}
- RecordType(map) => ser_seq!(ser; tag(7), RecordDupMap(map)),
+ RecordType(map) => ser_seq!(ser; tag(7), RecordMap(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) => {
- use syntax::BinOp::*;
+ Op(Field(x, l)) => ser_seq!(ser; tag(9), expr(x), label(l)),
+ Op(BinOp(op, x, y)) => {
+ use self::BinOp::*;
let op = match op {
BoolOr => 0,
BoolAnd => 1,
@@ -152,21 +154,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),
}
}
@@ -260,11 +264,6 @@ impl<'a> serde::ser::Serialize for Serialize<'a> {
match self {
Serialize::Expr(e) => serialize_subexpr(ser, e),
Serialize::CBOR(v) => v.serialize(ser),
- Serialize::RecordDupMap(map) => {
- ser.collect_map(map.iter().map(|(k, v)| {
- (cbor::Value::String(k.into()), Serialize::Expr(v))
- }))
- }
Serialize::RecordMap(map) => {
ser.collect_map(map.iter().map(|(k, v)| {
(cbor::Value::String(k.into()), Serialize::Expr(v))
@@ -286,7 +285,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..dcaf5e4 100644
--- a/dhall/src/syntax/text/parser.rs
+++ b/dhall/src/syntax/text/parser.rs
@@ -1,13 +1,13 @@
use itertools::Itertools;
use pest::prec_climber as pcl;
use pest::prec_climber::PrecClimber;
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
use std::iter::once;
use std::rc::Rc;
use pest_consume::{match_nodes, Parser};
-use crate::syntax::map::{DupTreeMap, DupTreeSet};
+use crate::operations::OpKind::*;
use crate::syntax::ExprKind::*;
use crate::syntax::NumKind::*;
use crate::syntax::{
@@ -31,50 +31,10 @@ pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Debug)]
enum Selector {
Field(Label),
- Projection(DupTreeSet<Label>),
+ Projection(BTreeSet<Label>),
ProjectionByExpr(Expr),
}
-impl crate::syntax::Builtin {
- pub fn parse(s: &str) -> Option<Self> {
- use crate::syntax::Builtin::*;
- match s {
- "Bool" => Some(Bool),
- "Natural" => Some(Natural),
- "Integer" => Some(Integer),
- "Double" => Some(Double),
- "Text" => Some(Text),
- "List" => Some(List),
- "Optional" => Some(Optional),
- "None" => Some(OptionalNone),
- "Natural/build" => Some(NaturalBuild),
- "Natural/fold" => Some(NaturalFold),
- "Natural/isZero" => Some(NaturalIsZero),
- "Natural/even" => Some(NaturalEven),
- "Natural/odd" => Some(NaturalOdd),
- "Natural/toInteger" => Some(NaturalToInteger),
- "Natural/show" => Some(NaturalShow),
- "Natural/subtract" => Some(NaturalSubtract),
- "Integer/toDouble" => Some(IntegerToDouble),
- "Integer/show" => Some(IntegerShow),
- "Integer/negate" => Some(IntegerNegate),
- "Integer/clamp" => Some(IntegerClamp),
- "Double/show" => Some(DoubleShow),
- "List/build" => Some(ListBuild),
- "List/fold" => Some(ListFold),
- "List/length" => Some(ListLength),
- "List/head" => Some(ListHead),
- "List/last" => Some(ListLast),
- "List/indexed" => Some(ListIndexed),
- "List/reverse" => Some(ListReverse),
- "Optional/fold" => Some(OptionalFold),
- "Optional/build" => Some(OptionalBuild),
- "Text/show" => Some(TextShow),
- _ => None,
- }
- }
-}
-
fn input_to_span(input: ParseInput) -> Span {
Span::make(input.user_data().clone(), input.as_pair().as_span())
}
@@ -128,7 +88,7 @@ fn trim_indent(lines: &mut Vec<ParsedText>) {
/// Insert the expr into the map; in case of collision, create a RecursiveRecordMerge node.
fn insert_recordlit_entry(map: &mut BTreeMap<Label, Expr>, l: Label, e: Expr) {
- use crate::syntax::BinOp::RecursiveRecordMerge;
+ use crate::operations::BinOp::RecursiveRecordMerge;
use std::collections::btree_map::Entry;
match map.entry(l) {
Entry::Vacant(entry) => {
@@ -138,7 +98,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,
));
}
@@ -146,18 +106,21 @@ fn insert_recordlit_entry(map: &mut BTreeMap<Label, Expr>, l: Label, e: Expr) {
}
fn desugar_with_expr(x: Expr, labels: &[Label], y: Expr) -> Expr {
- use crate::syntax::BinOp::RightBiasedRecordMerge;
+ use crate::operations::BinOp::RightBiasedRecordMerge;
let expr = |k| Expr::new(k, Span::WithSugar);
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())),
- ))
+ )))
}
}
}
@@ -387,7 +350,7 @@ impl DhallParser {
#[alias(expression)]
fn builtin(input: ParseInput) -> ParseResult<Expr> {
let s = input.as_str();
- let e = match crate::syntax::Builtin::parse(s) {
+ let e = match crate::builtins::Builtin::parse(s) {
Some(b) => Builtin(b),
None => match s {
"True" => Num(Bool(true)),
@@ -725,7 +688,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 +710,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))
@@ -780,7 +743,7 @@ impl DhallParser {
op: ParseInput,
r: Expr,
) -> ParseResult<Expr> {
- use crate::syntax::BinOp::*;
+ use crate::operations::BinOp::*;
use Rule::*;
let op = match op.as_rule() {
import_alt => ImportAlt,
@@ -801,7 +764,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 +803,7 @@ impl DhallParser {
spanned_union(
acc.span(),
e.span(),
- App(acc, e)
+ Op(App(acc, e))
)
}
)
@@ -855,10 +818,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 +838,7 @@ impl DhallParser {
spanned_union(
acc.span(),
e.span(),
- Completion(acc, e),
+ Op(Completion(acc, e)),
)
}
)
@@ -895,9 +858,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))
}
)
}
@@ -915,9 +878,20 @@ impl DhallParser {
Ok((stor, input_to_span(input)))
}
- fn labels(input: ParseInput) -> ParseResult<DupTreeSet<Label>> {
- Ok(match_nodes!(input.into_children();
- [label(ls)..] => ls.collect(),
+ fn labels(input: ParseInput) -> ParseResult<BTreeSet<Label>> {
+ Ok(match_nodes!(input.children();
+ [label(ls)..] => {
+ let mut set = BTreeSet::default();
+ for l in ls {
+ if set.contains(&l) {
+ return Err(
+ input.error(format!("Duplicate field in projection"))
+ )
+ }
+ set.insert(l);
+ }
+ set
+ },
))
}
@@ -957,9 +931,26 @@ impl DhallParser {
fn non_empty_record_type(
input: ParseInput,
- ) -> ParseResult<DupTreeMap<Label, Expr>> {
- Ok(match_nodes!(input.into_children();
- [record_type_entry(entries)..] => entries.collect()
+ ) -> ParseResult<BTreeMap<Label, Expr>> {
+ Ok(match_nodes!(input.children();
+ [record_type_entry(entries)..] => {
+ let mut map = BTreeMap::default();
+ for (l, t) in entries {
+ use std::collections::btree_map::Entry;
+ match map.entry(l) {
+ Entry::Occupied(_) => {
+ return Err(input.error(
+ "Duplicate field in record type"
+ .to_string(),
+ ));
+ }
+ Entry::Vacant(e) => {
+ e.insert(t);
+ }
+ }
+ }
+ map
+ },
))
}
@@ -1008,7 +999,24 @@ impl DhallParser {
fn union_type(input: ParseInput) -> ParseResult<UnspannedExpr> {
let map = match_nodes!(input.children();
[empty_union_type(_)] => Default::default(),
- [union_type_entry(entries)..] => entries.collect(),
+ [union_type_entry(entries)..] => {
+ let mut map = BTreeMap::default();
+ for (l, t) in entries {
+ use std::collections::btree_map::Entry;
+ match map.entry(l) {
+ Entry::Occupied(_) => {
+ return Err(input.error(
+ "Duplicate variant in union type"
+ .to_string(),
+ ));
+ }
+ Entry::Vacant(e) => {
+ e.insert(t);
+ }
+ }
+ }
+ map
+ },
);
Ok(UnionType(map))
}
diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs
index 378f408..9e90660 100644
--- a/dhall/src/syntax/text/printer.rs
+++ b/dhall/src/syntax/text/printer.rs
@@ -1,3 +1,5 @@
+use crate::builtins::Builtin;
+use crate::operations::{BinOp, OpKind};
use crate::syntax::*;
use itertools::Itertools;
use std::fmt::{self, Display};
@@ -5,15 +7,16 @@ 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
- BinOp(ast::BinOp),
+ // All the `<operator>-expression`s
+ BinOp(self::BinOp),
// `application-expression`
App,
// `import-expression`
@@ -36,7 +39,8 @@ impl<'a> PhasedExpr<'a> {
impl UnspannedExpr {
// Annotate subexpressions with the appropriate phase, defaulting to Base
fn annotate_with_phases(&self) -> ExprKind<PhasedExpr<'_>> {
- use crate::syntax::ExprKind::*;
+ use ExprKind::*;
+ use OpKind::*;
use PrintPhase::*;
let with_base = self.map_ref(|e| PhasedExpr(e, Base));
match with_base {
@@ -47,31 +51,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)))
@@ -85,22 +91,24 @@ impl UnspannedExpr {
f: &mut fmt::Formatter,
phase: PrintPhase,
) -> Result<(), fmt::Error> {
- use crate::syntax::ExprKind::*;
+ use ExprKind::*;
+ use 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 +151,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 +168,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 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 +237,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 +250,6 @@ impl<SE: Display + Clone> Display for ExprKind<SE> {
Completion(a, b) => {
write!(f, "{}::{}", a, b)?;
}
- Import(a) => a.fmt(f)?,
}
Ok(())
}
@@ -315,7 +336,7 @@ impl Display for Const {
impl Display for BinOp {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- use crate::syntax::BinOp::*;
+ use BinOp::*;
f.write_str(match self {
BoolOr => "||",
TextAppend => "++",
@@ -363,7 +384,7 @@ impl Display for Label {
let is_reserved = match s.as_str() {
"let" | "in" | "if" | "then" | "else" | "Type" | "Kind"
| "Sort" | "True" | "False" | "Some" => true,
- _ => crate::syntax::Builtin::parse(&s).is_some(),
+ _ => Builtin::parse(&s).is_some(),
};
if !is_reserved && s.chars().all(|c| c.is_ascii_alphanumeric()) {
write!(f, "{}", s)
@@ -461,45 +482,6 @@ impl<SubExpr: Display> Display for Import<SubExpr> {
}
}
-impl Display for Builtin {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- use crate::syntax::Builtin::*;
- f.write_str(match *self {
- Bool => "Bool",
- Natural => "Natural",
- Integer => "Integer",
- Double => "Double",
- Text => "Text",
- List => "List",
- Optional => "Optional",
- OptionalNone => "None",
- NaturalBuild => "Natural/build",
- NaturalFold => "Natural/fold",
- NaturalIsZero => "Natural/isZero",
- NaturalEven => "Natural/even",
- NaturalOdd => "Natural/odd",
- NaturalToInteger => "Natural/toInteger",
- NaturalShow => "Natural/show",
- NaturalSubtract => "Natural/subtract",
- IntegerToDouble => "Integer/toDouble",
- IntegerNegate => "Integer/negate",
- IntegerClamp => "Integer/clamp",
- IntegerShow => "Integer/show",
- DoubleShow => "Double/show",
- ListBuild => "List/build",
- ListFold => "List/fold",
- ListLength => "List/length",
- ListHead => "List/head",
- ListLast => "List/last",
- ListIndexed => "List/indexed",
- ListReverse => "List/reverse",
- OptionalFold => "Optional/fold",
- OptionalBuild => "Optional/build",
- TextShow => "Text/show",
- })
- }
-}
-
impl Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
use crate::syntax::Scheme::*;