summaryrefslogtreecommitdiff
path: root/pest_consume
diff options
context:
space:
mode:
authorNadrieril2019-09-10 13:55:35 +0200
committerNadrieril2019-09-10 13:56:07 +0200
commitfc8fce6facee9bd50958e78f3b177e16ed065c19 (patch)
tree7a2dbbb7a7e550c92ef0cfdc289e2856132529bb /pest_consume
parentaccaf45aa77099654f94319ed1fb12855dd568b4 (diff)
Generalize parse_children and change its invocation
Diffstat (limited to '')
-rw-r--r--pest_consume/src/lib.rs95
-rw-r--r--pest_consume_macros/src/parse_children.rs27
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)
)),
}
}))