diff options
author | Nadrieril | 2019-09-10 16:29:48 +0200 |
---|---|---|
committer | Nadrieril | 2019-09-10 16:38:28 +0200 |
commit | 26f54b10314f90dc5457cd0760af7f109be78e5f (patch) | |
tree | 892fd7e0be529e9a5c67f1893b854fb3e2a7172b | |
parent | 65fd9a895ba3093f9b5d9d02fb8bd18a9be61808 (diff) |
Use an enum instead of strings for rule aliasing
-rw-r--r-- | pest_consume/src/lib.rs | 7 | ||||
-rw-r--r-- | pest_consume_macros/src/make_parser.rs | 42 | ||||
-rw-r--r-- | pest_consume_macros/src/match_inputs.rs | 11 |
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() { |