summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--dhall_generated_parser/src/dhall.pest.visibility6
-rw-r--r--dhall_syntax/Cargo.toml1
-rw-r--r--dhall_syntax/src/lib.rs1
-rw-r--r--dhall_syntax/src/parser.rs502
-rw-r--r--tests_buffer1
6 files changed, 288 insertions, 224 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c073fad..f754891 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -107,7 +107,6 @@ dependencies = [
"dhall_generated_parser 0.1.0",
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "improved_slice_patterns 2.0.0",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility
index 6fa5e01..dcebf45 100644
--- a/dhall_generated_parser/src/dhall.pest.visibility
+++ b/dhall_generated_parser/src/dhall.pest.visibility
@@ -106,7 +106,7 @@ unquoted_path_component
quoted_path_component
path_component
path
-# local
+local
parent_path
here_path
home_path
@@ -141,7 +141,7 @@ hash
import_hashed
import
expression
-annotated_expression
+# annotated_expression
let_binding
empty_list_literal
operator_expression
@@ -160,7 +160,7 @@ not_equal_expression
equivalent_expression
application_expression
first_application_expression
-# import_expression
+import_expression
selector_expression
selector
labels
diff --git a/dhall_syntax/Cargo.toml b/dhall_syntax/Cargo.toml
index 6a61b09..08d0195 100644
--- a/dhall_syntax/Cargo.toml
+++ b/dhall_syntax/Cargo.toml
@@ -16,4 +16,3 @@ either = "1.5.2"
take_mut = "0.2.2"
hex = "0.3.2"
dhall_generated_parser = { path = "../dhall_generated_parser" }
-improved_slice_patterns = { version = "2.0.0", path = "../improved_slice_patterns" }
diff --git a/dhall_syntax/src/lib.rs b/dhall_syntax/src/lib.rs
index 4566e64..e4a6077 100644
--- a/dhall_syntax/src/lib.rs
+++ b/dhall_syntax/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(slice_patterns)]
#![feature(try_blocks)]
#![feature(never_type)]
+#![feature(bind_by_move_pattern_guards)]
#![allow(
clippy::many_single_char_names,
clippy::should_implement_trait,
diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs
index bcaa00e..4da1dfc 100644
--- a/dhall_syntax/src/parser.rs
+++ b/dhall_syntax/src/parser.rs
@@ -119,124 +119,208 @@ fn debug_pair(pair: Pair<Rule>) -> String {
s
}
-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);
+macro_rules! parse_children {
+ // Variable length pattern with a common unary variant
+ (@match_forwards,
+ $parse_args:expr,
+ $iter:expr,
+ ($body:expr),
+ $variant:ident ($x:ident)..,
+ $($rest:tt)*
+ ) => {
+ parse_children!(@match_backwards,
+ $parse_args, $iter,
+ ({
+ let $x = $iter
+ .map(|x| Parsers::$variant($parse_args, x))
+ .collect::<Result<Vec<_>, _>>()?
+ .into_iter();
+ $body
+ }),
+ $($rest)*
+ )
+ };
+ // Single item pattern
+ (@match_forwards,
+ $parse_args:expr,
+ $iter:expr,
+ ($body:expr),
+ $variant:ident ($x:pat),
+ $($rest:tt)*
+ ) => {{
+ let p = $iter.next().unwrap();
+ let $x = Parsers::$variant($parse_args, p)?;
+ parse_children!(@match_forwards,
+ $parse_args, $iter,
+ ($body),
+ $($rest)*
+ )
+ }};
+ // Single item pattern after a variable length one: declare reversed and take from the end
+ (@match_backwards,
+ $parse_args:expr,
+ $iter:expr,
+ ($body:expr),
+ $variant:ident ($x:pat),
+ $($rest:tt)*
+ ) => {
+ parse_children!(@match_backwards, $parse_args, $iter, ({
+ let p = $iter.next_back().unwrap();
+ let $x = Parsers::$variant($parse_args, p)?;
+ $body
+ }), $($rest)*)
+ };
- (@construct_climber,
- ($map:expr),
- rule!(
- $name:ident<$o:ty>
- as $group:ident;
- prec_climb!( $climber:expr, $($_rest:tt)* )
+ // Check no elements remain
+ (@match_forwards, $parse_args:expr, $iter:expr, ($body:expr) $(,)*) => {
+ $body
+ };
+ // After a variable length pattern, everything has already been consumed
+ (@match_backwards, $parse_args:expr, $iter:expr, ($body:expr) $(,)*) => {
+ $body
+ };
+
+ ($parse_args:expr, $iter:expr; [$($args:tt)*] => $body:expr) => {
+ parse_children!(@match_forwards,
+ $parse_args, $iter,
+ ($body),
+ $($args)*,
)
- ) => ({
- $map.insert(Rule::$name, $climber)
- });
- (@construct_climber, ($($things:tt)*), $($args:tt)*) => (());
+ };
+}
+
+macro_rules! make_parser {
+ (@children_pattern,
+ $varpat:ident,
+ ($($acc:tt)*),
+ [$variant:ident ($x:pat), $($rest:tt)*]
+ ) => (
+ make_parser!(@children_pattern,
+ $varpat,
+ ($($acc)* , Rule::$variant),
+ [$($rest)*]
+ )
+ );
+ (@children_pattern,
+ $varpat:ident,
+ ($($acc:tt)*),
+ [$variant:ident ($x:ident).., $($rest:tt)*]
+ ) => (
+ make_parser!(@children_pattern,
+ $varpat,
+ ($($acc)* , $varpat..),
+ [$($rest)*]
+ )
+ );
+ (@children_pattern,
+ $varpat:ident,
+ (, $($acc:tt)*), [$(,)*]
+ ) => ([$($acc)*]);
+ (@children_pattern,
+ $varpat:ident,
+ ($($acc:tt)*), [$(,)*]
+ ) => ([$($acc)*]);
+
+ (@children_filter,
+ $varpat:ident,
+ [$variant:ident ($x:pat), $($rest:tt)*]
+ ) => (
+ make_parser!(@children_filter, $varpat, [$($rest)*])
+ );
+ (@children_filter,
+ $varpat:ident,
+ [$variant:ident ($x:ident).., $($rest:tt)*]
+ ) => (
+ $varpat.iter().all(|r| r == &Rule::$variant) &&
+ make_parser!(@children_filter, $varpat, [$($rest)*])
+ );
+ (@children_filter, $varpat:ident, [$(,)*]) => (true);
(@body,
($climbers:expr, $input:expr, $pair:expr),
rule!(
- $name:ident<$o:ty>
- as $group:ident;
+ $name:ident<$o:ty>;
$span:ident;
captured_str!($x:pat) => $body:expr
)
) => ({
- let res: Result<_, String> = try {
- let $span = Span::make($input, $pair.as_span());
- let $x = $pair.as_str();
- ParsedValue::$group($body)
- };
+ let $span = Span::make($input.clone(), $pair.as_span());
+ let $x = $pair.as_str();
+ let res: Result<_, String> = try { $body };
res.map_err(|msg| custom_parse_error(&$pair, msg))
});
(@body,
($climbers:expr, $input:expr, $pair:expr),
rule!(
- $name:ident<$o:ty>
- as $group:ident;
+ $name:ident<$o:ty>;
$span:ident;
children!( $( [$($args:tt)*] => $body:expr ),* $(,)* )
)
) => ({
- let children: Vec<_> = $pair
+ let children_rules: Vec<Rule> = $pair
.clone()
.into_inner()
- .map(|p| parse_any($climbers, $input.clone(), p))
- .collect::<Result<_, _>>()?;
+ .map(|p| p.as_rule())
+ .collect();
- #[allow(unreachable_code)]
- let res: Result<_, String> = try {
- #[allow(unused_imports)]
- use ParsedValue::*;
- let $span = Span::make($input, $pair.as_span());
-
- improved_slice_patterns::match_vec!(children;
- $( [$($args)*] => $body, )*
- [x..] => Err(
- format!("Unexpected children: {:?}", x.collect::<Vec<_>>())
- )?,
- ).map_err(|_| -> String { unreachable!() })?
- };
+ let $span = Span::make($input.clone(), $pair.as_span());
+ #[allow(unused_mut)]
+ let mut iter = $pair.clone().into_inner();
- let res = res.map_err(|msg| custom_parse_error(&$pair, msg))?;
- Ok(ParsedValue::$group(res))
+ #[allow(unreachable_code)]
+ match children_rules.as_slice() {
+ $(
+ make_parser!(@children_pattern, x, (), [$($args)*,])
+ if make_parser!(@children_filter, x, [$($args)*,])
+ => {
+ parse_children!(($climbers, $input.clone()), iter;
+ [$($args)*] => {
+ let res: Result<_, String> = try { $body };
+ res.map_err(|msg| custom_parse_error(&$pair, msg))
+ }
+ )
+ }
+ ,
+ )*
+ [..] => Err(custom_parse_error(
+ &$pair,
+ format!("Unexpected children: {:?}", children_rules)
+ )),
+ }
});
(@body,
($climbers:expr, $input:expr, $pair:expr),
rule!(
- $name:ident<$o:ty>
- as $group:ident;
- prec_climb!( $_climber:expr, $args:pat => $body:expr $(,)* )
+ $name:ident<$o:ty>;
+ prec_climb!(
+ $other_rule:ident,
+ $_climber:expr,
+ $args:pat => $body:expr $(,)*
+ )
)
) => ({
let climber = $climbers.get(&Rule::$name).unwrap();
climber.climb(
$pair.clone().into_inner(),
- |p| parse_any($climbers, $input.clone(), p),
+ |p| Parsers::$other_rule(($climbers, $input.clone()), p),
|l, op, r| {
- let (l, r) = (l?, r?);
- let res: Result<_, String> = try {
- #[allow(unused_imports)]
- use ParsedValue::*;
- match (l, op, r) {
- $args => ParsedValue::$group($body),
- children => Err(
- format!("Unexpected children: {:?}", children)
- )?,
- }
- };
+ let $args = (l?, op, r?);
+ let res: Result<_, String> = try { $body };
res.map_err(|msg| custom_parse_error(&$pair, msg))
},
)
});
(@body,
($($things:tt)*),
- rule!( $name:ident<$o:ty>; $($args:tt)* )
- ) => (
- make_parser!(@body,
- ($($things)*),
- rule!( $name<$o> as $name; $($args)* )
- )
- );
- (@body,
- ($($things:tt)*),
rule!(
- $name:ident<$o:ty>
- as $group:ident;
+ $name:ident<$o:ty>;
$($args:tt)*
)
) => ({
make_parser!(@body,
($($things)*),
rule!(
- $name<$o>
- as $group;
+ $name<$o>;
_span;
$($args)*
)
@@ -244,19 +328,36 @@ macro_rules! make_parser {
});
(@body,
($($things:tt)*),
- token_rule!($name:ident<$o:ty>)
+ rule!($name:ident<$o:ty>)
) => ({
- Ok(ParsedValue::$name(()))
+ Ok(())
});
- (@body, ($($things:tt)*), rule_group!( $name:ident<$o:ty> )) => (
- unreachable!()
- );
+
+ (@construct_climber,
+ ($map:expr),
+ rule!(
+ $name:ident<$o:ty>;
+ prec_climb!($other_rule:ident, $climber:expr, $($_rest:tt)* )
+ )
+ ) => ({
+ $map.insert(Rule::$name, $climber)
+ });
+ (@construct_climber, ($($things:tt)*), $($args:tt)*) => (());
($( $submac:ident!( $name:ident<$o:ty> $($args:tt)* ); )*) => (
- #[allow(non_camel_case_types, dead_code, clippy::large_enum_variant)]
- #[derive(Debug)]
- enum ParsedValue<'a> {
- $( $name($o), )*
+ struct Parsers;
+
+ impl Parsers {
+ $(
+ #[allow(non_snake_case, unused_variables)]
+ fn $name<'a>(
+ (climbers, input): (&HashMap<Rule, PrecClimber<Rule>>, Rc<str>),
+ pair: Pair<'a, Rule>,
+ ) -> ParseResult<$o> {
+ make_parser!(@body, (climbers, input, pair),
+ $submac!( $name<$o> $($args)* ))
+ }
+ )*
}
fn construct_precclimbers() -> HashMap<Rule, PrecClimber<Rule>> {
@@ -268,81 +369,23 @@ macro_rules! make_parser {
map
}
- struct Parsers;
+ struct EntryPoint;
- impl Parsers {
+ impl EntryPoint {
$(
- #[allow(non_snake_case, unused_variables)]
+ #[allow(non_snake_case, dead_code)]
fn $name<'a>(
- climbers: &HashMap<Rule, PrecClimber<Rule>>,
input: Rc<str>,
pair: Pair<'a, Rule>,
- ) -> ParseResult<ParsedValue<'a>> {
- make_parser!(@body, (climbers, input, pair),
- $submac!( $name<$o> $($args)* ))
+ ) -> ParseResult<$o> {
+ let climbers = construct_precclimbers();
+ Parsers::$name((&climbers, input), pair)
}
)*
}
-
- fn parse_any<'a>(
- climbers: &HashMap<Rule, PrecClimber<Rule>>,
- input: Rc<str>,
- mut pair: Pair<'a, Rule>,
- ) -> ParseResult<ParsedValue<'a>> {
- // Avoid parsing while the pair has exactly one child that can be returned as-is
- loop {
- if can_be_shortcutted(pair.as_rule()) {
- let mut i = pair.clone().into_inner();
- let first = i.next();
- let second = i.next();
- match (first, second) {
- // If pair has exactly one child, just go on parsing that child
- (Some(p), None) => {
- pair = p;
- continue;
- }
- // Otherwise parse normally
- _ => break,
- }
- }
- break;
- }
-
- match pair.as_rule() {
- $(
- make_parser!(@pattern, $submac, $name)
- if make_parser!(@filter, $submac)
- => Parsers::$name(climbers, input, pair)
- ,
- )*
- r => Err(custom_parse_error(&pair, format!("Unexpected {:?}", r))),
- }
- }
);
}
-fn do_parse<'a>(
- input: Rc<str>,
- pair: Pair<'a, Rule>,
-) -> ParseResult<ParsedValue<'a>> {
- let climbers = construct_precclimbers();
- parse_any(&climbers, input, pair)
-}
-
-// List of rules that can be shortcutted if they have a single child
-fn can_be_shortcutted(rule: Rule) -> bool {
- use Rule::*;
- match rule {
- expression
- | operator_expression
- | application_expression
- | first_application_expression
- | selector_expression
- | annotated_expression => true,
- _ => false,
- }
-}
-
// Trim the shared indent off of a vec of lines, as defined by the Dhall semantics of multiline
// literals.
fn trim_indent(lines: &mut Vec<ParsedText>) {
@@ -385,7 +428,7 @@ fn trim_indent(lines: &mut Vec<ParsedText>) {
}
make_parser! {
- token_rule!(EOI<()>);
+ rule!(EOI<()>);
rule!(simple_label<Label>;
captured_str!(s) => Label::from(s.trim().to_owned())
@@ -502,10 +545,10 @@ make_parser! {
rule!(single_quote_char<&'a str>;
captured_str!(s) => s
);
- rule!(escaped_quote_pair<&'a str> as single_quote_char;
+ rule!(escaped_quote_pair<&'a str>;
captured_str!(_) => "''"
);
- rule!(escaped_interpolation<&'a str> as single_quote_char;
+ rule!(escaped_interpolation<&'a str>;
captured_str!(_) => "${"
);
rule!(interpolation<ParsedSubExpr>; children!(
@@ -520,21 +563,29 @@ make_parser! {
lines.last_mut().unwrap().push(c);
lines
},
- [single_quote_char("\n"), single_quote_continue(lines)] => {
+ [escaped_quote_pair(c), single_quote_continue(lines)] => {
let mut lines = lines;
- lines.push(vec![]);
+ // TODO: don't allocate for every char
+ let c = InterpolatedTextContents::Text(c.to_owned());
+ lines.last_mut().unwrap().push(c);
lines
},
- [single_quote_char("\r\n"), single_quote_continue(lines)] => {
+ [escaped_interpolation(c), single_quote_continue(lines)] => {
let mut lines = lines;
- lines.push(vec![]);
+ // TODO: don't allocate for every char
+ let c = InterpolatedTextContents::Text(c.to_owned());
+ lines.last_mut().unwrap().push(c);
lines
},
[single_quote_char(c), single_quote_continue(lines)] => {
- // TODO: don't allocate for every char
- let c = InterpolatedTextContents::Text(c.to_owned());
let mut lines = lines;
- lines.last_mut().unwrap().push(c);
+ if c == "\n" || c == "\r\n" {
+ lines.push(vec![]);
+ } else {
+ // TODO: don't allocate for every char
+ let c = InterpolatedTextContents::Text(c.to_owned());
+ lines.last_mut().unwrap().push(c);
+ }
lines
},
[] => {
@@ -560,9 +611,9 @@ make_parser! {
}
);
- token_rule!(NaN<()>);
- token_rule!(minus_infinity_literal<()>);
- token_rule!(plus_infinity_literal<()>);
+ rule!(NaN<()>);
+ rule!(minus_infinity_literal<()>);
+ rule!(plus_infinity_literal<()>);
rule!(numeric_double_literal<core::Double>;
captured_str!(s) => {
@@ -599,7 +650,7 @@ make_parser! {
}
);
- rule!(identifier<ParsedSubExpr> as expression; span; children!(
+ rule!(identifier<ParsedSubExpr>; span; children!(
[variable(v)] => {
spanned(span, Var(v))
},
@@ -631,18 +682,23 @@ make_parser! {
}
));
- rule_group!(local<(FilePrefix, Vec<String>)>);
+ rule!(local<(FilePrefix, Vec<String>)>; children!(
+ [parent_path(l)] => l,
+ [here_path(l)] => l,
+ [home_path(l)] => l,
+ [absolute_path(l)] => l,
+ ));
- rule!(parent_path<(FilePrefix, Vec<String>)> as local; children!(
+ rule!(parent_path<(FilePrefix, Vec<String>)>; children!(
[path(p)] => (FilePrefix::Parent, p)
));
- rule!(here_path<(FilePrefix, Vec<String>)> as local; children!(
+ rule!(here_path<(FilePrefix, Vec<String>)>; children!(
[path(p)] => (FilePrefix::Here, p)
));
- rule!(home_path<(FilePrefix, Vec<String>)> as local; children!(
+ rule!(home_path<(FilePrefix, Vec<String>)>; children!(
[path(p)] => (FilePrefix::Home, p)
));
- rule!(absolute_path<(FilePrefix, Vec<String>)> as local; children!(
+ rule!(absolute_path<(FilePrefix, Vec<String>)>; children!(
[path(p)] => (FilePrefix::Absolute, p)
));
@@ -675,7 +731,7 @@ make_parser! {
rule!(http<URL<ParsedSubExpr>>; children!(
[http_raw(url)] => url,
- [http_raw(url), expression(e)] =>
+ [http_raw(url), import_expression(e)] =>
URL { headers: Some(e), ..url },
));
@@ -706,7 +762,7 @@ make_parser! {
}
);
- token_rule!(missing<()>);
+ rule!(missing<()>);
rule!(import_type<ImportLocation<ParsedSubExpr>>; children!(
[missing(_)] => {
@@ -740,10 +796,10 @@ make_parser! {
crate::Import {mode: ImportMode::Code, location, hash: Some(h) },
));
- token_rule!(Text<()>);
- token_rule!(Location<()>);
+ rule!(Text<()>);
+ rule!(Location<()>);
- rule!(import<ParsedSubExpr> as expression; span; children!(
+ rule!(import<ParsedSubExpr>; span; children!(
[import_hashed(imp)] => {
spanned(span, Import(crate::Import {
mode: ImportMode::Code,
@@ -764,21 +820,21 @@ make_parser! {
},
));
- token_rule!(lambda<()>);
- token_rule!(forall<()>);
- token_rule!(arrow<()>);
- token_rule!(merge<()>);
- token_rule!(assert<()>);
- token_rule!(if_<()>);
- token_rule!(in_<()>);
+ rule!(lambda<()>);
+ rule!(forall<()>);
+ rule!(arrow<()>);
+ rule!(merge<()>);
+ rule!(assert<()>);
+ rule!(if_<()>);
+ rule!(in_<()>);
- rule!(empty_list_literal<ParsedSubExpr> as expression; span; children!(
- [expression(e)] => {
+ rule!(empty_list_literal<ParsedSubExpr>; span; children!(
+ [application_expression(e)] => {
spanned(span, EmptyListLit(e))
},
));
- rule!(expression<ParsedSubExpr> as expression; span; children!(
+ rule!(expression<ParsedSubExpr>; span; children!(
[lambda(()), label(l), expression(typ),
arrow(()), expression(body)] => {
spanned(span, Lam(l, typ, body))
@@ -796,16 +852,21 @@ make_parser! {
arrow(()), expression(body)] => {
spanned(span, Pi(l, typ, body))
},
- [expression(typ), arrow(()), expression(body)] => {
+ [operator_expression(typ), arrow(()), expression(body)] => {
spanned(span, Pi("_".into(), typ, body))
},
- [merge(()), expression(x), expression(y), expression(z)] => {
+ [merge(()), import_expression(x), import_expression(y),
+ application_expression(z)] => {
spanned(span, Merge(x, y, Some(z)))
},
+ [empty_list_literal(e)] => e,
[assert(()), expression(x)] => {
spanned(span, Assert(x))
},
- [expression(e)] => e,
+ [operator_expression(e)] => e,
+ [operator_expression(e), expression(annot)] => {
+ spanned(span, Annot(e, annot))
+ },
));
rule!(let_binding<(Label, Option<ParsedSubExpr>, ParsedSubExpr)>;
@@ -816,17 +877,11 @@ make_parser! {
(name, None, expr),
));
- token_rule!(List<()>);
- token_rule!(Optional<()>);
+ rule!(List<()>);
+ rule!(Optional<()>);
- rule!(annotated_expression<ParsedSubExpr> as expression; span; children!(
- [expression(e)] => e,
- [expression(e), expression(annot)] => {
- spanned(span, Annot(e, annot))
- },
- ));
-
- rule!(operator_expression<ParsedSubExpr> as expression; prec_climb!(
+ rule!(operator_expression<ParsedSubExpr>; prec_climb!(
+ application_expression,
{
use Rule::*;
// In order of precedence
@@ -852,7 +907,7 @@ make_parser! {
.collect(),
)
},
- (expression(l), op, expression(r)) => {
+ (l, op, r) => {
use crate::BinOp::*;
use Rule::*;
let op = match op.as_rule() {
@@ -878,35 +933,41 @@ make_parser! {
}
));
- token_rule!(Some_<()>);
- token_rule!(toMap<()>);
+ rule!(Some_<()>);
+ rule!(toMap<()>);
- rule!(application_expression<ParsedSubExpr> as expression; children!(
- [expression(e)] => e,
- [expression(first), expression(rest)..] => {
+ rule!(application_expression<ParsedSubExpr>; children!(
+ [first_application_expression(e)] => e,
+ [first_application_expression(first), import_expression(rest)..] => {
rest.fold(first, |acc, e| unspanned(App(acc, e)))
},
));
- rule!(first_application_expression<ParsedSubExpr> as expression; span;
+ rule!(first_application_expression<ParsedSubExpr>; span;
children!(
- [expression(e)] => e,
- [Some_(()), expression(e)] => {
+ [Some_(()), import_expression(e)] => {
spanned(span, SomeLit(e))
},
- [merge(()), expression(x), expression(y)] => {
+ [merge(()), import_expression(x), import_expression(y)] => {
spanned(span, Merge(x, y, None))
},
+ [import_expression(e)] => e,
));
- rule!(selector_expression<ParsedSubExpr> as expression; children!(
- [expression(e)] => e,
- [expression(first), selector(rest)..] => {
+ rule!(import_expression<ParsedSubExpr>; span;
+ children!(
+ [selector_expression(e)] => e,
+ [import(e)] => e,
+ ));
+
+ rule!(selector_expression<ParsedSubExpr>; children!(
+ [primitive_expression(e)] => e,
+ [primitive_expression(first), selector(rest)..] => {
rest.fold(first, |acc, e| unspanned(match e {
Either::Left(l) => Field(acc, l),
Either::Right(ls) => Projection(acc, ls),
}))
- }
+ },
));
rule!(selector<Either<Label, DupTreeSet<Label>>>; children!(
@@ -919,24 +980,30 @@ make_parser! {
[label(ls)..] => ls.collect(),
));
- rule!(primitive_expression<ParsedSubExpr> as expression; span; children!(
+ rule!(primitive_expression<ParsedSubExpr>; span; children!(
[double_literal(n)] => spanned(span, DoubleLit(n)),
[natural_literal(n)] => spanned(span, NaturalLit(n)),
[integer_literal(n)] => spanned(span, IntegerLit(n)),
[double_quote_literal(s)] => spanned(span, TextLit(s)),
[single_quote_literal(s)] => spanned(span, TextLit(s)),
+ [empty_record_type(e)] => e,
+ [empty_record_literal(e)] => e,
+ [non_empty_record_type_or_literal(e)] => e,
+ [union_type(e)] => e,
+ [non_empty_list_literal(e)] => e,
+ [identifier(e)] => e,
[expression(e)] => e,
));
- rule!(empty_record_literal<ParsedSubExpr> as expression; span;
+ rule!(empty_record_literal<ParsedSubExpr>; span;
captured_str!(_) => spanned(span, RecordLit(Default::default()))
);
- rule!(empty_record_type<ParsedSubExpr> as expression; span;
+ rule!(empty_record_type<ParsedSubExpr>; span;
captured_str!(_) => spanned(span, RecordType(Default::default()))
);
- rule!(non_empty_record_type_or_literal<ParsedSubExpr> as expression; span;
+ rule!(non_empty_record_type_or_literal<ParsedSubExpr>; span;
children!(
[label(first_label), non_empty_record_type(rest)] => {
let (first_expr, mut map) = rest;
@@ -972,7 +1039,7 @@ make_parser! {
[label(name), expression(expr)] => (name, expr)
));
- rule!(union_type<ParsedSubExpr> as expression; span; children!(
+ rule!(union_type<ParsedSubExpr>; span; children!(
[empty_union_type(_)] => {
spanned(span, UnionType(Default::default()))
},
@@ -981,14 +1048,14 @@ make_parser! {
},
));
- token_rule!(empty_union_type<()>);
+ rule!(empty_union_type<()>);
rule!(union_type_entry<(Label, Option<ParsedSubExpr>)>; children!(
[label(name), expression(expr)] => (name, Some(expr)),
[label(name)] => (name, None),
));
- rule!(non_empty_list_literal<ParsedSubExpr> as expression; span;
+ rule!(non_empty_list_literal<ParsedSubExpr>; span;
children!(
[expression(items)..] => spanned(
span,
@@ -996,7 +1063,7 @@ make_parser! {
)
));
- rule!(final_expression<ParsedSubExpr> as expression; children!(
+ rule!(final_expression<ParsedSubExpr>; children!(
[expression(e), EOI(_eoi)] => e
));
}
@@ -1004,10 +1071,7 @@ make_parser! {
pub fn parse_expr(s: &str) -> ParseResult<ParsedSubExpr> {
let mut pairs = DhallParser::parse(Rule::final_expression, s)?;
let rc_input = s.to_string().into();
- let expr = do_parse(rc_input, pairs.next().unwrap())?;
+ let expr = EntryPoint::final_expression(rc_input, pairs.next().unwrap())?;
assert_eq!(pairs.next(), None);
- match expr {
- ParsedValue::expression(e) => Ok(e),
- _ => unreachable!(),
- }
+ Ok(expr)
}
diff --git a/tests_buffer b/tests_buffer
index 1ad880e..67de9eb 100644
--- a/tests_buffer
+++ b/tests_buffer
@@ -9,6 +9,7 @@ success/
PrecedenceAll2 a b != c == d * e ⩓ f ⫽ g ∧ h && i # j ++ k + l || m ? n
LetNoAnnot let x = y in e
LetAnnot let x: T = y in e
+ EmptyRecordLiteral {=}
failure/
AssertNoAnnotation assert