summaryrefslogtreecommitdiff
path: root/pest_consume
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pest_consume/src/lib.rs302
-rw-r--r--pest_consume_macros/src/lib.rs2
-rw-r--r--pest_consume_macros/src/make_parser.rs8
-rw-r--r--pest_consume_macros/src/match_inputs.rs27
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() {