summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-09-10 16:29:48 +0200
committerNadrieril2019-09-10 16:38:28 +0200
commit26f54b10314f90dc5457cd0760af7f109be78e5f (patch)
tree892fd7e0be529e9a5c67f1893b854fb3e2a7172b
parent65fd9a895ba3093f9b5d9d02fb8bd18a9be61808 (diff)
Use an enum instead of strings for rule aliasing
-rw-r--r--pest_consume/src/lib.rs7
-rw-r--r--pest_consume_macros/src/make_parser.rs42
-rw-r--r--pest_consume_macros/src/match_inputs.rs11
3 files changed, 41 insertions, 19 deletions
diff --git a/pest_consume/src/lib.rs b/pest_consume/src/lib.rs
index 439effb..62361f2 100644
--- a/pest_consume/src/lib.rs
+++ b/pest_consume/src/lib.rs
@@ -78,7 +78,7 @@ impl<'i, 'd, R: RuleType, D> ParseInput<'i, 'd, R, D> {
pub fn as_rule(&self) -> R {
self.pair.as_rule()
}
- pub fn as_rule_alias<C>(&self) -> String
+ pub fn as_rule_alias<C>(&self) -> C::AliasedRule
where
C: PestConsumer<Rule = R>,
<C as PestConsumer>::Parser: PestParser<R>,
@@ -104,7 +104,7 @@ impl<'i, 'd, R: RuleType, D> ParseInputs<'i, 'd, R, D> {
self.span.clone(),
)
}
- pub fn aliased_rules<C>(&self) -> Vec<String>
+ pub fn aliased_rules<C>(&self) -> Vec<C::AliasedRule>
where
C: PestConsumer<Rule = R>,
<C as PestConsumer>::Parser: PestParser<R>,
@@ -120,8 +120,9 @@ impl<'i, 'd, R: RuleType, D> ParseInputs<'i, 'd, R, D> {
/// Used by the macros.
pub trait PestConsumer {
type Rule: RuleType;
+ type AliasedRule: RuleType;
type Parser: PestParser<Self::Rule>;
- fn rule_alias(rule: Self::Rule) -> String;
+ fn rule_alias(rule: Self::Rule) -> Self::AliasedRule;
fn allows_shortcut(rule: Self::Rule) -> bool;
fn parse_with_userdata<'i, 'd, D>(
diff --git a/pest_consume_macros/src/make_parser.rs b/pest_consume_macros/src/make_parser.rs
index 4165046..e8d861f 100644
--- a/pest_consume_macros/src/make_parser.rs
+++ b/pest_consume_macros/src/make_parser.rs
@@ -136,6 +136,15 @@ fn collect_aliases(
is_shortcut: args.is_shortcut,
},
);
+ } else {
+ // Self entry
+ alias_map
+ .entry(fn_name.clone())
+ .or_insert_with(Vec::new)
+ .push(AliasSrc {
+ ident: fn_name,
+ is_shortcut: false,
+ });
}
if let Some(attr) = alias_attrs.next() {
return Err(Error::new(
@@ -238,17 +247,22 @@ fn apply_special_attrs(f: &mut ParsedFn, rule_enum: &Path) -> Result<()> {
}
// `alias` attr
- if !f.alias_srcs.is_empty() {
- let aliases = f.alias_srcs.iter().map(|src| &src.ident);
+ // f.alias_srcs has always at least 1 element because it has an entry pointing from itself.
+ if f.alias_srcs.len() > 1 {
+ let aliases = f
+ .alias_srcs
+ .iter()
+ .map(|src| &src.ident)
+ .filter(|i| i != &fn_name);
let block = &function.block;
+ let self_ty = quote!(<Self as ::pest_consume::PestConsumer>);
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 as pest_consume::PestConsumer>::allows_shortcut(#input_arg.as_rule()) {
+ while #self_ty::allows_shortcut(#input_arg.as_rule()) {
if let Some(child) = #input_arg.single_child() {
- if &<Self as pest_consume::PestConsumer>::rule_alias(child.as_rule())
- == stringify!(#fn_name) {
+ if child.as_rule_alias::<Self>() == #self_ty::AliasedRule::#fn_name {
#input_arg = child;
continue;
}
@@ -287,10 +301,12 @@ pub fn make_parser(
.map(|(tgt, src)| {
let ident = &src.ident;
quote!(
- #rule_enum::#ident => stringify!(#tgt).to_string(),
+ #rule_enum::#ident => Self::AliasedRule::#tgt,
)
})
.collect();
+ let aliased_rule_variants: Vec<_> =
+ alias_map.iter().map(|(tgt, _)| tgt.clone()).collect();
let shortcut_branches: Vec<_> = alias_map
.iter()
.flat_map(|(_tgt, srcs)| srcs)
@@ -353,13 +369,21 @@ pub fn make_parser(
let ty = &imp.self_ty;
let (impl_generics, _, where_clause) = imp.generics.split_for_impl();
Ok(quote!(
- impl #impl_generics pest_consume::PestConsumer for #ty #where_clause {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[allow(non_camel_case_types)]
+ enum AliasedRule {
+ #(#aliased_rule_variants,)*
+ }
+
+ impl #impl_generics ::pest_consume::PestConsumer for #ty #where_clause {
type Rule = #rule_enum;
+ type AliasedRule = AliasedRule;
type Parser = #parser;
- fn rule_alias(rule: Self::Rule) -> String {
+ fn rule_alias(rule: Self::Rule) -> Self::AliasedRule {
match rule {
#(#rule_alias_branches)*
- r => format!("{:?}", r),
+ // TODO: return a proper error ?
+ r => unreachable!("Rule {:?} does not have a corresponding parsing method", r),
}
}
fn allows_shortcut(rule: Self::Rule) -> bool {
diff --git a/pest_consume_macros/src/match_inputs.rs b/pest_consume_macros/src/match_inputs.rs
index d4bc492..34bfd38 100644
--- a/pest_consume_macros/src/match_inputs.rs
+++ b/pest_consume_macros/src/match_inputs.rs
@@ -95,6 +95,8 @@ fn make_parser_branch(
use ChildrenBranchPatternItem::{Multiple, Single};
let body = &branch.body;
+ let aliased_rule =
+ quote!(<#consumer as ::pest_consume::PestConsumer>::AliasedRule);
// Convert the input pattern into a pattern-match on the Rules of the children. This uses
// slice_patterns.
@@ -103,7 +105,7 @@ fn make_parser_branch(
let i_variable_pattern =
Ident::new("___variable_pattern", Span::call_site());
let match_pat = branch.pattern.iter().map(|item| match item {
- Single { rule_name, .. } => quote!(stringify!(#rule_name)),
+ Single { rule_name, .. } => quote!(#aliased_rule::#rule_name),
Multiple { .. } => quote!(#i_variable_pattern @ ..),
});
let match_filter = branch.pattern.iter().map(|item| match item {
@@ -114,7 +116,7 @@ fn make_parser_branch(
// https://github.com/rust-lang/rust/issues/59803.
let all_match = |slice: &[_]| {
slice.iter().all(|r|
- *r == stringify!(#rule_name)
+ *r == #aliased_rule::#rule_name
)
};
all_match(#i_variable_pattern)
@@ -204,12 +206,7 @@ pub fn match_inputs(
Ok(quote!({
#[allow(unused_mut)]
let mut #i_inputs = #input_expr;
-
let #i_input_rules = #i_inputs.aliased_rules::<#consumer>();
- let #i_input_rules: Vec<&str> = #i_input_rules
- .iter()
- .map(String::as_str)
- .collect();
#[allow(unreachable_code)]
match #i_input_rules.as_slice() {