summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-09-02 18:46:53 +0200
committerNadrieril2019-09-02 18:46:53 +0200
commit41f598a75de41665dd9ec0aad56b5ef526698151 (patch)
tree7ffcef71c5d868066bb1a60bfc0d74852b44b68b
parent49f142e3cd173549b8d63883380b5e780c9fefb1 (diff)
Use proper hygiene for `Parsers` and `Rule`
Diffstat (limited to '')
-rw-r--r--dhall_proc_macros/src/lib.rs4
-rw-r--r--dhall_proc_macros/src/parser.rs49
-rw-r--r--dhall_syntax/src/lib.rs1
-rw-r--r--dhall_syntax/src/parser.rs9
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(())