From 26f54b10314f90dc5457cd0760af7f109be78e5f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 10 Sep 2019 16:29:48 +0200 Subject: Use an enum instead of strings for rule aliasing --- pest_consume_macros/src/make_parser.rs | 42 ++++++++++++++++++++++++++------- pest_consume_macros/src/match_inputs.rs | 11 ++++----- 2 files changed, 37 insertions(+), 16 deletions(-) (limited to 'pest_consume_macros/src') 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!(); 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 ::allows_shortcut(#input_arg.as_rule()) { + while #self_ty::allows_shortcut(#input_arg.as_rule()) { if let Some(child) = #input_arg.single_child() { - if &::rule_alias(child.as_rule()) - == stringify!(#fn_name) { + if child.as_rule_alias::() == #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() { -- cgit v1.2.3