diff options
author | Nadrieril | 2020-04-06 17:19:31 +0100 |
---|---|---|
committer | Nadrieril | 2020-04-06 17:19:31 +0100 |
commit | 08e1d8ece4314b56d64fa08595c2e043b97896d1 (patch) | |
tree | 22d9fcf951d7e6e86d33e8e1e89465b0e61381c3 /dhall/src/syntax | |
parent | d35cb130d80d628807a4247ddf84a8d0230c87ab (diff) |
Split off operations from main expr enum
Diffstat (limited to '')
-rw-r--r-- | dhall/src/syntax/ast/expr.rs | 121 | ||||
-rw-r--r-- | dhall/src/syntax/ast/visitor.rs | 100 | ||||
-rw-r--r-- | dhall/src/syntax/binary/decode.rs | 34 | ||||
-rw-r--r-- | dhall/src/syntax/binary/encode.rs | 33 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 36 | ||||
-rw-r--r-- | dhall/src/syntax/text/printer.rs | 141 |
6 files changed, 253 insertions, 212 deletions
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(()) } |