diff options
author | Nadrieril | 2020-03-10 16:34:59 +0000 |
---|---|---|
committer | Nadrieril | 2020-03-10 16:35:53 +0000 |
commit | 0169e9347ec7ffcf86066e1e5753ce5f77e71bc7 (patch) | |
tree | 7d179c9300d7c46a1251bb0e819157107528e316 | |
parent | 3f9194f47185fe30c9e410aa7c5e651df9694b3f (diff) |
Add support for `with` keyword
-rw-r--r-- | README.md | 1 | ||||
m--------- | dhall-lang | 0 | ||||
-rw-r--r-- | dhall/build.rs | 15 | ||||
-rw-r--r-- | dhall/src/syntax/ast/span.rs | 1 | ||||
-rw-r--r-- | dhall/src/syntax/text/dhall.pest.visibility | 3 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 41 | ||||
-rw-r--r-- | dhall/tests/parser/failure/spacing/MergeNoSpace2.txt | 2 | ||||
-rw-r--r-- | dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt | 2 | ||||
-rw-r--r-- | dhall/tests/type-inference/failure/unit/WithInvalidOverrideA.txt | 1 | ||||
-rw-r--r-- | dhall/tests/type-inference/failure/unit/WithUnderscore.txt | 7 |
10 files changed, 69 insertions, 4 deletions
@@ -160,6 +160,7 @@ same name as the corresponding test. [???] +- Add support for `with` keyword - Implement remote imports with conservative sanity checking - Implement `missing` and `env:VAR` imports - Implement `as Text` and `as Location` imports diff --git a/dhall-lang b/dhall-lang -Subproject 1a20024421d4e0574e7d9c85a7b0e751b0534dc +Subproject 527f391fc8e48b3c8847b6982b76ac959808c0d diff --git a/dhall/build.rs b/dhall/build.rs index 4b6e52b..3d062da 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -376,6 +376,19 @@ fn convert_abnf_to_pest() -> std::io::Result<()> { rules.remove("url_path"); writeln!(&mut file, "url_path = _{{ path }}")?; + // TODO: upstream this tweak + rules.remove("with_expression"); + writeln!( + &mut file, + r#" + with_expression = {{ application_expression ~ (whsp1 ~ with ~ whsp1 ~ with_clause)* }} + with_clause = {{ + any_label_or_some ~ (whsp ~ "." ~ whsp ~ any_label_or_some)* + ~ whsp ~ "=" ~ whsp ~ application_expression + }} + "# + )?; + // Work around some greediness issue in the grammar. rules.remove("missing"); writeln!( @@ -439,7 +452,7 @@ fn convert_abnf_to_pest() -> std::io::Result<()> { bool_or | import_alt }} - operator_expression = {{ application_expression ~ (whsp ~ operator ~ whsp ~ application_expression)* }} + operator_expression = {{ with_expression ~ (whsp ~ operator ~ whsp ~ with_expression)* }} "##)?; writeln!( diff --git a/dhall/src/syntax/ast/span.rs b/dhall/src/syntax/ast/span.rs index 7c004c5..50985e1 100644 --- a/dhall/src/syntax/ast/span.rs +++ b/dhall/src/syntax/ast/span.rs @@ -21,6 +21,7 @@ pub(crate) enum Span { /// Desugarings DuplicateRecordFieldsSugar, DottedFieldSugar, + WithSugar, /// For expressions obtained from decoding binary Decoded, /// For expressions constructed during normalization/typecheck 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, diff --git a/dhall/tests/parser/failure/spacing/MergeNoSpace2.txt b/dhall/tests/parser/failure/spacing/MergeNoSpace2.txt index 96d937b..307d873 100644 --- a/dhall/tests/parser/failure/spacing/MergeNoSpace2.txt +++ b/dhall/tests/parser/failure/spacing/MergeNoSpace2.txt @@ -3,4 +3,4 @@ 1 | merge x(y)␊ | ^--- | - = expected missing, double_quote_literal, single_quote_literal, if_, merge, non_empty_list_literal, NaN, Some_, toMap, assert, forall, numeric_double_literal, minus_infinity_literal, plus_infinity_literal, natural_literal, integer_literal, or import_hashed + = expected missing, double_quote_literal, single_quote_literal, if_, merge, NaN, Some_, toMap, assert, forall, numeric_double_literal, minus_infinity_literal, plus_infinity_literal, natural_literal, integer_literal, import_hashed, or non_empty_list_literal diff --git a/dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt b/dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt index 9c1eaef..f6427a4 100644 --- a/dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt +++ b/dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt @@ -3,4 +3,4 @@ 1 | { x :T }␊ | ^--- | - = expected empty_record_literal or non_empty_record_type_or_literal + = expected non_empty_record_type_or_literal or empty_record_literal diff --git a/dhall/tests/type-inference/failure/unit/WithInvalidOverrideA.txt b/dhall/tests/type-inference/failure/unit/WithInvalidOverrideA.txt new file mode 100644 index 0000000..de101e0 --- /dev/null +++ b/dhall/tests/type-inference/failure/unit/WithInvalidOverrideA.txt @@ -0,0 +1 @@ +Type error: error: MustCombineRecord diff --git a/dhall/tests/type-inference/failure/unit/WithUnderscore.txt b/dhall/tests/type-inference/failure/unit/WithUnderscore.txt new file mode 100644 index 0000000..77b0777 --- /dev/null +++ b/dhall/tests/type-inference/failure/unit/WithUnderscore.txt @@ -0,0 +1,7 @@ +Type error: error: unbound variable ``_`` + --> <current file>:1:23 + | +... +5 | { a.b = 1 } with a.c = _ + | ^ not found in this scope + | |