diff options
author | Nadrieril Feneanar | 2020-02-20 20:22:39 +0000 |
---|---|---|
committer | GitHub | 2020-02-20 20:22:39 +0000 |
commit | 92b5604c1049a771239a70ab14c393e8e1807c68 (patch) | |
tree | 73ffbfd6417da6b8c650ba17c40c376dc7b23c4a /dhall/src/syntax/text | |
parent | ffbde252a850c7d96e1000e1be52792c41733a28 (diff) | |
parent | e5f0602e431bc602f9e1f0045f48056ce6465481 (diff) |
Merge pull request #132 from Nadrieril/catchup-spec
Catchup spec
Diffstat (limited to 'dhall/src/syntax/text')
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index f3ebd2b..ba64a75 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use pest::prec_climber as pcl; use pest::prec_climber::PrecClimber; +use std::collections::BTreeMap; use std::rc::Rc; use pest_consume::{match_nodes, Parser}; @@ -124,6 +125,25 @@ 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 std::collections::btree_map::Entry; + match map.entry(l) { + Entry::Vacant(entry) => { + entry.insert(e); + } + Entry::Occupied(mut entry) => { + let dummy = Expr::new(Lit(Bool(false)), Span::Artificial); + let other = entry.insert(dummy); + entry.insert(Expr::new( + BinOp(RecursiveRecordMerge, other, e), + Span::DuplicateRecordFieldsSugar, + )); + } + } +} + lazy_static::lazy_static! { static ref PRECCLIMBER: PrecClimber<Rule> = { use Rule::*; @@ -860,26 +880,16 @@ impl DhallParser { input: ParseInput, ) -> ParseResult<UnspannedExpr> { Ok(match_nodes!(input.children(); - [label(first_label), non_empty_record_type(rest)] => { - let (first_expr, mut map) = rest; - map.insert(first_label, first_expr); - RecordType(map) - }, - [label(first_label), non_empty_record_literal(rest)] => { - let (first_expr, mut map) = rest; - map.insert(first_label, first_expr); - RecordLit(map) - }, + [non_empty_record_type(map)] => RecordType(map), + [non_empty_record_literal(map)] => RecordLit(map), )) } fn non_empty_record_type( input: ParseInput, - ) -> ParseResult<(Expr, DupTreeMap<Label, Expr>)> { + ) -> ParseResult<DupTreeMap<Label, Expr>> { Ok(match_nodes!(input.into_children(); - [expression(expr), record_type_entry(entries)..] => { - (expr, entries.collect()) - } + [record_type_entry(entries)..] => entries.collect() )) } @@ -891,17 +901,32 @@ impl DhallParser { fn non_empty_record_literal( input: ParseInput, - ) -> ParseResult<(Expr, DupTreeMap<Label, Expr>)> { + ) -> ParseResult<BTreeMap<Label, Expr>> { Ok(match_nodes!(input.into_children(); - [expression(expr), record_literal_entry(entries)..] => { - (expr, entries.collect()) + [record_literal_entry(entries)..] => { + let mut map = BTreeMap::new(); + for (l, e) in entries { + insert_recordlit_entry(&mut map, l, e); + } + map } )) } fn record_literal_entry(input: ParseInput) -> ParseResult<(Label, Expr)> { Ok(match_nodes!(input.into_children(); - [label(name), expression(expr)] => (name, expr) + [label(name), expression(expr)] => (name, expr), + [label(first_name), label(names).., expression(expr)] => { + // Desugar dotted field syntax into nested records + let expr = names.rev().fold(expr, |e, l| { + let map = Some((l, e)).into_iter().collect(); + Expr::new( + RecordLit(map), + Span::DottedFieldSugar, + ) + }); + (first_name, expr) + }, )) } |