diff options
Diffstat (limited to '')
-rw-r--r-- | pest_consume/src/lib.rs | 302 | ||||
-rw-r--r-- | pest_consume_macros/src/lib.rs | 2 | ||||
-rw-r--r-- | pest_consume_macros/src/make_parser.rs | 8 | ||||
-rw-r--r-- | pest_consume_macros/src/match_inputs.rs | 27 |
4 files changed, 177 insertions, 162 deletions
diff --git a/pest_consume/src/lib.rs b/pest_consume/src/lib.rs index 62361f2..701fbba 100644 --- a/pest_consume/src/lib.rs +++ b/pest_consume/src/lib.rs @@ -1,183 +1,199 @@ -use pest::error::{Error, ErrorVariant}; -use pest::iterators::{Pair, Pairs}; +use pest::error::Error; use pest::Parser as PestParser; -use pest::{RuleType, Span}; +use pest::RuleType; -pub use pest_consume_macros::make_parser; #[proc_macro_hack::proc_macro_hack] pub use pest_consume_macros::match_inputs; +pub use pest_consume_macros::parser; static UNIT: () = (); -/// Carries a pest Pair alongside custom user data. -#[derive(Debug)] -pub struct ParseInput<'input, 'data, Rule: RuleType, Data> { - pair: Pair<'input, Rule>, - user_data: &'data Data, -} - -/// Iterator over `ParseInput`s. It is created by `ParseInput::children` or `ParseInputs::new`. -#[derive(Debug)] -pub struct ParseInputs<'input, 'data, Rule: RuleType, Data> { - pairs: Pairs<'input, Rule>, - span: Span<'input>, - user_data: &'data Data, -} +mod node { + use super::Parser; + use pest::error::{Error, ErrorVariant}; + use pest::iterators::{Pair, Pairs}; + use pest::Parser as PestParser; + use pest::{RuleType, Span}; -impl<'i, 'd, R: RuleType, D> ParseInput<'i, 'd, R, D> { - pub fn new(pair: Pair<'i, R>, user_data: &'d D) -> Self { - ParseInput { pair, user_data } + /// Carries a pest Pair alongside custom user data. + #[derive(Debug)] + pub struct Node<'input, 'data, Rule: RuleType, Data> { + pair: Pair<'input, Rule>, + user_data: &'data Data, } - /// Create an error that points to the span of the input. - pub fn error(&self, message: String) -> Error<R> { - Error::new_from_span( - ErrorVariant::CustomError { message }, - self.as_span(), - ) + + /// Iterator over `Node`s. It is created by `Node::children` or `Nodes::new`. + #[derive(Debug)] + pub struct Nodes<'input, 'data, Rule: RuleType, Data> { + pairs: Pairs<'input, Rule>, + span: Span<'input>, + user_data: &'data Data, } - /// Reconstruct the input with a new pair, passing the user data along. - pub fn with_pair(&self, new_pair: Pair<'i, R>) -> Self { - ParseInput { - pair: new_pair, - user_data: self.user_data, + + impl<'i, 'd, R: RuleType, D> Node<'i, 'd, R, D> { + pub fn new(pair: Pair<'i, R>, user_data: &'d D) -> Self { + Node { pair, user_data } } - } - /// If the contained pair has exactly one child, return a new Self containing it. - pub fn single_child(&self) -> Option<Self> { - let mut children = self.pair.clone().into_inner(); - if let Some(child) = children.next() { - if children.next().is_none() { - return Some(self.with_pair(child)); + /// Create an error that points to the span of the input. + pub fn error(&self, message: String) -> Error<R> { + Error::new_from_span( + ErrorVariant::CustomError { message }, + self.as_span(), + ) + } + /// Reconstruct the input with a new pair, passing the user data along. + pub fn with_pair(&self, new_pair: Pair<'i, R>) -> Self { + Node { + pair: new_pair, + user_data: self.user_data, } } - 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<'i, 'd, R, D> { - ParseInputs { - pairs: self.as_pair().clone().into_inner(), - span: self.as_span(), - user_data: self.user_data(), + /// If the contained pair has exactly one child, return a new Self containing it. + pub fn single_child(&self) -> Option<Self> { + let mut children = self.pair.clone().into_inner(); + if let Some(child) = children.next() { + if children.next().is_none() { + return Some(self.with_pair(child)); + } + } + 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) -> Nodes<'i, 'd, R, D> { + Nodes { + pairs: self.as_pair().clone().into_inner(), + span: self.as_span(), + user_data: self.user_data(), + } } - } - pub fn user_data(&self) -> &'d D { - self.user_data - } - pub fn as_pair(&self) -> &Pair<'i, R> { - &self.pair - } - pub fn as_span(&self) -> Span<'i> { - self.pair.as_span() - } - pub fn as_str(&self) -> &'i str { - self.pair.as_str() - } - pub fn as_rule(&self) -> R { - self.pair.as_rule() + pub fn user_data(&self) -> &'d D { + self.user_data + } + pub fn as_pair(&self) -> &Pair<'i, R> { + &self.pair + } + pub fn as_span(&self) -> Span<'i> { + self.pair.as_span() + } + pub fn as_str(&self) -> &'i str { + self.pair.as_str() + } + pub fn as_rule(&self) -> R { + self.pair.as_rule() + } + pub fn as_aliased_rule<C>(&self) -> C::AliasedRule + where + C: Parser<Rule = R>, + <C as Parser>::Parser: PestParser<R>, + { + C::rule_alias(self.as_rule()) + } } - pub fn as_rule_alias<C>(&self) -> C::AliasedRule - where - C: PestConsumer<Rule = R>, - <C as PestConsumer>::Parser: PestParser<R>, - { - C::rule_alias(self.as_rule()) + + impl<'i, 'd, R: RuleType, D> Nodes<'i, 'd, R, D> { + /// `input` must be the _original_ input that `pairs` is pointing to. + pub fn new( + input: &'i str, + pairs: Pairs<'i, R>, + user_data: &'d D, + ) -> Self { + let span = Span::new(input, 0, input.len()).unwrap(); + Nodes { + pairs, + span, + user_data, + } + } + /// Create an error that points to the span of the input. + pub fn error(&self, message: String) -> Error<R> { + Error::new_from_span( + ErrorVariant::CustomError { message }, + self.span.clone(), + ) + } + pub fn aliased_rules<C>(&self) -> Vec<C::AliasedRule> + where + C: Parser<Rule = R>, + <C as Parser>::Parser: PestParser<R>, + { + self.clone().map(|p| p.as_aliased_rule::<C>()).collect() + } + /// Reconstruct the input with a new pair, passing the user data along. + fn with_pair(&self, new_pair: Pair<'i, R>) -> Node<'i, 'd, R, D> { + Node::new(new_pair, self.user_data) + } } -} -impl<'i, 'd, R: RuleType, D> ParseInputs<'i, 'd, R, D> { - /// `input` must be the _original_ input that `pairs` is pointing to. - pub fn new(input: &'i str, pairs: Pairs<'i, R>, user_data: &'d D) -> Self { - let span = Span::new(input, 0, input.len()).unwrap(); - ParseInputs { - pairs, - span, - user_data, + impl<'i, 'd, R: RuleType, D> Iterator for Nodes<'i, 'd, R, D> { + type Item = Node<'i, 'd, R, D>; + + fn next(&mut self) -> Option<Self::Item> { + let child_pair = self.pairs.next()?; + let child = self.with_pair(child_pair); + Some(child) } } - /// Create an error that points to the span of the input. - pub fn error(&self, message: String) -> Error<R> { - Error::new_from_span( - ErrorVariant::CustomError { message }, - self.span.clone(), - ) + + impl<'i, 'd, R: RuleType, D> DoubleEndedIterator for Nodes<'i, 'd, R, D> { + fn next_back(&mut self) -> Option<Self::Item> { + let child_pair = self.pairs.next_back()?; + let child = self.with_pair(child_pair); + Some(child) + } } - pub fn aliased_rules<C>(&self) -> Vec<C::AliasedRule> - where - C: PestConsumer<Rule = R>, - <C as PestConsumer>::Parser: PestParser<R>, - { - self.clone().map(|p| p.as_rule_alias::<C>()).collect() + + // Manual impl to avoid stupid `D: Clone` trait bound + impl<'i, 'd, R: RuleType, D> Clone for Node<'i, 'd, R, D> { + fn clone(&self) -> Self { + Node { + pair: self.pair.clone(), + user_data: self.user_data, + } + } } - /// Reconstruct the input with a new pair, passing the user data along. - fn with_pair(&self, new_pair: Pair<'i, R>) -> ParseInput<'i, 'd, R, D> { - ParseInput::new(new_pair, self.user_data) + + // Manual impl to avoid stupid `D: Clone` trait bound + impl<'i, 'd, R: RuleType, D> Clone for Nodes<'i, 'd, R, D> { + fn clone(&self) -> Self { + Nodes { + pairs: self.pairs.clone(), + span: self.span.clone(), + user_data: self.user_data, + } + } } } +pub use node::{Node, Nodes}; + /// Used by the macros. -pub trait PestConsumer { +/// Do not implement manually. +pub trait Parser { type Rule: RuleType; type AliasedRule: RuleType; type Parser: PestParser<Self::Rule>; + fn rule_alias(rule: Self::Rule) -> Self::AliasedRule; fn allows_shortcut(rule: Self::Rule) -> bool; - fn parse_with_userdata<'i, 'd, D>( - rule: Self::Rule, - input_str: &'i str, - user_data: &'d D, - ) -> Result<ParseInputs<'i, 'd, Self::Rule, D>, Error<Self::Rule>> { - let pairs = Self::Parser::parse(rule, input_str)?; - Ok(ParseInputs::new(input_str, pairs, user_data)) - } - + /// Parses a `&str` starting from `rule` fn parse<'i>( rule: Self::Rule, input_str: &'i str, - ) -> Result<ParseInputs<'i, 'static, Self::Rule, ()>, Error<Self::Rule>> - { + ) -> Result<Nodes<'i, 'static, Self::Rule, ()>, Error<Self::Rule>> { Self::parse_with_userdata(rule, input_str, &UNIT) } -} - -impl<'i, 'd, R: RuleType, D> Iterator for ParseInputs<'i, 'd, R, D> { - type Item = ParseInput<'i, 'd, R, D>; - - fn next(&mut self) -> Option<Self::Item> { - let child_pair = self.pairs.next()?; - let child = self.with_pair(child_pair); - Some(child) - } -} - -impl<'i, 'd, R: RuleType, D> DoubleEndedIterator for ParseInputs<'i, 'd, R, D> { - fn next_back(&mut self) -> Option<Self::Item> { - let child_pair = self.pairs.next_back()?; - let child = self.with_pair(child_pair); - Some(child) - } -} - -// Manual impl to avoid stupid `D: Clone` trait bound -impl<'i, 'd, R: RuleType, D> Clone for ParseInput<'i, 'd, R, D> { - fn clone(&self) -> Self { - ParseInput { - pair: self.pair.clone(), - user_data: self.user_data, - } - } -} -// Manual impl to avoid stupid `D: Clone` trait bound -impl<'i, 'd, R: RuleType, D> Clone for ParseInputs<'i, 'd, R, D> { - fn clone(&self) -> Self { - ParseInputs { - pairs: self.pairs.clone(), - span: self.span.clone(), - user_data: self.user_data, - } + /// Parses a `&str` starting from `rule`, carrying `user_data` through the parser methods. + fn parse_with_userdata<'i, 'd, D>( + rule: Self::Rule, + input_str: &'i str, + user_data: &'d D, + ) -> Result<Nodes<'i, 'd, Self::Rule, D>, Error<Self::Rule>> { + let pairs = Self::Parser::parse(rule, input_str)?; + Ok(Nodes::new(input_str, pairs, user_data)) } } diff --git a/pest_consume_macros/src/lib.rs b/pest_consume_macros/src/lib.rs index db21f37..7f9f464 100644 --- a/pest_consume_macros/src/lib.rs +++ b/pest_consume_macros/src/lib.rs @@ -11,7 +11,7 @@ mod match_inputs; use proc_macro::TokenStream; #[proc_macro_attribute] -pub fn make_parser(attrs: TokenStream, input: TokenStream) -> TokenStream { +pub fn parser(attrs: TokenStream, input: TokenStream) -> TokenStream { TokenStream::from(match make_parser::make_parser(attrs, input) { Ok(tokens) => tokens, Err(err) => err.to_compile_error(), diff --git a/pest_consume_macros/src/make_parser.rs b/pest_consume_macros/src/make_parser.rs index e8d861f..2ed3271 100644 --- a/pest_consume_macros/src/make_parser.rs +++ b/pest_consume_macros/src/make_parser.rs @@ -64,7 +64,7 @@ struct ParsedFn<'a> { function: &'a mut ImplItemMethod, // Name of the function. fn_name: Ident, - // Name of the first argument of the function, which should be of type `ParseInput`. + // Name of the first argument of the function, which should be of type `Node`. input_arg: Ident, // List of aliases pointing to this function alias_srcs: Vec<AliasSrc>, @@ -255,14 +255,14 @@ fn apply_special_attrs(f: &mut ParsedFn, rule_enum: &Path) -> Result<()> { .map(|src| &src.ident) .filter(|i| i != &fn_name); let block = &function.block; - let self_ty = quote!(<Self as ::pest_consume::PestConsumer>); + let self_ty = quote!(<Self as ::pest_consume::Parser>); function.block = parse_quote!({ let mut #input_arg = #input_arg; // While the current rule allows shortcutting, and there is a single child, and the // child can still be parsed by the current function, then skip to that child. while #self_ty::allows_shortcut(#input_arg.as_rule()) { if let Some(child) = #input_arg.single_child() { - if child.as_rule_alias::<Self>() == #self_ty::AliasedRule::#fn_name { + if child.as_aliased_rule::<Self>() == #self_ty::AliasedRule::#fn_name { #input_arg = child; continue; } @@ -375,7 +375,7 @@ pub fn make_parser( #(#aliased_rule_variants,)* } - impl #impl_generics ::pest_consume::PestConsumer for #ty #where_clause { + impl #impl_generics ::pest_consume::Parser for #ty #where_clause { type Rule = #rule_enum; type AliasedRule = AliasedRule; type Parser = #parser; diff --git a/pest_consume_macros/src/match_inputs.rs b/pest_consume_macros/src/match_inputs.rs index 34bfd38..773f806 100644 --- a/pest_consume_macros/src/match_inputs.rs +++ b/pest_consume_macros/src/match_inputs.rs @@ -23,7 +23,7 @@ enum ChildrenBranchPatternItem { #[derive(Debug, Clone)] struct ParseChildrenInput { - consumer: Type, + parser: Type, input_expr: Expr, branches: Punctuated<ChildrenBranch, Token![,]>, } @@ -66,12 +66,12 @@ impl Parse for ChildrenBranchPatternItem { impl Parse for ParseChildrenInput { fn parse(input: ParseStream) -> Result<Self> { - let consumer = if input.peek(token::Lt) { + let parser = if input.peek(token::Lt) { let _: token::Lt = input.parse()?; - let consumer = input.parse()?; + let parser = input.parse()?; let _: token::Gt = input.parse()?; let _: Token![;] = input.parse()?; - consumer + parser } else { parse_quote!(Self) }; @@ -80,7 +80,7 @@ impl Parse for ParseChildrenInput { let branches = Punctuated::parse_terminated(input)?; Ok(ParseChildrenInput { - consumer, + parser, input_expr, branches, }) @@ -90,13 +90,12 @@ impl Parse for ParseChildrenInput { fn make_parser_branch( branch: &ChildrenBranch, i_inputs: &Ident, - consumer: &Type, + parser: &Type, ) -> Result<TokenStream> { use ChildrenBranchPatternItem::{Multiple, Single}; let body = &branch.body; - let aliased_rule = - quote!(<#consumer as ::pest_consume::PestConsumer>::AliasedRule); + let aliased_rule = quote!(<#parser as ::pest_consume::Parser>::AliasedRule); // Convert the input pattern into a pattern-match on the Rules of the children. This uses // slice_patterns. @@ -156,7 +155,7 @@ fn make_parser_branch( let mut parses = Vec::new(); for (rule_name, binder) in singles_before_multiple.into_iter() { parses.push(quote!( - let #binder = #consumer::#rule_name( + let #binder = #parser::#rule_name( #i_inputs.next().unwrap() )?; )) @@ -165,7 +164,7 @@ fn make_parser_branch( // only the unmatched inputs are left for the variable-length pattern, if any. for (rule_name, binder) in singles_after_multiple.into_iter().rev() { parses.push(quote!( - let #binder = #consumer::#rule_name( + let #binder = #parser::#rule_name( #i_inputs.next_back().unwrap() )?; )) @@ -173,7 +172,7 @@ fn make_parser_branch( if let Some((rule_name, binder)) = multiple { parses.push(quote!( let #binder = #i_inputs - .map(|i| #consumer::#rule_name(i)) + .map(|i| #parser::#rule_name(i)) .collect::<Result<Vec<_>, _>>()? .into_iter(); )) @@ -196,17 +195,17 @@ pub fn match_inputs( let i_inputs = Ident::new("___inputs", Span::call_site()); let input_expr = &input.input_expr; - let consumer = &input.consumer; + let parser = &input.parser; let branches = input .branches .iter() - .map(|br| make_parser_branch(br, &i_inputs, consumer)) + .map(|br| make_parser_branch(br, &i_inputs, parser)) .collect::<Result<Vec<_>>>()?; Ok(quote!({ #[allow(unused_mut)] let mut #i_inputs = #input_expr; - let #i_input_rules = #i_inputs.aliased_rules::<#consumer>(); + let #i_input_rules = #i_inputs.aliased_rules::<#parser>(); #[allow(unreachable_code)] match #i_input_rules.as_slice() { |