From 640a36906361ef5ef98fb66fd37246f084739d25 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 20 Mar 2019 00:44:27 +0100 Subject: Handle simple parsing cases with new macros --- dhall_core/src/core.rs | 1 + dhall_core/src/lib.rs | 2 + dhall_core/src/parser.rs | 234 +++++++++++++++++++++++++---------------------- 3 files changed, 127 insertions(+), 110 deletions(-) (limited to 'dhall_core') diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index 32f9c85..e7c9f2a 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -199,6 +199,7 @@ impl From for InterpolatedText { } } +#[derive(Debug, Clone)] pub enum InterpolatedTextContents<'a, Note, Embed> { Text(&'a str), Expr(SubExpr), diff --git a/dhall_core/src/lib.rs b/dhall_core/src/lib.rs index c728a75..43c8d9a 100644 --- a/dhall_core/src/lib.rs +++ b/dhall_core/src/lib.rs @@ -1,4 +1,6 @@ #![feature(trace_macros)] +#![feature(slice_patterns)] +#![recursion_limit="128"] #![allow( clippy::many_single_char_names, clippy::should_implement_trait, diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 9a9560f..4bbb08a 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -77,33 +77,6 @@ enum IterMatchError { Other(T), // Allow other macros to inject their own errors } -/* Extends match_iter with typed matches. Takes a callback that determines - * when a capture matches. - * Returns `Result<_, IterMatchError<_>>`; errors returned by the callback will - * get propagated using IterMatchError::Other. - * - * Example: - * ``` - * macro_rules! callback { - * (@type_callback, positive, $x:expr) => { - * if $x >= 0 { Ok($x) } else { Err(()) } - * }; - * (@type_callback, negative, $x:expr) => { - * if $x <= 0 { Ok($x) } else { Err(()) } - * }; - * (@type_callback, any, $x:expr) => { - * Ok($x) - * }; - * } - * - * let vec = vec![-1, 2, 3]; - * - * match_iter_typed!(callback; vec.into_iter(); - * (x: positive, y?: negative, z: any) => { ... }, - * ) - * ``` - * -*/ macro_rules! match_iter_typed { // Collect untyped arguments to pass to match_iter! (@collect, ($($vars:tt)*), ($($args:tt)*), ($($acc:tt)*), ($x:ident : $ty:ident, $($rest:tt)*)) => { @@ -163,41 +136,6 @@ macro_rules! match_iter_typed { }; } -/* Extends match_iter and match_iter_typed with branching. - * Returns `Result<_, IterMatchError<_>>`; errors returned by the callback will - * get propagated using IterMatchError::Other. - * Allows multiple branches. The passed iterator must be Clone. - * Will check the branches in order, testing each branch using the callback macro provided. - * - * Example: - * ``` - * macro_rules! callback { - * (@type_callback, positive, $x:expr) => { - * if $x >= 0 { Ok($x) } else { Err(()) } - * }; - * (@type_callback, negative, $x:expr) => { - * if $x <= 0 { Ok($x) } else { Err(()) } - * }; - * (@type_callback, any, $x:expr) => { - * Ok($x) - * }; - * (@branch_callback, typed, $($args:tt)*) => { - * match_iter_typed!(callback; $($args)*) - * }; - * (@branch_callback, untyped, $($args:tt)*) => { - * match_iter!($($args)*) - * }; - * } - * - * let vec = vec![-1, 2, 3]; - * - * match_iter_branching!(branch_callback; vec.into_iter(); - * typed!(x: positive, y?: negative, z: any) => { ... }, - * untyped!(x, y, z) => { ... }, - * ) - * ``` - * -*/ macro_rules! match_iter_branching { (@noclone, $callback:ident; $arg:expr; $( $submac:ident!($($args:tt)*) => $body:expr ),* $(,)*) => { { @@ -263,6 +201,23 @@ macro_rules! match_pair { } }; + ($pair:expr; $( children!($($x:ident : $ty:ident),*) => $body:expr ),* $(,)*) => { + { + let pair = $pair; + let rule = pair.as_rule(); + let err = custom_parse_error(&pair, "No match found".to_owned()); + let parsed: Vec<_> = pair.into_inner().map(ParseWrapped::parse_any_fast).collect::>()?; + #[allow(unreachable_code)] + iter_patterns::match_vec!(parsed; + $( + [$(ParsedValue::$ty($x)),*] => { + $body + }, + )* + [x..] => panic!("Unexpected children while parsing rule '{:?}': {:?}", rule, x.collect::>()), + ).ok_or(err) + } + }; ($pair:expr; $($args:tt)*) => { { let pair = $pair; @@ -276,6 +231,23 @@ macro_rules! match_pair { } macro_rules! make_parser { + (@branch_rules, $pair:expr, ($($acc:tt)*), rule!( $name:ident<$o:ty>; $($args:tt)* ); $($rest:tt)*) => ( + make_parser!(@branch_rules, $pair, ($($acc)* Rule::$name => ParseWrapped::$name($pair),), $($rest)*) + ); + (@branch_rules, $pair:expr, ($($acc:tt)*), rule_group!( $name:ident<$o:ty>; $($ty:ident),* ); $($rest:tt)*) => ( + make_parser!(@branch_rules, $pair, ($($acc)* $( Rule::$ty => ParseUnwrapped::$ty($pair).map(ParsedValue::$name),)* ), $($rest)*) + ); + (@branch_rules, $pair:expr, ($($acc:tt)*), $submac:ident!( $name:ident<$o:ty>; $($args:tt)* ); $($rest:tt)*) => ( + make_parser!(@branch_rules, $pair, ($($acc)*), $($rest)*) + ); + (@branch_rules, $pair:expr, ($($acc:tt)*),) => ( + #[allow(unreachable_patterns)] + match $pair.as_rule() { + $($acc)* + r => Err(custom_parse_error(&$pair, format!("parse_any_fast: Unexpected {:?}", r))), + // [x..] => panic!("{:?}", x.collect::>()), + } + ); ($( $submac:ident!( $name:ident<$o:ty>; $($args:tt)* ); )*) => ( // #[allow(non_camel_case_types, dead_code)] // enum ParsedType { @@ -302,8 +274,10 @@ macro_rules! make_parser { struct ParseUnwrapped; #[allow(non_camel_case_types, dead_code)] + #[derive(Debug)] enum ParsedValue<'a> { $( $name($o), )* + parse_any(Box>), } impl<'a> ParsedValue<'a> { @@ -316,6 +290,31 @@ macro_rules! make_parser { } } )* + #[allow(non_snake_case, dead_code)] + fn parse_any(self) -> Box> { + match self { + ParsedValue::parse_any(x) => x, + x => Box::new(x), + } + } + #[allow(non_snake_case, dead_code)] + fn parse_any_fast(self) -> Box> { + self.parse_any() + } + } + + named!(parse_any>>; + // self!(x: parse_any_fast) => x, + $( + self!(x: $name) => Box::new(ParsedValue::$name(x)), + )* + ); + + impl ParseWrapped { + #[allow(non_snake_case, dead_code)] + fn parse_any_fast(pair: Pair) -> ParseResult { + make_parser!(@branch_rules, pair, (), $( $submac!( $name<$o>; $($args)* ); )*) + } } // fn do_the_parse(s: &str, r: Rule, ty: ParsedType) -> ParseResult { @@ -459,6 +458,8 @@ named!(raw_str<&'a str>; captured_str!(s) => s); named!(label