diff options
author | Nadrieril | 2019-03-23 23:24:11 +0100 |
---|---|---|
committer | Nadrieril | 2019-03-23 23:24:11 +0100 |
commit | 062fc44a93a18ee432e51db852290ab5849f4dd9 (patch) | |
tree | c9dd53daf9cd99f5dcf982e1d98099a078f63110 | |
parent | f610bc0aac5eaa365c95b489fb2d06cab449ec77 (diff) |
Handle merge and record projection
Diffstat (limited to '')
-rw-r--r-- | dhall/src/normalize.rs | 41 | ||||
-rw-r--r-- | dhall/tests/normalization.rs | 12 | ||||
-rw-r--r-- | dhall_core/src/core.rs | 15 | ||||
-rw-r--r-- | dhall_core/src/parser.rs | 21 | ||||
-rw-r--r-- | dhall_core/src/printer.rs | 5 |
5 files changed, 74 insertions, 20 deletions
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs index 4652b25..2ffa5a5 100644 --- a/dhall/src/normalize.rs +++ b/dhall/src/normalize.rs @@ -276,14 +276,45 @@ where (o, _, _) => BinOp(*o, x, y), }) } - Field(e, x) => { + Merge(x, y, t) => { + let x = normalize_whnf(x); + let y = normalize_whnf(y); + match (x.as_ref(), y.as_ref()) { + (RecordLit(handlers), UnionLit(k, v, _)) => { + match handlers.get(&k) { + Some(h) => { + normalize_whnf(&rc(App(h.clone(), vec![v.clone()]))) + } + None => rc(Merge(x, y, t.clone())), + } + } + _ => rc(Merge(x, y, t.clone())), + } + } + Field(e, l) => { let e = normalize_whnf(e); - match (e.as_ref(), x) { - (RecordLit(kvs), x) => match kvs.get(&x) { + match e.as_ref() { + RecordLit(kvs) => match kvs.get(&l) { Some(r) => normalize_whnf(r), - None => rc(Field(e, x.clone())), + None => rc(Field(e, l.clone())), }, - (_, x) => rc(Field(e, x.clone())), + _ => rc(Field(e, l.clone())), + } + } + Projection(_, ls) if ls.is_empty() => { + rc(RecordLit(std::collections::BTreeMap::new())) + } + Projection(e, ls) => { + let e = normalize_whnf(e); + match e.as_ref() { + RecordLit(kvs) => rc(RecordLit( + ls.iter() + .filter_map(|l| { + kvs.get(l).map(|x| (l.clone(), x.clone())) + }) + .collect(), + )), + _ => rc(Projection(e, ls.clone())), } } _ => Rc::clone(e), diff --git a/dhall/tests/normalization.rs b/dhall/tests/normalization.rs index 9ecad74..5df46a6 100644 --- a/dhall/tests/normalization.rs +++ b/dhall/tests/normalization.rs @@ -13,7 +13,7 @@ norm!(spec_normalization_success_haskell_tutorial_access_0, "haskell-tutorial/ac // norm!(spec_normalization_success_haskell_tutorial_combineTypes_0, "haskell-tutorial/combineTypes/0"); // norm!(spec_normalization_success_haskell_tutorial_combineTypes_1, "haskell-tutorial/combineTypes/1"); // norm!(spec_normalization_success_haskell_tutorial_prefer_0, "haskell-tutorial/prefer/0"); -// norm!(spec_normalization_success_haskell_tutorial_projection_0, "haskell-tutorial/projection/0"); +norm!(spec_normalization_success_haskell_tutorial_projection_0, "haskell-tutorial/projection/0"); // norm!(spec_normalization_success_multiline_escape, "multiline/escape"); // norm!(spec_normalization_success_multiline_hangingIndent, "multiline/hangingIndent"); // norm!(spec_normalization_success_multiline_interesting, "multiline/interesting"); @@ -228,9 +228,9 @@ norm!(spec_normalization_success_unit_ListNormalizeTypeAnnotation, "unit/ListNor norm!(spec_normalization_success_unit_ListReverse, "unit/ListReverse"); norm!(spec_normalization_success_unit_ListReverseEmpty, "unit/ListReverseEmpty"); norm!(spec_normalization_success_unit_ListReverseTwo, "unit/ListReverseTwo"); -// norm!(spec_normalization_success_unit_Merge, "unit/Merge"); +norm!(spec_normalization_success_unit_Merge, "unit/Merge"); norm!(spec_normalization_success_unit_MergeNormalizeArguments, "unit/MergeNormalizeArguments"); -// norm!(spec_normalization_success_unit_MergeWithType, "unit/MergeWithType"); +norm!(spec_normalization_success_unit_MergeWithType, "unit/MergeWithType"); norm!(spec_normalization_success_unit_MergeWithTypeNormalizeArguments, "unit/MergeWithTypeNormalizeArguments"); norm!(spec_normalization_success_unit_Natural, "unit/Natural"); norm!(spec_normalization_success_unit_NaturalBuild, "unit/NaturalBuild"); @@ -302,9 +302,9 @@ norm!(spec_normalization_success_unit_OptionalFoldNone, "unit/OptionalFoldNone") norm!(spec_normalization_success_unit_OptionalFoldSome, "unit/OptionalFoldSome"); norm!(spec_normalization_success_unit_Record, "unit/Record"); norm!(spec_normalization_success_unit_RecordEmpty, "unit/RecordEmpty"); -// norm!(spec_normalization_success_unit_RecordProjection, "unit/RecordProjection"); -// norm!(spec_normalization_success_unit_RecordProjectionEmpty, "unit/RecordProjectionEmpty"); -// norm!(spec_normalization_success_unit_RecordProjectionNormalizeArguments, "unit/RecordProjectionNormalizeArguments"); +norm!(spec_normalization_success_unit_RecordProjection, "unit/RecordProjection"); +norm!(spec_normalization_success_unit_RecordProjectionEmpty, "unit/RecordProjectionEmpty"); +norm!(spec_normalization_success_unit_RecordProjectionNormalizeArguments, "unit/RecordProjectionNormalizeArguments"); norm!(spec_normalization_success_unit_RecordSelection, "unit/RecordSelection"); norm!(spec_normalization_success_unit_RecordSelectionNormalizeArguments, "unit/RecordSelectionNormalizeArguments"); norm!(spec_normalization_success_unit_RecordType, "unit/RecordType"); diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index bc5a666..502a9bc 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -241,8 +241,10 @@ pub enum Expr<Note, Embed> { SubExpr<Note, Embed>, Option<SubExpr<Note, Embed>>, ), - /// `Field e x ~ e.x` + /// e.x Field(SubExpr<Note, Embed>, Label), + /// e.{ x, y, z } + Projection(SubExpr<Note, Embed>, Vec<Label>), /// Annotation on the AST. Unused for now but could hold e.g. file location information Note(Note, SubExpr<Note, Embed>), /// Embeds an import or the result of resolving the import @@ -353,9 +355,9 @@ where }; match e { Const(k) => Const(*k), - Var(V(x, n)) => Var(V(map_label(x), *n)), - Lam(x, t, b) => Lam(map_label(x), map(t), map_under_binder(x, b)), - Pi(x, t, b) => Pi(map_label(x), map(t), map_under_binder(x, b)), + Var(V(l, n)) => Var(V(map_label(l), *n)), + Lam(l, t, b) => Lam(map_label(l), map(t), map_under_binder(l, b)), + Pi(l, t, b) => Pi(map_label(l), map(t), map_under_binder(l, b)), App(f, args) => App(map(f), vec(args)), Let(l, t, a, b) => { Let(map_label(l), opt(t), map(a), map_under_binder(l, b)) @@ -378,7 +380,10 @@ where UnionType(kts) => UnionType(btmap(kts)), UnionLit(k, v, kvs) => UnionLit(map_label(k), map(v), btmap(kvs)), Merge(x, y, t) => Merge(map(x), map(y), opt(t)), - Field(r, x) => Field(map(r), map_label(x)), + Field(e, l) => Field(map(e), map_label(l)), + Projection(e, ls) => { + Projection(map(e), ls.iter().map(&map_label).collect()) + } Note(n, e) => Note(map_note(n), map(e)), Embed(a) => Embed(map_embed(a)), } diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index f959d2e..a62f861 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -19,6 +19,12 @@ pub type ParseError = pest::error::Error<Rule>; pub type ParseResult<T> = Result<T, ParseError>; +#[derive(Debug)] +enum Either<A, B> { + Left(A), + Right(B), +} + impl Builtin { pub fn parse(s: &str) -> Option<Self> { use self::Builtin::*; @@ -649,13 +655,20 @@ make_parser! { rule!(selector_expression<ParsedExpr> as expression; children!( [expression(e)] => e, [expression(first), selector(rest..)] => { - rest.fold(first, |acc, e| bx(Expr::Field(acc, e))) + rest.fold(first, |acc, e| match e { + Either::Left(l) => bx(Expr::Field(acc, l)), + Either::Right(ls) => bx(Expr::Projection(acc, ls)), + }) } )); - // TODO: handle record projection - rule!(selector<Label>; children!( - [label(l)] => l + rule!(selector<Either<Label, Vec<Label>>>; children!( + [label(l)] => Either::Left(l), + [labels(ls)] => Either::Right(ls), + )); + + rule!(labels<Vec<Label>>; children!( + [label(ls..)] => ls.collect(), )); rule!(literal_expression<ParsedExpr> as expression; children!( diff --git a/dhall_core/src/printer.rs b/dhall_core/src/printer.rs index 5ecf5ce..d93336e 100644 --- a/dhall_core/src/printer.rs +++ b/dhall_core/src/printer.rs @@ -165,6 +165,11 @@ impl<S, A: Display> Expr<S, A> { a.fmt_e(f)?; write!(f, ".{}", b) } + &Projection(ref e, ref ls) => { + e.fmt_e(f)?; + write!(f, ".")?; + fmt_list("{ ", ", ", " }", ls, f, |l, f| write!(f, "{}", l)) + } &Note(_, ref b) => b.fmt_e(f), a => a.fmt_f(f), } |