From 880321e9c44cd0ab3f13bd3f7152a60a2941951c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 23 Mar 2019 15:54:28 +0100 Subject: Improve error ergonomics in parser --- dhall_core/src/parser.rs | 115 +++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 9b73bfd..b4c1df4 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -110,9 +110,7 @@ macro_rules! match_pair { match_pair!(@make_child_match, ($pair, $($vars)*), ($($outer_acc)*), ($($acc)*, xs..), ($($rest_of_match)*) => { let xs = xs.map(|x| match x { ParsedValue::$ty(y) => Ok(y), - x => Err(custom_parse_error(&$pair, - format!("Unexpected child: {:?}", x) - )), + x => Err(format!("Unexpected child: {:?}", x)), }).collect::, _>>()?; let $x = xs.into_iter(); $body @@ -131,18 +129,15 @@ macro_rules! match_pair { (@make_matches, ($($vars:tt)*), ($($acc:tt)*), [$($args:tt)*] => $body:expr, $($rest:tt)*) => { match_pair!(@make_child_match, ($($vars)*), ($($acc)*), (), ($($args)*) => $body, $($rest)*) }; - (@make_matches, ($pair:expr, $parsed:expr), ($($acc:tt)*) $(,)*) => { + (@make_matches, ($pair:expr, $children:expr), ($($acc:tt)*) $(,)*) => { { - let pair = $pair.clone(); #[allow(unreachable_code)] - iter_patterns::match_vec!($parsed; + iter_patterns::match_vec!($children; $($acc)* [x..] => Err( - custom_parse_error(&pair, - format!("Unexpected children: {:?}", x.collect::>()) - ) + format!("Unexpected children: {:?}", x.collect::>()) )?, - ).ok_or_else(|| unreachable!()) + ).ok_or_else(|| -> String { unreachable!() }) } }; @@ -157,24 +152,19 @@ macro_rules! make_parser { (@filter, rule) => (true); (@filter, rule_group) => (false); - (@body, $pair:expr, $parsed:expr, rule!( $name:ident<$o:ty>; $($args:tt)* )) => ( - make_parser!(@body, $pair, $parsed, rule!( $name<$o> as $name; $($args)* )) + (@body, $pair:expr, $children:expr, rule!( $name:ident<$o:ty>; $($args:tt)* )) => ( + make_parser!(@body, $pair, $children, rule!( $name<$o> as $name; $($args)* )) ); - (@body, $pair:expr, $parsed:expr, rule!( $name:ident<$o:ty> as $group:ident; raw_pair!($x:pat) => $body:expr )) => ( { - let $x = $pair; - let res: $o = $body; - Ok(ParsedValue::$group(res)) - }); - (@body, $pair:expr, $parsed:expr, rule!( $name:ident<$o:ty> as $group:ident; captured_str!($x:pat) => $body:expr )) => ( { + (@body, $pair:expr, $children:expr, rule!( $name:ident<$o:ty> as $group:ident; captured_str!($x:pat) => $body:expr )) => ( { let $x = $pair.as_str(); let res: $o = $body; Ok(ParsedValue::$group(res)) }); - (@body, $pair:expr, $parsed:expr, rule!( $name:ident<$o:ty> as $group:ident; children!( $($args:tt)* ) )) => ( { - let res: $o = match_pair!(($pair, $parsed); $($args)*)?; + (@body, $pair:expr, $children:expr, rule!( $name:ident<$o:ty> as $group:ident; children!( $($args:tt)* ) )) => ( { + let res: $o = match_pair!(($pair, $children); $($args)*)?; Ok(ParsedValue::$group(res)) }); - (@body, $pair:expr, $parsed:expr, rule_group!( $name:ident<$o:ty> )) => ( + (@body, $pair:expr, $children:expr, rule_group!( $name:ident<$o:ty> )) => ( unreachable!() ); @@ -185,8 +175,20 @@ macro_rules! make_parser { $( $name($o), )* } + fn parse_any<'a>(pair: Pair<'a, Rule>, children: Vec>) -> Result, String> { + match pair.as_rule() { + $( + make_parser!(@pattern, $submac, $name) + if make_parser!(@filter, $submac) + => make_parser!(@body, pair, children, $submac!( $name<$o> $($args)* )) + , + )* + r => Err(format!("Unexpected {:?}", r)), + } + } + // Non-recursive implementation to avoid stack overflows - fn parse_any<'a>(initial_pair: Pair<'a, Rule>) -> ParseResult> { + fn do_parse<'a>(initial_pair: Pair<'a, Rule>) -> ParseResult> { enum StackFrame<'a> { Unprocessed(Pair<'a, Rule>), Processed(Pair<'a, Rule>, usize), @@ -211,17 +213,12 @@ macro_rules! make_parser { } } Processed(pair, n) => { - let mut parsed: Vec<_> = values_stack.split_off(values_stack.len() - n); - parsed.reverse(); - let val = match pair.as_rule() { - $( - make_parser!(@pattern, $submac, $name) - if make_parser!(@filter, $submac) - => make_parser!(@body, pair, parsed, $submac!( $name<$o> $($args)* )) - , - )* - r => Err(custom_parse_error(&pair, format!("parse_any: Unexpected {:?}", r))), - }?; + let mut children: Vec<_> = values_stack.split_off(values_stack.len() - n); + children.reverse(); + let val = match parse_any(pair.clone(), children) { + Ok(v) => v, + Err(msg) => Err(custom_parse_error(&pair, msg))?, + }; values_stack.push(val); } } @@ -255,7 +252,7 @@ fn can_be_shortcutted(rule: Rule) -> bool { } make_parser! { - rule!(EOI<()>; raw_pair!(_) => ()); + rule!(EOI<()>; captured_str!(_) => ()); rule!(simple_label