summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
m---------dhall-lang0
-rw-r--r--dhall/build.rs15
-rw-r--r--dhall/src/syntax/ast/span.rs1
-rw-r--r--dhall/src/syntax/text/dhall.pest.visibility3
-rw-r--r--dhall/src/syntax/text/parser.rs41
-rw-r--r--dhall/tests/parser/failure/spacing/MergeNoSpace2.txt2
-rw-r--r--dhall/tests/parser/failure/spacing/RecordTypeNoSpace.txt2
-rw-r--r--dhall/tests/type-inference/failure/unit/WithInvalidOverrideA.txt1
-rw-r--r--dhall/tests/type-inference/failure/unit/WithUnderscore.txt7
10 files changed, 69 insertions, 4 deletions
diff --git a/README.md b/README.md
index 1d77e95..072dd10 100644
--- a/README.md
+++ b/README.md
@@ -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
+ |