diff options
author | Nadrieril | 2019-09-02 18:46:53 +0200 |
---|---|---|
committer | Nadrieril | 2019-09-02 18:46:53 +0200 |
commit | 41f598a75de41665dd9ec0aad56b5ef526698151 (patch) | |
tree | 7ffcef71c5d868066bb1a60bfc0d74852b44b68b | |
parent | 49f142e3cd173549b8d63883380b5e780c9fefb1 (diff) |
Use proper hygiene for `Parsers` and `Rule`
Diffstat (limited to '')
-rw-r--r-- | dhall_proc_macros/src/lib.rs | 4 | ||||
-rw-r--r-- | dhall_proc_macros/src/parser.rs | 49 | ||||
-rw-r--r-- | dhall_syntax/src/lib.rs | 1 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 9 |
4 files changed, 44 insertions, 19 deletions
diff --git a/dhall_proc_macros/src/lib.rs b/dhall_proc_macros/src/lib.rs index 3e41254..63dd29a 100644 --- a/dhall_proc_macros/src/lib.rs +++ b/dhall_proc_macros/src/lib.rs @@ -17,8 +17,8 @@ pub fn derive_static_type(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn make_parser(_attr: TokenStream, input: TokenStream) -> TokenStream { - TokenStream::from(match parser::make_parser(input) { +pub fn make_parser(attrs: TokenStream, input: TokenStream) -> TokenStream { + TokenStream::from(match parser::make_parser(attrs, input) { Ok(tokens) => tokens, Err(err) => err.to_compile_error(), }) diff --git a/dhall_proc_macros/src/parser.rs b/dhall_proc_macros/src/parser.rs index d775ca8..a440b16 100644 --- a/dhall_proc_macros/src/parser.rs +++ b/dhall_proc_macros/src/parser.rs @@ -76,7 +76,10 @@ impl Parse for ParseChildrenInput { } } -fn apply_special_attrs(function: &mut ImplItemMethod) -> Result<()> { +fn apply_special_attrs( + rule_enum: &Ident, + function: &mut ImplItemMethod, +) -> Result<()> { let recognized_attrs: Vec<_> = function .attrs .drain_filter(|attr| attr.path.is_ident("prec_climb")) @@ -106,14 +109,14 @@ fn apply_special_attrs(function: &mut ImplItemMethod) -> Result<()> { *function = parse_quote!( fn #name<'a>( - input: ParseInput<'a, Rule>, + input: ParseInput<'a, #rule_enum>, ) -> #output_type { #[allow(non_snake_case, dead_code)] #function #climber.climb( input.pair.clone().into_inner(), - |p| Parsers::#child_rule(input.with_pair(p)), + |p| Self::#child_rule(input.with_pair(p)), |l, op, r| { #name(input.clone(), l?, op, r?) }, @@ -131,17 +134,29 @@ fn apply_special_attrs(function: &mut ImplItemMethod) -> Result<()> { } pub fn make_parser( + attrs: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> Result<proc_macro2::TokenStream> { + let rule_enum: Ident = syn::parse(attrs)?; + let mut imp: ItemImpl = syn::parse(input)?; imp.items .iter_mut() .map(|item| match item { - ImplItem::Method(m) => apply_special_attrs(m), + ImplItem::Method(m) => apply_special_attrs(&rule_enum, m), _ => Ok(()), }) .collect::<Result<()>>()?; - Ok(quote!( #imp )) + + let ty = &imp.self_ty; + let (impl_generics, _, where_clause) = imp.generics.split_for_impl(); + Ok(quote!( + impl #impl_generics PestConsumer for #ty #where_clause { + type RuleEnum = #rule_enum; + } + + #imp + )) } fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { @@ -156,18 +171,22 @@ fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { let variable_pattern_ident = Ident::new("variable_pattern", Span::call_site()); let match_pat = branch.pattern.iter().map(|item| match item { - Single { rule_name, .. } => quote!(Rule::#rule_name), + Single { rule_name, .. } => { + quote!(<<Self as PestConsumer>::RuleEnum>::#rule_name) + } Multiple { .. } => quote!(#variable_pattern_ident..), }); let match_filter = branch.pattern.iter().map(|item| match item { Single { .. } => quote!(), Multiple { rule_name, .. } => quote!( { - // We can't use .all() directly in the pattern guard without the - // bind_by_move_pattern_guards feature. - fn all_match(slice: &[Rule]) -> bool { - slice.iter().all(|r| r == &Rule::#rule_name) - } + // We can't use .all() directly in the pattern guard; see + // https://github.com/rust-lang/rust/issues/59803. + let all_match = |slice: &[_]| { + slice.iter().all(|r| + r == &<<Self as PestConsumer>::RuleEnum>::#rule_name + ) + }; all_match(#variable_pattern_ident) } && ), @@ -205,7 +224,7 @@ fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { let mut parses = Vec::new(); for (rule_name, binder) in singles_before_multiple.into_iter() { parses.push(quote!( - let #binder = Parsers::#rule_name( + let #binder = Self::#rule_name( inputs.next().unwrap() )?; )) @@ -214,7 +233,7 @@ fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { // 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 = Parsers::#rule_name( + let #binder = Self::#rule_name( inputs.next_back().unwrap() )?; )) @@ -222,7 +241,7 @@ fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { if let Some((rule_name, binder)) = multiple { parses.push(quote!( let #binder = inputs - .map(|i| Parsers::#rule_name(i)) + .map(|i| Self::#rule_name(i)) .collect::<Result<Vec<_>, _>>()? .into_iter(); )) @@ -248,7 +267,7 @@ pub fn parse_children( .map(make_parser_branch) .collect::<Result<Vec<_>>>()?; Ok(quote!({ - let children_rules: Vec<Rule> = #input_expr.pair + let children_rules: Vec<_> = #input_expr.pair .clone() .into_inner() .map(|p| p.as_rule()) diff --git a/dhall_syntax/src/lib.rs b/dhall_syntax/src/lib.rs index fb12af4..1636c8b 100644 --- a/dhall_syntax/src/lib.rs +++ b/dhall_syntax/src/lib.rs @@ -3,6 +3,7 @@ #![feature(try_blocks)] #![feature(never_type)] #![feature(proc_macro_hygiene)] +#![feature(type_alias_enum_variants)] #![allow( clippy::many_single_char_names, clippy::should_implement_trait, diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index fac6ecc..b1e429b 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -30,7 +30,7 @@ pub type ParseResult<T> = Result<T, ParseError>; #[derive(Debug, Clone)] struct ParseInput<'input, Rule> where - Rule: std::fmt::Debug + Copy + std::hash::Hash + Ord, + Rule: pest::RuleType, { pair: Pair<'input, Rule>, original_input_str: Rc<str>, @@ -70,6 +70,11 @@ impl<'input> ParseInput<'input, Rule> { } } +// Used to retrieve the `Rule` enum associated with the `Self` type in `parse_children`. +trait PestConsumer { + type RuleEnum: pest::RuleType; +} + fn debug_pair(pair: Pair<Rule>) -> String { use std::fmt::Write; let mut s = String::new(); @@ -226,7 +231,7 @@ lazy_static::lazy_static! { struct Parsers; -#[make_parser] +#[make_parser(Rule)] impl Parsers { fn EOI(_: ParseInput<Rule>) -> ParseResult<()> { Ok(()) |