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),          }  | 
