From 66260f8e386f7a447352bd8ccbda064b00b698bc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 23:44:52 +0200 Subject: Implement inline headers parsing --- dhall_generated_parser/build.rs | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'dhall_generated_parser') diff --git a/dhall_generated_parser/build.rs b/dhall_generated_parser/build.rs index 5275097..070aa9c 100644 --- a/dhall_generated_parser/build.rs +++ b/dhall_generated_parser/build.rs @@ -26,16 +26,15 @@ fn main() -> std::io::Result<()> { rules.get_mut(&line[2..]).map(|x| x.silent = true); } } - rules.remove("http"); - rules.remove("url_path"); - rules.remove("simple_label"); - rules.remove("nonreserved_label"); let mut file = File::create(pest_path)?; writeln!(&mut file, "// AUTO-GENERATED FILE. See build.rs.")?; - writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; - writeln!(&mut file)?; + // TODO: this is a cheat; properly support RFC3986 URLs instead + rules.remove("url_path"); + writeln!(&mut file, "url_path = _{{ path }}")?; + + rules.remove("simple_label"); writeln!( &mut file, "simple_label = {{ @@ -43,30 +42,23 @@ fn main() -> std::io::Result<()> { | !keyword ~ simple_label_first_char ~ simple_label_next_char* }}" )?; - // TODO: this is a cheat; actually implement inline headers instead - writeln!( - &mut file, - "http = {{ - http_raw - ~ (whsp - ~ using - ~ whsp1 - ~ (import_hashed | ^\"(\" ~ whsp ~ import_hashed ~ whsp ~ ^\")\"))? - }}" - )?; - // TODO: this is a cheat; properly support RFC3986 URLs instead - writeln!(&mut file, "url_path = _{{ path }}")?; + + rules.remove("nonreserved_label"); writeln!( &mut file, "nonreserved_label = _{{ !(builtin ~ !simple_label_next_char) ~ label }}" )?; + writeln!( &mut file, "final_expression = ${{ SOI ~ complete_expression ~ EOI }}" )?; + writeln!(&mut file)?; + writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; + // Generate pest parser manually to avoid spurious recompilations let derived = { let pest_path = "dhall.pest"; -- cgit v1.3.1 From e4bdadabeda8ff8dbae0376f9d1c25478b8c8821 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 15 Aug 2019 15:33:53 +0200 Subject: Use precedence climbing to parse expressions with operators This speeds up parsing around 30% --- dhall/build.rs | 5 +- dhall_generated_parser/build.rs | 31 ++++ dhall_generated_parser/src/dhall.pest.visibility | 10 +- dhall_syntax/src/parser.rs | 227 +++++++++++------------ 4 files changed, 147 insertions(+), 126 deletions(-) (limited to 'dhall_generated_parser') diff --git a/dhall/build.rs b/dhall/build.rs index cbda288..2305208 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -91,8 +91,9 @@ fn main() -> std::io::Result<()> { let mut file = File::create(parser_tests_path)?; make_test_module(&mut file, "parse", "parser/", "Parser", |path| { - // Too slow in debug mode - path == "success/largeExpression" + false + // Too slow in debug mode + || path == "success/largeExpression" // TODO: projection by expression || path == "success/recordProjectionByExpression" || path == "success/RecordProjectionByType" diff --git a/dhall_generated_parser/build.rs b/dhall_generated_parser/build.rs index 070aa9c..c562fad 100644 --- a/dhall_generated_parser/build.rs +++ b/dhall_generated_parser/build.rs @@ -51,6 +51,37 @@ fn main() -> std::io::Result<()> { }}" )?; + // Setup grammar for precedence climbing + rules.remove("operator_expression"); + writeln!(&mut file, r##" + import_alt = {{ "?" ~ whsp1 }} + bool_or = {{ "||" }} + natural_plus = {{ "+" ~ whsp1 }} + text_append = {{ "++" }} + list_append = {{ "#" }} + bool_and = {{ "&&" }} + natural_times = {{ "*" }} + bool_eq = {{ "==" }} + bool_ne = {{ "!=" }} + + operator = _{{ + equivalent | + bool_ne | + bool_eq | + natural_times | + combine_types | + prefer | + combine | + bool_and | + list_append | + text_append | + natural_plus | + bool_or | + import_alt + }} + operator_expression = {{ application_expression ~ (whsp ~ operator ~ whsp ~ application_expression)* }} + "##)?; + writeln!( &mut file, "final_expression = ${{ SOI ~ complete_expression ~ EOI }}" diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility index 6b4c974..6fa5e01 100644 --- a/dhall_generated_parser/src/dhall.pest.visibility +++ b/dhall_generated_parser/src/dhall.pest.visibility @@ -84,10 +84,10 @@ Location # Optional_fold # Optional_build # Text_show -# combine -# combine_types -# equivalent -# prefer +combine +combine_types +equivalent +prefer lambda forall arrow @@ -144,7 +144,7 @@ expression annotated_expression let_binding empty_list_literal -# operator_expression +operator_expression import_alt_expression or_expression plus_expression diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 8ecd0ab..5b213d1 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -1,5 +1,6 @@ use itertools::Itertools; use pest::iterators::Pair; +use pest::prec_climber as pcl; use pest::Parser; use std::borrow::Cow; use std::rc::Rc; @@ -219,7 +220,7 @@ macro_rules! make_parser { ); } -// Non-recursive implementation to avoid stack overflows +// (Mostly) non-recursive implementation to avoid stack overflows fn do_parse<'a>( input: Rc, initial_pair: Pair<'a, Rule>, @@ -232,30 +233,122 @@ fn do_parse<'a>( let mut pairs_stack: Vec = vec![Unprocessed(initial_pair.clone())]; let mut values_stack: Vec = vec![]; + + let operators = { + use Rule::*; + // In order of precedence + vec![ + import_alt, + bool_or, + natural_plus, + text_append, + list_append, + bool_and, + combine, + prefer, + combine_types, + natural_times, + bool_eq, + bool_ne, + equivalent, + ] + }; + let rule_to_binop = { + use crate::BinOp::*; + use Rule::*; + |r| { + Some(match r { + import_alt => ImportAlt, + bool_or => BoolOr, + natural_plus => NaturalPlus, + text_append => TextAppend, + list_append => ListAppend, + bool_and => BoolAnd, + combine => RecursiveRecordMerge, + prefer => RightBiasedRecordMerge, + combine_types => RecursiveRecordTypeMerge, + natural_times => NaturalTimes, + bool_eq => BoolEQ, + bool_ne => BoolNE, + equivalent => Equivalence, + _ => return None, + }) + } + }; + let climber = pcl::PrecClimber::new( + operators + .into_iter() + .map(|op| pcl::Operator::new(op, pcl::Assoc::Left)) + .collect(), + ); + while let Some(p) = pairs_stack.pop() { match p { Unprocessed(mut pair) => loop { - let mut pairs: Vec<_> = pair.clone().into_inner().collect(); - let n_children = pairs.len(); - if n_children == 1 && can_be_shortcutted(pair.as_rule()) { - pair = pairs.pop().unwrap(); - continue; + 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 + _ => {} + } + } + + // Use precedence climbing to parse operator_expression + if pair.as_rule() == Rule::operator_expression { + let val = climber.climb( + pair.clone().into_inner(), + |p| do_parse(input.clone(), p), + |l, p, r| { + let o = match rule_to_binop(p.as_rule()) { + Some(o) => o, + None => Err(custom_parse_error( + &pair, + format!( + "Rule {:?} isn't an operator", + p.as_rule() + ), + ))?, + }; + use ParsedValue::expression; + match (l?, r?) { + (expression(l), expression(r)) => { + Ok(expression(unspanned(BinOp(o, l, r)))) + } + (l, r) => Err(custom_parse_error( + &pair, + format!( + "Unexpected children: {:?}", + [l, r] + ), + ))?, + } + }, + )?; + values_stack.push(val); + break; } else { - pairs_stack.push(Processed(pair, n_children)); - pairs_stack - .extend(pairs.into_iter().map(StackFrame::Unprocessed)); + let n_children = pair.clone().into_inner().count(); + pairs_stack.push(Processed(pair.clone(), n_children)); + // Push the unparsed children onto the stack + pairs_stack.extend(pair.into_inner().map(Unprocessed)); break; } }, Processed(pair, n) => { + // Take as many values from the values stack as that pair had children. This + // means we get exactly the children of the pair, but now they are parsed. let mut children: Vec<_> = values_stack.split_off(values_stack.len() - n); children.reverse(); - let val = match parse_any(input.clone(), pair.clone(), children) - { - Ok(v) => v, - Err(msg) => Err(custom_parse_error(&pair, msg))?, - }; + let val = parse_any(input.clone(), pair.clone(), children) + .map_err(|msg| custom_parse_error(&pair, msg))?; values_stack.push(val); } } @@ -268,19 +361,7 @@ fn can_be_shortcutted(rule: Rule) -> bool { use Rule::*; match rule { expression - | import_alt_expression - | or_expression - | plus_expression - | text_append_expression - | list_append_expression - | and_expression - | combine_expression - | prefer_expression - | combine_types_expression - | times_expression - | equal_expression - | not_equal_expression - | equivalent_expression + | operator_expression | application_expression | first_application_expression | selector_expression @@ -765,98 +846,6 @@ make_parser! { token_rule!(List<()>); token_rule!(Optional<()>); - rule!(import_alt_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::ImportAlt; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(or_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::BoolOr; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(plus_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::NaturalPlus; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(text_append_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::TextAppend; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(list_append_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::ListAppend; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(and_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::BoolAnd; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(combine_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::RecursiveRecordMerge; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(prefer_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::RightBiasedRecordMerge; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(combine_types_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::RecursiveRecordTypeMerge; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(times_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::NaturalTimes; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(equal_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::BoolEQ; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(not_equal_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::BoolNE; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(equivalent_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { - let o = crate::BinOp::Equivalence; - rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e))) - }, - )); - rule!(annotated_expression as expression; span; children!( [expression(e)] => e, [expression(e), expression(annot)] => { -- cgit v1.3.1 From 8eb169713ea1220f2d515391c08d34509d75ab73 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 10:34:10 +0200 Subject: Match on rules in parser instead of on ParsedValues --- dhall_generated_parser/src/dhall.pest.visibility | 2 +- dhall_syntax/src/lib.rs | 1 + dhall_syntax/src/parser.rs | 153 +++++++++++++++++++---- 3 files changed, 130 insertions(+), 26 deletions(-) (limited to 'dhall_generated_parser') diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility index 6fa5e01..8235735 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 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..366103e 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -127,17 +127,75 @@ macro_rules! make_parser { (@filter, token_rule) => (true); (@filter, rule_group) => (false); - (@construct_climber, - ($map:expr), + (@child_pattern, + $varpat:ident, + ($($acc:tt)*), + [$variant:ident ($x:pat), $($rest:tt)*] + ) => ( + make_parser!(@child_pattern, + $varpat, + ($($acc)* , Rule::$variant), + [$($rest)*] + ) + ); + (@child_pattern, + $varpat:ident, + ($($acc:tt)*), + [$variant:ident ($x:ident).., $($rest:tt)*] + ) => ( + make_parser!(@child_pattern, + $varpat, + ($($acc)* , $varpat..), + [$($rest)*] + ) + ); + (@child_pattern, + $varpat:ident, + (, $($acc:tt)*), [$(,)*] + ) => ([$($acc)*]); + (@child_pattern, + $varpat:ident, + ($($acc:tt)*), [$(,)*] + ) => ([$($acc)*]); + + (@child_filter, + $varpat:ident, + [$variant:ident ($x:pat), $($rest:tt)*] + ) => ( + true && + make_parser!(@child_filter, $varpat, [$($rest)*]) + ); + (@child_filter, + $varpat:ident, + [$variant:ident ($x:ident).., $($rest:tt)*] + ) => ( + $varpat.iter().all(|r| r == &Rule::$variant) && + make_parser!(@child_filter, $varpat, [$($rest)*]) + ); + (@child_filter, $varpat:ident, [$(,)*]) => (true); + + (@rule_alias, + rule!( $name:ident<$o:ty>; $($args:tt)* ) + ) => ( + Rule::$name + ); + (@rule_alias, rule!( $name:ident<$o:ty> as $group:ident; - prec_climb!( $climber:expr, $($_rest:tt)* ) + $($args:tt)* ) ) => ({ - $map.insert(Rule::$name, $climber) + Rule::$group }); - (@construct_climber, ($($things:tt)*), $($args:tt)*) => (()); + (@rule_alias, + token_rule!($name:ident<$o:ty>) + ) => ({ + Rule::$name + }); + (@rule_alias, rule_group!( $name:ident<$o:ty> )) => ( + unreachable!() + ); (@body, ($climbers:expr, $input:expr, $pair:expr), @@ -169,19 +227,43 @@ macro_rules! make_parser { .into_inner() .map(|p| parse_any($climbers, $input.clone(), p)) .collect::>()?; + let children_rules: Vec = $pair + .clone() + .into_inner() + .map(|p| p.as_rule()) + .map(rule_alias) + .collect(); #[allow(unreachable_code)] let res: Result<_, String> = try { #[allow(unused_imports)] use ParsedValue::*; let $span = Span::make($input, $pair.as_span()); + #[allow(unused_mut)] + let mut iter = children.into_iter(); - improved_slice_patterns::match_vec!(children; - $( [$($args)*] => $body, )* - [x..] => Err( - format!("Unexpected children: {:?}", x.collect::>()) - )?, - ).map_err(|_| -> String { unreachable!() })? + match children_rules.as_slice() { + $( + make_parser!(@child_pattern, x, (), [$($args)*,]) + if make_parser!(@child_filter, x, [$($args)*,]) + => { + let ret = + improved_slice_patterns::destructure_iter!(iter; + [$($args)*] => $body + ); + match ret { + Some(x) => x, + None => Err({ + format!("Unexpected children: {:?}", children_rules) + })? + } + } + , + )* + [..] => Err({ + format!("Unexpected children: {:?}", children_rules) + })?, + } }; let res = res.map_err(|msg| custom_parse_error(&$pair, msg))?; @@ -252,6 +334,18 @@ macro_rules! make_parser { unreachable!() ); + (@construct_climber, + ($map:expr), + rule!( + $name:ident<$o:ty> + as $group:ident; + prec_climb!( $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)] @@ -284,6 +378,19 @@ macro_rules! make_parser { )* } + fn rule_alias(r: Rule) -> Rule { + match r { + $( + make_parser!(@pattern, $submac, $name) + if make_parser!(@filter, $submac) + => make_parser!(@rule_alias, + $submac!( $name<$o> $($args)* )) + , + )* + r => r, + } + } + fn parse_any<'a>( climbers: &HashMap>, input: Rc, @@ -520,21 +627,15 @@ make_parser! { lines.last_mut().unwrap().push(c); lines }, - [single_quote_char("\n"), single_quote_continue(lines)] => { - let mut lines = lines; - lines.push(vec![]); - lines - }, - [single_quote_char("\r\n"), single_quote_continue(lines)] => { - let mut lines = lines; - lines.push(vec![]); - 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 }, [] => { @@ -631,7 +732,9 @@ make_parser! { } )); - rule_group!(local<(FilePrefix, Vec)>); + rule!(local<(FilePrefix, Vec)>; children!( + [local(l)] => l + )); rule!(parent_path<(FilePrefix, Vec)> as local; children!( [path(p)] => (FilePrefix::Parent, p) -- cgit v1.3.1 From c13a100c36c3b54d76dba2207aa75fa6736ebadc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 26 Aug 2019 23:18:11 +0200 Subject: Remove rule aliasing --- dhall_generated_parser/src/dhall.pest.visibility | 2 +- dhall_syntax/src/parser.rs | 200 +++++++++++------------ tests_buffer | 1 + 3 files changed, 95 insertions(+), 108 deletions(-) (limited to 'dhall_generated_parser') diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility index 8235735..2ac7fe4 100644 --- a/dhall_generated_parser/src/dhall.pest.visibility +++ b/dhall_generated_parser/src/dhall.pest.visibility @@ -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/src/parser.rs b/dhall_syntax/src/parser.rs index d11eb18..2debc8b 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -174,12 +174,11 @@ macro_rules! make_parser { ); (@rule_alias, rule!( - $name:ident<$o:ty> - as $group:ident; + $name:ident<$o:ty>; $($args:tt)* ) ) => ({ - Rule::$group + Rule::$name }); (@rule_alias, token_rule!($name:ident<$o:ty>) @@ -190,8 +189,7 @@ macro_rules! make_parser { (@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 ) @@ -199,15 +197,14 @@ macro_rules! make_parser { let res: Result<_, String> = try { let $span = Span::make($input, $pair.as_span()); let $x = $pair.as_str(); - ParsedValue::$group($body) + ParsedValue::$name($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 ),* $(,)* ) ) @@ -257,27 +254,33 @@ macro_rules! make_parser { }; let res = res.map_err(|msg| custom_parse_error(&$pair, msg))?; - Ok(ParsedValue::$group(res)) + Ok(ParsedValue::$name(res)) }); (@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_name:ident, $_climber:expr, $args:pat => $body:expr $(,)* ) ) ) => ({ - let climber = $climbers.get(&Rule::$name).unwrap(); + let climber = $climbers.get(&Rule::$name).expect(&format!("UUUU: {:?}", $climbers)); climber.climb( $pair.clone().into_inner(), - |p| parse_any($climbers, $input.clone(), p), + |p| { + let parsed = parse_any($climbers, $input.clone(), p)?; + if let ParsedValue::$other_name(x) = parsed { + Ok(ParsedValue::$name(x)) + } else { + unreachable!() + } + }, |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), + $args => ParsedValue::$name($body), children => Err( format!("Unexpected children: {:?}", children) )?, @@ -289,26 +292,13 @@ macro_rules! make_parser { }); (@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; - $($args:tt)* + rule!( $name:ident<$o:ty>; $($args:tt)* ) ) => ({ make_parser!(@body, ($($things)*), rule!( - $name<$o> - as $group; + $name<$o>; _span; $($args)* ) @@ -324,9 +314,8 @@ macro_rules! make_parser { (@construct_climber, ($map:expr), rule!( - $name:ident<$o:ty> - as $group:ident; - prec_climb!( $climber:expr, $($_rest:tt)* ) + $name:ident<$o:ty>; + prec_climb!( $other_name:ident, $climber:expr, $($_rest:tt)* ) ) ) => ({ $map.insert(Rule::$name, $climber) @@ -379,27 +368,8 @@ macro_rules! make_parser { fn parse_any<'a>( climbers: &HashMap>, input: Rc, - mut pair: Pair<'a, Rule>, + pair: Pair<'a, Rule>, ) -> ParseResult> { - // 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() { $( Rule::$name => Parsers::$name(climbers, input, pair), @@ -418,20 +388,6 @@ fn do_parse<'a>( 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) { @@ -591,10 +547,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; children!( @@ -609,6 +565,20 @@ make_parser! { lines.last_mut().unwrap().push(c); lines }, + [escaped_quote_pair(c), single_quote_continue(lines)] => { + let mut lines = lines; + // TODO: don't allocate for every char + let c = InterpolatedTextContents::Text(c.to_owned()); + lines.last_mut().unwrap().push(c); + lines + }, + [escaped_interpolation(c), single_quote_continue(lines)] => { + let mut lines = lines; + // 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)] => { let mut lines = lines; if c == "\n" || c == "\r\n" { @@ -682,7 +652,7 @@ make_parser! { } ); - rule!(identifier as expression; span; children!( + rule!(identifier; span; children!( [variable(v)] => { spanned(span, Var(v)) }, @@ -715,19 +685,22 @@ make_parser! { )); rule!(local<(FilePrefix, Vec)>; children!( - [local(l)] => l + [parent_path(l)] => l, + [here_path(l)] => l, + [home_path(l)] => l, + [absolute_path(l)] => l, )); - rule!(parent_path<(FilePrefix, Vec)> as local; children!( + rule!(parent_path<(FilePrefix, Vec)>; children!( [path(p)] => (FilePrefix::Parent, p) )); - rule!(here_path<(FilePrefix, Vec)> as local; children!( + rule!(here_path<(FilePrefix, Vec)>; children!( [path(p)] => (FilePrefix::Here, p) )); - rule!(home_path<(FilePrefix, Vec)> as local; children!( + rule!(home_path<(FilePrefix, Vec)>; children!( [path(p)] => (FilePrefix::Home, p) )); - rule!(absolute_path<(FilePrefix, Vec)> as local; children!( + rule!(absolute_path<(FilePrefix, Vec)>; children!( [path(p)] => (FilePrefix::Absolute, p) )); @@ -760,7 +733,7 @@ make_parser! { rule!(http>; children!( [http_raw(url)] => url, - [http_raw(url), expression(e)] => + [http_raw(url), import_expression(e)] => URL { headers: Some(e), ..url }, )); @@ -828,7 +801,7 @@ make_parser! { token_rule!(Text<()>); token_rule!(Location<()>); - rule!(import as expression; span; children!( + rule!(import; span; children!( [import_hashed(imp)] => { spanned(span, Import(crate::Import { mode: ImportMode::Code, @@ -857,13 +830,13 @@ make_parser! { token_rule!(if_<()>); token_rule!(in_<()>); - rule!(empty_list_literal as expression; span; children!( - [expression(e)] => { + rule!(empty_list_literal; span; children!( + [application_expression(e)] => { spanned(span, EmptyListLit(e)) }, )); - rule!(expression as expression; span; children!( + rule!(expression; span; children!( [lambda(()), label(l), expression(typ), arrow(()), expression(body)] => { spanned(span, Lam(l, typ, body)) @@ -881,16 +854,17 @@ 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, + [annotated_expression(e)] => e, )); rule!(let_binding<(Label, Option, ParsedSubExpr)>; @@ -904,14 +878,14 @@ make_parser! { token_rule!(List<()>); token_rule!(Optional<()>); - rule!(annotated_expression as expression; span; children!( - [expression(e)] => e, - [expression(e), expression(annot)] => { + rule!(annotated_expression; span; children!( + [operator_expression(e)] => e, + [operator_expression(e), expression(annot)] => { spanned(span, Annot(e, annot)) }, )); - rule!(operator_expression as expression; prec_climb!( + rule!(operator_expression; prec_climb!(application_expression, { use Rule::*; // In order of precedence @@ -937,7 +911,7 @@ make_parser! { .collect(), ) }, - (expression(l), op, expression(r)) => { + (operator_expression(l), op, operator_expression(r)) => { use crate::BinOp::*; use Rule::*; let op = match op.as_rule() { @@ -966,32 +940,38 @@ make_parser! { token_rule!(Some_<()>); token_rule!(toMap<()>); - rule!(application_expression as expression; children!( - [expression(e)] => e, - [expression(first), expression(rest)..] => { + rule!(application_expression; 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 as expression; span; + rule!(first_application_expression; 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 as expression; children!( - [expression(e)] => e, - [expression(first), selector(rest)..] => { + rule!(import_expression; span; + children!( + [selector_expression(e)] => e, + [import(e)] => e, + )); + + rule!(selector_expression; 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>>; children!( @@ -1004,24 +984,30 @@ make_parser! { [label(ls)..] => ls.collect(), )); - rule!(primitive_expression as expression; span; children!( + rule!(primitive_expression; 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 as expression; span; + rule!(empty_record_literal; span; captured_str!(_) => spanned(span, RecordLit(Default::default())) ); - rule!(empty_record_type as expression; span; + rule!(empty_record_type; span; captured_str!(_) => spanned(span, RecordType(Default::default())) ); - rule!(non_empty_record_type_or_literal as expression; span; + rule!(non_empty_record_type_or_literal; span; children!( [label(first_label), non_empty_record_type(rest)] => { let (first_expr, mut map) = rest; @@ -1057,7 +1043,7 @@ make_parser! { [label(name), expression(expr)] => (name, expr) )); - rule!(union_type as expression; span; children!( + rule!(union_type; span; children!( [empty_union_type(_)] => { spanned(span, UnionType(Default::default())) }, @@ -1073,7 +1059,7 @@ make_parser! { [label(name)] => (name, None), )); - rule!(non_empty_list_literal as expression; span; + rule!(non_empty_list_literal; span; children!( [expression(items)..] => spanned( span, @@ -1081,7 +1067,7 @@ make_parser! { ) )); - rule!(final_expression as expression; children!( + rule!(final_expression; children!( [expression(e), EOI(_eoi)] => e )); } @@ -1092,7 +1078,7 @@ pub fn parse_expr(s: &str) -> ParseResult { let expr = do_parse(rc_input, pairs.next().unwrap())?; assert_eq!(pairs.next(), None); match expr { - ParsedValue::expression(e) => Ok(e), + ParsedValue::final_expression(e) => Ok(e), _ => unreachable!(), } } 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 -- cgit v1.3.1 From 7b891800afa932660bc889e43c41c5d8f805cdc2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Aug 2019 13:42:53 +0200 Subject: Rework parse macros to avoid the large ParsedValue enum --- Cargo.lock | 1 - dhall_generated_parser/src/dhall.pest.visibility | 2 +- dhall_syntax/Cargo.toml | 1 - dhall_syntax/src/parser.rs | 285 +++++++++++------------ 4 files changed, 140 insertions(+), 149 deletions(-) (limited to 'dhall_generated_parser') 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 2ac7fe4..dcebf45 100644 --- a/dhall_generated_parser/src/dhall.pest.visibility +++ b/dhall_generated_parser/src/dhall.pest.visibility @@ -141,7 +141,7 @@ hash import_hashed import expression -annotated_expression +# annotated_expression let_binding empty_list_literal operator_expression 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/parser.rs b/dhall_syntax/src/parser.rs index 2debc8b..8facb3e 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -119,6 +119,76 @@ fn debug_pair(pair: Pair) -> String { s } +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::, _>>()? + .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)*) + }; + + // 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)*, + ) + }; +} + macro_rules! make_parser { (@children_pattern, $varpat:ident, @@ -155,7 +225,6 @@ macro_rules! make_parser { $varpat:ident, [$variant:ident ($x:pat), $($rest:tt)*] ) => ( - true && make_parser!(@children_filter, $varpat, [$($rest)*]) ); (@children_filter, @@ -167,25 +236,6 @@ macro_rules! make_parser { ); (@children_filter, $varpat:ident, [$(,)*]) => (true); - (@rule_alias, - rule!( $name:ident<$o:ty>; $($args:tt)* ) - ) => ( - Rule::$name - ); - (@rule_alias, - rule!( - $name:ident<$o:ty>; - $($args:tt)* - ) - ) => ({ - Rule::$name - }); - (@rule_alias, - token_rule!($name:ident<$o:ty>) - ) => ({ - Rule::$name - }); - (@body, ($climbers:expr, $input:expr, $pair:expr), rule!( @@ -194,11 +244,9 @@ macro_rules! make_parser { 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::$name($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, @@ -209,90 +257,64 @@ macro_rules! make_parser { children!( $( [$($args:tt)*] => $body:expr ),* $(,)* ) ) ) => ({ - let children: Vec<_> = $pair - .clone() - .into_inner() - .map(|p| parse_any($climbers, $input.clone(), p)) - .collect::>()?; let children_rules: Vec = $pair .clone() .into_inner() .map(|p| p.as_rule()) - .map(rule_alias) .collect(); + let $span = Span::make($input.clone(), $pair.as_span()); + #[allow(unused_mut)] + let mut iter = $pair.clone().into_inner(); + #[allow(unreachable_code)] - let res: Result<_, String> = try { - #[allow(unused_imports)] - use ParsedValue::*; - let $span = Span::make($input, $pair.as_span()); - #[allow(unused_mut)] - let mut iter = children.into_iter(); - - match children_rules.as_slice() { - $( - make_parser!(@children_pattern, x, (), [$($args)*,]) - if make_parser!(@children_filter, x, [$($args)*,]) - => { - let ret = - improved_slice_patterns::destructure_iter!(iter; - [$($args)*] => $body - ); - match ret { - Some(x) => x, - None => Err({ - format!("Unexpected children: {:?}", children_rules) - })? + 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({ - format!("Unexpected children: {:?}", children_rules) - })?, - } - }; - - let res = res.map_err(|msg| custom_parse_error(&$pair, msg))?; - Ok(ParsedValue::$name(res)) + ) + } + , + )* + [..] => Err(custom_parse_error( + &$pair, + format!("Unexpected children: {:?}", children_rules) + )), + } }); (@body, ($climbers:expr, $input:expr, $pair:expr), rule!( $name:ident<$o:ty>; - prec_climb!($other_name:ident, $_climber:expr, $args:pat => $body:expr $(,)* ) + prec_climb!( + $other_rule:ident, + $_climber:expr, + $args:pat => $body:expr $(,)* + ) ) ) => ({ - let climber = $climbers.get(&Rule::$name).expect(&format!("UUUU: {:?}", $climbers)); + let climber = $climbers.get(&Rule::$name).unwrap(); climber.climb( $pair.clone().into_inner(), - |p| { - let parsed = parse_any($climbers, $input.clone(), p)?; - if let ParsedValue::$other_name(x) = parsed { - Ok(ParsedValue::$name(x)) - } else { - unreachable!() - } - }, + |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::$name($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)* + rule!( + $name:ident<$o:ty>; + $($args:tt)* ) ) => ({ make_parser!(@body, @@ -308,14 +330,14 @@ macro_rules! make_parser { ($($things:tt)*), token_rule!($name:ident<$o:ty>) ) => ({ - Ok(ParsedValue::$name(())) + Ok(()) }); (@construct_climber, ($map:expr), rule!( $name:ident<$o:ty>; - prec_climb!( $other_name:ident, $climber:expr, $($_rest:tt)* ) + prec_climb!($other_rule:ident, $climber:expr, $($_rest:tt)* ) ) ) => ({ $map.insert(Rule::$name, $climber) @@ -323,10 +345,19 @@ macro_rules! make_parser { (@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>, Rc), + pair: Pair<'a, Rule>, + ) -> ParseResult<$o> { + make_parser!(@body, (climbers, input, pair), + $submac!( $name<$o> $($args)* )) + } + )* } fn construct_precclimbers() -> HashMap> { @@ -338,56 +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>, input: Rc, pair: Pair<'a, Rule>, - ) -> ParseResult> { - make_parser!(@body, (climbers, input, pair), - $submac!( $name<$o> $($args)* )) + ) -> ParseResult<$o> { + let climbers = construct_precclimbers(); + Parsers::$name((&climbers, input), pair) } )* } - - fn rule_alias(r: Rule) -> Rule { - match r { - $( - Rule::$name => { - make_parser!(@rule_alias, $submac!($name<$o> $($args)*)) - } - )* - r => r, - } - } - - fn parse_any<'a>( - climbers: &HashMap>, - input: Rc, - pair: Pair<'a, Rule>, - ) -> ParseResult> { - match pair.as_rule() { - $( - Rule::$name => Parsers::$name(climbers, input, pair), - )* - r => Err(custom_parse_error(&pair, format!("Unexpected {:?}", r))), - } - } ); } -fn do_parse<'a>( - input: Rc, - pair: Pair<'a, Rule>, -) -> ParseResult> { - let climbers = construct_precclimbers(); - parse_any(&climbers, input, pair) -} - // 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) { @@ -857,14 +855,18 @@ make_parser! { [operator_expression(typ), arrow(()), expression(body)] => { spanned(span, Pi("_".into(), typ, body)) }, - [merge(()), import_expression(x), import_expression(y), application_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)) }, - [annotated_expression(e)] => e, + [operator_expression(e)] => e, + [operator_expression(e), expression(annot)] => { + spanned(span, Annot(e, annot)) + }, )); rule!(let_binding<(Label, Option, ParsedSubExpr)>; @@ -878,14 +880,8 @@ make_parser! { token_rule!(List<()>); token_rule!(Optional<()>); - rule!(annotated_expression; span; children!( - [operator_expression(e)] => e, - [operator_expression(e), expression(annot)] => { - spanned(span, Annot(e, annot)) - }, - )); - - rule!(operator_expression; prec_climb!(application_expression, + rule!(operator_expression; prec_climb!( + application_expression, { use Rule::*; // In order of precedence @@ -911,7 +907,7 @@ make_parser! { .collect(), ) }, - (operator_expression(l), op, operator_expression(r)) => { + (l, op, r) => { use crate::BinOp::*; use Rule::*; let op = match op.as_rule() { @@ -1075,10 +1071,7 @@ make_parser! { pub fn parse_expr(s: &str) -> ParseResult { 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::final_expression(e) => Ok(e), - _ => unreachable!(), - } + Ok(expr) } -- cgit v1.3.1