diff options
Diffstat (limited to 'dhall/src/syntax/text')
-rw-r--r-- | dhall/src/syntax/text/dhall.pest.visibility | 3 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 41 |
2 files changed, 43 insertions, 1 deletions
diff --git a/dhall/src/syntax/text/dhall.pest.visibility b/dhall/src/syntax/text/dhall.pest.visibility index 03a000b..0ff1bfe 100644 --- a/dhall/src/syntax/text/dhall.pest.visibility +++ b/dhall/src/syntax/text/dhall.pest.visibility @@ -95,6 +95,7 @@ equivalent prefer lambda forall +# with arrow # complete # exponent @@ -164,6 +165,8 @@ times_expression equal_expression not_equal_expression equivalent_expression +with_expression +with_clause application_expression first_application_expression # import_expression diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index 7140332..f59cf06 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -2,6 +2,7 @@ use itertools::Itertools; use pest::prec_climber as pcl; use pest::prec_climber::PrecClimber; use std::collections::BTreeMap; +use std::iter::once; use std::rc::Rc; use pest_consume::{match_nodes, Parser}; @@ -144,6 +145,23 @@ 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; + 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( + RightBiasedRecordMerge, + x, + expr(RecordLit(once((l.clone(), res)).collect())), + )) + } + } +} + lazy_static::lazy_static! { static ref PRECCLIMBER: PrecClimber<Rule> = { use Rule::*; @@ -760,6 +778,27 @@ impl DhallParser { } #[alias(expression, shortcut = true)] + fn with_expression(input: ParseInput) -> ParseResult<Expr> { + Ok(match_nodes!(input.children(); + [expression(e)] => e, + [expression(first), with_clause(clauses)..] => { + clauses.fold( + first, + |acc, (labels, e)| { + desugar_with_expr(acc, &labels, e) + } + ) + }, + )) + } + + fn with_clause(input: ParseInput) -> ParseResult<(Vec<Label>, Expr)> { + Ok(match_nodes!(input.children(); + [label(labels).., expression(e)] => (labels.collect(), e), + )) + } + + #[alias(expression, shortcut = true)] fn application_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [expression(e)] => e, @@ -919,7 +958,7 @@ impl DhallParser { [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(); + let map = once((l, e)).collect(); Expr::new( RecordLit(map), Span::DottedFieldSugar, |