diff --git a/derive/tests/grammar.pest b/derive/tests/grammar.pest index eec3ec5..e387feb 100644 --- a/derive/tests/grammar.pest +++ b/derive/tests/grammar.pest @@ -36,17 +36,17 @@ repeat_min_atomic = string{2..} repeat_max = string~{..2} repeat_max_atomic = string{..2} soi_at_start = pest::SOI - string -repeat_mutate_stack = (pest::push('a'..'c') - ",")* - pest::pop - pest::pop - pest::pop -repeat_mutate_stack_pop_all = (pest::push('a'..'c') - ",")* - pest::pop_all +repeat_mutate_stack = (pest::stack::push('a'..'c') - ",")* - pest::stack::pop - pest::stack::pop - pest::stack::pop +repeat_mutate_stack_pop_all = (pest::stack::push('a'..'c') - ",")* - pest::stack::pop_all will_fail = repeat_mutate_stack_pop_all - "FAIL" stack_resume_after_fail = will_fail | repeat_mutate_stack_pop_all -peek_ = pest::push(range) - pest::push(range) - pest::peek - pest::peek -peek_all = pest::push(range) - pest::push(range) - pest::peek_all -peek_slice_23 = pest::push(range) - pest::push(range) - pest::push(range) ~ pest::push(range) ~ pest::push(range) ~ pest::peek[1..-2] -pop_ = pest::push(range) - pest::push(range) - pest::pop - pest::pop -pop_all = pest::push(range) - pest::push(range) - pest::pop_all -pop_fail = pest::push(range) - !pest::pop - range - pest::pop -checkpoint_restore = pest::push("") - (pest::push("a") - "b" - pest::pop | pest::drop - "b" | pest::pop - "a") - pest::EOI +peek_ = pest::stack::push(range) - pest::stack::push(range) - pest::stack::peek - pest::stack::peek +peek_all = pest::stack::push(range) - pest::stack::push(range) - pest::stack::peek_all +peek_slice_23 = pest::stack::push(range) - pest::stack::push(range) - pest::stack::push(range) ~ pest::stack::push(range) ~ pest::stack::push(range) ~ pest::stack::peek[1..-2] +pop_ = pest::stack::push(range) - pest::stack::push(range) - pest::stack::pop - pest::stack::pop +pop_all = pest::stack::push(range) - pest::stack::push(range) - pest::stack::pop_all +pop_fail = pest::stack::push(range) - !pest::stack::pop - range - pest::stack::pop +checkpoint_restore = pest::stack::push("") - (pest::stack::push("a") - "b" - pest::stack::pop | pest::stack::drop - "b" | pest::stack::pop - "a") - pest::EOI /* ascii_digits = ASCII_DIGIT+ diff --git a/derive/tests/json.pest b/derive/tests/json.pest new file mode 100644 index 0000000..e5c7555 --- /dev/null +++ b/derive/tests/json.pest @@ -0,0 +1,42 @@ +//! A parser for JSON file. +//! +//! And this is a example for JSON parser. +//! +//! Created by [Tomas Tauber](https://github.com/tomtau). +//! Modified by [Boyi Huang](https://github.com/TheVeryDarkness). + +json = pest::SOI ~ value ~ pest::EOI + +/// Matches object, e.g.: `{ "foo": "bar" }` +/// Foobar +object = "{" ~ pair^* ~ "}" +pair = string ~ ":" ~ value + +array = "[" ~ value ~ ("," ~ value)* ~ "]" | "[" ~ "]" + + +////////////////////// +/// Matches value, e.g.: `"foo"`, `42`, `true`, `null`, `[]`, `{}`. +////////////////////// +value = string | number | object | array | bool | null + +string = "\"" - inner - "\"" +inner = (!("\"" | "\\") - pest::any)* - (escape ~ inner)? +escape = "\\" - ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | unicode) +// FIXME: should be under pest::* +ascii_hex_digit = ascii_digit | "A" | "B" | "C" | "D" | "E" | "F" +ascii_digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" +ascii_nonzero_digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" +unicode = "u" - ascii_hex_digit{4} + +number = "-"? - int - ("." ~ ascii_digit+ ~ exp? | exp)? +int = "0" | ascii_nonzero_digit - ascii_digit* +exp = ("E" | "e") - ("+" | "-")? - ascii_digit+ + +bool = "true" | "false" + +null = "null" + +space = " " | "\t" | "\r" | "\n" +~ = space* +^ = space* - "," - space* diff --git a/derive/tests/json.rs b/derive/tests/json.rs new file mode 100644 index 0000000..e2c4200 --- /dev/null +++ b/derive/tests/json.rs @@ -0,0 +1,57 @@ +//! Created by [Tomas Tauber](https://github.com/tomtau). +//! Modified by [Boyi Huang](https://github.com/TheVeryDarkness). + +/// Grammar rules of a sample JSON parser +#[allow(missing_docs)] +pub mod json { + use pest_derive::Parser; + + /// JSON parser. + #[derive(Parser)] + #[grammar = "tests/json.pest"] + pub struct JsonParser; +} + +#[cfg(test)] +mod tests { + use pest::typed::{PairContainer, TypedParser}; + + use crate::{json, json::generics::*}; + #[test] + fn json_basic_test() { + let sample1 = "{\"key\": \"value\"}"; + let s1: json::rules::json = json::JsonParser::try_parse(sample1).unwrap(); + let values = s1.vec_children_pairs(); + assert_eq!(&values[0].rule, &json::Rule::value); + let obj = &values[0].children; + assert_eq!(obj[0].rule, json::Rule::object); + let pair = &obj[0].children; + assert_eq!(pair[0].rule, json::Rule::pair); + let key = &pair[0].children; + assert_eq!(key[0].rule, json::Rule::string); + assert_eq!(&sample1[key[0].start..key[0].end], "\"key\""); + let value = &key[1].children; + assert_eq!(value[0].rule, json::Rule::string); + assert_eq!(&sample1[value[0].start..value[0].end], "\"value\""); + } + + /// Test in structural style. + #[test] + fn json_structural_test() { + let sample1 = "{\"key\": \"value\"}"; + let s1: json::rules::json = json::JsonParser::try_parse(sample1).unwrap(); + let value: json::rules::value<'_> = s1.content.field_1; + match *value.content { + Choice6::Choice2(object) => { + let (_, mut pairs, _) = object.content.into_tuple(); + assert_eq!(pairs.content.len(), 1); + let pair = pairs.content.pop().unwrap(); + let (key, _, value) = pair.content.into_tuple(); + let (_, key, _) = key.content.into_tuple(); + assert_eq!(key.span.as_str(), "key"); + assert_eq!(value.span.as_str(), "\"value\""); + } + _ => {} + } + } +} diff --git a/derive/tests/sample.rs b/derive/tests/sample.rs new file mode 100644 index 0000000..56ee19c --- /dev/null +++ b/derive/tests/sample.rs @@ -0,0 +1,36 @@ +#![allow(unused_variables)] +use anyhow::Result; +use pest::typed::TypedNode as _; +use pest_derive::Parser; + +#[derive(Parser)] +#[grammar = "../meta/tests/pest3sample.pest"] +struct Parser; + +#[test] +fn comment() -> Result<()> { + rules::main::try_parse_partial("x x x /*x*/")?; + rules::main::try_parse("x x x /*x*/").unwrap_err(); + Ok(()) +} + +#[test] +fn skip_on_two_end() -> Result<()> { + rules::main::try_parse_partial("x x ")?; + rules::main::try_parse(" x x").unwrap_err(); + rules::main::try_parse("x x ").unwrap_err(); + Ok(()) +} + +#[test] +fn post_skip() -> Result<()> { + let program = rules::program::try_parse("x x /*x*/")?; + Ok(()) +} + +#[test] +fn pre_skip() -> Result<()> { + rules::program::try_parse("/* x x */ ")?; + rules::program::try_parse("/* x x */ x x")?; + Ok(()) +} diff --git a/generator/Cargo.toml b/generator/Cargo.toml index 6dc70c1..f560bca 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -9,7 +9,7 @@ proc-macro2 = "1.0" quote = "1.0" syn = "2.0" pest_meta.workspace = true +pest.workspace = true [dev-dependencies] lazy_static = { version = "1.4.0" } -pest.workspace = true diff --git a/generator/src/common.rs b/generator/src/common.rs index 6c59862..f267318 100644 --- a/generator/src/common.rs +++ b/generator/src/common.rs @@ -42,23 +42,17 @@ pub(crate) fn generate_rule_enum(rules: &[ParseRule], doc_comment: &DocComment) .map(|rule| { let rule_name = format_ident!("r#{}", rule.name); - match doc_comment.line_docs.get(&rule.name) { - Some(doc) => quote! { + let doc = &rule.doc; + quote! { + #( #[doc = #doc] - #rule_name, - }, - None => quote! { - #rule_name, - }, + )* + #rule_name, } }); let grammar_doc = &doc_comment.grammar_doc; - let grammar_doc = if let Some(grammar_doc) = grammar_doc { - quote! {#[doc = #grammar_doc]} - } else { - quote! {} - }; + let grammar_doc = quote! {#(#[doc = #grammar_doc])*}; quote! { #grammar_doc #[allow(dead_code, missing_docs, non_camel_case_types, clippy::upper_case_acronyms)] diff --git a/generator/src/typed/attr.rs b/generator/src/typed/attr.rs index a737b32..c8db507 100644 --- a/generator/src/typed/attr.rs +++ b/generator/src/typed/attr.rs @@ -21,6 +21,8 @@ pub(crate) fn parse_derive(ast: DeriveInput) -> (Ident, Generics, Vec Self { @@ -10,6 +11,7 @@ impl Default for Config { emit_rule_reference: false, do_not_emit_span: false, no_warnings: false, + box_all_rules: false, } } } diff --git a/generator/src/typed/generator.rs b/generator/src/typed/generator.rs index c79a68e..3b0057b 100644 --- a/generator/src/typed/generator.rs +++ b/generator/src/typed/generator.rs @@ -44,9 +44,16 @@ struct RuleInfo<'g> { pub boxed: bool, } impl<'g> RuleInfo<'g> { - fn from(rule: &'g ParseRule) -> Self { + fn new( + rule: &'g ParseRule, + config: Config, + reachability: &BTreeMap<&str, BTreeSet<&str>>, + ) -> Self { let rule_name = rule.name.as_str(); - let boxed = true; + let boxed = match config.box_all_rules { + true => true, + false => !reachability.contains_key(rule_name), + }; let rule_id = format_ident!("r#{}", rule_name); let silent = rule.silent; Self { @@ -113,17 +120,6 @@ impl<'g> RuleRef<'g> { let path = path.iter().map(String::as_str).collect::>(); Self { path, args } } - /// Create from a name of a rule defined in current module. - pub fn from_current(path: Vec<&'g str>) -> Self { - let args = None; - Self { path, args } - } - /// Create from a name of a rule defined in current module. - fn from_top_level(name: &'g str) -> Self { - let path = vec![name]; - let args = None; - Self { path, args } - } } impl<'g> Display for RuleRef<'g> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -137,6 +133,7 @@ impl<'g> Display for RuleRef<'g> { } fn create_rule<'g>( + config: Config, rule_config: &RuleConfig<'g>, rule_info: &RuleInfo<'g>, inner_type: TokenStream, @@ -148,16 +145,22 @@ fn create_rule<'g>( "Generated for rule `{}`. Grammar: `{}`.", rule_info.rule_name, rule_config.grammar.node, ); + let args: Vec<_> = rule_config + .grammar + .args + .iter() + .map(|s| format_ident!("r#{}", s)) + .collect(); // Pairs inside silent rule will be ignored. let pair_api = match rule_info.silent { true => quote! { - impl<'i> #this::typed::PairContainer<#root::Rule> for #name<'i> { + impl<'i, #(#args, )*> #this::typed::PairContainer<#root::Rule> for #name<'i, #(#args, )*> { fn for_each_child_pair(&self, f: &mut impl #this::std::FnMut(#this::token::Pair<#root::Rule>)) {} fn for_self_or_for_each_child_pair(&self, f: &mut impl #this::std::FnMut(#this::token::Pair<#root::Rule>)) {} } }, false => quote! { - impl<'i> #this::typed::PairContainer<#root::Rule> for #name<'i> { + impl<'i, #(#args, )*> #this::typed::PairContainer<#root::Rule> for #name<'i, #(#args, )*> { fn for_each_child_pair(&self, f: &mut impl #this::std::FnMut(#this::token::Pair<#root::Rule>)) { self.content.for_self_or_for_each_child_pair(f) } @@ -166,36 +169,37 @@ fn create_rule<'g>( f(self.as_pair_tree()) } } - impl<'i> #this::typed::PairTree<#root::Rule> for #name<'i> { + impl<'i, #(#args, )*> #this::typed::PairTree<#root::Rule> for #name<'i, #(#args, )*> { fn get_span(&self) -> (#this::std::usize, #this::std::usize) { (self.span.start(), self.span.end()) } } }, }; + let content_type = if rule_info.boxed { + quote! {#this::std::Box<#inner_type>} + } else { + inner_type.clone() + }; quote! { #[doc = #doc] #[derive(Clone, Debug, Eq, PartialEq)] - pub struct #name<'i> { - content: #this::std::Box<#inner_type>, - span: #this::Span<'i>, + pub struct #name<'i, #(#args, )*> { + /// Matched structure. + pub content: #content_type, + /// Matched span. + pub span: #this::Span<'i>, } - impl<'i> #this::typed::wrapper::Rule<#root::Rule> for #name<'i> { + impl<'i, #(#args, )*> #this::typed::wrapper::Rule for #name<'i, #(#args, )*> { type Rule = #root::Rule; const RULE: #root::Rule = #root::Rule::#name; } - impl<'i> #this::typed::TypedNode<'i, #root::Rule> for #name<'i> { - fn try_parse_with_partial( - input: #this::Position<'i>, - stack: &mut #this::Stack<#this::Span<'i>>, - tracker: &mut #this::typed::Tracker<'i, #root::Rule>, - ) -> #this::std::Option<(#this::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = #inner_type::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - #this::std::Some((pos, Self{ content, span })) - }) + impl<'i, #(#args, )*> #this::typed::FullRuleStruct<'i> for #name<'i, #(#args, )*> { + type Inner = #inner_type; + type Content = #content_type; + #[inline] + fn new(content: >::Content, span: #this::Span<'i>) -> Self { + Self { content, span } } } #pair_api @@ -285,10 +289,8 @@ fn process_expr<'g>( ProcessedPathArgs::process(args, rule_config, output, config, mod_sys, root) }); let rule_ref = RuleRef::new(prefix, args); - let typename = mod_sys.resolve(&rule_ref, root).expect(&format!( - "`{rule_ref}` can't be resolved. Available rules are: {:?}", - mod_sys.keys() - )); + let typename = mod_sys + .resolve(rule_config.grammar, &rule_ref, root); Intermediate { typename } } ParseExpr::PosPred(node) => { @@ -389,6 +391,7 @@ fn process_expr<'g>( fn process_rule<'g: 'f, 'f>( rule: &'g ParseRule, mod_sys: &ModuleSystem<'g>, + reachability: &BTreeMap<&str, BTreeSet<&str>>, config: Config, res: &mut Output<'g>, ) { @@ -405,8 +408,9 @@ fn process_rule<'g: 'f, 'f>( "~" => res.add_option_trivia(inter.typename), "^" => res.add_mandatory_trivia(inter.typename), _ => { - let rule_info = RuleInfo::from(rule); + let rule_info = RuleInfo::new(rule, config, reachability); res.insert_rule_struct(create_rule( + config, &rule_config, &rule_info, inter.typename, @@ -421,15 +425,16 @@ fn process_rules<'g: 'f, 'f>( mod_sys: &mut ModuleSystem<'g>, config: Config, ) -> Output<'g> { + let reachability = collect_reachability(rules); for rule in rules.iter() { match rule.name.as_str() { "~" | "^" => {} - _ => mod_sys.insert_rule(&rule.name), + _ => mod_sys.insert_rule(rule), } } let mut res = Output::new(); for rule in rules.iter() { - process_rule(rule, mod_sys, config, &mut res); + process_rule(rule, mod_sys, &reachability, config, &mut res); } res } @@ -492,6 +497,7 @@ fn collect_used_rule<'g>( } } +#[cfg(test)] fn collect_used_rules<'s>(rules: &'s [ParseRule]) -> BTreeSet<&'s str> { let mut res = BTreeSet::new(); let rule_trivia = rules.iter().find(|rule| rule.name == "~"); @@ -501,6 +507,13 @@ fn collect_used_rules<'s>(rules: &'s [ParseRule]) -> BTreeSet<&'s str> { res } +/// Wrap some nodes in [std::boxed::Box] to avoid infinite size struct, +/// which can break the edges in the reference graph, +/// and then collect reachability. +/// +/// Rules that are not in map keys are wrapped. +/// +/// We won't promise anything on which nodes are boxed. fn collect_reachability(rules: &[ParseRule]) -> BTreeMap<&str, BTreeSet<&str>> { let mut res = BTreeMap::new(); let rule_trivia = rules.iter().find(|rule| rule.name == "~"); @@ -508,7 +521,11 @@ fn collect_reachability(rules: &[ParseRule]) -> BTreeMap<&str, BTreeSet<&str>> { let entry = res.entry(rule.name.as_str()).or_default(); collect_used_rule(rule, rule_trivia, entry); } + // Length of any path is no more than `rules.len()`. for _ in 0..rules.len() { + // Before the `i`-th iteration, + // `res[a]` contains all nodes that can be reached from `a` + // in no more than `i+1` steps. for rule in rules { let rule_ref = rule.name.as_str(); if let Some(cur) = res.remove(&rule_ref) { @@ -528,7 +545,6 @@ fn collect_reachability(rules: &[ParseRule]) -> BTreeMap<&str, BTreeSet<&str>> { } fn generate_typed_pair_from_rule(rules: &[ParseRule], config: Config) -> TokenStream { - let defined_rules: BTreeSet<&str> = rules.iter().map(|rule| rule.name.as_str()).collect(); let mut mod_sys = ModuleSystem::new(); let graph = process_rules(rules, &mut mod_sys, config); graph.collect() @@ -572,6 +588,7 @@ fn generate_typed( res } +/// Derive typed parser from given grammar, attributes and type. pub fn derive_typed_parser( input: TokenStream, include_grammar: bool, diff --git a/generator/src/typed/module.rs b/generator/src/typed/module.rs index c85c85c..fd56497 100644 --- a/generator/src/typed/module.rs +++ b/generator/src/typed/module.rs @@ -2,14 +2,23 @@ use super::{ generator::{ProcessedPathArgs, RuleRef}, output::generics, }; +use pest::unicode::unicode_property_names; +use pest_meta::parser::ParseRule; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use std::collections::{btree_map::Keys, BTreeMap}; +use std::{ + cell::RefCell, + collections::{btree_map::Keys, BTreeMap, HashMap, HashSet}, + rc::Rc, +}; #[derive(Clone, Debug)] pub enum RuleGenerics { /// Defined rule in current module. - Rule, + Rule { + argc: usize, + }, + Unicode(Ident), BuiltIn { /// Built-in rule that accepts nothing as argument. /// @@ -27,36 +36,48 @@ pub enum RuleGenerics { }, } impl RuleGenerics { - pub fn call(&self, rule_ref: &RuleRef<'_>, root: &TokenStream) -> TokenStream { - let getter = || { - let mut path = rule_ref.path.iter().map(|s| format_ident!("{}", s)); - let name = path.next_back().unwrap(); - (path, name) - }; - let builtin_getter = || { - assert_eq!(rule_ref.path.len(), 2); - let name = rule_ref.path.last().unwrap(); - let name = format_ident!("r#{}", name); - name - }; + pub fn call( + &self, + name: &str, + rule_ref: &RuleRef<'_>, + args: Option<&ProcessedPathArgs>, + root: &TokenStream, + ) -> TokenStream { let generics = generics(); + let name = format_ident!("r#{}", name); match self { - Self::Rule => { - assert!( - rule_ref.args.is_none(), - "Unexpected arguments in `{}`.", - rule_ref, - ); - let (path, name) = getter(); - quote! { #root::rules::#( #path:: )* #name :: <'i> } + Self::Rule { argc } => match (argc, args) { + (0, None) => { + quote! { #root::rules::#name::<'i> } + } + (0, Some(_args)) => { + panic!("Unexpected arguments in `{}`.", rule_ref,); + } + (argc, None) => { + panic!("Expect {argc} arguments in `{rule_ref}`."); + } + (_argc, Some(ProcessedPathArgs::Slice(slice))) => { + panic!("Unexpected slice {slice} in `{rule_ref}`."); + } + (argc, Some(ProcessedPathArgs::Call(args))) => { + assert_eq!( + *argc, + args.len(), + "Argument count not matched in `{}`.", + rule_ref + ); + quote! { #root::rules::#name::<'i, #(#args, )*> } + } + }, + Self::Unicode(ident) => { + quote! { #root::rules::unicode::#ident } } Self::BuiltIn { direct, slice, callable, - } => match &rule_ref.args { + } => match args { None => { - let name = builtin_getter(); let (lifetime,) = direct.expect(&format!( "Built-in rule {rule_ref} can't be called without arguments." )); @@ -83,7 +104,6 @@ impl RuleGenerics { if let Some(argc) = argc { assert_eq!(args.len(), argc, "Argument count not matched."); } - let name = builtin_getter(); quote! { #root::#generics::#name::< #( #args, )* > } } }, @@ -91,13 +111,62 @@ impl RuleGenerics { } } +#[derive(Clone, Debug)] +enum ModuleNode<'g> { + // MutableCollection(RefCell>>>), + Collection(HashMap<&'g str, Rc>>), + Map { + bound: HashSet, + mapper: fn(&'g str) -> TokenStream, + }, + Generics(RuleGenerics), + Imported(Rc), +} + +impl<'g> ModuleNode<'g> { + /// [Err] here is actually not an error. + fn child(&self, node: &'g str) -> &Self { + match self { + Self::Collection(map) => map.get(node).unwrap_or_else(|| { + panic!( + "Node {} can't be resolved. Available nodes are {:?}.", + node, + map.keys() + ) + }), + Self::Map { bound, mapper } => { + assert!(bound.contains(node), "{node} is out of bound."); + panic!("No child found.") + } + Self::Generics(_generics) => panic!("No child found."), + Self::Imported(rc) => rc.child(node), + } + } + fn get( + &self, + root: &TokenStream, + node: &'g str, + rule_ref: &RuleRef<'g>, + args: &Option, + ) -> TokenStream { + match self { + Self::Collection(map) => panic!("Collection can't be called."), + Self::Map { bound, mapper } => { + assert!(args.is_none(), "Unexpected arguments."); + mapper(node) + } + Self::Generics(generics) => generics.call(node, rule_ref, args.as_ref(), root), + Self::Imported(rc) => rc.get(root, node, rule_ref, args), + } + } +} + /// Module system for pest3. /// /// `'g` stands for the lifetime of grammar file content. #[derive(Clone, Debug)] pub struct ModuleSystem<'g> { - /// Path -> Rule. - tree: BTreeMap, RuleGenerics>, + root: ModuleNode<'g>, } impl<'g> ModuleSystem<'g> { @@ -123,19 +192,20 @@ impl<'g> ModuleSystem<'g> { macro_rules! pest_builtin { ( $name:ident $( {$($direct:tt)*} )? $( [$($slice:tt)*] )? $( ($($callable:tt)*) )? ) => { ( - vec!["pest", core::stringify!($name)], - RuleGenerics::BuiltIn { - direct: None $( .or(Some(pest_direct! { $($direct)* })) )?, - slice: None $( .or(Some(pest_slice! { $( $slice )* })) )?, - callable: None $( .or(Some(pest_callable! { $( $callable )* })) )?, - }, + core::stringify!($name), + Rc::new( + ModuleNode::Generics( + RuleGenerics::BuiltIn { + direct: None $( .or(Some(pest_direct! { $($direct)* })) )?, + slice: None $( .or(Some(pest_slice! { $( $slice )* })) )?, + callable: None $( .or(Some(pest_callable! { $( $callable )* })) )?, + }, + ) + ) ) }; } - let tree = BTreeMap::from([ - pest_builtin!(SOI {}), - pest_builtin!(EOI {}), - pest_builtin!(any {}), + let pest_stack = HashMap::from([ pest_builtin!(peek {'i} [PeekSlice1, PeekSlice2]), pest_builtin!(peek_all {'i}), pest_builtin!(drop {}), @@ -143,18 +213,65 @@ impl<'g> ModuleSystem<'g> { pest_builtin!(pop {'i}), pest_builtin!(pop_all {'i}), ]); - Self { tree } - } - pub fn insert_rule(&mut self, key: &'g str) { - let value = RuleGenerics::Rule; - self.tree.insert(vec![key], value); + let bound = HashSet::from_iter(unicode_property_names().map(|unicode| { + assert!(unicode.is_ascii()); + // let ident = format_ident!("{}", unicode.to_ascii_lowercase()); + unicode.to_ascii_lowercase() + })); + let mapper = |s: &'g str| { + let ident = format_ident!("{}", s.to_ascii_uppercase()); + quote! {#ident} + }; + let pest_unicode = ModuleNode::Map { bound, mapper }; + let pest = HashMap::from([ + pest_builtin!(SOI {}), + pest_builtin!(EOI {}), + pest_builtin!(soi {}), + pest_builtin!(eoi {}), + pest_builtin!(any {}), + ("stack", Rc::new(ModuleNode::Collection(pest_stack))), + ("unicode", Rc::new(pest_unicode)), + ]); + let root = ModuleNode::Collection(HashMap::from([( + "pest", + Rc::new(ModuleNode::Collection(pest)), + )])); + + Self { root } } - pub fn resolve(&self, rule_ref: &RuleRef<'g>, root: &TokenStream) -> Option { - self.tree - .get(&rule_ref.path) - .map(|rg| rg.call(rule_ref, root)) + pub fn insert_rule(&mut self, rule: &'g ParseRule) { + let key = &rule.name; + let argc = rule.args.len(); + let value = RuleGenerics::Rule { argc }; + if let ModuleNode::Collection(root) = &mut self.root { + root.insert(key, Rc::new(ModuleNode::Generics(value))); + } } - pub fn keys(&self) -> Keys<'_, Vec<&'g str>, RuleGenerics> { - self.tree.keys() + pub fn resolve( + &self, + rule: &'g ParseRule, + rule_ref: &RuleRef<'g>, + root: &TokenStream, + ) -> TokenStream { + // Rule generics arguments. + if let None = rule_ref.args { + if rule_ref.path.len() == 1 { + let arg = rule.args.iter().find(|arg| arg == &rule_ref.path[0]); + if let Some(arg) = arg { + let ident = format_ident!("r#{}", arg); + return quote! {#ident}; + } + } + } + let mut rc = &self.root; + for node in &rule_ref.path { + rc = rc.child(node); + } + rc.get( + root, + rule_ref.path.last().unwrap(), + rule_ref, + &rule_ref.args, + ) } } diff --git a/generator/src/typed/output.rs b/generator/src/typed/output.rs index e344d8b..1fbc930 100644 --- a/generator/src/typed/output.rs +++ b/generator/src/typed/output.rs @@ -165,8 +165,9 @@ impl<'g> Output<'g> { Positive, Negative, CharRange, Str, Insens, Rep, RepOnce, RepMin, RepMax, RepMinMax, - SOI as SOI, - EOI as EOI, + SOI,EOI, + SOI as soi, + EOI as eoi, ANY as any, PEEK as peek, PeekSlice1, PeekSlice2, diff --git a/generator/tests/.gitignore b/generator/tests/.gitignore index 3c52ba5..9e4a659 100644 --- a/generator/tests/.gitignore +++ b/generator/tests/.gitignore @@ -1 +1,2 @@ -generated.rs \ No newline at end of file +generated.rs +generated_sample.rs \ No newline at end of file diff --git a/generator/tests/expected.rs b/generator/tests/expected.rs index 9724ac6..880aca4 100644 --- a/generator/tests/expected.rs +++ b/generator/tests/expected.rs @@ -1,9 +1,18 @@ -#[allow(dead_code, missing_docs, non_camel_case_types, clippy::upper_case_acronyms)] +#[doc = "For compatibility."] +#[allow( + dead_code, + missing_docs, + non_camel_case_types, + clippy::upper_case_acronyms +)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum Rule { EOI, + #[doc = "Regular rule."] r#Regular, + #[doc = "Atomic rule."] r#Atomic, + #[doc = "Silent rule."] r#NonAtomic, r#ExactString, r#CharRange, @@ -36,8 +45,10 @@ impl ::pest::typed::RuleType for Rule { type MandatoryTrivia<'i> = trivia::MandatoryTrivia<'i>; } mod trivia { - pub type OptionalTrivia<'i> = super::generics::Rep, 0u8>; - pub type MandatoryTrivia<'i> = super::generics::RepOnce, 0u8>; + pub type OptionalTrivia<'i> = + super::generics::Rep, 0u8>; + pub type MandatoryTrivia<'i> = + super::generics::RepOnce, 0u8>; } mod wrapper { #[doc = "A wrapper for `\" \"`."] @@ -112,28 +123,37 @@ pub mod rules { #[doc = "Generated for rule `Regular`. Grammar: `'0'..'9'+`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Regular<'i> { - content: ::pest::std::Box, 0u8>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::RepOnce, 0u8>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Regular<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Regular<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Regular; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Regular<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepOnce::, 0u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Regular<'i> { + type Inner = super::generics::RepOnce, 0u8>; + type Content = super::generics::RepOnce, 0u8>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Regular<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -146,28 +166,58 @@ pub mod rules { #[doc = "Generated for rule `Atomic`. Grammar: `(CharRange+ ~ (\"+\" ~ CharRange+))`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Atomic<'i> { - content: ::pest::std::Box, 0u8>, 0u8, super::generics::Str, 1u8, super::generics::RepOnce, 0u8>, 1u8>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Atomic<'i> { + #[doc = r" Matched structure."] + pub content: super::generics::Sequence3< + super::generics::RepOnce, 0u8>, + 0u8, + super::generics::Str, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Atomic<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Atomic; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Atomic<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Sequence3::, 0u8>, 0u8, super::generics::Str, 1u8, super::generics::RepOnce, 0u8>, 1u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Atomic<'i> { + type Inner = super::generics::Sequence3< + super::generics::RepOnce, 0u8>, + 0u8, + super::generics::Str, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + >; + type Content = super::generics::Sequence3< + super::generics::RepOnce, 0u8>, + 0u8, + super::generics::Str, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Atomic<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -180,28 +230,52 @@ pub mod rules { #[doc = "Generated for rule `NonAtomic`. Grammar: `(\"(\" ^ \")\")`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#NonAtomic<'i> { - content: ::pest::std::Box, 0u8, super::generics::Str, 2u8>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#NonAtomic<'i> { + #[doc = r" Matched structure."] + pub content: super::generics::Sequence2< + super::generics::Str, + 0u8, + super::generics::Str, + 2u8, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#NonAtomic<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#NonAtomic; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#NonAtomic<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Sequence2::, 0u8, super::generics::Str, 2u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#NonAtomic<'i> { + type Inner = super::generics::Sequence2< + super::generics::Str, + 0u8, + super::generics::Str, + 2u8, + >; + type Content = super::generics::Sequence2< + super::generics::Str, + 0u8, + super::generics::Str, + 2u8, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#NonAtomic<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -214,28 +288,37 @@ pub mod rules { #[doc = "Generated for rule `ExactString`. Grammar: `\"r#\"`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#ExactString<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::Str, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#ExactString<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#ExactString<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#ExactString; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#ExactString<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Str::::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#ExactString<'i> { + type Inner = super::generics::Str; + type Content = super::generics::Str; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#ExactString<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -248,28 +331,37 @@ pub mod rules { #[doc = "Generated for rule `CharRange`. Grammar: `'0'..'9'`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#CharRange<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::CharRange<'0', '9'>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#CharRange<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#CharRange<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#CharRange; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#CharRange<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::CharRange::<'0', '9'>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#CharRange<'i> { + type Inner = super::generics::CharRange<'0', '9'>; + type Content = super::generics::CharRange<'0', '9'>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#CharRange<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -282,28 +374,37 @@ pub mod rules { #[doc = "Generated for rule `Any`. Grammar: `pest::any`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Any<'i> { - content: ::pest::std::Box, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#any, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Any<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Any<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Any; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Any<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#any::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Any<'i> { + type Inner = super::generics::r#any; + type Content = super::generics::r#any; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Any<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -316,28 +417,58 @@ pub mod rules { #[doc = "Generated for rule `Seq`. Grammar: `(\"1\" ~ ('2'..'9' ~ \".\"))`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Seq<'i> { - content: ::pest::std::Box, 0u8, super::generics::CharRange<'2', '9'>, 1u8, super::generics::Str, 1u8>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Seq<'i> { + #[doc = r" Matched structure."] + pub content: super::generics::Sequence3< + super::generics::Str, + 0u8, + super::generics::CharRange<'2', '9'>, + 1u8, + super::generics::Str, + 1u8, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Seq<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Seq; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Seq<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Sequence3::, 0u8, super::generics::CharRange<'2', '9'>, 1u8, super::generics::Str, 1u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Seq<'i> { + type Inner = super::generics::Sequence3< + super::generics::Str, + 0u8, + super::generics::CharRange<'2', '9'>, + 1u8, + super::generics::Str, + 1u8, + >; + type Content = super::generics::Sequence3< + super::generics::Str, + 0u8, + super::generics::CharRange<'2', '9'>, + 1u8, + super::generics::Str, + 1u8, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Seq<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -350,28 +481,113 @@ pub mod rules { #[doc = "Generated for rule `Choice`. Grammar: `(\"a\" | ((\"b\"+ ~ RepAtLeastOnce) | ((&\"c\" ~ (Choice ~ (Rep ~ Opt))) | (Peek | (PeekLeft | (PeekRight | (PeekLeftRight | (Drop | PeekAll))))))))`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Choice<'i> { - content: ::pest::std::Box, super::generics::Sequence2, 0u8>, 0u8, super::rules::RepAtLeastOnce<'i>, 1u8>, super::generics::Sequence4>, 0u8, super::rules::Choice<'i>, 1u8, super::rules::Rep<'i>, 1u8, super::rules::Opt<'i>, 1u8>, super::rules::Peek<'i>, super::rules::PeekLeft<'i>, super::rules::PeekRight<'i>, super::rules::PeekLeftRight<'i>, super::rules::Drop<'i>, super::rules::PeekAll<'i>>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Choice<'i> { + #[doc = r" Matched structure."] + pub content: ::pest::std::Box< + super::generics::Choice9< + super::generics::Str, + super::generics::Sequence2< + super::generics::RepOnce, 0u8>, + 0u8, + super::rules::r#RepAtLeastOnce<'i>, + 1u8, + >, + super::generics::Sequence4< + super::generics::Positive>, + 0u8, + super::rules::r#Choice<'i>, + 1u8, + super::rules::r#Rep<'i>, + 1u8, + super::rules::r#Opt<'i>, + 1u8, + >, + super::rules::r#Peek<'i>, + super::rules::r#PeekLeft<'i>, + super::rules::r#PeekRight<'i>, + super::rules::r#PeekLeftRight<'i>, + super::rules::r#Drop<'i>, + super::rules::r#PeekAll<'i>, + >, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Choice<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Choice; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Choice<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Choice9::, super::generics::Sequence2, 0u8>, 0u8, super::rules::RepAtLeastOnce<'i>, 1u8>, super::generics::Sequence4>, 0u8, super::rules::Choice<'i>, 1u8, super::rules::Rep<'i>, 1u8, super::rules::Opt<'i>, 1u8>, super::rules::Peek<'i>, super::rules::PeekLeft<'i>, super::rules::PeekRight<'i>, super::rules::PeekLeftRight<'i>, super::rules::Drop<'i>, super::rules::PeekAll<'i>>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Choice<'i> { + type Inner = super::generics::Choice9< + super::generics::Str, + super::generics::Sequence2< + super::generics::RepOnce, 0u8>, + 0u8, + super::rules::r#RepAtLeastOnce<'i>, + 1u8, + >, + super::generics::Sequence4< + super::generics::Positive>, + 0u8, + super::rules::r#Choice<'i>, + 1u8, + super::rules::r#Rep<'i>, + 1u8, + super::rules::r#Opt<'i>, + 1u8, + >, + super::rules::r#Peek<'i>, + super::rules::r#PeekLeft<'i>, + super::rules::r#PeekRight<'i>, + super::rules::r#PeekLeftRight<'i>, + super::rules::r#Drop<'i>, + super::rules::r#PeekAll<'i>, + >; + type Content = ::pest::std::Box< + super::generics::Choice9< + super::generics::Str, + super::generics::Sequence2< + super::generics::RepOnce, 0u8>, + 0u8, + super::rules::r#RepAtLeastOnce<'i>, + 1u8, + >, + super::generics::Sequence4< + super::generics::Positive>, + 0u8, + super::rules::r#Choice<'i>, + 1u8, + super::rules::r#Rep<'i>, + 1u8, + super::rules::r#Opt<'i>, + 1u8, + >, + super::rules::r#Peek<'i>, + super::rules::r#PeekLeft<'i>, + super::rules::r#PeekRight<'i>, + super::rules::r#PeekLeftRight<'i>, + super::rules::r#Drop<'i>, + super::rules::r#PeekAll<'i>, + >, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Choice<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -384,28 +600,37 @@ pub mod rules { #[doc = "Generated for rule `Rep`. Grammar: `\"b\"*`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Rep<'i> { - content: ::pest::std::Box, 0u8>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::Rep, 0u8>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Rep<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Rep<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Rep; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Rep<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Rep::, 0u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Rep<'i> { + type Inner = super::generics::Rep, 0u8>; + type Content = super::generics::Rep, 0u8>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Rep<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -418,28 +643,37 @@ pub mod rules { #[doc = "Generated for rule `RepAtLeastOnce`. Grammar: `'0'..'9'+`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#RepAtLeastOnce<'i> { - content: ::pest::std::Box, 0u8>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::RepOnce, 0u8>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#RepAtLeastOnce<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#RepAtLeastOnce<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#RepAtLeastOnce; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#RepAtLeastOnce<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepOnce::, 0u8>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#RepAtLeastOnce<'i> { + type Inner = super::generics::RepOnce, 0u8>; + type Content = super::generics::RepOnce, 0u8>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#RepAtLeastOnce<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -452,28 +686,37 @@ pub mod rules { #[doc = "Generated for rule `Opt`. Grammar: `\"?\"?`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Opt<'i> { - content: ::pest::std::Box<::pest::std::Option>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: ::pest::std::Option>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Opt<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Opt<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Opt; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Opt<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = ::pest::std::Option::>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Opt<'i> { + type Inner = ::pest::std::Option>; + type Content = ::pest::std::Option>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Opt<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -486,28 +729,40 @@ pub mod rules { #[doc = "Generated for rule `RepExact`. Grammar: `RepAtLeastOnce[3..3]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#RepExact<'i> { - content: ::pest::std::Box, 0u8, 3usize, 3usize>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: + super::generics::RepMinMax, 0u8, 3usize, 3usize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#RepExact<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#RepExact<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#RepExact; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#RepExact<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepMinMax::, 0u8, 3usize, 3usize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#RepExact<'i> { + type Inner = + super::generics::RepMinMax, 0u8, 3usize, 3usize>; + type Content = + super::generics::RepMinMax, 0u8, 3usize, 3usize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#RepExact<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -520,28 +775,37 @@ pub mod rules { #[doc = "Generated for rule `RepLeft`. Grammar: `RepExact[1..]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#RepLeft<'i> { - content: ::pest::std::Box, 0u8, 1usize>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::RepMin, 0u8, 1usize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#RepLeft<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#RepLeft<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#RepLeft; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#RepLeft<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepMin::, 0u8, 1usize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#RepLeft<'i> { + type Inner = super::generics::RepMin, 0u8, 1usize>; + type Content = super::generics::RepMin, 0u8, 1usize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#RepLeft<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -554,28 +818,37 @@ pub mod rules { #[doc = "Generated for rule `RepRight`. Grammar: `RepLeft[..2]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#RepRight<'i> { - content: ::pest::std::Box, 0u8, 2usize>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::RepMax, 0u8, 2usize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#RepRight<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#RepRight<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#RepRight; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#RepRight<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepMax::, 0u8, 2usize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#RepRight<'i> { + type Inner = super::generics::RepMax, 0u8, 2usize>; + type Content = super::generics::RepMax, 0u8, 2usize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#RepRight<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -588,28 +861,38 @@ pub mod rules { #[doc = "Generated for rule `RepLeftRight`. Grammar: `RepRight[1..2]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#RepLeftRight<'i> { - content: ::pest::std::Box, 0u8, 1usize, 2usize>>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::RepMinMax, 0u8, 1usize, 2usize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#RepLeftRight<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#RepLeftRight<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#RepLeftRight; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#RepLeftRight<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::RepMinMax::, 0u8, 1usize, 2usize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#RepLeftRight<'i> { + type Inner = super::generics::RepMinMax, 0u8, 1usize, 2usize>; + type Content = + super::generics::RepMinMax, 0u8, 1usize, 2usize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#RepLeftRight<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -622,28 +905,58 @@ pub mod rules { #[doc = "Generated for rule `Pos`. Grammar: `&(pest::SOI ~ RepLeftRight[2..4])`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Pos<'i> { - content: ::pest::std::Box, 0u8, 2usize, 4usize>, 1u8>>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Pos<'i> { + #[doc = r" Matched structure."] + pub content: super::generics::Positive< + super::generics::Sequence2< + super::generics::r#SOI, + 0u8, + super::generics::RepMinMax, 0u8, 2usize, 4usize>, + 1u8, + >, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Pos<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Pos; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Pos<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Positive::, 0u8, 2usize, 4usize>, 1u8>>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Pos<'i> { + type Inner = super::generics::Positive< + super::generics::Sequence2< + super::generics::r#SOI, + 0u8, + super::generics::RepMinMax, 0u8, 2usize, 4usize>, + 1u8, + >, + >; + type Content = super::generics::Positive< + super::generics::Sequence2< + super::generics::r#SOI, + 0u8, + super::generics::RepMinMax, 0u8, 2usize, 4usize>, + 1u8, + >, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Pos<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -656,28 +969,43 @@ pub mod rules { #[doc = "Generated for rule `Neg`. Grammar: `!(pest::EOI ~ Pos)`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Neg<'i> { - content: ::pest::std::Box, 1u8>>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Neg<'i> { + #[doc = r" Matched structure."] + pub content: super::generics::Negative< + super::generics::Sequence2, 1u8>, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Neg<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Neg; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Neg<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::Negative::, 1u8>>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Neg<'i> { + type Inner = super::generics::Negative< + super::generics::Sequence2, 1u8>, + >; + type Content = super::generics::Negative< + super::generics::Sequence2, 1u8>, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Neg<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -687,31 +1015,95 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `Push`. Grammar: `pest::push((RepLeft* ~ (Neg ~ (ExactString+ ~ (Push ~ (Pop ~ (Push ~ PopAll)))))))`."] + #[doc = "Generated for rule `Push`. Grammar: `pest::stack::push((RepLeft* ~ (Neg ~ (ExactString+ ~ (Push ~ (Pop ~ (Push ~ PopAll)))))))`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Push<'i> { - content: ::pest::std::Box, 0u8>, 0u8, super::rules::Neg<'i>, 1u8, super::generics::RepOnce, 0u8>, 1u8, super::rules::Push<'i>, 1u8, super::rules::Pop<'i>, 1u8, super::rules::Push<'i>, 1u8, super::rules::PopAll<'i>, 1u8>>>, - span: ::pest::Span<'i>, - } - impl<'i> ::pest::typed::wrapper::Rule for r#Push<'i> { + #[doc = r" Matched structure."] + pub content: ::pest::std::Box< + super::generics::r#push< + super::generics::Sequence7< + super::generics::Rep, 0u8>, + 0u8, + super::rules::r#Neg<'i>, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#Pop<'i>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#PopAll<'i>, + 1u8, + >, + >, + >, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, + } + impl<'i> ::pest::typed::wrapper::Rule for r#Push<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Push; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Push<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#push::, 0u8>, 0u8, super::rules::Neg<'i>, 1u8, super::generics::RepOnce, 0u8>, 1u8, super::rules::Push<'i>, 1u8, super::rules::Pop<'i>, 1u8, super::rules::Push<'i>, 1u8, super::rules::PopAll<'i>, 1u8>>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Push<'i> { + type Inner = super::generics::r#push< + super::generics::Sequence7< + super::generics::Rep, 0u8>, + 0u8, + super::rules::r#Neg<'i>, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#Pop<'i>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#PopAll<'i>, + 1u8, + >, + >; + type Content = ::pest::std::Box< + super::generics::r#push< + super::generics::Sequence7< + super::generics::Rep, 0u8>, + 0u8, + super::rules::r#Neg<'i>, + 1u8, + super::generics::RepOnce, 0u8>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#Pop<'i>, + 1u8, + super::rules::r#Push<'i>, + 1u8, + super::rules::r#PopAll<'i>, + 1u8, + >, + >, + >; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Push<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -721,31 +1113,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `Pop`. Grammar: `pest::pop`."] + #[doc = "Generated for rule `Pop`. Grammar: `pest::stack::pop`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Pop<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#pop<'i>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Pop<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Pop<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Pop; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Pop<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#pop::<'i>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Pop<'i> { + type Inner = super::generics::r#pop<'i>; + type Content = super::generics::r#pop<'i>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Pop<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -755,31 +1156,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PopAll`. Grammar: `pest::pop_all`."] + #[doc = "Generated for rule `PopAll`. Grammar: `pest::stack::pop_all`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PopAll<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#pop_all<'i>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PopAll<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PopAll<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PopAll; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PopAll<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#pop_all::<'i>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PopAll<'i> { + type Inner = super::generics::r#pop_all<'i>; + type Content = super::generics::r#pop_all<'i>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PopAll<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -789,31 +1199,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `Peek`. Grammar: `pest::peek`."] + #[doc = "Generated for rule `Peek`. Grammar: `pest::stack::peek`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Peek<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#peek<'i>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Peek<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Peek<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Peek; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Peek<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#peek::<'i>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Peek<'i> { + type Inner = super::generics::r#peek<'i>; + type Content = super::generics::r#peek<'i>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Peek<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -823,31 +1242,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PeekUnlimited`. Grammar: `pest::peek[..]`."] + #[doc = "Generated for rule `PeekUnlimited`. Grammar: `pest::stack::peek[..]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PeekUnlimited<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::PeekSlice1<0isize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PeekUnlimited<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PeekUnlimited<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PeekUnlimited; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PeekUnlimited<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::PeekSlice1::<0isize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PeekUnlimited<'i> { + type Inner = super::generics::PeekSlice1<0isize>; + type Content = super::generics::PeekSlice1<0isize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PeekUnlimited<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -857,31 +1285,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PeekLeft`. Grammar: `pest::peek[1..]`."] + #[doc = "Generated for rule `PeekLeft`. Grammar: `pest::stack::peek[1..]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PeekLeft<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::PeekSlice1<1isize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PeekLeft<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PeekLeft<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PeekLeft; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PeekLeft<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::PeekSlice1::<1isize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PeekLeft<'i> { + type Inner = super::generics::PeekSlice1<1isize>; + type Content = super::generics::PeekSlice1<1isize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PeekLeft<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -891,31 +1328,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PeekRight`. Grammar: `pest::peek[..]`."] + #[doc = "Generated for rule `PeekRight`. Grammar: `pest::stack::peek[..]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PeekRight<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::PeekSlice1<0isize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PeekRight<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PeekRight<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PeekRight; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PeekRight<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::PeekSlice1::<0isize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PeekRight<'i> { + type Inner = super::generics::PeekSlice1<0isize>; + type Content = super::generics::PeekSlice1<0isize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PeekRight<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -925,31 +1371,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PeekLeftRight`. Grammar: `pest::peek[1..2]`."] + #[doc = "Generated for rule `PeekLeftRight`. Grammar: `pest::stack::peek[1..2]`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PeekLeftRight<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::PeekSlice2<1isize, 2isize>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PeekLeftRight<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PeekLeftRight<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PeekLeftRight; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PeekLeftRight<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::PeekSlice2::<1isize, 2isize>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PeekLeftRight<'i> { + type Inner = super::generics::PeekSlice2<1isize, 2isize>; + type Content = super::generics::PeekSlice2<1isize, 2isize>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PeekLeftRight<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -959,31 +1414,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `Drop`. Grammar: `pest::drop`."] + #[doc = "Generated for rule `Drop`. Grammar: `pest::stack::drop`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#Drop<'i> { - content: ::pest::std::Box, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#drop, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#Drop<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#Drop<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#Drop; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#Drop<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#drop::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#Drop<'i> { + type Inner = super::generics::r#drop; + type Content = super::generics::r#drop; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#Drop<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -993,31 +1457,40 @@ pub mod rules { (self.span.start(), self.span.end()) } } - #[doc = "Generated for rule `PeekAll`. Grammar: `pest::peek_all`."] + #[doc = "Generated for rule `PeekAll`. Grammar: `pest::stack::peek_all`."] #[derive(Clone, Debug, Eq, PartialEq)] pub struct r#PeekAll<'i> { - content: ::pest::std::Box>, - span: ::pest::Span<'i>, + #[doc = r" Matched structure."] + pub content: super::generics::r#peek_all<'i>, + #[doc = r" Matched span."] + pub span: ::pest::Span<'i>, } - impl<'i> ::pest::typed::wrapper::Rule for r#PeekAll<'i> { + impl<'i> ::pest::typed::wrapper::Rule for r#PeekAll<'i> { type Rule = super::Rule; const RULE: super::Rule = super::Rule::r#PeekAll; } - impl<'i> ::pest::typed::TypedNode<'i, super::Rule> for r#PeekAll<'i> { - fn try_parse_with_partial(input: ::pest::Position<'i>, stack: &mut ::pest::Stack<::pest::Span<'i>>, tracker: &mut ::pest::typed::Tracker<'i, super::Rule>) -> ::pest::std::Option<(::pest::Position<'i>, Self)> { - tracker.record_option_during(input, |tracker| { - let (pos, content) = super::generics::r#peek_all::<'i>::try_parse_with_partial(input, stack, tracker)?; - let content = content.into(); - let span = input.span(&pos); - ::pest::std::Some((pos, Self { content, span })) - }) + impl<'i> ::pest::typed::FullRuleStruct<'i> for r#PeekAll<'i> { + type Inner = super::generics::r#peek_all<'i>; + type Content = super::generics::r#peek_all<'i>; + #[inline] + fn new( + content: >::Content, + span: ::pest::Span<'i>, + ) -> Self { + Self { content, span } } } impl<'i> ::pest::typed::PairContainer for r#PeekAll<'i> { - fn for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { self.content.for_self_or_for_each_child_pair(f) } - fn for_self_or_for_each_child_pair(&self, f: &mut impl ::pest::std::FnMut(::pest::token::Pair)) { + fn for_self_or_for_each_child_pair( + &self, + f: &mut impl ::pest::std::FnMut(::pest::token::Pair), + ) { use pest::typed::PairTree; f(self.as_pair_tree()) } @@ -1035,5 +1508,9 @@ pub mod generics { pub use pest::sequence::Sequence3; pub use pest::sequence::Sequence4; pub use pest::sequence::Sequence7; - pub use pest::typed::template::{CharRange, Insens, Negative, PeekSlice1, PeekSlice2, Positive, Rep, RepMax, RepMin, RepMinMax, RepOnce, Str, ANY as any, DROP as drop, EOI, PEEK as peek, PEEK_ALL as peek_all, POP as pop, POP_ALL as pop_all, PUSH as push, SOI}; + pub use pest::typed::template::{ + CharRange, Insens, Negative, PeekSlice1, PeekSlice2, Positive, Rep, RepMax, RepMin, + RepMinMax, RepOnce, Str, ANY as any, DROP as drop, EOI, EOI as eoi, PEEK as peek, + PEEK_ALL as peek_all, POP as pop, POP_ALL as pop_all, PUSH as push, SOI, SOI as soi, + }; } diff --git a/generator/tests/generator.rs b/generator/tests/generator.rs index 013275d..54070d3 100644 --- a/generator/tests/generator.rs +++ b/generator/tests/generator.rs @@ -7,7 +7,7 @@ use quote::quote; /// rustfmt generator/tests/generated.txt /// ``` #[test] -fn generated_rules() { +fn generated() { let path_generated = "tests/generated.rs"; let path_expected = "tests/expected.rs"; let actual = derive_typed_parser( @@ -22,8 +22,36 @@ fn generated_rules() { std::fs::write(path_generated, &actual).unwrap(); let output = std::process::Command::new("rustfmt") .arg(path_generated) - .arg("--config") - .arg("use_small_heuristics=Max,max_width=1000") + .output() + .unwrap(); + assert!( + output.status.success(), + "STDOUT:\n{}\nSTDERR:\n{}", + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + ); + + if std::fs::read(path_generated).unwrap() != std::fs::read(path_expected).unwrap() { + panic!("Generated codes have changed.") + } +} + +#[test] +fn generated_sample() { + let path_generated = "tests/generated_sample.rs"; + let path_expected = "tests/expected_sample.rs"; + let actual = derive_typed_parser( + quote! { + #[grammar = "../meta/tests/pest3sample.pest"] + struct Parser; + }, + false, + false, + ); + let actual = actual.to_string(); + std::fs::write(path_generated, &actual).unwrap(); + let output = std::process::Command::new("rustfmt") + .arg(path_generated) .output() .unwrap(); assert!( diff --git a/generator/tests/syntax.pest b/generator/tests/syntax.pest index d081471..39da322 100644 --- a/generator/tests/syntax.pest +++ b/generator/tests/syntax.pest @@ -1,3 +1,5 @@ +//! For compatibility. + /// Regular rule. Regular = ('0'..'9')+ @@ -26,17 +28,17 @@ RepLeftRight = RepRight{1..2} Pos = &(pest::SOI ~ RepLeftRight{2..4}) Neg = !(pest::EOI ~ Pos) -Push = pest::push(RepLeft* ~ Neg ~ ExactString+ ~ Push ~ Pop ~ Push ~ PopAll) +Push = pest::stack::push(RepLeft* ~ Neg ~ ExactString+ ~ Push ~ Pop ~ Push ~ PopAll) -Pop = pest::pop -PopAll = pest::pop_all +Pop = pest::stack::pop +PopAll = pest::stack::pop_all -Peek = pest::peek -PeekUnlimited = pest::peek[..] -PeekLeft = pest::peek[1..] -PeekRight = pest::peek[..] -PeekLeftRight = pest::peek[1..2] +Peek = pest::stack::peek +PeekUnlimited = pest::stack::peek[..] +PeekLeft = pest::stack::peek[1..] +PeekRight = pest::stack::peek[..] +PeekLeftRight = pest::stack::peek[1..2] -Drop = pest::drop +Drop = pest::stack::drop -PeekAll = pest::peek_all +PeekAll = pest::stack::peek_all diff --git a/meta/src/doc.rs b/meta/src/doc.rs index fbc4b66..8eea3d2 100644 --- a/meta/src/doc.rs +++ b/meta/src/doc.rs @@ -2,9 +2,6 @@ use std::collections::HashMap; #[derive(Debug, Default)] pub struct DocComment { - pub grammar_doc: Option, - - /// HashMap for store all doc_comments for rules. - /// key is rule name, value is doc_comment. - pub line_docs: HashMap, + /// Document comments for the whole grammar file. + pub grammar_doc: Vec, } diff --git a/meta/src/grammar.pest b/meta/src/grammar.pest index f040516..fc0aa65 100644 --- a/meta/src/grammar.pest +++ b/meta/src/grammar.pest @@ -8,12 +8,13 @@ // modified, or distributed except according to those terms. grammar_rules = _{ - SOI ~ import* ~ grammar_rule ~ (import | grammar_rule)* ~ EOI + SOI ~ grammar_doc* ~ import* ~ grammar_rule ~ (import | grammar_rule)* ~ EOI } import = { "use" ~ path ~ ("as" ~ identifier)? } grammar_rule = { + rule_doc* ~ (identifier | overridable_operator) ~ arguments? ~ assignment_operator ~ silent_modifier? ~ ( @@ -106,4 +107,7 @@ newline = _{ "\n" | "\r\n" } WHITESPACE = _{ " " | "\t" | newline } block_comment = _{ "/*" ~ (block_comment | !"*/" ~ ANY)* ~ "*/" } -COMMENT = _{ block_comment | ("//" ~ (!newline ~ ANY)*) } +COMMENT = _{ block_comment | ("//" ~ !("/" | "!") ~ (!newline ~ ANY)*) ~ &(newline | EOI) } +doc_content = ${ (!newline ~ ANY)* } +rule_doc = ${ "///" ~ " "? ~ doc_content } +grammar_doc = ${ "//!" ~ " "? ~ doc_content } diff --git a/meta/src/parser.rs b/meta/src/parser.rs index 490a6a1..9ef71c1 100644 --- a/meta/src/parser.rs +++ b/meta/src/parser.rs @@ -115,6 +115,7 @@ impl Display for Range { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct ParseRule { + pub doc: Vec, pub name: String, pub args: Vec, pub span: Span, @@ -330,6 +331,7 @@ fn _parse>( Rule::grammar_rule => { rules.push(parse_rule(pair, root.as_ref().to_path_buf())?); } + Rule::grammar_doc => doc.grammar_doc.push(parse_grammar_doc(pair)?), _ => (), } } @@ -368,6 +370,19 @@ fn parse_rule(rule: Pair, path: PathBuf) -> Result> let mut pairs = rule.into_inner(); + let mut doc = vec![]; + while let Some(pair) = pairs.peek() { + if pair.as_rule() == Rule::rule_doc { + doc.push(parse_rule_doc( + pairs + .next() + .expect("Peek says there is still at least one more pair."), + )?); + } else { + break; + } + } + let name = pairs .next() .expect("expected Rule::identifier") @@ -398,6 +413,7 @@ fn parse_rule(rule: Pair, path: PathBuf) -> Result> let node = parse_node(pairs.next().unwrap(), &span, &pratt_parser)?; Ok(ParseRule { + doc, name, args, span, @@ -459,6 +475,32 @@ fn parse_path( Ok(ParseNode { expr, span }) } +fn parse_grammar_doc(pair: Pair) -> Result> { + let string = &pair.as_str()[3..]; + let string = string.trim(); + let content = Some(string).ok_or(Error::new_from_span( + ErrorVariant::CustomError { + message: "incorrect grammar doc comment".to_string(), + }, + pair.as_span(), + ))?; + + Ok(content.to_string()) +} + +fn parse_rule_doc(pair: Pair) -> Result> { + let string = &pair.as_str()[3..]; + let string = string.trim(); + let content = Some(string).ok_or(Error::new_from_span( + ErrorVariant::CustomError { + message: "incorrect rule doc comment".to_string(), + }, + pair.as_span(), + ))?; + + Ok(content.to_string()) +} + fn parse_string(pair: Pair, span: &Span) -> Result> { let string = pair.as_str(); let content = unescape(&string[1..string.len() - 1]).ok_or(Error::new_from_span( @@ -805,8 +847,13 @@ mod tests { #[test] fn grammar_test() { let input = include_str!("../tests/pest3sample.pest"); - let parsed = parse(input, &Path::new("../tests/pest3sample.pest")); - assert!(parsed.is_ok()) + let parsed = parse_with_doc_comment(input, &Path::new("../tests/pest3sample.pest")); + let (rules, doc_comment) = match parsed { + Ok(parsed) => parsed, + Err(err) => panic!("{err}"), + }; + assert_ne!(rules.len(), 0); + assert_ne!(doc_comment.grammar_doc.len(), 0); } #[test] @@ -1150,7 +1197,8 @@ mod tests { rule: Rule::grammar_rules, positives: vec![ Rule::import, - Rule::grammar_rule + Rule::grammar_rule, + Rule::grammar_doc ], negatives: vec![], pos: 0 @@ -1402,6 +1450,79 @@ mod tests { }; } + #[test] + fn parse_comment() { + let pair = PestParser::parse(Rule::COMMENT, r#"// A test for grammar with doc comments."#) + .unwrap(); + assert_eq!(pair.into_iter().len(), 0); + + PestParser::parse( + Rule::COMMENT, + r#"//! A test for grammar with doc comments."#, + ) + .unwrap_err(); + + PestParser::parse( + Rule::COMMENT, + r#"/// A test for grammar with doc comments."#, + ) + .unwrap_err(); + } + + #[test] + fn parse_grammar_doc_comment() { + let input = r#"//! A test for grammar with doc comments."#; + + let pair = PestParser::parse(Rule::grammar_doc, input) + .unwrap_or_else(|e| panic!("{e}")) + .next() + .unwrap(); + + assert_eq!( + parse_grammar_doc(pair).unwrap(), + "A test for grammar with doc comments.", + ); + + let input = + "//! A test for grammar with doc comments.\n//! Second line should not be included."; + + let pair = PestParser::parse(Rule::grammar_doc, input) + .unwrap_or_else(|e| panic!("{e}")) + .next() + .unwrap(); + + assert_eq!( + parse_grammar_doc(pair).unwrap(), + "A test for grammar with doc comments.", + ); + + let input = r#" +//! A test for grammar with doc comments. +x = " "+ +"#; + PestParser::parse(Rule::grammar_rules, input).unwrap_or_else(|e| panic!("{e}")); + } + + #[test] + fn parse_rule_doc_comment() { + let input = r#"/// A test for rule with doc comments."#; + + let pair = PestParser::parse(Rule::rule_doc, input) + .unwrap_or_else(|e| panic!("{e}")) + .next() + .unwrap(); + + assert_eq!( + parse_rule_doc(pair).unwrap(), + "A test for rule with doc comments.", + ); + + let input = "\ +/// A test for grammar with doc comments. +x = pest::any+"; + PestParser::parse(Rule::grammar_rule, input).unwrap_or_else(|e| panic!("{e}")); + } + #[test] fn parse_string_escaped() { let input = r#""a\nb""#; diff --git a/meta/tests/pest3sample.pest b/meta/tests/pest3sample.pest index 87c541e..b0c0a33 100644 --- a/meta/tests/pest3sample.pest +++ b/meta/tests/pest3sample.pest @@ -1,3 +1,4 @@ +//! This is a grammar test written by [Tomas Tauber](https://github.com/tomtau). string = "abc" insensitive = i"abc" range = '0'..'9' @@ -79,7 +80,13 @@ emoji() = pest::unicode::emoji+ whitespace = " " comment = "$"+ +/// Rule `~` has almost the same behaviour with `^`, +/// except where they are used. +/// For example, +/// `a ~ b` and `a~*` uses rule `~`, +/// while `a ^ b` and `a^*` uses rule `^`. ~ = (whitespace | comment)* +/// See rule `~`. ^ = (whitespace | comment)* // Line comment diff --git a/pest/src/choice.rs b/pest/src/choice.rs index 1d7ab53..b52c989 100644 --- a/pest/src/choice.rs +++ b/pest/src/choice.rs @@ -1,11 +1,25 @@ +//! A [macro](crate::choice_type) to generate choice type +//! and generated choice types that has 2 to 15 variants, +//! which are named `Choice{i}`. + // TODO: peek to decide matched choice when possible. +/// Generate choice type. +/// +/// ## Example +/// +/// ```rust +/// pest::choice_type!(Choice2, (Choice0, T0), (Choice1, T1)); +/// ``` #[macro_export] macro_rules! choice_type { ( $name:ident, $( ( $variant:ident, $type:ident ) ),* $(,)? ) => { /// Choice type generated by `pest::choice_type!`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum $name<$( $type ),*> { - $( $variant($type) ),* + $( + #[doc = ::core::stringify!(A choice for $type.)] + $variant($type) + ),* } impl<'i, R, $($type, )*> $crate::typed::TypedNode<'i, R> for $name<$($type, )*> @@ -36,6 +50,26 @@ macro_rules! choice_type { )* ::core::option::Option::None } + #[inline] + fn check_with_partial( + input: $crate::Position<'i>, + stack: &mut $crate::Stack<$crate::Span<'i>>, + tracker: &mut $crate::typed::Tracker<'i, R>, + ) -> ::core::option::Option<$crate::Position<'i>> { + $( + stack.snapshot(); + match $type::check_with_partial(input, stack, tracker) { + ::core::option::Option::Some(input) => { + stack.clear_snapshot(); + return ::core::option::Option::Some(input) + } + ::core::option::Option::None => { + stack.restore(); + } + } + )* + ::core::option::Option::None + } } impl $crate::typed::PairContainer for $name<$($type, )*> diff --git a/pest/src/formatter.rs b/pest/src/formatter.rs index b164312..5e892d4 100644 --- a/pest/src/formatter.rs +++ b/pest/src/formatter.rs @@ -1,5 +1,5 @@ //! Copied from [pest-typed/formatter.rs]. -//! +//! //! [pest-typed/formatter.rs]: https://github.com/TheVeryDarkness/pest-typed/blob/0.12.1/main/src/formatter.rs use crate::{Position, Span}; @@ -112,8 +112,11 @@ impl<'i> Partition<'i> { /// Formatter options for [Span](crate::Span). pub struct FormatOption { + /// Formatter for characters in span. pub span_formatter: SpanFormatter, + /// Formatter for position marker. pub marker_formatter: MarkerFormatter, + /// Formatter for line numbers and column numbers of start and end. pub number_formatter: NumberFormatter, } diff --git a/pest/src/lib.rs b/pest/src/lib.rs index f743ae8..4670b08 100644 --- a/pest/src/lib.rs +++ b/pest/src/lib.rs @@ -1,3 +1,5 @@ +//! Core part of pest3. + // #![no_std] #![warn(rust_2018_idioms, rust_2021_compatibility, missing_docs)] @@ -11,14 +13,56 @@ pub mod typed; extern crate alloc; -pub use pest2::{error, RuleType, Stack}; +pub use pest2::{error, unicode, RuleType, Stack}; pub use position::Position; pub use span::Span; +/// Re-exported items from [std]. pub mod std { pub use std::boxed::Box; pub use std::ops::FnMut; pub use std::option::{Option, Option::None, Option::Some}; - pub use std::primitive::usize; + pub use std::primitive::{bool, char, usize}; + pub use std::result::{Result, Result::Err, Result::Ok}; pub use std::vec::Vec; } + +/// Generate unicode property type. +#[macro_export] +macro_rules! unicode { + ($property:ident) => { + #[doc = ::core::stringify!(Auto generated. Unicode property $property.)] + #[derive(Clone, Debug, Hash, PartialEq, Eq)] + #[allow(non_camel_case_types)] + pub struct $property { + pub content: $crate::std::char, + } + impl<'i, R: $crate::typed::RuleType> $crate::typed::TypedNode<'i, R> for $property { + #[inline] + fn try_parse_with_partial( + mut input: $crate::Position<'i>, + _stack: &mut $crate::Stack<$crate::Span<'i>>, + tracker: &mut $crate::typed::Tracker<'i, R>, + ) -> $crate::std::Option<($crate::Position<'i>, Self)> { + match $crate::typed::template::match_char_by(&mut input, $crate::unicode::$property) + { + $crate::std::Some(content) => $crate::std::Some((input, Self { content })), + $crate::std::None => $crate::std::None, + } + } + #[inline] + fn check_with_partial( + mut input: $crate::Position<'i>, + _stack: &mut $crate::Stack<$crate::Span<'i>>, + tracker: &mut $crate::typed::Tracker<'i, R>, + ) -> $crate::std::Option<$crate::Position<'i>> { + match $crate::typed::template::match_char_by(&mut input, $crate::unicode::$property) + { + $crate::std::Some(_) => $crate::std::Some(input), + $crate::std::None => $crate::std::None, + } + } + } + impl $crate::typed::EmptyPairContainer for $property {} + }; +} diff --git a/pest/src/sequence.rs b/pest/src/sequence.rs index 950b31a..47ce4f0 100644 --- a/pest/src/sequence.rs +++ b/pest/src/sequence.rs @@ -1,6 +1,17 @@ +//! A [macro](crate::sequence_type) to generate sequence type +//! and generated sequence types that has 2 to 15 fields, +//! which are named `field_{i}`. + +/// Generate sequence type. +/// +/// ## Example +/// +/// ```rust +/// pest::sequence_type!(Sequence2, (field_0, T0, TRIVIA_0), (field_1, T1, TRIVIA_1)); +/// ``` #[macro_export] macro_rules! sequence_type { - ( $name:ident, $( ( $variant:ident, $type:ident, $trivia:ident ) ),* $(,)? ) => { + ( $name:ident, $( ( $field:ident, $type:ident, $trivia:ident ) ),* $(,)? ) => { /// Sequence type generated by `pest::sequence_type!`. /// /// - `0`: No trivia. @@ -8,7 +19,21 @@ macro_rules! sequence_type { /// - `2`: Mandatory trivia. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct $name<$( $type, const $trivia: ::core::primitive::u8, )*> { - $( $variant: $type ),* + $( + #[doc = ::core::stringify!(Field for $type.)] + pub $field: $type, + )* + } + impl<'i, $($type, const $trivia: ::core::primitive::u8, )*> + $name<$($type, $trivia, )*> { + /// As a tuple of references. + pub fn as_tuple(&self) -> ($(&$type, )*) { + ( $( &self.$field, )* ) + } + /// Into a tuple of values. + pub fn into_tuple(self) -> ($($type, )*) { + ( $( self.$field, )* ) + } } impl<'i, R, $($type, const $trivia: ::core::primitive::u8, )*> $crate::typed::TypedNode<'i, R> for $name<$($type, $trivia, )*> @@ -30,14 +55,31 @@ macro_rules! sequence_type { if i > 1 { input = $crate::typed::template::try_handle_trivia::(input, stack, tracker)?; } - let (next, $variant) = $type::try_parse_with_partial(input, stack, tracker)?; + let (next, $field) = $type::try_parse_with_partial(input, stack, tracker)?; input = next; )* let res = Self { - $($variant, )* + $($field, )* }; ::core::option::Option::Some((input, res)) } + #[inline] + fn check_with_partial( + mut input: $crate::Position<'i>, + stack: &mut $crate::Stack<$crate::Span<'i>>, + tracker: &mut $crate::typed::Tracker<'i, R>, + ) -> ::core::option::Option<$crate::Position<'i>> { + let mut i = 0usize; + $( + i += 1; + if i > 1 { + input = $crate::typed::template::try_handle_trivia::(input, stack, tracker)?; + } + let next = $type::check_with_partial(input, stack, tracker)?; + input = next; + )* + ::core::option::Option::Some(input) + } } impl $crate::typed::PairContainer for $name<$($type, $trivia, )*> @@ -48,7 +90,7 @@ macro_rules! sequence_type { { fn for_each_child_pair(&self, f: &mut impl $crate::std::FnMut($crate::token::Pair)) { $( - self.$variant.for_self_or_for_each_child_pair(f); + self.$field.for_self_or_for_each_child_pair(f); )* } } diff --git a/pest/src/typed/mod.rs b/pest/src/typed/mod.rs index 190ad98..ed7966a 100644 --- a/pest/src/typed/mod.rs +++ b/pest/src/typed/mod.rs @@ -1,7 +1,12 @@ +//! Definitions related to typed syntax tree. + pub mod template; mod tracker; mod traits; pub mod wrapper; pub use tracker::Tracker; -pub use traits::{NeverFailedTypedNode, PairContainer, PairTree, RuleType, TypedNode, TypedParser}; +pub use traits::{ + EmptyPairContainer, FullRuleStruct, NeverFailedTypedNode, PairContainer, PairTree, RuleType, + TypedNode, TypedParser, +}; diff --git a/pest/src/typed/template/mod.rs b/pest/src/typed/template/mod.rs index afa5246..0ebe008 100644 --- a/pest/src/typed/template/mod.rs +++ b/pest/src/typed/template/mod.rs @@ -12,7 +12,7 @@ use super::{ tracker::Tracker, traits::{EmptyPairContainer, PairContainer}, wrapper::String as StringWrapper, - RuleType, TypedNode, + NeverFailedTypedNode, RuleType, TypedNode, }; use crate::{Position, Span, Stack}; use core::{ @@ -38,6 +38,7 @@ impl From<()> for Str { } } impl<'i, R: RuleType, T: StringWrapper> TypedNode<'i, R> for Str { + #[inline] fn try_parse_with_partial( mut input: Position<'i>, _stack: &mut Stack>, @@ -49,6 +50,18 @@ impl<'i, R: RuleType, T: StringWrapper> TypedNode<'i, R> for Str { None } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + if input.match_string(Self::CONTENT) { + Some(input) + } else { + None + } + } } impl Debug for Str { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -83,6 +96,7 @@ impl<'i, T: StringWrapper> From<&'i str> for Insens<'i, T> { } } impl<'i, R: RuleType, T: StringWrapper> TypedNode<'i, R> for Insens<'i, T> { + #[inline] fn try_parse_with_partial( mut input: Position<'i>, _stack: &mut Stack>, @@ -96,6 +110,18 @@ impl<'i, R: RuleType, T: StringWrapper> TypedNode<'i, R> for Insens<'i, T> { None } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + if input.match_insensitive(Self::CONTENT) { + Some(input) + } else { + None + } + } } impl<'i, T: StringWrapper> Debug for Insens<'i, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -114,6 +140,7 @@ pub struct SkipChar<'i, const N: usize> { pub span: Span<'i>, } impl<'i, R: RuleType, const N: usize> TypedNode<'i, R> for SkipChar<'i, N> { + #[inline] fn try_parse_with_partial( mut input: Position<'i>, _stack: &mut Stack>, @@ -128,6 +155,17 @@ impl<'i, R: RuleType, const N: usize> TypedNode<'i, R> for SkipChar<'i, N> { false => None, } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + match input.skip(N) { + true => Some(input), + false => None, + } + } } impl<'i, const N: usize> Debug for SkipChar<'i, N> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -163,6 +201,17 @@ impl<'i, R: RuleType, const MIN: char, const MAX: char> TypedNode<'i, R> for Cha false => None, } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + match input.match_range(MIN..MAX) { + true => Some(input), + false => None, + } + } } impl Debug for CharRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -190,6 +239,17 @@ impl<'i, R: RuleType, const CHAR: char> TypedNode<'i, R> for Char { false => None, } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + match input.match_char_by(|c| c == CHAR) { + true => Some(input), + false => None, + } + } } impl Debug for Char { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -290,6 +350,7 @@ impl DerefMut for Positive { } } impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Positive { + #[inline] fn try_parse_with_partial( input: Position<'i>, stack: &mut Stack>, @@ -309,6 +370,26 @@ impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Positive { } }) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + tracker.positive_during(|tracker| { + stack.snapshot(); + match T::check_with_partial(input, stack, tracker) { + Some(_pos) => { + stack.restore(); + Some(input) + } + None => { + stack.restore(); + None + } + } + }) + } } impl EmptyPairContainer for Positive {} @@ -327,6 +408,7 @@ impl From<()> for Negative { } } impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Negative { + #[inline] fn try_parse_with_partial( input: Position<'i>, stack: &mut Stack>, @@ -346,6 +428,26 @@ impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Negative { } }) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + tracker.negative_during(|tracker| { + stack.snapshot(); + match T::check_with_partial(input, stack, tracker) { + Some(_) => { + stack.restore(); + None + } + None => { + stack.restore(); + Some(input) + } + } + }) + } } impl Debug for Negative { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -376,6 +478,21 @@ impl<'i, R: RuleType> TypedNode<'i, R> for ANY { false => None, } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + let mut c: char = ' '; + match input.match_char_by(|ch| { + c = ch; + true + }) { + true => Some(input), + false => None, + } + } } impl Debug for ANY { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -396,11 +513,19 @@ impl<'i, R: RuleType> TypedNode<'i, R> for NONE { ) -> Option<(Position<'i>, Self)> { None } + #[inline] + fn check_with_partial( + _input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + None + } } impl EmptyPairContainer for NONE {} /// Always accept and consume no input. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)] pub struct Empty; impl<'i, R: RuleType> TypedNode<'i, R> for Empty { #[inline] @@ -411,6 +536,22 @@ impl<'i, R: RuleType> TypedNode<'i, R> for Empty { ) -> Option<(Position<'i>, Self)> { Some((input, Self)) } + #[inline] + fn check_with_partial( + input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + Some(input) + } +} +impl<'i, R: RuleType> NeverFailedTypedNode<'i, R> for Empty { + fn parse_with_partial( + input: Position<'i>, + _stack: &mut Stack>, + ) -> (Position<'i>, Self) { + (input, Self) + } } impl EmptyPairContainer for Empty {} @@ -430,6 +571,18 @@ impl<'i, R: RuleType> TypedNode<'i, R> for SOI { None } } + #[inline] + fn check_with_partial( + input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + if input.at_start() { + Some(input) + } else { + None + } + } } impl EmptyPairContainer for SOI {} @@ -451,6 +604,18 @@ impl<'i, R: RuleType> TypedNode<'i, R> for EOI { None } } + #[inline] + fn check_with_partial( + input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + if input.at_end() { + Some(input) + } else { + None + } + } } impl EmptyPairContainer for EOI {} @@ -490,6 +655,23 @@ impl<'i, R: RuleType> TypedNode<'i, R> for NEWLINE { }; Some((input, Self { content: t })) } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + _stack: &mut Stack>, + _tracker: &mut Tracker<'i, R>, + ) -> Option> { + let input = if input.match_string("\r\n") { + input + } else if input.match_string("\n") { + input + } else if input.match_string("\r") { + input + } else { + return None; + }; + Some(input) + } } impl Debug for NEWLINE { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -517,6 +699,16 @@ impl<'i, R: RuleType> TypedNode<'i, R> for PEEK_ALL<'i> { let (input, span) = peek_spans::(input, spans, tracker)?; Some((input, Self { span })) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + let spans = stack[0..stack.len()].iter().rev(); + let (input, _span) = peek_spans::(input, spans, tracker)?; + Some(input) + } } impl<'i> Debug for PEEK_ALL<'i> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -556,6 +748,23 @@ impl<'i, R: RuleType> TypedNode<'i, R> for PEEK<'i> { } } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + match stack.peek() { + Some(string) => match input.match_string(string.as_str()) { + true => Some(input), + false => None, + }, + None => { + tracker.empty_stack(input); + None + } + } + } } impl<'i> Debug for PEEK<'i> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -584,6 +793,20 @@ impl<'i, R: RuleType> TypedNode<'i, R> for DROP { } } } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + match stack.pop() { + Some(_) => Some(input), + None => { + tracker.empty_stack(input); + None + } + } + } } impl EmptyPairContainer for DROP {} @@ -617,6 +840,23 @@ impl<'i, R: RuleType> TypedNode<'i, R> for POP<'i> { } } } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + match stack.pop() { + Some(span) => match input.match_string(span.as_str()) { + true => Some(input), + false => None, + }, + None => { + tracker.empty_stack(input); + None + } + } + } } impl<'i> Debug for POP<'i> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -648,6 +888,16 @@ impl<'i, R: RuleType> TypedNode<'i, R> for POP_ALL<'i> { while stack.pop().is_some() {} Some((input, Self::from(res.span))) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + let input = PEEK_ALL::check_with_partial(input, stack, tracker)?; + while stack.pop().is_some() {} + Some(input) + } } impl<'i> Debug for POP_ALL<'i> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -679,6 +929,17 @@ impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for PUSH { stack.push(start.span(&input)); Some((input, Self::from(content))) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + let start = input; + let input = T::check_with_partial(input, stack, tracker)?; + stack.push(start.span(&input)); + Some(input) + } } impl Deref for PUSH { type Target = T; @@ -721,6 +982,16 @@ impl<'i, R: RuleType, const START: isize, const END: isize> TypedNode<'i, R> let (input, _) = peek_spans::(input, spans, tracker)?; Some((input, Self)) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + let spans = stack_slice(input, START, Some(END), stack, tracker)?; + let (input, _) = peek_spans::(input, spans, tracker)?; + Some(input) + } } impl EmptyPairContainer for PeekSlice2 {} @@ -738,6 +1009,16 @@ impl<'i, R: RuleType, const START: isize> TypedNode<'i, R> for PeekSlice1 let (input, _) = peek_spans::(input, spans, tracker)?; Some((input, Self)) } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + let spans = stack_slice(input, START, None, stack, tracker)?; + let (input, _) = peek_spans::(input, spans, tracker)?; + Some(input) + } } impl EmptyPairContainer for PeekSlice1 {} diff --git a/pest/src/typed/template/repetition.rs b/pest/src/typed/template/repetition.rs index 15a209b..06ffb78 100644 --- a/pest/src/typed/template/repetition.rs +++ b/pest/src/typed/template/repetition.rs @@ -37,7 +37,10 @@ impl< > NeverFailedTypedNode<'i, R> for RepMinMax { #[inline] - fn parse_with(mut input: Position<'i>, stack: &mut Stack>) -> (Position<'i>, Self) { + fn parse_with_partial( + mut input: Position<'i>, + stack: &mut Stack>, + ) -> (Position<'i>, Self) { let mut vec = Vec::new(); let mut tracker = Tracker::new(input); @@ -96,6 +99,31 @@ impl< Some((input, Self { content: vec })) } + #[inline] + fn check_with_partial( + mut input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + for i in 0..MAX { + match restore_on_none(stack, |stack| { + check_unit::(input, stack, tracker, i) + }) { + Some(next) => { + input = next; + } + None => { + if i < MIN { + return None; + } else { + break; + } + } + } + } + + Some(input) + } } impl IntoIterator for RepMinMax @@ -160,3 +188,18 @@ fn try_parse_unit<'i, R: RuleType, T: TypedNode<'i, R>, const TRIVIA: u8>( input = next; Some((input, matched)) } + +#[inline] +fn check_unit<'i, R: RuleType, T: TypedNode<'i, R>, const TRIVIA: u8>( + mut input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + i: usize, +) -> Option> { + if i > 0 { + input = try_handle_trivia::(input, stack, tracker)?; + } + let next = T::check_with_partial(input, stack, tracker)?; + input = next; + Some(input) +} diff --git a/pest/src/typed/tracker.rs b/pest/src/typed/tracker.rs index 215df30..93cd5e6 100644 --- a/pest/src/typed/tracker.rs +++ b/pest/src/typed/tracker.rs @@ -169,9 +169,9 @@ impl<'i, R: RuleType> Tracker<'i, R> { pub(crate) fn record_option_during_with( &mut self, pos: Position<'i>, - f: impl FnOnce(&mut Self) -> Option<(Position<'i>, T)>, + f: impl FnOnce(&mut Self) -> Option, rule: R, - ) -> Option<(Position<'i>, T)> { + ) -> Option { if let Some((_, _, has_children)) = self.stack.last_mut() { *has_children = true; } @@ -186,7 +186,7 @@ impl<'i, R: RuleType> Tracker<'i, R> { } /// Record if the result doesn't match the state during calling `f`. #[inline] - pub fn record_during, E>( + pub fn record_result_during, E>( &mut self, pos: Position<'i>, f: impl FnOnce(&mut Self) -> Result<(Position<'i>, T), E>, @@ -195,13 +195,22 @@ impl<'i, R: RuleType> Tracker<'i, R> { } /// Record if the result doesn't match the state during calling `f`. #[inline] - pub fn record_option_during>( + pub fn record_option_during>( &mut self, pos: Position<'i>, f: impl FnOnce(&mut Self) -> Option<(Position<'i>, T)>, ) -> Option<(Position<'i>, T)> { self.record_option_during_with(pos, f, T::RULE) } + /// Record if the result doesn't match the state during calling `f`. + #[inline] + pub fn record_empty_during>( + &mut self, + pos: Position<'i>, + f: impl FnOnce(&mut Self) -> Option>, + ) -> Option> { + self.record_option_during_with(pos, f, T::RULE) + } fn collect_to_message(self) -> String { let (pos, attempts) = self.finish(); // "{} | " @@ -299,7 +308,7 @@ mod tests { use super::*; #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] - enum Rule { + pub enum Rule { Program, SOI, Main, @@ -319,7 +328,7 @@ mod tests { ($name:ident) => { #[derive(Clone, PartialEq)] pub struct $name; - impl RuleWrapper for $name { + impl RuleWrapper for $name { const RULE: Rule = Rule::$name; type Rule = Rule; } @@ -335,12 +344,12 @@ mod tests { fn negative() -> Result<(), ()> { let pos = Position::from_start("abc\ndef\nghi"); let mut tracker = Tracker::<'_, Rule>::new(pos); - let _ = tracker.record_during(pos, |tracker| { + let _ = tracker.record_result_during(pos, |tracker| { tracker.positive_during(|tracker| { - tracker.record_during(pos, |_| Ok((pos, rule_wrappers::Main))) + tracker.record_result_during(pos, |_| Ok((pos, rule_wrappers::Main))) })?; tracker.negative_during(|tracker| { - tracker.record_during(pos, |_| Ok((pos, rule_wrappers::Main))) + tracker.record_result_during(pos, |_| Ok((pos, rule_wrappers::Main))) })?; Ok((pos, rule_wrappers::Program)) })?; @@ -361,19 +370,19 @@ mod tests { fn positive() -> Result<(), ()> { let pos = Position::from_start("abc\ndef\nghi"); let mut tracker = Tracker::<'_, Rule>::new(pos); - let _ = tracker.record_during(pos, |tracker| { + let _ = tracker.record_result_during(pos, |tracker| { let _ = tracker.positive_during(|tracker| { if false { Ok((pos, rule_wrappers::SOI)) } else { - tracker.record_during(pos, |_| Err(())) + tracker.record_result_during(pos, |_| Err(())) } }); let _ = tracker.negative_during(|tracker| { if false { Ok((pos, rule_wrappers::SOI)) } else { - tracker.record_during(pos, |_| Err(())) + tracker.record_result_during(pos, |_| Err(())) } }); Ok((pos, rule_wrappers::Program)) @@ -395,14 +404,14 @@ mod tests { fn unicode() -> Result<(), ()> { let mut pos = Position::from_start("αβψ\nδεφ\nγηι"); let mut tracker = Tracker::<'_, Rule>::new(pos); - let _ = tracker.record_during(pos, |tracker| { + let _ = tracker.record_result_during(pos, |tracker| { let suc = pos.match_string("α"); assert!(suc); tracker.positive_during(|tracker| { - tracker.record_during(pos, |_| Ok((pos, rule_wrappers::Main))) + tracker.record_result_during(pos, |_| Ok((pos, rule_wrappers::Main))) })?; tracker.negative_during(|tracker| { - tracker.record_during(pos, |_| Ok((pos, rule_wrappers::Main))) + tracker.record_result_during(pos, |_| Ok((pos, rule_wrappers::Main))) })?; Ok((pos, rule_wrappers::Program)) })?; @@ -423,13 +432,13 @@ mod tests { fn nested() -> Result<(), ()> { let mut pos = Position::from_start("αβψ\nδεφ\nγηι"); let mut tracker = Tracker::<'_, Rule>::new(pos); - let _ = tracker.record_during(pos, |tracker| { + let _ = tracker.record_result_during(pos, |tracker| { let suc = pos.match_string("α"); assert!(suc); tracker.negative_during(|tracker| { - tracker.record_during(pos, |tracker| { + tracker.record_result_during(pos, |tracker| { tracker.negative_during(|tracker| { - tracker.record_during(pos, |_| Ok((pos, rule_wrappers::Body))) + tracker.record_result_during(pos, |_| Ok((pos, rule_wrappers::Body))) })?; Ok((pos, rule_wrappers::Main)) }) diff --git a/pest/src/typed/traits.rs b/pest/src/typed/traits.rs index 5797de4..3a92782 100644 --- a/pest/src/typed/traits.rs +++ b/pest/src/typed/traits.rs @@ -17,6 +17,12 @@ pub trait RuleType: Copy + Debug + Eq + Hash + Ord { /// Node of a typed syntax tree. pub trait TypedNode<'i, R: RuleType>: Sized { + /// Try parse a part of or all of remained string into a node. + fn try_parse_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option<(Position<'i>, Self)>; /// Try parse remained string into a node. #[inline] fn try_parse_with( @@ -24,59 +30,131 @@ pub trait TypedNode<'i, R: RuleType>: Sized { stack: &mut Stack>, tracker: &mut Tracker<'i, R>, ) -> Option { - let (input, res) = match Self::try_parse_with_partial(input, stack, tracker) { - Some((input, res)) => (input, res), - None => return None, - }; - let (_input, _eoi) = match tracker.record_option_during_with( + let (input, res) = Self::try_parse_with_partial(input, stack, tracker)?; + let (_input, _eoi) = tracker.record_option_during_with( input, |tracker| EOI::try_parse_with_partial(input, stack, tracker), ::EOI, - ) { - Some((input, res)) => (input, res), - None => return None, - }; + )?; Some(res) } - /// Try parse a part of or all of remained string into a node. - fn try_parse_with_partial( + /// Try parsing leading part of string into a node. + #[inline] + fn try_parse_partial(input: &'i str) -> Result<(Position<'i>, Self), Error> { + let mut stack = Stack::new(); + let input = Position::from_start(input); + let mut tracker = Tracker::new(input); + Self::try_parse_with_partial(input, &mut stack, &mut tracker) + .ok_or_else(|| tracker.collect()) + } + /// Try parsing given string into a node. + #[inline] + fn try_parse(input: &'i str) -> Result> { + let mut stack = Stack::new(); + let input = Position::from_start(input); + let mut tracker = Tracker::new(input); + Self::try_parse_with(input, &mut stack, &mut tracker).ok_or_else(|| tracker.collect()) + } + /// Check whether the some leading part of the result can be accepted. + fn check_with_partial( input: Position<'i>, stack: &mut Stack>, tracker: &mut Tracker<'i, R>, - ) -> Option<(Position<'i>, Self)>; - /// Try parse given string into a node. + ) -> Option>; + /// Check whether the some leading part of the result can be accepted. #[inline] - fn try_parse(input: &'i str) -> Result> { + fn check_with( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> bool { + let input = match Self::check_with_partial(input, stack, tracker) { + Some(input) => input, + None => return false, + }; + let _input = match tracker.record_option_during_with( + input, + |tracker| EOI::check_with_partial(input, stack, tracker), + ::EOI, + ) { + Some(input) => input, + None => return false, + }; + true + } + /// Try parsing leading part of string into a node. + #[inline] + fn check_partial(input: &'i str) -> Result, Error> { let mut stack = Stack::new(); let input = Position::from_start(input); let mut tracker = Tracker::new(input); - match Self::try_parse_with(input, &mut stack, &mut tracker) { - Some(res) => Ok(res), - None => Err(tracker.collect()), - } + Self::check_with_partial(input, &mut stack, &mut tracker).ok_or_else(|| tracker.collect()) } - /// Try parse leading part of string into a node. + /// Try parsing given string into a node. #[inline] - fn try_parse_partial(input: &'i str) -> Result<(Position<'i>, Self), Error> { + fn check(input: &'i str) -> Result<(), Error> { let mut stack = Stack::new(); let input = Position::from_start(input); let mut tracker = Tracker::new(input); - match Self::try_parse_with_partial(input, &mut stack, &mut tracker) { - Some((input, res)) => Ok((input, res)), - None => Err(tracker.collect()), + match Self::check_with(input, &mut stack, &mut tracker) { + true => Ok(()), + false => Err(tracker.collect()), } } + // /// Whether this node will modify the stack. + // /// Must be evaluated correctly, + // /// otherwise the stack won't be restored correctly. + // const MODIFY_STACK: bool; + // /// Whether this node accepts null input. // const NULLABLE: bool; // /// Leading characters that this node accepts. // const FIRST: &'static [char]; } +/// Struct for rules with full capacity. +pub trait FullRuleStruct<'i>: wrapper::Rule { + /// Wrapped inner type. + type Inner: TypedNode<'i, Self::Rule>; + /// Wrapped content type. + type Content: From; + /// Create from span and content. + fn new(content: Self::Content, span: Span<'i>) -> Self; +} +impl<'i, R: RuleType, T: FullRuleStruct<'i, Rule = R>> TypedNode<'i, R> for T { + fn try_parse_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option<(Position<'i>, Self)> { + tracker.record_option_during(input, |tracker| { + let (pos, content) = ::try_parse_with_partial(input, stack, tracker)?; + let content = content.into(); + let span = input.span(&pos); + Some((pos, Self::new(content, span))) + }) + } + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + tracker.record_empty_during::(input, |tracker| { + let pos = ::check_with_partial(input, stack, tracker)?; + Some(pos) + }) + } +} + +/// A container of pairs. pub trait PairContainer { + /// for `Self` as a pair if it is, otherwise for each child pair. fn for_self_or_for_each_child_pair(&self, f: &mut impl FnMut(Pair)) { self.for_each_child_pair(f) } + /// For each child pair. fn for_each_child_pair(&self, f: &mut impl FnMut(Pair)); + /// Convert children pairs into a [Vec]. fn vec_children_pairs(&self) -> Vec> { let mut vec = vec![]; self.for_each_child_pair(&mut |token| vec.push(token)); @@ -93,13 +171,17 @@ impl> PairContainer for Option { } } -pub(super) trait EmptyPairContainer {} +/// Contains no pair. +pub trait EmptyPairContainer {} impl PairContainer for T { fn for_each_child_pair(&self, _f: &mut impl FnMut(Pair)) {} } -pub trait PairTree: PairContainer + wrapper::Rule { +/// A pair that can be converted to a pair tree. +pub trait PairTree: PairContainer + wrapper::Rule { + /// Get pair span. fn get_span(&self) -> (usize, usize); + /// Convert `Self` to a pair tree. fn as_pair_tree(&self) -> Pair { let rule = Self::RULE; let (start, end) = self.get_span(); @@ -114,6 +196,7 @@ pub trait PairTree: PairContainer + wrapper::Rule { } impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Option { + #[inline] fn try_parse_with_partial( input: Position<'i>, stack: &mut Stack>, @@ -131,9 +214,29 @@ impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Option { } } } + #[inline] + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, R>, + ) -> Option> { + stack.snapshot(); + match T::check_with_partial(input, stack, tracker) { + Some(pos) => { + stack.clear_snapshot(); + Some(pos) + } + None => { + stack.restore(); + Some(input) + } + } + } } +/// Parser that can produce typed syntax tree. pub trait TypedParser { + /// See [TypedNode::try_parse_with]. #[inline] fn try_parse_with<'i, T: TypedNode<'i, R>>( input: Position<'i>, @@ -142,6 +245,7 @@ pub trait TypedParser { ) -> Option { T::try_parse_with(input, stack, tracker) } + /// See [TypedNode::try_parse_with_partial]. #[inline] fn try_parse_with_partial<'i, T: TypedNode<'i, R>>( input: Position<'i>, @@ -150,10 +254,12 @@ pub trait TypedParser { ) -> Option<(Position<'i>, T)> { T::try_parse_with_partial(input, stack, tracker) } + /// See [TypedNode::try_parse]. #[inline] fn try_parse<'i, T: TypedNode<'i, R>>(input: &'i str) -> Result> { T::try_parse(input) } + /// See [TypedNode::try_parse_partial]. #[inline] fn try_parse_partial<'i, T: TypedNode<'i, R>>( input: &'i str, @@ -167,7 +273,13 @@ pub trait NeverFailedTypedNode<'i, R: RuleType> where Self: Sized + Debug + Clone + PartialEq + Default, { - /// Create typed node. - /// `ATOMIC` refers to the external status, and it can be overriden by rule definition. - fn parse_with(input: Position<'i>, stack: &mut Stack>) -> (Position<'i>, Self); + /// Parse leading part of given input into a typed node. + fn parse_with_partial(input: Position<'i>, stack: &mut Stack>) + -> (Position<'i>, Self); + /// Parse leading part of given input into a typed node. + fn parse_partial(input: &'i str) -> (Position<'i>, Self) { + let input = Position::from_start(input); + let mut stack = Stack::new(); + Self::parse_with_partial(input, &mut stack) + } } diff --git a/pest/src/typed/wrapper.rs b/pest/src/typed/wrapper.rs index 02af4c7..3a80dfc 100644 --- a/pest/src/typed/wrapper.rs +++ b/pest/src/typed/wrapper.rs @@ -1,14 +1,22 @@ -use pest2::RuleType; +//! Wrapper. +use super::RuleType; /// A wrapper for string constant. pub trait String { + /// String content. const CONTENT: &'static str; + /// Get content. + fn get_const(&self) -> &'static str { + Self::CONTENT + } } /// A wrapper for string constant. -pub trait Rule { +pub trait Rule { + /// Should be the type of wrapped rule. type Rule: RuleType; - const RULE: R; + /// Wrapped rule. + const RULE: Self::Rule; } /// Bound for the length of vector. diff --git a/pest/tests/predefined_node.rs b/pest/tests/predefined_node.rs index add50cc..83937d0 100644 --- a/pest/tests/predefined_node.rs +++ b/pest/tests/predefined_node.rs @@ -13,11 +13,11 @@ mod tests { wrapper::{Rule as RuleWrapper, String as StringWrapper}, RuleType, Tracker, TypedNode, TypedParser, }, - Position, Span, Stack, + unicode, Position, Span, Stack, }; #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - enum Rule { + pub enum Rule { Foo, EOI, } @@ -28,6 +28,8 @@ mod tests { type MandatoryTrivia<'i> = Empty; } + unicode!(MATH); + struct Parser; impl TypedParser for Parser {} @@ -41,7 +43,7 @@ mod tests { pub struct StrFoo { content: Str, } - impl RuleWrapper for StrFoo { + impl RuleWrapper for StrFoo { type Rule = Rule; const RULE: Rule = Rule::Foo; } @@ -54,6 +56,14 @@ mod tests { let (pos, content) = Str::::try_parse_with_partial(input, stack, tracker)?; Some((pos, Self { content })) } + fn check_with_partial( + input: Position<'i>, + stack: &mut Stack>, + tracker: &mut Tracker<'i, Rule>, + ) -> Option> { + let pos = Str::::check_with_partial(input, stack, tracker)?; + Some(pos) + } } #[test]