diff options
Diffstat (limited to '')
-rw-r--r-- | pest_consume/src/lib.rs | 95 | ||||
-rw-r--r-- | pest_consume_macros/src/parse_children.rs | 27 |
2 files changed, 103 insertions, 19 deletions
diff --git a/pest_consume/src/lib.rs b/pest_consume/src/lib.rs index 6e4b2e3..70aee56 100644 --- a/pest_consume/src/lib.rs +++ b/pest_consume/src/lib.rs @@ -5,7 +5,7 @@ use pest::Span; pub use pest_consume_macros::{make_parser, parse_children}; /// Carries a pest Pair alongside custom user data. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ParseInput<'input, 'data, Rule, Data> where Rule: pest::RuleType, @@ -14,6 +14,16 @@ where user_data: &'data Data, } +/// Iterator over `ParseInput`s. It is created by `ParseInput::children`. +#[derive(Debug)] +pub struct ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + input: ParseInput<'input, 'data, Rule, Data>, + pairs: pest::iterators::Pairs<'input, Rule>, +} + impl<'input, 'data, Rule, Data> ParseInput<'input, 'data, Rule, Data> where Rule: pest::RuleType, @@ -50,6 +60,15 @@ where } None } + /// Return an iterator over the children of this input + // Can't use `-> impl Iterator` because of weird lifetime limitations + // (see https://github.com/rust-lang/rust/issues/61997). + pub fn children(&self) -> ParseInputs<'input, 'data, Rule, Data> { + ParseInputs { + input: self.clone(), + pairs: self.as_pair().clone().into_inner(), + } + } pub fn user_data(&self) -> &'data Data { self.user_data @@ -66,6 +85,28 @@ where pub fn as_rule(&self) -> Rule { self.pair.as_rule() } + pub fn as_rule_alias<T>(&self) -> String + where + T: PestConsumer<Rule = Rule>, + { + T::rule_alias(self.as_rule()) + } +} + +impl<'input, 'data, Rule, Data> ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + /// Create an error that points to the span of the input. + pub fn error(&self, message: String) -> Error<Rule> { + self.input.error(message) + } + pub fn aliased_rules<T>(&self) -> Vec<String> + where + T: PestConsumer<Rule = Rule>, + { + self.clone().map(|p| p.as_rule_alias::<T>()).collect() + } } /// Used by the macros. @@ -121,3 +162,55 @@ fn debug_pair<Rule: pest::RuleType>(pair: Pair<Rule>) -> String { aux(&mut s, 0, "".into(), pair); s } + +impl<'input, 'data, Rule, Data> Iterator + for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + type Item = ParseInput<'input, 'data, Rule, Data>; + + fn next(&mut self) -> Option<Self::Item> { + let child_pair = self.pairs.next()?; + let child = self.input.with_pair(child_pair); + Some(child) + } +} + +impl<'input, 'data, Rule, Data> DoubleEndedIterator + for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn next_back(&mut self) -> Option<Self::Item> { + let child_pair = self.pairs.next_back()?; + let child = self.input.with_pair(child_pair); + Some(child) + } +} + +// Manual impl to avoid stupid `Data: Clone` trait bound +impl<'input, 'data, Rule, Data> Clone for ParseInput<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn clone(&self) -> Self { + ParseInput { + pair: self.pair.clone(), + user_data: self.user_data, + } + } +} + +// Manual impl to avoid stupid `Data: Clone` trait bound +impl<'input, 'data, Rule, Data> Clone for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn clone(&self) -> Self { + ParseInputs { + input: self.input.clone(), + pairs: self.pairs.clone(), + } + } +} diff --git a/pest_consume_macros/src/parse_children.rs b/pest_consume_macros/src/parse_children.rs index d6474a7..8feef03 100644 --- a/pest_consume_macros/src/parse_children.rs +++ b/pest_consume_macros/src/parse_children.rs @@ -175,7 +175,7 @@ pub fn parse_children( ) -> Result<proc_macro2::TokenStream> { let input: ParseChildrenInput = syn::parse(input)?; - let i_children_rules = Ident::new("___children_rules", Span::call_site()); + let i_input_rules = Ident::new("___input_rules", Span::call_site()); let i_inputs = Ident::new("___inputs", Span::call_site()); let input_expr = &input.input_expr; @@ -186,29 +186,20 @@ pub fn parse_children( .collect::<Result<Vec<_>>>()?; Ok(quote!({ - let #i_children_rules: Vec<_> = #input_expr.as_pair() - .clone() - .into_inner() - .map(|p| p.as_rule()) - .map(<Self as pest_consume::PestConsumer>::rule_alias) - .collect(); - let #i_children_rules: Vec<&str> = #i_children_rules + #[allow(unused_mut)] + let mut #i_inputs = #input_expr; + + let #i_input_rules = #i_inputs.aliased_rules::<Self>(); + let #i_input_rules: Vec<&str> = #i_input_rules .iter() .map(String::as_str) .collect(); - #[allow(unused_mut)] - let mut #i_inputs = #input_expr - .as_pair() - .clone() - .into_inner() - .map(|p| #input_expr.with_pair(p)); - #[allow(unreachable_code)] - match #i_children_rules.as_slice() { + match #i_input_rules.as_slice() { #(#branches,)* - [..] => return Err(#input_expr.error( - format!("Unexpected children: {:?}", #i_children_rules) + [..] => return Err(#i_inputs.error( + format!("Unexpected children: {:?}", #i_input_rules) )), } })) |