summaryrefslogtreecommitdiff
path: root/src/generator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/generator.rs')
-rw-r--r--src/generator.rs143
1 files changed, 118 insertions, 25 deletions
diff --git a/src/generator.rs b/src/generator.rs
index 0dbcaa3..7a527c5 100644
--- a/src/generator.rs
+++ b/src/generator.rs
@@ -11,17 +11,17 @@ use std::path::PathBuf;
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
-use syn::{self, Generics, Ident};
+use syn::{self, Ident};
use pest::unicode::unicode_property_names;
use pest_meta::ast::*;
use pest_meta::optimizer::*;
use crate::docs::DocComment;
+use crate::ParsedDerive;
pub(crate) fn generate(
- name: Ident,
- generics: &Generics,
+ parsed_derive: ParsedDerive,
paths: Vec<PathBuf>,
rules: Vec<OptimizedRule>,
defaults: Vec<&str>,
@@ -29,14 +29,14 @@ pub(crate) fn generate(
include_grammar: bool,
) -> TokenStream {
let uses_eoi = defaults.iter().any(|name| *name == "EOI");
-
+ let name = parsed_derive.name;
let builtins = generate_builtin_rules();
let include_fix = if include_grammar {
generate_include(&name, paths)
} else {
quote!()
};
- let rule_enum = generate_enum(&rules, doc_comment, uses_eoi);
+ let rule_enum = generate_enum(&rules, doc_comment, uses_eoi, parsed_derive.non_exhaustive);
let patterns = generate_patterns(&rules, uses_eoi);
let skip = generate_skip(&rules);
@@ -49,7 +49,7 @@ pub(crate) fn generate(
}
}));
- let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+ let (impl_generics, ty_generics, where_clause) = parsed_derive.generics.split_for_impl();
let result = result_type();
@@ -197,8 +197,13 @@ fn generate_include(name: &Ident, paths: Vec<PathBuf>) -> TokenStream {
}
}
-fn generate_enum(rules: &[OptimizedRule], doc_comment: &DocComment, uses_eoi: bool) -> TokenStream {
- let rules = rules.iter().map(|rule| {
+fn generate_enum(
+ rules: &[OptimizedRule],
+ doc_comment: &DocComment,
+ uses_eoi: bool,
+ non_exhaustive: bool,
+) -> TokenStream {
+ let rule_variants = rules.iter().map(|rule| {
let rule_name = format_ident!("r#{}", rule.name);
match doc_comment.line_docs.get(&rule.name) {
@@ -213,26 +218,49 @@ fn generate_enum(rules: &[OptimizedRule], doc_comment: &DocComment, uses_eoi: bo
});
let grammar_doc = &doc_comment.grammar_doc;
+ let mut result = quote! {
+ #[doc = #grammar_doc]
+ #[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ };
+ if non_exhaustive {
+ result.append_all(quote! {
+ #[non_exhaustive]
+ });
+ }
+ result.append_all(quote! {
+ pub enum Rule
+ });
if uses_eoi {
- quote! {
- #[doc = #grammar_doc]
- #[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
- #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
- pub enum Rule {
+ result.append_all(quote! {
+ {
+ #[doc = "End-of-input"]
EOI,
- #( #rules ),*
+ #( #rule_variants ),*
}
- }
+ });
} else {
- quote! {
- #[doc = #grammar_doc]
- #[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
- #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
- pub enum Rule {
- #( #rules ),*
+ result.append_all(quote! {
+ {
+ #( #rule_variants ),*
+ }
+ })
+ };
+
+ let rules = rules.iter().map(|rule| {
+ let rule_name = format_ident!("r#{}", rule.name);
+ quote! { #rule_name }
+ });
+
+ result.append_all(quote! {
+ impl Rule {
+ pub fn all_rules() -> &'static[Rule] {
+ &[ #(Rule::#rules), * ]
}
}
- }
+ });
+
+ result
}
fn generate_patterns(rules: &[OptimizedRule], uses_eoi: bool) -> TokenStream {
@@ -496,6 +524,26 @@ fn generate_expr(expr: OptimizedExpr) -> TokenStream {
})
}
}
+ #[cfg(feature = "grammar-extras")]
+ OptimizedExpr::RepOnce(expr) => {
+ let expr = generate_expr(*expr);
+
+ quote! {
+ state.sequence(|state| {
+ #expr.and_then(|state| {
+ state.repeat(|state| {
+ state.sequence(|state| {
+ super::hidden::skip(
+ state
+ ).and_then(|state| {
+ #expr
+ })
+ })
+ })
+ })
+ })
+ }
+ }
OptimizedExpr::Skip(strings) => {
quote! {
let strings = [#(#strings),*];
@@ -517,6 +565,13 @@ fn generate_expr(expr: OptimizedExpr) -> TokenStream {
state.restore_on_err(|state| #expr)
}
}
+ #[cfg(feature = "grammar-extras")]
+ OptimizedExpr::NodeTag(expr, tag) => {
+ let expr = generate_expr(*expr);
+ quote! {
+ #expr.and_then(|state| state.tag_node(#tag))
+ }
+ }
}
}
@@ -628,6 +683,22 @@ fn generate_expr_atomic(expr: OptimizedExpr) -> TokenStream {
})
}
}
+ #[cfg(feature = "grammar-extras")]
+ OptimizedExpr::RepOnce(expr) => {
+ let expr = generate_expr_atomic(*expr);
+
+ quote! {
+ state.sequence(|state| {
+ #expr.and_then(|state| {
+ state.repeat(|state| {
+ state.sequence(|state| {
+ #expr
+ })
+ })
+ })
+ })
+ }
+ }
OptimizedExpr::Skip(strings) => {
quote! {
let strings = [#(#strings),*];
@@ -649,6 +720,13 @@ fn generate_expr_atomic(expr: OptimizedExpr) -> TokenStream {
state.restore_on_err(|state| #expr)
}
}
+ #[cfg(feature = "grammar-extras")]
+ OptimizedExpr::NodeTag(expr, tag) => {
+ let expr = generate_expr_atomic(*expr);
+ quote! {
+ #expr.and_then(|state| state.tag_node(#tag))
+ }
+ }
}
}
@@ -694,6 +772,7 @@ mod tests {
use proc_macro2::Span;
use std::collections::HashMap;
+ use syn::Generics;
#[test]
fn rule_enum_simple() {
@@ -712,7 +791,7 @@ mod tests {
};
assert_eq!(
- generate_enum(&rules, doc_comment, false).to_string(),
+ generate_enum(&rules, doc_comment, false, false).to_string(),
quote! {
#[doc = "Rule doc\nhello"]
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
@@ -721,6 +800,11 @@ mod tests {
#[doc = "This is rule comment"]
r#f
}
+ impl Rule {
+ pub fn all_rules() -> &'static [Rule] {
+ &[Rule::r#f]
+ }
+ }
}
.to_string()
);
@@ -1033,9 +1117,13 @@ mod tests {
let base_path = current_dir.join("base.pest").to_str().unwrap().to_string();
let test_path = current_dir.join("test.pest").to_str().unwrap().to_string();
-
+ let parsed_derive = ParsedDerive {
+ name,
+ generics,
+ non_exhaustive: false,
+ };
assert_eq!(
- generate(name, &generics, vec![PathBuf::from("base.pest"), PathBuf::from("test.pest")], rules, defaults, doc_comment, true).to_string(),
+ generate(parsed_derive, vec![PathBuf::from("base.pest"), PathBuf::from("test.pest")], rules, defaults, doc_comment, true).to_string(),
quote! {
#[allow(non_upper_case_globals)]
const _PEST_GRAMMAR_MyParser: [&'static str; 2usize] = [include_str!(#base_path), include_str!(#test_path)];
@@ -1048,6 +1136,11 @@ mod tests {
#[doc = "If statement"]
r#if
}
+ impl Rule {
+ pub fn all_rules() -> &'static [Rule] {
+ &[Rule::r#a, Rule::r#if]
+ }
+ }
#[allow(clippy::all)]
impl ::pest::Parser<Rule> for MyParser {