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_syntax/src/lib.rs | 1 + dhall_syntax/src/parser.rs | 153 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 129 insertions(+), 25 deletions(-) (limited to 'dhall_syntax') 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.2.3