summaryrefslogtreecommitdiff
path: root/dhall
diff options
context:
space:
mode:
Diffstat (limited to '')
m---------dhall-lang0
-rw-r--r--dhall/build.rs1
-rwxr-xr-xdhall/compare.fish9
-rw-r--r--dhall/src/normalize.rs2
-rw-r--r--dhall_core/src/core.rs19
-rw-r--r--dhall_core/src/parser.rs340
-rw-r--r--dhall_parser/build.rs7
-rw-r--r--dhall_parser/src/dhall.abnf312
-rw-r--r--dhall_parser/src/dhall.pest.visibility100
9 files changed, 393 insertions, 397 deletions
diff --git a/dhall-lang b/dhall-lang
-Subproject 1f87b0285ffc098a3ef05c93a8186c32736bd4a
+Subproject 30841349fd02fd4eb965cba23a8dc557e99fbd1
diff --git a/dhall/build.rs b/dhall/build.rs
index f7a31c0..e80115f 100644
--- a/dhall/build.rs
+++ b/dhall/build.rs
@@ -23,6 +23,7 @@ fn dhall_files_in_dir<'a>(dir: &'a Path) -> impl Iterator<Item = String> + 'a {
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=../dhall-lang/.git");
+ println!("cargo:rerun-if-changed=../.git/modules/dhall-lang/refs/heads/master");
let out_dir = env::var("OUT_DIR").unwrap();
let tests_dir = Path::new("../dhall-lang/tests/");
diff --git a/dhall/compare.fish b/dhall/compare.fish
deleted file mode 100755
index 154f06a..0000000
--- a/dhall/compare.fish
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env fish
-
-set dhall_hs_path ../dhall
-set dhall_hs $dhall_hs_path/.stack-work/install/**/bin/dhall
-set dhall_rs target/debug/dhall
-set input_file $argv[1]
-diff -u \
- --label "dhall-hs < $input_file" (eval $dhall_hs < $input_file ^&1 | psub) \
- --label "dhall-rs < $input_file" (eval $dhall_rs < $input_file ^&1 | psub)
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs
index cd4669d..7574c2f 100644
--- a/dhall/src/normalize.rs
+++ b/dhall/src/normalize.rs
@@ -85,7 +85,7 @@ where
dhall_expr!(
g
(List a0)
- (λ(a : a0) -> λ(as : List a1) -> [ a ] # as)
+ (λ(x : a0) -> λ(xs : List a1) -> [ x ] # xs)
([] : List a0)
),
rest,
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs
index db83a1e..3d1b9f3 100644
--- a/dhall_core/src/core.rs
+++ b/dhall_core/src/core.rs
@@ -598,6 +598,25 @@ pub fn rc<N, E>(x: Expr<N, E>) -> SubExpr<N, E> {
SubExpr(Rc::new(x))
}
+pub fn app<N, E>(f: Expr<N, E>, args: Vec<SubExpr<N, E>>) -> Expr<N, E> {
+ if args.is_empty() {
+ f
+ } else {
+ ExprF::App(rc(f), args)
+ }
+}
+
+pub fn app_rc<N, E>(
+ f: SubExpr<N, E>,
+ args: Vec<SubExpr<N, E>>,
+) -> SubExpr<N, E> {
+ if args.is_empty() {
+ f
+ } else {
+ rc(ExprF::App(f, args))
+ }
+}
+
fn add_ui(u: usize, i: isize) -> usize {
if i < 0 {
u.checked_sub(i.checked_neg().unwrap() as usize).unwrap()
diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs
index 343a895..e18a709 100644
--- a/dhall_core/src/parser.rs
+++ b/dhall_core/src/parser.rs
@@ -15,6 +15,8 @@ use crate::*;
use crate::ExprF::*;
+type ParsedExpr = Expr<X, Import>;
+type ParsedSubExpr = SubExpr<X, Import>;
type ParsedText = InterpolatedText<SubExpr<X, Import>>;
type ParsedTextContents = InterpolatedTextContents<SubExpr<X, Import>>;
@@ -116,8 +118,10 @@ fn debug_pair(pair: Pair<Rule>) -> String {
macro_rules! make_parser {
(@pattern, rule, $name:ident) => (Rule::$name);
+ (@pattern, token_rule, $name:ident) => (Rule::$name);
(@pattern, rule_group, $name:ident) => (_);
(@filter, rule) => (true);
+ (@filter, token_rule) => (true);
(@filter, rule_group) => (false);
(@body,
@@ -164,6 +168,13 @@ macro_rules! make_parser {
).ok_or_else(|| -> String { unreachable!() })?;
Ok(ParsedValue::$group(res))
});
+ (@body,
+ $pair:expr,
+ $children:expr,
+ token_rule!($name:ident<$o:ty>)
+ ) => ({
+ Ok(ParsedValue::$name(()))
+ });
(@body, $pair:expr, $children:expr, rule_group!( $name:ident<$o:ty> )) => (
unreachable!()
);
@@ -235,7 +246,8 @@ fn do_parse<'a>(initial_pair: Pair<'a, Rule>) -> ParseResult<ParsedValue<'a>> {
fn can_be_shortcutted(rule: Rule) -> bool {
use Rule::*;
match rule {
- import_alt_expression
+ expression
+ | import_alt_expression
| or_expression
| plus_expression
| text_append_expression
@@ -255,7 +267,7 @@ fn can_be_shortcutted(rule: Rule) -> bool {
}
make_parser! {
- rule!(EOI<()>; captured_str!(_) => ());
+ token_rule!(EOI<()>);
rule!(simple_label<Label>;
captured_str!(s) => Label::from(s.trim().to_owned())
@@ -267,7 +279,7 @@ make_parser! {
[simple_label(l)] => l,
[quoted_label(l)] => l,
));
- rule!(unreserved_label<Label>; children!(
+ rule!(nonreserved_label<Label>; children!(
[label(l)] => {
if crate::Builtin::parse(&String::from(&l)).is_some() {
Err(
@@ -286,7 +298,7 @@ make_parser! {
rule!(double_quote_chunk<ParsedTextContents>; children!(
[interpolation(e)] => {
- InterpolatedTextContents::Expr(e)
+ InterpolatedTextContents::Expr(rc(e))
},
[double_quote_escaped(s)] => {
InterpolatedTextContents::Text(s)
@@ -321,10 +333,8 @@ make_parser! {
captured_str!(s) => s
);
- rule!(end_of_line<()>; captured_str!(_) => ());
-
rule!(single_quote_literal<ParsedText>; children!(
- [end_of_line(eol), single_quote_continue(lines)] => {
+ [single_quote_continue(lines)] => {
let space = InterpolatedTextContents::Text(" ".to_owned());
let newline = InterpolatedTextContents::Text("\n".to_owned());
let min_indent = lines
@@ -359,7 +369,7 @@ make_parser! {
rule!(single_quote_continue<Vec<Vec<ParsedTextContents>>>; children!(
[interpolation(c), single_quote_continue(lines)] => {
- let c = InterpolatedTextContents::Expr(c);
+ let c = InterpolatedTextContents::Expr(rc(c));
let mut lines = lines;
lines.last_mut().unwrap().push(c);
lines
@@ -392,11 +402,11 @@ make_parser! {
},
));
- rule!(NaN<()>; captured_str!(_) => ());
- rule!(minus_infinity_literal<()>; captured_str!(_) => ());
- rule!(plus_infinity_literal<()>; captured_str!(_) => ());
+ token_rule!(NaN<()>);
+ token_rule!(minus_infinity_literal<()>);
+ token_rule!(plus_infinity_literal<()>);
- rule!(double_literal<core::Double>;
+ rule!(numeric_double_literal<core::Double>;
captured_str!(s) => {
let s = s.trim();
match s.parse::<f64>() {
@@ -408,6 +418,13 @@ make_parser! {
}
);
+ rule!(double_literal<core::Double>; children!(
+ [numeric_double_literal(n)] => n,
+ [minus_infinity_literal(n)] => std::f64::NEG_INFINITY.into(),
+ [plus_infinity_literal(n)] => std::f64::INFINITY.into(),
+ [NaN(n)] => std::f64::NAN.into(),
+ ));
+
rule!(natural_literal<core::Natural>;
captured_str!(s) => {
s.trim()
@@ -462,15 +479,15 @@ make_parser! {
scheme: sch,
authority: auth,
path: p,
- query: None,
- headers: None,
+ query: Option::None,
+ headers: Option::None,
},
[scheme(sch), authority(auth), path(p), query(q)] => URL {
scheme: sch,
authority: auth,
path: p,
- query: Some(q),
- headers: None,
+ query: Option::Some(q),
+ headers: Option::None,
},
));
@@ -481,7 +498,7 @@ make_parser! {
rule!(http<URL>; children!(
[http_raw(url)] => url,
[http_raw(url), import_hashed(ih)] =>
- URL { headers: Some(Box::new(ih)), ..url },
+ URL { headers: Option::Some(Box::new(ih)), ..url },
));
rule!(env<String>; children!(
@@ -491,7 +508,7 @@ make_parser! {
rule!(bash_environment_variable<String>; captured_str!(s) => s.to_owned());
rule!(posix_environment_variable<String>; captured_str!(s) => s.to_owned());
- rule!(missing<()>; captured_str!(_) => ());
+ token_rule!(missing<()>);
rule!(import_type<ImportLocation>; children!(
[missing(_)] => {
@@ -517,92 +534,85 @@ make_parser! {
rule!(import_hashed<ImportHashed>; children!(
[import_type(location)] =>
- ImportHashed { location, hash: None },
+ ImportHashed { location, hash: Option::None },
[import_type(location), hash(h)] =>
- ImportHashed { location, hash: Some(h) },
+ ImportHashed { location, hash: Option::Some(h) },
));
- rule_group!(expression<ParsedExpr>);
-
- rule!(Text<()>; captured_str!(_) => ());
+ token_rule!(Text<()>);
rule!(import<ParsedExpr> as expression; children!(
[import_hashed(location_hashed)] => {
- bx(Embed(Import {
+ Embed(Import {
mode: ImportMode::Code,
location_hashed
- }))
+ })
},
[import_hashed(location_hashed), Text(_)] => {
- bx(Embed(Import {
+ Embed(Import {
mode: ImportMode::RawText,
location_hashed
- }))
+ })
},
));
- rule!(lambda_expression<ParsedExpr> as expression; children!(
- [unreserved_label(l), expression(typ), expression(body)] => {
- bx(Lam(l, typ, body))
- }
- ));
-
- rule!(ifthenelse_expression<ParsedExpr> as expression; children!(
- [expression(cond), expression(left), expression(right)] => {
- bx(BoolIf(cond, left, right))
- }
- ));
+ token_rule!(lambda<()>);
+ token_rule!(forall<()>);
+ token_rule!(arrow<()>);
+ token_rule!(merge<()>);
+ token_rule!(if_<()>);
+ token_rule!(in_<()>);
- rule!(let_expression<ParsedExpr> as expression; children!(
- [let_binding(bindings).., expression(final_expr)] => {
+ rule!(expression<ParsedExpr> as expression; children!(
+ [lambda(()), nonreserved_label(l), expression(typ), arrow(()), expression(body)] => {
+ Lam(l, rc(typ), rc(body))
+ },
+ [if_(()), expression(cond), expression(left), expression(right)] => {
+ BoolIf(rc(cond), rc(left), rc(right))
+ },
+ [let_binding(bindings).., in_(()), expression(final_expr)] => {
bindings.fold(
final_expr,
- |acc, x| bx(Let(x.0, x.1, x.2, acc))
+ |acc, x| Let(x.0, x.1, x.2, rc(acc))
)
- }
- ));
-
- rule!(let_binding<(Label, Option<ParsedExpr>, ParsedExpr)>; children!(
- [unreserved_label(name), expression(annot), expression(expr)] =>
- (name, Some(annot), expr),
- [unreserved_label(name), expression(expr)] =>
- (name, None, expr),
- ));
-
- rule!(forall_expression<ParsedExpr> as expression; children!(
- [unreserved_label(l), expression(typ), expression(body)] => {
- bx(Pi(l, typ, body))
- }
- ));
-
- rule!(arrow_expression<ParsedExpr> as expression; children!(
- [expression(typ), expression(body)] => {
- bx(Pi("_".into(), typ, body))
- }
+ },
+ [forall(()), nonreserved_label(l), expression(typ), arrow(()), expression(body)] => {
+ Pi(l, rc(typ), rc(body))
+ },
+ [expression(typ), arrow(()), expression(body)] => {
+ Pi("_".into(), rc(typ), rc(body))
+ },
+ [merge(()), expression(x), expression(y), expression(z)] => {
+ Merge(rc(x), rc(y), Option::Some(rc(z)))
+ },
+ [merge(()), expression(x), expression(y)] => {
+ Merge(rc(x), rc(y), Option::None)
+ },
+ [expression(e)] => e,
));
- rule!(merge_expression<ParsedExpr> as expression; children!(
- [expression(x), expression(y), expression(z)] =>
- bx(Merge(x, y, Some(z))),
- [expression(x), expression(y)] =>
- bx(Merge(x, y, None)),
+ rule!(let_binding<(Label, Option<ParsedSubExpr>, ParsedSubExpr)>; children!(
+ [nonreserved_label(name), expression(annot), expression(expr)] =>
+ (name, Option::Some(rc(annot)), rc(expr)),
+ [nonreserved_label(name), expression(expr)] =>
+ (name, Option::None, rc(expr)),
));
- rule!(List<()>; captured_str!(_) => ());
- rule!(Optional<()>; captured_str!(_) => ());
+ token_rule!(List<()>);
+ token_rule!(Optional<()>);
rule!(empty_collection<ParsedExpr> as expression; children!(
[List(_), expression(t)] => {
- bx(EmptyListLit(t))
+ EmptyListLit(rc(t))
},
[Optional(_), expression(t)] => {
- bx(EmptyOptionalLit(t))
+ EmptyOptionalLit(rc(t))
},
));
rule!(non_empty_optional<ParsedExpr> as expression; children!(
[expression(x), Optional(_), expression(t)] => {
- rc(Annot(rc(NEOptionalLit(x)), t))
+ Annot(rc(NEOptionalLit(rc(x))), rc(t))
}
));
@@ -610,118 +620,107 @@ make_parser! {
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::ImportAlt;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(or_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::BoolOr;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(plus_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::NaturalPlus;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(text_append_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::TextAppend;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(list_append_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::ListAppend;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(and_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::BoolAnd;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(combine_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::Combine;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(prefer_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::Prefer;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(combine_types_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::CombineTypes;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(times_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::NaturalTimes;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(equal_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::BoolEQ;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(not_equal_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
let o = crate::BinOp::BoolNE;
- rest.fold(first, |acc, e| bx(BinOp(o, acc, e)))
+ rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e)))
},
));
rule!(annotated_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
[expression(e), expression(annot)] => {
- bx(Annot(e, annot))
+ Annot(rc(e), rc(annot))
},
));
+ token_rule!(Some<()>);
+
rule!(application_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(second)] => {
- match first.as_ref() {
- Builtin(crate::Builtin::OptionalNone) =>
- bx(EmptyOptionalLit(second)),
- Builtin(crate::Builtin::OptionalSome) =>
- bx(NEOptionalLit(second)),
- _ => bx(App(first, vec![second])),
- }
+ [expression(Builtin(crate::Builtin::OptionalNone)),
+ expression(e), expression(rest)..] => {
+ app(EmptyOptionalLit(rc(e)), rest.map(rc).collect())
},
- [expression(first), expression(second), expression(rest)..] => {
- match first.as_ref() {
- Builtin(crate::Builtin::OptionalNone) =>
- bx(App(bx(EmptyOptionalLit(second)),
- rest.collect())),
- Builtin(crate::Builtin::OptionalSome) =>
- bx(App(bx(NEOptionalLit(second)),
- rest.collect())),
- _ => bx(App(first,
- std::iter::once(second)
- .chain(rest)
- .collect())),
- }
+ [Some(()), expression(e), expression(rest)..] => {
+ app(NEOptionalLit(rc(e)), rest.map(rc).collect())
+ },
+ [expression(first), expression(rest)..] => {
+ app(first, rest.map(rc).collect())
},
));
@@ -729,8 +728,8 @@ make_parser! {
[expression(e)] => e,
[expression(first), selector(rest)..] => {
rest.fold(first, |acc, e| match e {
- Either::Left(l) => bx(Field(acc, l)),
- Either::Right(ls) => bx(Projection(acc, ls)),
+ Either::Left(l) => Field(rc(acc), l),
+ Either::Right(ls) => Projection(rc(acc), ls),
})
}
));
@@ -744,17 +743,12 @@ make_parser! {
[label(ls)..] => ls.collect(),
));
- rule!(literal_expression<ParsedExpr> as expression; children!(
- [double_literal(n)] => bx(DoubleLit(n)),
- [minus_infinity_literal(n)] =>
- bx(DoubleLit(std::f64::NEG_INFINITY.into())),
- [plus_infinity_literal(n)] =>
- bx(DoubleLit(std::f64::INFINITY.into())),
- [NaN(n)] => bx(DoubleLit(std::f64::NAN.into())),
- [natural_literal(n)] => bx(NaturalLit(n)),
- [integer_literal(n)] => bx(IntegerLit(n)),
- [double_quote_literal(s)] => bx(TextLit(s)),
- [single_quote_literal(s)] => bx(TextLit(s)),
+ rule!(primitive_expression<ParsedExpr> as expression; children!(
+ [double_literal(n)] => DoubleLit(n),
+ [natural_literal(n)] => NaturalLit(n),
+ [integer_literal(n)] => IntegerLit(n),
+ [double_quote_literal(s)] => TextLit(s),
+ [single_quote_literal(s)] => TextLit(s),
[expression(e)] => e,
));
@@ -762,116 +756,128 @@ make_parser! {
[label(l), natural_literal(idx)] => {
let name = String::from(&l);
match crate::Builtin::parse(name.as_str()) {
- Some(b) => bx(Builtin(b)),
- None => match name.as_str() {
- "True" => bx(BoolLit(true)),
- "False" => bx(BoolLit(false)),
- "Type" => bx(Const(crate::Const::Type)),
- "Kind" => bx(Const(crate::Const::Kind)),
- _ => bx(Var(V(l, idx))),
+ Option::Some(b) => Builtin(b),
+ Option::None => match name.as_str() {
+ "True" => BoolLit(true),
+ "False" => BoolLit(false),
+ "Type" => Const(crate::Const::Type),
+ "Kind" => Const(crate::Const::Kind),
+ _ => Var(V(l, idx)),
}
}
},
[label(l)] => {
let name = String::from(&l);
match crate::Builtin::parse(name.as_str()) {
- Some(b) => bx(Builtin(b)),
- None => match name.as_str() {
- "True" => bx(BoolLit(true)),
- "False" => bx(BoolLit(false)),
- "Type" => bx(Const(crate::Const::Type)),
- "Kind" => bx(Const(crate::Const::Kind)),
- _ => bx(Var(V(l, 0))),
+ Option::Some(b) => Builtin(b),
+ Option::None => match name.as_str() {
+ "True" => BoolLit(true),
+ "False" => BoolLit(false),
+ "Type" => Const(crate::Const::Type),
+ "Kind" => Const(crate::Const::Kind),
+ _ => Var(V(l, 0)),
}
}
},
));
rule!(empty_record_literal<ParsedExpr> as expression;
- captured_str!(_) => bx(RecordLit(BTreeMap::new()))
+ captured_str!(_) => RecordLit(BTreeMap::new())
);
rule!(empty_record_type<ParsedExpr> as expression;
- captured_str!(_) => bx(RecordType(BTreeMap::new()))
+ captured_str!(_) => RecordType(BTreeMap::new())
);
rule!(non_empty_record_type_or_literal<ParsedExpr> as expression; children!(
[label(first_label), non_empty_record_type(rest)] => {
let (first_expr, mut map) = rest;
- map.insert(first_label, first_expr);
- bx(RecordType(map))
+ map.insert(first_label, rc(first_expr));
+ RecordType(map)
},
[label(first_label), non_empty_record_literal(rest)] => {
let (first_expr, mut map) = rest;
- map.insert(first_label, first_expr);
- bx(RecordLit(map))
+ map.insert(first_label, rc(first_expr));
+ RecordLit(map)
},
));
rule!(non_empty_record_type
- <(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!(
+ <(ParsedExpr, BTreeMap<Label, ParsedSubExpr>)>; children!(
[expression(expr), record_type_entry(entries)..] => {
(expr, entries.collect())
}
));
- rule!(record_type_entry<(Label, ParsedExpr)>; children!(
- [label(name), expression(expr)] => (name, expr)
+ rule!(record_type_entry<(Label, ParsedSubExpr)>; children!(
+ [label(name), expression(expr)] => (name, rc(expr))
));
rule!(non_empty_record_literal
- <(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!(
+ <(ParsedExpr, BTreeMap<Label, ParsedSubExpr>)>; children!(
[expression(expr), record_literal_entry(entries)..] => {
(expr, entries.collect())
}
));
- rule!(record_literal_entry<(Label, ParsedExpr)>; children!(
- [label(name), expression(expr)] => (name, expr)
+ rule!(record_literal_entry<(Label, ParsedSubExpr)>; children!(
+ [label(name), expression(expr)] => (name, rc(expr))
));
rule!(union_type_or_literal<ParsedExpr> as expression; children!(
[empty_union_type(_)] => {
- bx(UnionType(BTreeMap::new()))
+ UnionType(BTreeMap::new())
},
- [non_empty_union_type_or_literal((Some((l, e)), entries))] => {
- bx(UnionLit(l, e, entries))
+ [non_empty_union_type_or_literal((Option::Some((l, e)), entries))] => {
+ UnionLit(l, e, entries)
},
- [non_empty_union_type_or_literal((None, entries))] => {
- bx(UnionType(entries))
+ [non_empty_union_type_or_literal((Option::None, entries))] => {
+ UnionType(entries)
},
));
- rule!(empty_union_type<()>; captured_str!(_) => ());
+ token_rule!(empty_union_type<()>);
rule!(non_empty_union_type_or_literal
- <(Option<(Label, ParsedExpr)>, BTreeMap<Label, ParsedExpr>)>;
+ <(Option<(Label, ParsedSubExpr)>, BTreeMap<Label, ParsedSubExpr>)>;
children!(
- [label(l), expression(e), union_type_entries(entries)] => {
- (Some((l, e)), entries)
+ [label(l), union_literal_variant_value((e, entries))] => {
+ (Option::Some((l, rc(e))), entries)
},
- [label(l), expression(e), non_empty_union_type_or_literal(rest)] => {
+ [label(l), union_type_or_literal_variant_type((e, rest))] => {
let (x, mut entries) = rest;
- entries.insert(l, e);
+ entries.insert(l, rc(e));
(x, entries)
},
- [label(l), expression(e)] => {
- let mut entries = BTreeMap::new();
- entries.insert(l, e);
- (None, entries)
+ ));
+
+ rule!(union_literal_variant_value
+ <(ParsedExpr, BTreeMap<Label, ParsedSubExpr>)>;
+ children!(
+ [expression(e), union_type_entry(entries)..] => {
+ (e, entries.collect())
},
));
- rule!(union_type_entries<BTreeMap<Label, ParsedExpr>>; children!(
- [union_type_entry(entries)..] => entries.collect()
+ rule!(union_type_entry<(Label, ParsedSubExpr)>; children!(
+ [label(name), expression(expr)] => (name, rc(expr))
));
- rule!(union_type_entry<(Label, ParsedExpr)>; children!(
- [label(name), expression(expr)] => (name, expr)
+ // TODO: unary union variants
+ rule!(union_type_or_literal_variant_type
+ <(ParsedExpr,
+ (Option<(Label, ParsedSubExpr)>, BTreeMap<Label, ParsedSubExpr>))>;
+ children!(
+ [expression(e), non_empty_union_type_or_literal(rest)] => {
+ (e, rest)
+ },
+ [expression(e)] => {
+ (e, (Option::None, BTreeMap::new()))
+ },
));
rule!(non_empty_list_literal<ParsedExpr> as expression; children!(
- [expression(items)..] => bx(NEListLit(items.collect()))
+ [expression(items)..] => NEListLit(items.map(rc).collect())
));
rule!(final_expression<ParsedExpr> as expression; children!(
@@ -879,15 +885,15 @@ make_parser! {
));
}
-pub fn parse_expr(s: &str) -> ParseResult<ParsedExpr> {
+pub fn parse_expr(s: &str) -> ParseResult<ParsedSubExpr> {
let mut pairs = DhallParser::parse(Rule::final_expression, s)?;
let expr = do_parse(pairs.next().unwrap())?;
assert_eq!(pairs.next(), None);
match expr {
- ParsedValue::expression(e) => Ok(e),
+ ParsedValue::expression(e) => Ok(rc(e)),
_ => unreachable!(),
}
- // Ok(bx(BoolLit(false)))
+ // Ok(rc(BoolLit(false)))
}
#[test]
diff --git a/dhall_parser/build.rs b/dhall_parser/build.rs
index 4e75181..615a55c 100644
--- a/dhall_parser/build.rs
+++ b/dhall_parser/build.rs
@@ -42,13 +42,6 @@ fn main() -> std::io::Result<()> {
)?;
writeln!(
&mut file,
- "keyword = _{{
- let_ | in_ | if_ | then
- | else_ | Infinity | NaN
- }}"
- )?;
- writeln!(
- &mut file,
"final_expression = ${{ SOI ~ complete_expression ~ EOI }}"
)?;
diff --git a/dhall_parser/src/dhall.abnf b/dhall_parser/src/dhall.abnf
index 02edc84..847da02 100644
--- a/dhall_parser/src/dhall.abnf
+++ b/dhall_parser/src/dhall.abnf
@@ -100,10 +100,9 @@
;
; For simplicity this supports Unix and Windows line-endings, which are the most
; common
-end-of-line-silent =
+end-of-line =
%x0A ; "\n"
/ %x0D.0A ; "\r\n"
-end-of-line = end-of-line-silent
tab = %x09 ; "\t"
@@ -113,7 +112,7 @@ block-comment-chunk =
block-comment
/ %x20-10FFFF
/ tab
- / end-of-line-silent
+ / end-of-line
block-comment-continue = "-}" / block-comment-chunk block-comment-continue
@@ -121,18 +120,19 @@ not-end-of-line = %x20-10FFFF / tab
; NOTE: Slightly different from Haskell-style single-line comments because this
; does not require a space after the dashes
-line-comment = "--" *not-end-of-line end-of-line-silent
+line-comment = "--" *not-end-of-line end-of-line
whitespace-chunk =
" "
/ tab
- / end-of-line-silent
+ / end-of-line
/ line-comment
/ block-comment
-whitespace = *whitespace-chunk
+whsp = *whitespace-chunk
-nonempty-whitespace = 1*whitespace-chunk
+; nonempty whitespace
+whsp1 = 1*whitespace-chunk
; Uppercase or lowercase ASCII letter
ALPHA = %x41-5A / %x61-7A
@@ -142,19 +142,13 @@ DIGIT = %x30-39 ; 0-9
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
-; A simple label cannot be one of the following reserved keywords:
-;
-; * if
-; * then
-; * else
-; * let
-; * in
-; * as
-; * using
-; * merge
-; * missing
-; * Infinity
-; * Some
+; A simple label cannot be one of the reserved keywords
+; listed in the `keyword` rule.
+; A PEG parser could use negative lookahead to
+; enforce this, e.g. as follows:
+; simple-label =
+; keyword 1*simple-label-next-char
+; / !keyword (simple-label-first-char *simple-label-next-char)
simple-label-first-char = ALPHA / "_"
simple-label-next-char = ALPHA / DIGIT / "-" / "/" / "_"
simple-label = simple-label-first-char *simple-label-next-char
@@ -170,11 +164,12 @@ quoted-label = 1*quoted-label-char
; for code obfuscation
label = ("`" quoted-label "`" / simple-label)
-; An unreserved-label cannot not be any of the reserved identifiers for builtins (unless quoted).
+; A nonreserved-label cannot not be any of the reserved identifiers for builtins (unless quoted).
; Their list can be found in semantics.md. This is not enforced by the grammar but
; should be checked by implementations. The only place where this restriction applies
; is bound variables.
-unreserved-label = label
+; A PEG parser could use negative lookahead to avoid parsing those identifiers.
+nonreserved-label = label
; An any-label is allowed to be one of the reserved identifiers.
any-label = label
@@ -216,8 +211,8 @@ any-label = label
; > "\uD834\uDD1E".
double-quote-chunk =
interpolation
- ; '\'
- / %x5C double-quote-escaped
+ ; '\' Beginning of escape sequence
+ / %x5C double-quote-escaped
/ double-quote-char
double-quote-escaped =
@@ -273,7 +268,6 @@ single-quote-char =
single-quote-literal = "''" end-of-line single-quote-continue
-; Interpolation
interpolation = "${" complete-expression "}"
text-literal = (double-quote-literal / single-quote-literal)
@@ -281,25 +275,34 @@ text-literal = (double-quote-literal / single-quote-literal)
; RFC 5234 interprets string literals as case-insensitive and recommends using
; hex instead for case-sensitive strings
;
-; If you don't feel like reading hex, these are all the same as the rule name,
-; except without the '' ending.
+; If you don't feel like reading hex, these are all the same as the rule name.
; Keywords that should never be parsed as identifiers
-if = %x69.66
-then = %x74.68.65.6e
-else = %x65.6c.73.65
-let = %x6c.65.74
-in = %x69.6e
-as = %x61.73
-using = %x75.73.69.6e.67
-merge = %x6d.65.72.67.65
-missing = %x6d.69.73.73.69.6e.67
-Infinity = %x49.6e.66.69.6e.69.74.79
+if = %x69.66
+then = %x74.68.65.6e
+else = %x65.6c.73.65
+let = %x6c.65.74
+in = %x69.6e
+as = %x61.73
+using = %x75.73.69.6e.67
+merge = %x6d.65.72.67.65
+missing = %x6d.69.73.73.69.6e.67
+Infinity = %x49.6e.66.69.6e.69.74.79
+NaN = %x4e.61.4e
+Some = %x53.6f.6d.65
+
+; Unused rule that could be used as negative lookahead in the
+; `simple-label` rule for parsers that support this.
+keyword =
+ if / then / else
+ / let / in
+ / using / missing / as
+ / Infinity / NaN
+ / merge / Some
+
; Reserved identifiers, only needed for some special cases of parsing
Optional = %x4f.70.74.69.6f.6e.61.6c
Text = %x54.65.78.74
List = %x4c.69.73.74
-NaN = %x4e.61.4e
-Some = %x53.6f.6d.65
combine = %x2227 / "/\"
combine-types = %x2A53 / "//\\"
@@ -310,7 +313,20 @@ arrow = %x2192 / "->"
exponent = "e" [ "+" / "-" ] 1*DIGIT
-double-literal = [ "+" / "-" ] 1*DIGIT ( "." 1*DIGIT [ exponent ] / exponent)
+numeric-double-literal = [ "+" / "-" ] 1*DIGIT ( "." 1*DIGIT [ exponent ] / exponent)
+
+minus-infinity-literal = "-" Infinity
+plus-infinity-literal = Infinity
+
+double-literal =
+ ; "2.0"
+ numeric-double-literal
+ ; "-Infinity"
+ / minus-infinity-literal
+ ; "Infinity"
+ / plus-infinity-literal
+ ; "NaN"
+ / NaN
natural-literal = 1*DIGIT
@@ -318,7 +334,7 @@ integer-literal = ( "+" / "-" ) natural-literal
; The implementation should recognize reserved names for builtins and treat them as special
; values instead of variables.
-identifier = any-label [ whitespace "@" whitespace natural-literal ]
+identifier = any-label [ whsp "@" whsp natural-literal ]
; Printable characters other than " ()[]{}<>/\,"
;
@@ -363,6 +379,8 @@ quoted-path-component = 1*quoted-path-character
path-component = "/" ( unquoted-path-component / %x22 quoted-path-component %x22 )
+; The last path-component matched by this rule is referred to as "file" in the semantics,
+; and the other path-components as "directory".
path = 1*path-component
local =
@@ -445,7 +463,7 @@ sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
http =
http-raw
- [ whitespace using nonempty-whitespace (import-hashed / "(" whitespace import-hashed whitespace ")") ]
+ [ whsp using whsp1 (import-hashed / "(" whsp import-hashed whsp ")") ]
; Dhall supports unquoted environment variables that are Bash-compliant or
; quoted environment variables that are POSIX-compliant
@@ -513,117 +531,106 @@ posix-environment-variable-character =
import-type = missing / local / http / env
-hash = %x73.68.61.32.35.36.3a 64HEXDIG ; "sha256:XXX...XXX"
+hash = %x73.68.61.32.35.36.3a 64HEXDIG ; "sha256:XXX...XXX"
-import-hashed = import-type [ whitespace hash ]
+import-hashed = import-type [ whsp hash ]
; "http://example.com"
; "./foo/bar"
; "env:FOO"
-import = import-hashed [ whitespace as nonempty-whitespace Text ]
-
-; NOTE: Every rule past this point should only reference rules that end with
-; whitespace. This ensures consistent handling of whitespace in the absence of
-; a separate lexing step.
-; The exception is the rules ending in , which should _not_ end in whitespace.
-; This is important to avoid the need for sequential backtracking in application-expression.
+import = import-hashed [ whsp as whsp1 Text ]
expression =
- lambda-expression
- / ifthenelse-expression
- / let-expression
- / forall-expression
+ ; "\(x : a) -> b"
+ lambda whsp "(" whsp nonreserved-label whsp ":" whsp1 expression whsp ")" whsp arrow whsp expression
+
+ ; "if a then b else c"
+ / if whsp1 expression whsp then whsp1 expression whsp else whsp1 expression
+
+ ; "let x : t = e1 in e2"
+ ; "let x = e1 in e2"
+ ; "let x = e1 let y = e2 in e3"
+ / 1*let-binding in whsp1 expression
+
+ ; "forall (x : a) -> b"
+ / forall whsp "(" whsp nonreserved-label whsp ":" whsp1 expression whsp ")" whsp arrow whsp expression
+
+ ; "a -> b"
+ ;
; NOTE: Backtrack if parsing this alternative fails
- / arrow-expression
- / merge-expression
+ / operator-expression whsp arrow whsp expression
+
+ ; "merge e1 e2 : t"
+ ; "merge e1 e2"
+ / merge whsp1 import-expression whsp import-expression [ whsp ":" whsp1 application-expression ]
+
+ ; "[] : List t"
+ ; "[] : Optional t"
+ ; "[x] : Optional t"
+ ;
; NOTE: Backtrack if parsing this alternative fails since we can't tell
; from the opening bracket whether or not this will be an empty list or
; a non-empty list
- / empty-list-or-optional
+ / "[" whsp (empty-collection / non-empty-optional)
+
+ ; "x : t"
/ annotated-expression
-; "\(x : a) -> b"
-lambda-expression = lambda whitespace "(" whitespace unreserved-label whitespace ":" nonempty-whitespace expression ")" whitespace arrow whitespace expression
-
-; "if a then b else c"
-ifthenelse-expression = if nonempty-whitespace expression then nonempty-whitespace expression else nonempty-whitespace expression
-
-; "let x : t = e1 in e2"
-; "let x = e1 in e2"
-; "let x = e1 let y = e2 in e3"
-let-expression = 1*let-binding in nonempty-whitespace expression
-let-binding = let nonempty-whitespace unreserved-label whitespace [ ":" nonempty-whitespace expression ] "=" whitespace expression
-
-; "forall (x : a) -> b"
-forall-expression = forall whitespace "(" whitespace unreserved-label whitespace ":" nonempty-whitespace expression ")" whitespace arrow whitespace expression
+; Nonempty-whitespace to disambiguate `env:VARIABLE` from type annotations
+annotated-expression = operator-expression [ whsp ":" whsp1 expression ]
-; "a -> b"
-arrow-expression = operator-expression arrow whitespace expression
+; "let x = e1"
+let-binding = let whsp1 nonreserved-label whsp [ ":" whsp1 expression whsp ] "=" whsp expression whsp
-; "merge e1 e2 : t"
-; "merge e1 e2"
-merge-expression = merge nonempty-whitespace import-expression whitespace import-expression whitespace [ ":" nonempty-whitespace application-expression ]
-
-; "[] : List t"
-; "[] : Optional t"
-; "[x] : Optional t"
-empty-list-or-optional = "[" whitespace (empty-collection / non-empty-optional)
-empty-collection = "]" whitespace ":" nonempty-whitespace (List whitespace / Optional whitespace) import-expression whitespace
-non-empty-optional = expression "]" whitespace ":" nonempty-whitespace Optional whitespace import-expression whitespace
-
-; "x : t"
-annotated-expression = operator-expression [ ":" nonempty-whitespace expression ]
+; "] : List t"
+; "] : Optional t"
+empty-collection = "]" whsp ":" whsp1 (List / Optional) whsp import-expression
+; "x] : Optional t"
+non-empty-optional = expression whsp "]" whsp ":" whsp1 Optional whsp import-expression
operator-expression = import-alt-expression
-import-alt-expression = or-expression *("?" nonempty-whitespace or-expression)
-or-expression = plus-expression *("||" whitespace plus-expression )
-plus-expression = text-append-expression *("+" nonempty-whitespace text-append-expression )
-text-append-expression = list-append-expression *("++" whitespace list-append-expression )
-list-append-expression = and-expression *("#" whitespace and-expression )
-and-expression = combine-expression *("&&" whitespace combine-expression )
-combine-expression = prefer-expression *(combine whitespace prefer-expression )
-prefer-expression = combine-types-expression *(prefer whitespace combine-types-expression)
-combine-types-expression = times-expression *(combine-types whitespace times-expression )
-times-expression = equal-expression *("*" whitespace equal-expression )
-equal-expression = not-equal-expression *("==" whitespace not-equal-expression )
-not-equal-expression = application-expression *("!=" whitespace application-expression )
+; Nonempty-whitespace to disambiguate `http://a/a?a`
+import-alt-expression = or-expression *(whsp "?" whsp1 or-expression)
+or-expression = plus-expression *(whsp "||" whsp plus-expression)
+; Nonempty-whitespace to disambiguate `f +2`
+plus-expression = text-append-expression *(whsp "+" whsp1 text-append-expression)
+text-append-expression = list-append-expression *(whsp "++" whsp list-append-expression)
+list-append-expression = and-expression *(whsp "#" whsp and-expression)
+and-expression = combine-expression *(whsp "&&" whsp combine-expression)
+combine-expression = prefer-expression *(whsp combine whsp prefer-expression)
+prefer-expression = combine-types-expression *(whsp prefer whsp combine-types-expression)
+combine-types-expression = times-expression *(whsp combine-types whsp times-expression)
+times-expression = equal-expression *(whsp "*" whsp equal-expression)
+equal-expression = not-equal-expression *(whsp "==" whsp not-equal-expression)
+not-equal-expression = application-expression *(whsp "!=" whsp application-expression)
; Import expressions need to be separated by some whitespace, otherwise there
; would be ambiguity: `./ab` could be interpreted as "import the file `./ab`",
; or "apply the import `./a` to label `b`"
application-expression =
- import-expression *(nonempty-whitespace import-expression) whitespace
+ [ Some whsp1 ] import-expression *(whsp1 import-expression)
-import-expression =
- import
- / selector-expression
+import-expression = import / selector-expression
; `record.field` extracts one field of a record
+;
; `record.{ field0, field1, field2 }` projects out several fields of a record
;
-; NOTE: Backtrack when parsing the `*(dot ...)`. The reason why is that you
+; NOTE: Backtrack when parsing the `*("." ...)`. The reason why is that you
; can't tell from parsing just the period whether "foo." will become "foo.bar"
; (i.e. accessing field `bar` of the record `foo`) or `foo./bar` (i.e. applying
; the function `foo` to the relative path `./bar`)
-selector-expression = primitive-expression *(whitespace "." whitespace selector)
+selector-expression = primitive-expression *(whsp "." whsp selector)
selector = any-label / labels
-labels = "{" whitespace [ any-label whitespace *("," whitespace any-label whitespace) ] "}"
-
-
-primitive-expression =
- literal-expression
- / "{" whitespace record-type-or-literal "}"
- / "<" whitespace union-type-or-literal ">"
- / non-empty-list-literal
- / parenthesized-expression
+labels = "{" whsp [ any-label whsp *("," whsp any-label whsp) ] "}"
; NOTE: Backtrack when parsing the first three alternatives (i.e. the numeric
; literals). This is because they share leading characters in common
-literal-expression =
+primitive-expression =
; "2.0"
double-literal
@@ -633,60 +640,65 @@ literal-expression =
; "+2"
/ integer-literal
- ; "-Infinity"
- / minus-infinity-literal
- ; "Infinity"
- / plus-infinity-literal
- ; "NaN"
- / NaN
-
; '"ABC"'
/ text-literal
+ ; "{ foo = 1 , bar = True }"
+ ; "{ foo : Integer, bar : Bool }"
+ / "{" whsp record-type-or-literal whsp "}"
+
+ ; "< Foo : Integer | Bar : Bool >"
+ ; "< Foo : Integer | Bar = True | Baz : Bool >"
+ ; "< Foo | Bar : Bool >"
+ / "<" whsp union-type-or-literal whsp ">"
+
+ ; "[1, 2, 3]"
+ ; `empty-collection` handles empty lists
+ / non-empty-list-literal
+
; "x"
; "x@2"
/ identifier
+
+ ; "( e )"
+ / "(" complete-expression ")"
-minus-infinity-literal = "-" Infinity
-plus-infinity-literal = Infinity
-
-; "{ foo = 1 , bar = True }"
-; "{ foo : Integer, bar : Bool }"
record-type-or-literal =
empty-record-literal
/ non-empty-record-type-or-literal
/ empty-record-type
-empty-record-literal = "=" whitespace
+
+empty-record-literal = "="
empty-record-type = ""
+
non-empty-record-type-or-literal =
- any-label whitespace (non-empty-record-literal / non-empty-record-type)
-non-empty-record-type = ":" nonempty-whitespace expression *("," whitespace record-type-entry)
-record-type-entry = any-label whitespace ":" nonempty-whitespace expression
-non-empty-record-literal = "=" whitespace expression *("," whitespace record-literal-entry)
-record-literal-entry = any-label whitespace "=" whitespace expression
-
-; "< Foo : Integer | Bar : Bool >"
-; "< Foo : Integer | Bar = True >"
+ any-label whsp (non-empty-record-literal / non-empty-record-type)
+
+non-empty-record-type = ":" whsp1 expression *(whsp "," whsp record-type-entry)
+record-type-entry = any-label whsp ":" whsp1 expression
+
+non-empty-record-literal = "=" whsp expression *(whsp "," whsp record-literal-entry)
+record-literal-entry = any-label whsp "=" whsp expression
+
union-type-or-literal =
non-empty-union-type-or-literal
/ empty-union-type
+
empty-union-type = ""
+
non-empty-union-type-or-literal =
- any-label whitespace
- ( "=" whitespace expression union-type-entries
- / ":" nonempty-whitespace expression [ "|" whitespace non-empty-union-type-or-literal ]
- )
-union-type-entries = *("|" whitespace union-type-entry)
-union-type-entry = any-label whitespace ":" nonempty-whitespace expression
+ any-label [ whsp ( union-literal-variant-value / union-type-or-literal-variant-type) ]
+
+; = True | ...
+union-literal-variant-value = "=" whsp expression *(whsp "|" whsp union-type-entry)
+union-type-entry = any-label whsp ":" whsp1 expression
-; "[1, 2, 3]"
-; `empty-list-or-optional` handles empty lists
-non-empty-list-literal = "[" whitespace expression *("," whitespace expression) "]"
+; : Integer | ...
+; | ...
+union-type-or-literal-variant-type = [ ":" whsp1 expression ] [ whsp "|" whsp non-empty-union-type-or-literal ]
-; "( e )"
-parenthesized-expression = "(" whitespace expression ")"
+non-empty-list-literal = "[" whsp expression whsp *("," whsp expression whsp) "]"
-; All expressions end with trailing whitespace. This just adds a final
-; whitespace prefix for the top-level of the program
-complete-expression = whitespace expression
+; This just adds surrounding whitespace for the top-level of the program
+complete-expression = whsp expression whsp
diff --git a/dhall_parser/src/dhall.pest.visibility b/dhall_parser/src/dhall.pest.visibility
index ee5ea2b..f881a50 100644
--- a/dhall_parser/src/dhall.pest.visibility
+++ b/dhall_parser/src/dhall.pest.visibility
@@ -1,5 +1,4 @@
-end_of_line
-# end_of_line_silent
+# end_of_line
# tab
# block_comment
# block_comment_chunk
@@ -7,91 +6,71 @@ end_of_line
# not_end_of_line
# line_comment
# whitespace_chunk
-# whitespace
-# whitespace_
-# nonempty_whitespace
+# whsp
+# whsp1
# ALPHA
# DIGIT
# HEXDIG
# simple_label_first_char
-# simple_label_next_other_char
# simple_label_next_char
-# simple_label_start
simple_label
# quoted_label_char
quoted_label
label
+nonreserved_label
# any_label
double_quote_chunk
double_quote_escaped
+double_quote_char
double_quote_literal
single_quote_continue
+escaped_quote_pair
+escaped_interpolation
+single_quote_char
single_quote_literal
+interpolation
# text_literal
-# if
-# then
-# else
-# let
-# in
-# as
-# using
-# merge
-missing
-# if_
+if_
# then
# else_
# let_
-# in_
+in_
# as_
# using
-# merge
+merge
+missing
# Infinity
+NaN
+Some
+# keyword
Optional
Text
List
-# equal
-# or
-# plus
-# text_append
-# list_append
-# and
-# times
-# double_equal
-# not_equal
-# dot
-# bar
-# comma
-# at
-# colon
-# import_alt
-# open_parens
-# close_parens
-# close_parens
-# open_brace
-# close_brace
-# close_brace
-# open_bracket
-# close_bracket
-# close_bracket
-# open_angle
-# close_angle
-# close_angle
# combine
# combine_types
# prefer
-# lambda
-# forall
-# arrow
+lambda
+forall
+arrow
# exponent
+numeric_double_literal
+minus_infinity_literal
+plus_infinity_literal
double_literal
natural_literal
integer_literal
identifier
# path_character
# quoted_path_character
+unquoted_path_component
+quoted_path_component
path_component
path
# local
+parent_path
+here_path
+home_path
+absolute_path
scheme
http_raw
authority
@@ -108,7 +87,6 @@ authority
# reg_name
# pchar
query
-fragment
# pct_encoded
# unreserved
# sub_delims
@@ -121,17 +99,11 @@ import_type
hash
import_hashed
import
-# expression
-lambda_expression
-ifthenelse_expression
-let_expression
-forall_expression
-arrow_expression
-merge_expression
-# empty_list_or_optional
+expression
+annotated_expression
+let_binding
empty_collection
non_empty_optional
-annotated_expression
# operator_expression
import_alt_expression
or_expression
@@ -146,22 +118,24 @@ times_expression
equal_expression
not_equal_expression
application_expression
-# atomic_expression
# import_expression
selector_expression
selector
labels
-# primitive_expression
-literal_expression
+primitive_expression
# record_type_or_literal
empty_record_literal
empty_record_type
non_empty_record_type_or_literal
non_empty_record_type
+record_type_entry
non_empty_record_literal
+record_literal_entry
union_type_or_literal
empty_union_type
non_empty_union_type_or_literal
+union_literal_variant_value
+union_type_entry
+union_type_or_literal_variant_type
non_empty_list_literal
-# parenthesized_expression
# complete_expression