From a8409b3d222e25e9e64653fea8218d0fb5596565 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Mon, 5 Feb 2024 08:00:33 +0100 Subject: Upgrade pest_meta to 2.7.6 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update external/rust/crates/pest_meta For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: I8ca53cf3b31907cb6b6356aa5cbe0ecb032c5396 --- Android.bp | 3 +- Cargo.toml | 17 +- Cargo.toml.orig | 14 +- METADATA | 23 +- _README.md | 39 +- src/ast.rs | 347 +++++++++++++- src/grammar.pest | 165 ++++--- src/grammar.rs | 2 +- src/optimizer/concatenator.rs | 1 - src/optimizer/factorizer.rs | 1 - src/optimizer/lister.rs | 1 - src/optimizer/mod.rs | 482 ++++++++++++++++++- src/optimizer/rotater.rs | 1 - src/optimizer/skipper.rs | 1 - src/optimizer/unroller.rs | 1 + src/parser.rs | 485 ++++++++++++-------- src/validator.rs | 1017 ++++++++++++++++++++++++++++++++++++++++- 17 files changed, 2293 insertions(+), 307 deletions(-) diff --git a/Android.bp b/Android.bp index 239744f..4e69e02 100644 --- a/Android.bp +++ b/Android.bp @@ -41,9 +41,10 @@ rust_library_host { name: "libpest_meta", crate_name: "pest_meta", cargo_env_compat: true, - cargo_pkg_version: "2.5.5", + cargo_pkg_version: "2.7.6", srcs: ["src/lib.rs"], edition: "2021", + features: ["default"], rustlibs: [ "libonce_cell", "libpest", diff --git a/Cargo.toml b/Cargo.toml index f49a725..2f5f2c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.56" +rust-version = "1.61" name = "pest_meta" -version = "2.5.5" +version = "2.7.6" authors = ["Dragoș Tiselice "] exclude = ["src/grammar.pest"] include = [ @@ -34,15 +34,24 @@ keywords = [ "optimizer", ] categories = ["parsing"] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/pest-parser/pest" [dependencies.once_cell] version = "1.8.0" [dependencies.pest] -version = "2.5.5" +version = "2.7.6" + +[build-dependencies.cargo] +version = "0.72.2" +optional = true [build-dependencies.sha2] version = "0.10" default-features = false + +[features] +default = [] +grammar-extras = [] +not-bootstrap-in-src = ["dep:cargo"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index accc303..8eaf42a 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,7 +1,7 @@ [package] name = "pest_meta" description = "pest meta language parser and validator" -version = "2.5.5" +version = "2.7.6" edition = "2021" authors = ["Dragoș Tiselice "] homepage = "https://pest.rs/" @@ -9,15 +9,21 @@ repository = "https://github.com/pest-parser/pest" documentation = "https://docs.rs/pest" keywords = ["pest", "parser", "meta", "optimizer"] categories = ["parsing"] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" readme = "_README.md" exclude = ["src/grammar.pest"] include = ["Cargo.toml", "src/**/*", "src/grammar.rs", "_README.md", "LICENSE-*"] -rust-version = "1.56" +rust-version = "1.61" [dependencies] -pest = { path = "../pest", version = "2.5.5" } +pest = { path = "../pest", version = "2.7.6" } once_cell = "1.8.0" [build-dependencies] sha2 = { version = "0.10", default-features = false } +cargo = { version = "0.72.2", optional = true } + +[features] +default = [] +not-bootstrap-in-src = ["dep:cargo"] +grammar-extras = [] diff --git a/METADATA b/METADATA index 325bf32..2df455b 100644 --- a/METADATA +++ b/METADATA @@ -1,23 +1,20 @@ # This project was upgraded with external_updater. -# Usage: tools/external_updater/updater.sh update rust/crates/pest_meta -# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md +# Usage: tools/external_updater/updater.sh update external/rust/crates/pest_meta +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md name: "pest_meta" description: "pest meta language parser and validator" third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/pest_meta" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/pest_meta/pest_meta-2.5.5.crate" - } - version: "2.5.5" license_type: NOTICE last_upgrade_date { - year: 2023 + year: 2024 month: 2 - day: 16 + day: 5 + } + homepage: "https://crates.io/crates/pest_meta" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/pest_meta/pest_meta-2.7.6.crate" + version: "2.7.6" } } diff --git a/_README.md b/_README.md index da30ab7..6d91eaf 100644 --- a/_README.md +++ b/_README.md @@ -11,7 +11,7 @@ [![pest Continuous Integration](https://github.com/pest-parser/pest/actions/workflows/ci.yml/badge.svg)](https://github.com/pest-parser/pest/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/pest-parser/pest/branch/master/graph/badge.svg)](https://codecov.io/gh/pest-parser/pest) -Rustc Version 1.56.1+ +Rustc Version 1.61.0+ [![Crates.io](https://img.shields.io/crates/d/pest.svg)](https://crates.io/crates/pest) [![Crates.io](https://img.shields.io/crates/v/pest.svg)](https://crates.io/crates/pest) @@ -93,10 +93,7 @@ The grammar can be used to derive a `Parser` implementation automatically. Parsing returns an iterator of nested token pairs: ```rust -extern crate pest; -#[macro_use] -extern crate pest_derive; - +use pest_derive::Parser; use pest::Parser; #[derive(Parser)] @@ -104,7 +101,7 @@ use pest::Parser; struct IdentParser; fn main() { -    let pairs = IdentParser::parse(Rule::ident_list, "a1 b2").unwrap_or_else(|e| panic!("{}", e)); + let pairs = IdentParser::parse(Rule::ident_list, "a1 b2").unwrap_or_else(|e| panic!("{}", e)); // Because ident_list is silent, the iterator will contain idents for pair in pairs { @@ -167,6 +164,8 @@ mod b { ## Projects using pest +You can find more projects and ecosystem tools in the [awesome-pest](https://github.com/pest-parser/awesome-pest) repo. + * [pest_meta](https://github.com/pest-parser/pest/blob/master/meta/src/grammar.pest) (bootstrapped) * [AshPaper](https://github.com/shnewto/ashpaper) * [brain](https://github.com/brain-lang/brain) @@ -197,11 +196,35 @@ mod b { * [qubit](https://github.com/abhimanyu003/qubit) * [caith](https://github.com/Geobert/caith) (a dice roller crate) * [Melody](https://github.com/yoav-lavi/melody) +* [json5-nodes](https://github.com/jlyonsmith/json5-nodes) +* [prisma](https://github.com/prisma/prisma) ## Minimum Supported Rust Version (MSRV) -This library should always compile with default features on **Rust 1.56.1** -or **Rust 1.61** with `const_prec_climber`. +This library should always compile with default features on **Rust 1.61.0**. + +## no_std support + +The `pest` and `pest_derive` crates can be built without the Rust standard +library and target embedded environments. To do so, you need to disable +their default features. In your `Cargo.toml`, you can specify it as follows: + +```toml +[dependencies] +# ... +pest = { version = "2", default-features = false } +pest_derive = { version = "2", default-features = false } +``` + +If you want to build these crates in the pest repository's workspace, you can +pass the `--no-default-features` flag to `cargo` and specify these crates using +the `--package` (`-p`) flag. For example: + +```bash +$ cargo build --target thumbv7em-none-eabihf --no-default-features -p pest +$ cargo bootstrap +$ cargo build --target thumbv7em-none-eabihf --no-default-features -p pest_derive +``` ## Special thanks diff --git a/src/ast.rs b/src/ast.rs index 77c48e8..9ef25dd 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -94,6 +94,9 @@ pub enum Expr { Skip(Vec), /// Matches an expression and pushes it to the stack, e.g. `push(e)` Push(Box), + /// Matches an expression and assigns a label to it, e.g. #label = exp + #[cfg(feature = "grammar-extras")] + NodeTag(Box, String), } impl Expr { @@ -114,7 +117,6 @@ impl Expr { let expr = f(expr); match expr { - // TODO: Use box syntax when it gets stabilized. Expr::PosPred(expr) => { let mapped = Box::new(map_internal(*expr, f)); Expr::PosPred(mapped) @@ -165,6 +167,11 @@ impl Expr { let mapped = Box::new(map_internal(*expr, f)); Expr::Push(mapped) } + #[cfg(feature = "grammar-extras")] + Expr::NodeTag(expr, tag) => { + let mapped = Box::new(map_internal(*expr, f)); + Expr::NodeTag(mapped, tag) + } expr => expr, } } @@ -183,7 +190,6 @@ impl Expr { { let mapped = match expr { Expr::PosPred(expr) => { - // TODO: Use box syntax when it gets stabilized. let mapped = Box::new(map_internal(*expr, f)); Expr::PosPred(mapped) } @@ -233,6 +239,11 @@ impl Expr { let mapped = Box::new(map_internal(*expr, f)); Expr::Push(mapped) } + #[cfg(feature = "grammar-extras")] + Expr::NodeTag(expr, tag) => { + let mapped = Box::new(map_internal(*expr, f)); + Expr::NodeTag(mapped, tag) + } expr => expr, }; @@ -243,6 +254,79 @@ impl Expr { } } +impl core::fmt::Display for Expr { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Expr::Str(s) => write!(f, "{:?}", s), + Expr::Insens(s) => write!(f, "^{:?}", s), + Expr::Range(start, end) => { + let start = start.chars().next().expect("Empty range start."); + let end = end.chars().next().expect("Empty range end."); + write!(f, "({:?}..{:?})", start, end) + } + Expr::Ident(id) => write!(f, "{}", id), + Expr::PeekSlice(start, end) => match end { + Some(end) => write!(f, "PEEK[{}..{}]", start, end), + None => write!(f, "PEEK[{}..]", start), + }, + Expr::PosPred(expr) => write!(f, "&{}", expr.as_ref()), + Expr::NegPred(expr) => write!(f, "!{}", expr.as_ref()), + Expr::Seq(lhs, rhs) => { + let mut nodes = Vec::new(); + nodes.push(lhs); + let mut current = rhs; + while let Expr::Seq(lhs, rhs) = current.as_ref() { + nodes.push(lhs); + current = rhs; + } + nodes.push(current); + let sequence = nodes + .iter() + .map(|node| format!("{}", node)) + .collect::>() + .join(" ~ "); + write!(f, "({})", sequence) + } + Expr::Choice(lhs, rhs) => { + let mut nodes = Vec::new(); + nodes.push(lhs); + let mut current = rhs; + while let Expr::Choice(lhs, rhs) = current.as_ref() { + nodes.push(lhs); + current = rhs; + } + nodes.push(current); + let sequence = nodes + .iter() + .map(|node| format!("{}", node)) + .collect::>() + .join(" | "); + write!(f, "({})", sequence) + } + Expr::Opt(expr) => write!(f, "{}?", expr), + Expr::Rep(expr) => write!(f, "{}*", expr), + Expr::RepOnce(expr) => write!(f, "{}+", expr), + Expr::RepExact(expr, n) => write!(f, "{}{{{}}}", expr, n), + Expr::RepMin(expr, min) => write!(f, "{}{{{},}}", expr, min), + Expr::RepMax(expr, max) => write!(f, "{}{{,{}}}", expr, max), + Expr::RepMinMax(expr, min, max) => write!(f, "{}{{{}, {}}}", expr, min, max), + Expr::Skip(strings) => { + let strings = strings + .iter() + .map(|s| format!("{:?}", s)) + .collect::>() + .join(" | "); + write!(f, "(!({}) ~ ANY)*", strings) + } + Expr::Push(expr) => write!(f, "PUSH({})", expr), + #[cfg(feature = "grammar-extras")] + Expr::NodeTag(expr, tag) => { + write!(f, "(#{} = {})", tag, expr) + } + } + } +} + /// The top down iterator for an expression. pub struct ExprTopDownIterator { current: Option, @@ -285,6 +369,10 @@ impl ExprTopDownIterator { | Expr::Push(expr) => { self.next = Some(*expr); } + #[cfg(feature = "grammar-extras")] + Expr::NodeTag(expr, _) => { + self.next = Some(*expr); + } _ => { self.next = None; } @@ -347,7 +435,260 @@ mod tests { expr.clone() .map_bottom_up(|expr| expr) .map_top_down(|expr| expr), - expr + expr, ); } + + mod display { + use super::super::*; + + #[test] + fn string() { + assert_eq!(Expr::Str("a".to_owned()).to_string(), r#""a""#); + } + + #[test] + fn insens() { + assert_eq!(Expr::Insens("a".to_owned()).to_string(), r#"^"a""#); + } + + #[test] + fn range() { + assert_eq!( + Expr::Range("a".to_owned(), "z".to_owned()).to_string(), + r#"('a'..'z')"#, + ); + } + + #[test] + fn ident() { + assert_eq!(Expr::Ident("a".to_owned()).to_string(), "a"); + } + + #[test] + fn peek_slice() { + assert_eq!(Expr::PeekSlice(0, None).to_string(), "PEEK[0..]"); + assert_eq!(Expr::PeekSlice(0, Some(-1)).to_string(), "PEEK[0..-1]"); + } + + #[test] + fn pos_pred() { + assert_eq!( + Expr::PosPred(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "&e", + ); + } + + #[test] + fn neg_pred() { + assert_eq!( + Expr::NegPred(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "!e", + ); + } + + #[test] + fn seq() { + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Ident("e2".to_owned())), + ) + .to_string(), + "(e1 ~ e2)", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Ident("e3".to_owned())), + )), + ) + .to_string(), + "(e1 ~ e2 ~ e3)", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ e2 ~ e3 ~ e4)", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ (e2 | (e3 ~ e4)))", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ e2 ~ (e3 | e4))", + ); + } + + #[test] + fn choice() { + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Ident("e2".to_owned())), + ) + .to_string(), + "(e1 | e2)", + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Ident("e3".to_owned())), + )), + ) + .to_string(), + "(e1 | e2 | e3)", + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 | e2 | e3 | e4)", + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 | (e2 ~ (e3 | e4)))", + ); + } + + #[test] + fn opt() { + assert_eq!( + Expr::Opt(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "e?", + ); + } + + #[test] + fn rep() { + assert_eq!( + Expr::Rep(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "e*", + ); + } + + #[test] + fn rep_once() { + assert_eq!( + Expr::RepOnce(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "e+", + ); + } + + #[test] + fn rep_exact() { + assert_eq!( + Expr::RepExact(Box::new(Expr::Ident("e".to_owned())), 1).to_string(), + "e{1}", + ); + } + + #[test] + fn rep_min() { + assert_eq!( + Expr::RepMin(Box::new(Expr::Ident("e".to_owned())), 1).to_string(), + "e{1,}", + ); + } + + #[test] + fn rep_max() { + assert_eq!( + Expr::RepMax(Box::new(Expr::Ident("e".to_owned())), 1).to_string(), + "e{,1}", + ); + } + + #[test] + fn rep_min_max() { + assert_eq!( + Expr::RepMinMax(Box::new(Expr::Ident("e".to_owned())), 1, 2).to_string(), + "e{1, 2}", + ); + } + + #[test] + fn skip() { + assert_eq!( + Expr::Skip( + ["a", "bc"] + .into_iter() + .map(|s| s.to_owned()) + .collect::>(), + ) + .to_string(), + r#"(!("a" | "bc") ~ ANY)*"#, + ); + } + + #[test] + fn push() { + assert_eq!( + Expr::Push(Box::new(Expr::Ident("e".to_owned()))).to_string(), + "PUSH(e)", + ); + } + + #[test] + #[cfg(feature = "grammar-extras")] + fn node_tag() { + assert_eq!( + Expr::NodeTag(Box::new(Expr::Ident("expr".to_owned())), "label".to_owned()) + .to_string(), + "(#label = expr)", + ); + } + } } diff --git a/src/grammar.pest b/src/grammar.pest index 405ab39..d97caba 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -1,6 +1,6 @@ // pest. The Elegant Parser // Copyright (c) 2018 Dragoș Tiselice -// +// // Licensed under the Apache License, Version 2.0 // or the MIT // license , at your @@ -16,97 +16,126 @@ //! future (e.g. by increasing MSRV and non_exhaustive annotations). /// The top-level rule of a grammar. -grammar_rules = _{ SOI ~ grammar_doc* ~ (grammar_rule)+ ~ EOI } +grammar_rules = _{ SOI ~ grammar_doc* ~ grammar_rule* ~ EOI } /// A rule of a grammar. grammar_rule = { - identifier ~ assignment_operator ~ modifier? ~ - opening_brace ~ expression ~ closing_brace | - line_doc + identifier ~ assignment_operator ~ modifier? ~ opening_brace ~ expression ~ closing_brace + | line_doc } /// Assignment operator. assignment_operator = { "=" } + /// Opening brace for a rule. -opening_brace = { "{" } +opening_brace = { "{" } + /// Closing brace for a rule. -closing_brace = { "}" } +closing_brace = { "}" } + /// Opening parenthesis for a branch, PUSH, etc. -opening_paren = { "(" } +opening_paren = { "(" } + /// Closing parenthesis for a branch, PUSH, etc. -closing_paren = { ")" } +closing_paren = { ")" } + /// Opening bracket for PEEK (slice inside). -opening_brack = { "[" } +opening_brack = { "[" } + /// Closing bracket for PEEK (slice inside). -closing_brack = { "]" } +closing_brack = { "]" } /// A rule modifier. modifier = _{ - silent_modifier | - atomic_modifier | - compound_atomic_modifier | - non_atomic_modifier + silent_modifier + | atomic_modifier + | compound_atomic_modifier + | non_atomic_modifier } /// Silent rule prefix. -silent_modifier = { "_" } +silent_modifier = { "_" } + /// Atomic rule prefix. -atomic_modifier = { "@" } +atomic_modifier = { "@" } + /// Compound atomic rule prefix. compound_atomic_modifier = { "$" } + /// Non-atomic rule prefix. -non_atomic_modifier = { "!" } +non_atomic_modifier = { "!" } + +/// A tag label. +tag_id = @{ "#" ~ ("_" | alpha) ~ ("_" | alpha_num)* } + +/// For assigning labels to nodes. +node_tag = _{ tag_id ~ assignment_operator } /// A rule expression. -expression = { choice_operator? ~ term ~ (infix_operator ~ term)* } +expression = { choice_operator? ~ term ~ (infix_operator ~ term)* } + /// A rule term. -term = { prefix_operator* ~ node ~ postfix_operator* } +term = { node_tag? ~ prefix_operator* ~ node ~ postfix_operator* } + /// A rule node (inside terms). -node = _{ opening_paren ~ expression ~ closing_paren | terminal } +node = _{ opening_paren ~ expression ~ closing_paren | terminal } + /// A terminal expression. -terminal = _{ _push | peek_slice | identifier | string | insensitive_string | range } +terminal = _{ _push | peek_slice | identifier | string | insensitive_string | range } /// Possible predicates for a rule. -prefix_operator = _{ positive_predicate_operator | negative_predicate_operator } +prefix_operator = _{ positive_predicate_operator | negative_predicate_operator } + /// Branches or sequences. -infix_operator = _{ sequence_operator | choice_operator } +infix_operator = _{ sequence_operator | choice_operator } + /// Possible modifiers for a rule. postfix_operator = _{ - optional_operator | - repeat_operator | - repeat_once_operator | - repeat_exact | - repeat_min | - repeat_max | - repeat_min_max + optional_operator + | repeat_operator + | repeat_once_operator + | repeat_exact + | repeat_min + | repeat_max + | repeat_min_max } /// A positive predicate. positive_predicate_operator = { "&" } + /// A negative predicate. negative_predicate_operator = { "!" } + /// A sequence operator. -sequence_operator = { "~" } +sequence_operator = { "~" } + /// A choice operator. -choice_operator = { "|" } +choice_operator = { "|" } + /// An optional operator. -optional_operator = { "?" } +optional_operator = { "?" } + /// A repeat operator. -repeat_operator = { "*" } +repeat_operator = { "*" } + /// A repeat at least once operator. -repeat_once_operator = { "+" } +repeat_once_operator = { "+" } /// A repeat exact times. -repeat_exact = { opening_brace ~ number ~ closing_brace } +repeat_exact = { opening_brace ~ number ~ closing_brace } + /// A repeat at least times. -repeat_min = { opening_brace ~ number ~ comma ~ closing_brace } +repeat_min = { opening_brace ~ number ~ comma ~ closing_brace } + /// A repeat at most times. -repeat_max = { opening_brace ~ comma ~ number ~ closing_brace } +repeat_max = { opening_brace ~ comma ~ number ~ closing_brace } + /// A repeat in a range. repeat_min_max = { opening_brace ~ number ~ comma ~ number ~ closing_brace } /// A number. number = @{ '0'..'9'+ } + /// An integer number (positive or negative). integer = @{ number | "-" ~ "0"* ~ '1'..'9' ~ number? } @@ -115,62 +144,82 @@ comma = { "," } /// A PUSH expression. _push = { "PUSH" ~ opening_paren ~ expression ~ closing_paren } + /// A PEEK expression. peek_slice = { "PEEK" ~ opening_brack ~ integer? ~ range_operator ~ integer? ~ closing_brack } /// An identifier. identifier = @{ !"PUSH" ~ ("_" | alpha) ~ ("_" | alpha_num)* } + /// An alpha character. -alpha = _{ 'a'..'z' | 'A'..'Z' } +alpha = _{ 'a'..'z' | 'A'..'Z' } + /// An alphanumeric character. -alpha_num = _{ alpha | '0'..'9' } +alpha_num = _{ alpha | '0'..'9' } /// A string. -string = ${ quote ~ inner_str ~ quote } +string = ${ quote ~ inner_str ~ quote } + /// An insensitive string. -insensitive_string = { "^" ~ string } +insensitive_string = { "^" ~ string } + /// A character range. -range = { character ~ range_operator ~ character } +range = { character ~ range_operator ~ character } + /// A single quoted character -character = ${ single_quote ~ inner_chr ~ single_quote } +character = ${ single_quote ~ inner_chr ~ single_quote } /// A quoted string. inner_str = @{ (!("\"" | "\\") ~ ANY)* ~ (escape ~ inner_str)? } + /// An escaped or any character. inner_chr = @{ escape | ANY } + /// An escape sequence. -escape = @{ "\\" ~ ("\"" | "\\" | "r" | "n" | "t" | "0" | "'" | code | unicode) } +escape = @{ "\\" ~ ("\"" | "\\" | "r" | "n" | "t" | "0" | "'" | code | unicode) } + /// A hexadecimal code. -code = @{ "x" ~ hex_digit{2} } +code = @{ "x" ~ hex_digit{2} } + /// A unicode code. -unicode = @{ "u" ~ opening_brace ~ hex_digit{2, 6} ~ closing_brace } +unicode = @{ "u" ~ opening_brace ~ hex_digit{2, 6} ~ closing_brace } + /// A hexadecimal digit. hex_digit = @{ '0'..'9' | 'a'..'f' | 'A'..'F' } /// A double quote. -quote = { "\"" } +quote = { "\"" } + /// A single quote. -single_quote = { "'" } +single_quote = { "'" } + /// A range operator. range_operator = { ".." } /// A newline character. -newline = _{ "\n" | "\r\n" } +newline = _{ "\n" | "\r\n" } + /// A whitespace character. -WHITESPACE = _{ " " | "\t" | newline } +WHITESPACE = _{ " " | "\t" | newline } + /// A single line comment. -line_comment = _{ ("//" ~ !("/" | "!") ~ (!newline ~ ANY)*) } +line_comment = _{ ("//" ~ !("/" | "!") ~ (!newline ~ ANY)*) } + /// A multi-line comment. -block_comment = _{ "/*" ~ (block_comment | !"*/" ~ ANY)* ~ "*/" } +block_comment = _{ "/*" ~ (block_comment | !"*/" ~ ANY)* ~ "*/" } + /// A grammar comment. -COMMENT = _{ block_comment | line_comment } +COMMENT = _{ block_comment | line_comment } // ref: https://doc.rust-lang.org/reference/comments.html /// A space character. -space = _{ " " | "\t" } +space = _{ " " | "\t" } + /// A top-level comment. grammar_doc = ${ "//!" ~ space? ~ inner_doc } + /// A rule comment. -line_doc = ${ "///" ~ space? ~ !"/" ~ inner_doc } +line_doc = ${ "///" ~ space? ~ inner_doc } + /// A comment content. -inner_doc = @{ (!newline ~ ANY)* } +inner_doc = @{ (!newline ~ ANY)* } diff --git a/src/grammar.rs b/src/grammar.rs index b612fb1..58cf5ff 100644 --- a/src/grammar.rs +++ b/src/grammar.rs @@ -1,2 +1,2 @@ pub struct PestParser; -# [doc = "Pest meta-grammar\n\n# Warning: Semantic Versioning\nThere may be non-breaking changes to the meta-grammar\nbetween minor versions. Those non-breaking changes, however,\nmay translate into semver-breaking changes due to the additional variants\nadded to the `Rule` enum. This is a known issue and will be fixed in the\nfuture (e.g. by increasing MSRV and non_exhaustive annotations)."] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] # [derive (Clone , Copy , Debug , Eq , Hash , Ord , PartialEq , PartialOrd)] pub enum Rule { EOI , # [doc = "The top-level rule of a grammar."] r#grammar_rules , # [doc = "A rule of a grammar."] r#grammar_rule , # [doc = "Assignment operator."] r#assignment_operator , # [doc = "Opening brace for a rule."] r#opening_brace , # [doc = "Closing brace for a rule."] r#closing_brace , # [doc = "Opening parenthesis for a branch, PUSH, etc."] r#opening_paren , # [doc = "Closing parenthesis for a branch, PUSH, etc."] r#closing_paren , # [doc = "Opening bracket for PEEK (slice inside)."] r#opening_brack , # [doc = "Closing bracket for PEEK (slice inside)."] r#closing_brack , # [doc = "A rule modifier."] r#modifier , # [doc = "Silent rule prefix."] r#silent_modifier , # [doc = "Atomic rule prefix."] r#atomic_modifier , # [doc = "Compound atomic rule prefix."] r#compound_atomic_modifier , # [doc = "Non-atomic rule prefix."] r#non_atomic_modifier , # [doc = "A rule expression."] r#expression , # [doc = "A rule term."] r#term , # [doc = "A rule node (inside terms)."] r#node , # [doc = "A terminal expression."] r#terminal , # [doc = "Possible predicates for a rule."] r#prefix_operator , # [doc = "Branches or sequences."] r#infix_operator , # [doc = "Possible modifiers for a rule."] r#postfix_operator , # [doc = "A positive predicate."] r#positive_predicate_operator , # [doc = "A negative predicate."] r#negative_predicate_operator , # [doc = "A sequence operator."] r#sequence_operator , # [doc = "A choice operator."] r#choice_operator , # [doc = "An optional operator."] r#optional_operator , # [doc = "A repeat operator."] r#repeat_operator , # [doc = "A repeat at least once operator."] r#repeat_once_operator , # [doc = "A repeat exact times."] r#repeat_exact , # [doc = "A repeat at least times."] r#repeat_min , # [doc = "A repeat at most times."] r#repeat_max , # [doc = "A repeat in a range."] r#repeat_min_max , # [doc = "A number."] r#number , # [doc = "An integer number (positive or negative)."] r#integer , # [doc = "A comma terminal."] r#comma , # [doc = "A PUSH expression."] r#_push , # [doc = "A PEEK expression."] r#peek_slice , # [doc = "An identifier."] r#identifier , # [doc = "An alpha character."] r#alpha , # [doc = "An alphanumeric character."] r#alpha_num , # [doc = "A string."] r#string , # [doc = "An insensitive string."] r#insensitive_string , # [doc = "A character range."] r#range , # [doc = "A single quoted character"] r#character , # [doc = "A quoted string."] r#inner_str , # [doc = "An escaped or any character."] r#inner_chr , # [doc = "An escape sequence."] r#escape , # [doc = "A hexadecimal code."] r#code , # [doc = "A unicode code."] r#unicode , # [doc = "A hexadecimal digit."] r#hex_digit , # [doc = "A double quote."] r#quote , # [doc = "A single quote."] r#single_quote , # [doc = "A range operator."] r#range_operator , # [doc = "A newline character."] r#newline , # [doc = "A whitespace character."] r#WHITESPACE , # [doc = "A single line comment."] r#line_comment , # [doc = "A multi-line comment."] r#block_comment , # [doc = "A grammar comment."] r#COMMENT , # [doc = "A space character."] r#space , # [doc = "A top-level comment."] r#grammar_doc , # [doc = "A rule comment."] r#line_doc , # [doc = "A comment content."] r#inner_doc } # [allow (clippy :: all)] impl :: pest :: Parser < Rule > for PestParser { fn parse < 'i > (rule : Rule , input : & 'i str) -> :: std :: result :: Result < :: pest :: iterators :: Pairs < 'i , Rule > , :: pest :: error :: Error < Rule > > { mod rules { # ! [allow (clippy :: upper_case_acronyms)] pub mod hidden { use super :: super :: Rule ; # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn skip (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { if state . atomicity () == :: pest :: Atomicity :: NonAtomic { state . sequence (| state | { state . repeat (| state | super :: visible :: WHITESPACE (state)) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: visible :: COMMENT (state) . and_then (| state | { state . repeat (| state | super :: visible :: WHITESPACE (state)) }) }) }) }) }) } else { Ok (state) } } } pub mod visible { use super :: super :: Rule ; # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_rules (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { self :: r#SOI (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#grammar_doc (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#grammar_doc (state) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { self :: r#grammar_rule (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#grammar_rule (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#grammar_rule (state) }) }) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#EOI (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_rule (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#grammar_rule , | state | { state . sequence (| state | { self :: r#identifier (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#assignment_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#modifier (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_brace (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) . or_else (| state | { self :: r#line_doc (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#assignment_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#assignment_operator , | state | { state . match_string ("=") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_brace (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_brace , | state | { state . match_string ("{") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_brace (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_brace , | state | { state . match_string ("}") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_paren (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_paren , | state | { state . match_string ("(") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_paren (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_paren , | state | { state . match_string (")") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_brack (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_brack , | state | { state . match_string ("[") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_brack (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_brack , | state | { state . match_string ("]") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#silent_modifier (state) . or_else (| state | { self :: r#atomic_modifier (state) }) . or_else (| state | { self :: r#compound_atomic_modifier (state) }) . or_else (| state | { self :: r#non_atomic_modifier (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#silent_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#silent_modifier , | state | { state . match_string ("_") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#atomic_modifier , | state | { state . match_string ("@") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#compound_atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#compound_atomic_modifier , | state | { state . match_string ("$") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#non_atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#non_atomic_modifier , | state | { state . match_string ("!") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#expression (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#expression , | state | { state . sequence (| state | { state . optional (| state | { self :: r#choice_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { self :: r#infix_operator (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { self :: r#infix_operator (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) }) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#term (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#term , | state | { state . sequence (| state | { state . sequence (| state | { state . optional (| state | { self :: r#prefix_operator (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#prefix_operator (state) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#node (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#postfix_operator (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#postfix_operator (state) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#node (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { self :: r#opening_paren (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_paren (state) }) }) . or_else (| state | { self :: r#terminal (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#terminal (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#_push (state) . or_else (| state | { self :: r#peek_slice (state) }) . or_else (| state | { self :: r#identifier (state) }) . or_else (| state | { self :: r#string (state) }) . or_else (| state | { self :: r#insensitive_string (state) }) . or_else (| state | { self :: r#range (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#prefix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#positive_predicate_operator (state) . or_else (| state | { self :: r#negative_predicate_operator (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#infix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#sequence_operator (state) . or_else (| state | { self :: r#choice_operator (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#postfix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#optional_operator (state) . or_else (| state | { self :: r#repeat_operator (state) }) . or_else (| state | { self :: r#repeat_once_operator (state) }) . or_else (| state | { self :: r#repeat_exact (state) }) . or_else (| state | { self :: r#repeat_min (state) }) . or_else (| state | { self :: r#repeat_max (state) }) . or_else (| state | { self :: r#repeat_min_max (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#positive_predicate_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#positive_predicate_operator , | state | { state . match_string ("&") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#negative_predicate_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#negative_predicate_operator , | state | { state . match_string ("!") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#sequence_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#sequence_operator , | state | { state . match_string ("~") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#choice_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#choice_operator , | state | { state . match_string ("|") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#optional_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#optional_operator , | state | { state . match_string ("?") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_operator , | state | { state . match_string ("*") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_once_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_once_operator , | state | { state . match_string ("+") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_exact (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_exact , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_min (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_min , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_max (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_max , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_min_max (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_min_max , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#number (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#number , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_range ('0' .. '9') . and_then (| state | { state . repeat (| state | { state . match_range ('0' .. '9') }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#integer (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#integer , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#number (state) . or_else (| state | { state . sequence (| state | { state . match_string ("-") . and_then (| state | { state . repeat (| state | { state . match_string ("0") }) }) . and_then (| state | { state . match_range ('1' .. '9') }) . and_then (| state | { state . optional (| state | { self :: r#number (state) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#comma (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#comma , | state | { state . match_string (",") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#_push (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#_push , | state | { state . sequence (| state | { state . match_string ("PUSH") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_paren (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_paren (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#peek_slice (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#peek_slice , | state | { state . sequence (| state | { state . match_string ("PEEK") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_brack (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#integer (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#range_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#integer (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brack (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#identifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#identifier , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("PUSH") }) . and_then (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha (state) }) }) . and_then (| state | { state . repeat (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha_num (state) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#alpha (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_range ('a' .. 'z') . or_else (| state | { state . match_range ('A' .. 'Z') }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#alpha_num (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#alpha (state) . or_else (| state | { state . match_range ('0' .. '9') }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#string (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#string , | state | { state . sequence (| state | { self :: r#quote (state) . and_then (| state | { self :: r#inner_str (state) }) . and_then (| state | { self :: r#quote (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#insensitive_string (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#insensitive_string , | state | { state . sequence (| state | { state . match_string ("^") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#string (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#range (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#range , | state | { state . sequence (| state | { self :: r#character (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#range_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#character (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#character (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#character , | state | { state . sequence (| state | { self :: r#single_quote (state) . and_then (| state | { self :: r#inner_chr (state) }) . and_then (| state | { self :: r#single_quote (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_str (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_str , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { let strings = ["\"" , "\\"] ; state . skip_until (& strings) . and_then (| state | { state . optional (| state | { state . sequence (| state | { self :: r#escape (state) . and_then (| state | { self :: r#inner_str (state) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_chr (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_chr , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#escape (state) . or_else (| state | { self :: r#ANY (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#escape (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#escape , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("\\") . and_then (| state | { state . match_string ("\"") . or_else (| state | { state . match_string ("\\") }) . or_else (| state | { state . match_string ("r") }) . or_else (| state | { state . match_string ("n") }) . or_else (| state | { state . match_string ("t") }) . or_else (| state | { state . match_string ("0") }) . or_else (| state | { state . match_string ("'") }) . or_else (| state | { self :: r#code (state) }) . or_else (| state | { self :: r#unicode (state) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#code (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#code , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("x") . and_then (| state | { self :: r#hex_digit (state) }) . and_then (| state | { self :: r#hex_digit (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#unicode (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#unicode , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("u") . and_then (| state | { self :: r#opening_brace (state) }) . and_then (| state | { state . sequence (| state | { self :: r#hex_digit (state) . and_then (| state | { self :: r#hex_digit (state) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) }) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#hex_digit (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#hex_digit , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . match_range ('0' .. '9') . or_else (| state | { state . match_range ('a' .. 'f') }) . or_else (| state | { state . match_range ('A' .. 'F') }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#quote (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#quote , | state | { state . match_string ("\"") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#single_quote (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#single_quote , | state | { state . match_string ("'") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#range_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#range_operator , | state | { state . match_string ("..") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#newline (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_string ("\n") . or_else (| state | { state . match_string ("\r\n") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#WHITESPACE (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . match_string (" ") . or_else (| state | { state . match_string ("\t") }) . or_else (| state | { self :: r#newline (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#line_comment (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { state . match_string ("//") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . lookahead (false , | state | { state . match_string ("/") . or_else (| state | { state . match_string ("!") }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#block_comment (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { state . match_string ("/*") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#block_comment (state) . or_else (| state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("*/") }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#block_comment (state) . or_else (| state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("*/") }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . match_string ("*/") }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#COMMENT (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#block_comment (state) . or_else (| state | { self :: r#line_comment (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#space (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_string (" ") . or_else (| state | { state . match_string ("\t") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#grammar_doc , | state | { state . sequence (| state | { state . match_string ("//!") . and_then (| state | { state . optional (| state | { self :: r#space (state) }) }) . and_then (| state | { self :: r#inner_doc (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#line_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#line_doc , | state | { state . sequence (| state | { state . match_string ("///") . and_then (| state | { state . optional (| state | { self :: r#space (state) }) }) . and_then (| state | { state . lookahead (false , | state | { state . match_string ("/") }) }) . and_then (| state | { self :: r#inner_doc (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_doc , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . repeat (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn ANY (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . skip (1) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn EOI (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: EOI , | state | state . end_of_input ()) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn SOI (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . start_of_input () } } pub use self :: visible :: * ; } :: pest :: state (input , | state | { match rule { Rule :: r#grammar_rules => rules :: r#grammar_rules (state) , Rule :: r#grammar_rule => rules :: r#grammar_rule (state) , Rule :: r#assignment_operator => rules :: r#assignment_operator (state) , Rule :: r#opening_brace => rules :: r#opening_brace (state) , Rule :: r#closing_brace => rules :: r#closing_brace (state) , Rule :: r#opening_paren => rules :: r#opening_paren (state) , Rule :: r#closing_paren => rules :: r#closing_paren (state) , Rule :: r#opening_brack => rules :: r#opening_brack (state) , Rule :: r#closing_brack => rules :: r#closing_brack (state) , Rule :: r#modifier => rules :: r#modifier (state) , Rule :: r#silent_modifier => rules :: r#silent_modifier (state) , Rule :: r#atomic_modifier => rules :: r#atomic_modifier (state) , Rule :: r#compound_atomic_modifier => rules :: r#compound_atomic_modifier (state) , Rule :: r#non_atomic_modifier => rules :: r#non_atomic_modifier (state) , Rule :: r#expression => rules :: r#expression (state) , Rule :: r#term => rules :: r#term (state) , Rule :: r#node => rules :: r#node (state) , Rule :: r#terminal => rules :: r#terminal (state) , Rule :: r#prefix_operator => rules :: r#prefix_operator (state) , Rule :: r#infix_operator => rules :: r#infix_operator (state) , Rule :: r#postfix_operator => rules :: r#postfix_operator (state) , Rule :: r#positive_predicate_operator => rules :: r#positive_predicate_operator (state) , Rule :: r#negative_predicate_operator => rules :: r#negative_predicate_operator (state) , Rule :: r#sequence_operator => rules :: r#sequence_operator (state) , Rule :: r#choice_operator => rules :: r#choice_operator (state) , Rule :: r#optional_operator => rules :: r#optional_operator (state) , Rule :: r#repeat_operator => rules :: r#repeat_operator (state) , Rule :: r#repeat_once_operator => rules :: r#repeat_once_operator (state) , Rule :: r#repeat_exact => rules :: r#repeat_exact (state) , Rule :: r#repeat_min => rules :: r#repeat_min (state) , Rule :: r#repeat_max => rules :: r#repeat_max (state) , Rule :: r#repeat_min_max => rules :: r#repeat_min_max (state) , Rule :: r#number => rules :: r#number (state) , Rule :: r#integer => rules :: r#integer (state) , Rule :: r#comma => rules :: r#comma (state) , Rule :: r#_push => rules :: r#_push (state) , Rule :: r#peek_slice => rules :: r#peek_slice (state) , Rule :: r#identifier => rules :: r#identifier (state) , Rule :: r#alpha => rules :: r#alpha (state) , Rule :: r#alpha_num => rules :: r#alpha_num (state) , Rule :: r#string => rules :: r#string (state) , Rule :: r#insensitive_string => rules :: r#insensitive_string (state) , Rule :: r#range => rules :: r#range (state) , Rule :: r#character => rules :: r#character (state) , Rule :: r#inner_str => rules :: r#inner_str (state) , Rule :: r#inner_chr => rules :: r#inner_chr (state) , Rule :: r#escape => rules :: r#escape (state) , Rule :: r#code => rules :: r#code (state) , Rule :: r#unicode => rules :: r#unicode (state) , Rule :: r#hex_digit => rules :: r#hex_digit (state) , Rule :: r#quote => rules :: r#quote (state) , Rule :: r#single_quote => rules :: r#single_quote (state) , Rule :: r#range_operator => rules :: r#range_operator (state) , Rule :: r#newline => rules :: r#newline (state) , Rule :: r#WHITESPACE => rules :: r#WHITESPACE (state) , Rule :: r#line_comment => rules :: r#line_comment (state) , Rule :: r#block_comment => rules :: r#block_comment (state) , Rule :: r#COMMENT => rules :: r#COMMENT (state) , Rule :: r#space => rules :: r#space (state) , Rule :: r#grammar_doc => rules :: r#grammar_doc (state) , Rule :: r#line_doc => rules :: r#line_doc (state) , Rule :: r#inner_doc => rules :: r#inner_doc (state) , Rule :: EOI => rules :: EOI (state) } }) } } +# [doc = "Pest meta-grammar\n\n# Warning: Semantic Versioning\nThere may be non-breaking changes to the meta-grammar\nbetween minor versions. Those non-breaking changes, however,\nmay translate into semver-breaking changes due to the additional variants\nadded to the `Rule` enum. This is a known issue and will be fixed in the\nfuture (e.g. by increasing MSRV and non_exhaustive annotations)."] # [allow (dead_code , non_camel_case_types , clippy :: upper_case_acronyms)] # [derive (Clone , Copy , Debug , Eq , Hash , Ord , PartialEq , PartialOrd)] pub enum Rule { # [doc = "End-of-input"] EOI , # [doc = "The top-level rule of a grammar."] r#grammar_rules , # [doc = "A rule of a grammar."] r#grammar_rule , # [doc = "Assignment operator."] r#assignment_operator , # [doc = "Opening brace for a rule."] r#opening_brace , # [doc = "Closing brace for a rule."] r#closing_brace , # [doc = "Opening parenthesis for a branch, PUSH, etc."] r#opening_paren , # [doc = "Closing parenthesis for a branch, PUSH, etc."] r#closing_paren , # [doc = "Opening bracket for PEEK (slice inside)."] r#opening_brack , # [doc = "Closing bracket for PEEK (slice inside)."] r#closing_brack , # [doc = "A rule modifier."] r#modifier , # [doc = "Silent rule prefix."] r#silent_modifier , # [doc = "Atomic rule prefix."] r#atomic_modifier , # [doc = "Compound atomic rule prefix."] r#compound_atomic_modifier , # [doc = "Non-atomic rule prefix."] r#non_atomic_modifier , # [doc = "A tag label."] r#tag_id , # [doc = "For assigning labels to nodes."] r#node_tag , # [doc = "A rule expression."] r#expression , # [doc = "A rule term."] r#term , # [doc = "A rule node (inside terms)."] r#node , # [doc = "A terminal expression."] r#terminal , # [doc = "Possible predicates for a rule."] r#prefix_operator , # [doc = "Branches or sequences."] r#infix_operator , # [doc = "Possible modifiers for a rule."] r#postfix_operator , # [doc = "A positive predicate."] r#positive_predicate_operator , # [doc = "A negative predicate."] r#negative_predicate_operator , # [doc = "A sequence operator."] r#sequence_operator , # [doc = "A choice operator."] r#choice_operator , # [doc = "An optional operator."] r#optional_operator , # [doc = "A repeat operator."] r#repeat_operator , # [doc = "A repeat at least once operator."] r#repeat_once_operator , # [doc = "A repeat exact times."] r#repeat_exact , # [doc = "A repeat at least times."] r#repeat_min , # [doc = "A repeat at most times."] r#repeat_max , # [doc = "A repeat in a range."] r#repeat_min_max , # [doc = "A number."] r#number , # [doc = "An integer number (positive or negative)."] r#integer , # [doc = "A comma terminal."] r#comma , # [doc = "A PUSH expression."] r#_push , # [doc = "A PEEK expression."] r#peek_slice , # [doc = "An identifier."] r#identifier , # [doc = "An alpha character."] r#alpha , # [doc = "An alphanumeric character."] r#alpha_num , # [doc = "A string."] r#string , # [doc = "An insensitive string."] r#insensitive_string , # [doc = "A character range."] r#range , # [doc = "A single quoted character"] r#character , # [doc = "A quoted string."] r#inner_str , # [doc = "An escaped or any character."] r#inner_chr , # [doc = "An escape sequence."] r#escape , # [doc = "A hexadecimal code."] r#code , # [doc = "A unicode code."] r#unicode , # [doc = "A hexadecimal digit."] r#hex_digit , # [doc = "A double quote."] r#quote , # [doc = "A single quote."] r#single_quote , # [doc = "A range operator."] r#range_operator , # [doc = "A newline character."] r#newline , # [doc = "A whitespace character."] r#WHITESPACE , # [doc = "A single line comment."] r#line_comment , # [doc = "A multi-line comment."] r#block_comment , # [doc = "A grammar comment."] r#COMMENT , # [doc = "A space character."] r#space , # [doc = "A top-level comment."] r#grammar_doc , # [doc = "A rule comment."] r#line_doc , # [doc = "A comment content."] r#inner_doc } impl Rule { pub fn all_rules () -> & 'static [Rule] { & [Rule :: r#grammar_rules , Rule :: r#grammar_rule , Rule :: r#assignment_operator , Rule :: r#opening_brace , Rule :: r#closing_brace , Rule :: r#opening_paren , Rule :: r#closing_paren , Rule :: r#opening_brack , Rule :: r#closing_brack , Rule :: r#modifier , Rule :: r#silent_modifier , Rule :: r#atomic_modifier , Rule :: r#compound_atomic_modifier , Rule :: r#non_atomic_modifier , Rule :: r#tag_id , Rule :: r#node_tag , Rule :: r#expression , Rule :: r#term , Rule :: r#node , Rule :: r#terminal , Rule :: r#prefix_operator , Rule :: r#infix_operator , Rule :: r#postfix_operator , Rule :: r#positive_predicate_operator , Rule :: r#negative_predicate_operator , Rule :: r#sequence_operator , Rule :: r#choice_operator , Rule :: r#optional_operator , Rule :: r#repeat_operator , Rule :: r#repeat_once_operator , Rule :: r#repeat_exact , Rule :: r#repeat_min , Rule :: r#repeat_max , Rule :: r#repeat_min_max , Rule :: r#number , Rule :: r#integer , Rule :: r#comma , Rule :: r#_push , Rule :: r#peek_slice , Rule :: r#identifier , Rule :: r#alpha , Rule :: r#alpha_num , Rule :: r#string , Rule :: r#insensitive_string , Rule :: r#range , Rule :: r#character , Rule :: r#inner_str , Rule :: r#inner_chr , Rule :: r#escape , Rule :: r#code , Rule :: r#unicode , Rule :: r#hex_digit , Rule :: r#quote , Rule :: r#single_quote , Rule :: r#range_operator , Rule :: r#newline , Rule :: r#WHITESPACE , Rule :: r#line_comment , Rule :: r#block_comment , Rule :: r#COMMENT , Rule :: r#space , Rule :: r#grammar_doc , Rule :: r#line_doc , Rule :: r#inner_doc] } } # [allow (clippy :: all)] impl :: pest :: Parser < Rule > for PestParser { fn parse < 'i > (rule : Rule , input : & 'i str) -> :: std :: result :: Result < :: pest :: iterators :: Pairs < 'i , Rule > , :: pest :: error :: Error < Rule > > { mod rules { # ! [allow (clippy :: upper_case_acronyms)] pub mod hidden { use super :: super :: Rule ; # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn skip (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { if state . atomicity () == :: pest :: Atomicity :: NonAtomic { state . sequence (| state | { state . repeat (| state | super :: visible :: WHITESPACE (state)) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: visible :: COMMENT (state) . and_then (| state | { state . repeat (| state | super :: visible :: WHITESPACE (state)) }) }) }) }) }) } else { Ok (state) } } } pub mod visible { use super :: super :: Rule ; # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_rules (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { self :: r#SOI (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#grammar_doc (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#grammar_doc (state) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#grammar_rule (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#grammar_rule (state) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#EOI (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_rule (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#grammar_rule , | state | { state . sequence (| state | { self :: r#identifier (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#assignment_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#modifier (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_brace (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) . or_else (| state | { self :: r#line_doc (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#assignment_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#assignment_operator , | state | { state . match_string ("=") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_brace (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_brace , | state | { state . match_string ("{") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_brace (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_brace , | state | { state . match_string ("}") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_paren (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_paren , | state | { state . match_string ("(") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_paren (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_paren , | state | { state . match_string (")") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#opening_brack (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#opening_brack , | state | { state . match_string ("[") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#closing_brack (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#closing_brack , | state | { state . match_string ("]") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#silent_modifier (state) . or_else (| state | { self :: r#atomic_modifier (state) }) . or_else (| state | { self :: r#compound_atomic_modifier (state) }) . or_else (| state | { self :: r#non_atomic_modifier (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#silent_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#silent_modifier , | state | { state . match_string ("_") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#atomic_modifier , | state | { state . match_string ("@") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#compound_atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#compound_atomic_modifier , | state | { state . match_string ("$") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#non_atomic_modifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#non_atomic_modifier , | state | { state . match_string ("!") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#tag_id (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#tag_id , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("#") . and_then (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha (state) }) }) . and_then (| state | { state . repeat (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha_num (state) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#node_tag (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { self :: r#tag_id (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#assignment_operator (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#expression (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#expression , | state | { state . sequence (| state | { state . optional (| state | { self :: r#choice_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { self :: r#infix_operator (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { self :: r#infix_operator (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#term (state) }) }) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#term (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#term , | state | { state . sequence (| state | { state . optional (| state | { self :: r#node_tag (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#prefix_operator (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#prefix_operator (state) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#node (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#postfix_operator (state) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#postfix_operator (state) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#node (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { self :: r#opening_paren (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_paren (state) }) }) . or_else (| state | { self :: r#terminal (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#terminal (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#_push (state) . or_else (| state | { self :: r#peek_slice (state) }) . or_else (| state | { self :: r#identifier (state) }) . or_else (| state | { self :: r#string (state) }) . or_else (| state | { self :: r#insensitive_string (state) }) . or_else (| state | { self :: r#range (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#prefix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#positive_predicate_operator (state) . or_else (| state | { self :: r#negative_predicate_operator (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#infix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#sequence_operator (state) . or_else (| state | { self :: r#choice_operator (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#postfix_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#optional_operator (state) . or_else (| state | { self :: r#repeat_operator (state) }) . or_else (| state | { self :: r#repeat_once_operator (state) }) . or_else (| state | { self :: r#repeat_exact (state) }) . or_else (| state | { self :: r#repeat_min (state) }) . or_else (| state | { self :: r#repeat_max (state) }) . or_else (| state | { self :: r#repeat_min_max (state) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#positive_predicate_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#positive_predicate_operator , | state | { state . match_string ("&") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#negative_predicate_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#negative_predicate_operator , | state | { state . match_string ("!") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#sequence_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#sequence_operator , | state | { state . match_string ("~") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#choice_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#choice_operator , | state | { state . match_string ("|") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#optional_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#optional_operator , | state | { state . match_string ("?") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_operator , | state | { state . match_string ("*") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_once_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_once_operator , | state | { state . match_string ("+") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_exact (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_exact , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_min (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_min , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_max (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_max , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#repeat_min_max (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#repeat_min_max , | state | { state . sequence (| state | { self :: r#opening_brace (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#comma (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#number (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#number (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#number , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_range ('0' .. '9') . and_then (| state | { state . repeat (| state | { state . match_range ('0' .. '9') }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#integer (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#integer , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#number (state) . or_else (| state | { state . sequence (| state | { state . match_string ("-") . and_then (| state | { state . repeat (| state | { state . match_string ("0") }) }) . and_then (| state | { state . match_range ('1' .. '9') }) . and_then (| state | { state . optional (| state | { self :: r#number (state) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#comma (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#comma , | state | { state . match_string (",") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#_push (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#_push , | state | { state . sequence (| state | { state . match_string ("PUSH") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_paren (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#expression (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_paren (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#peek_slice (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#peek_slice , | state | { state . sequence (| state | { state . match_string ("PEEK") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#opening_brack (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#integer (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#range_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . optional (| state | { self :: r#integer (state) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#closing_brack (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#identifier (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#identifier , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("PUSH") }) . and_then (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha (state) }) }) . and_then (| state | { state . repeat (| state | { state . match_string ("_") . or_else (| state | { self :: r#alpha_num (state) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#alpha (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_range ('a' .. 'z') . or_else (| state | { state . match_range ('A' .. 'Z') }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#alpha_num (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { self :: r#alpha (state) . or_else (| state | { state . match_range ('0' .. '9') }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#string (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#string , | state | { state . sequence (| state | { self :: r#quote (state) . and_then (| state | { self :: r#inner_str (state) }) . and_then (| state | { self :: r#quote (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#insensitive_string (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#insensitive_string , | state | { state . sequence (| state | { state . match_string ("^") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#string (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#range (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#range , | state | { state . sequence (| state | { self :: r#character (state) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#range_operator (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#character (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#character (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#character , | state | { state . sequence (| state | { self :: r#single_quote (state) . and_then (| state | { self :: r#inner_chr (state) }) . and_then (| state | { self :: r#single_quote (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_str (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_str , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { let strings = ["\"" , "\\"] ; state . skip_until (& strings) . and_then (| state | { state . optional (| state | { state . sequence (| state | { self :: r#escape (state) . and_then (| state | { self :: r#inner_str (state) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_chr (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_chr , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#escape (state) . or_else (| state | { self :: r#ANY (state) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#escape (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#escape , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("\\") . and_then (| state | { state . match_string ("\"") . or_else (| state | { state . match_string ("\\") }) . or_else (| state | { state . match_string ("r") }) . or_else (| state | { state . match_string ("n") }) . or_else (| state | { state . match_string ("t") }) . or_else (| state | { state . match_string ("0") }) . or_else (| state | { state . match_string ("'") }) . or_else (| state | { self :: r#code (state) }) . or_else (| state | { self :: r#unicode (state) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#code (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#code , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("x") . and_then (| state | { self :: r#hex_digit (state) }) . and_then (| state | { self :: r#hex_digit (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#unicode (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#unicode , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . sequence (| state | { state . match_string ("u") . and_then (| state | { self :: r#opening_brace (state) }) . and_then (| state | { state . sequence (| state | { self :: r#hex_digit (state) . and_then (| state | { self :: r#hex_digit (state) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) . and_then (| state | { state . optional (| state | { self :: r#hex_digit (state) }) }) }) }) . and_then (| state | { self :: r#closing_brace (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#hex_digit (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#hex_digit , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . match_range ('0' .. '9') . or_else (| state | { state . match_range ('a' .. 'f') }) . or_else (| state | { state . match_range ('A' .. 'F') }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#quote (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#quote , | state | { state . match_string ("\"") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#single_quote (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#single_quote , | state | { state . match_string ("'") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#range_operator (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#range_operator , | state | { state . match_string ("..") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#newline (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_string ("\n") . or_else (| state | { state . match_string ("\r\n") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#WHITESPACE (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . match_string (" ") . or_else (| state | { state . match_string ("\t") }) . or_else (| state | { self :: r#newline (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#line_comment (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { state . match_string ("//") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . lookahead (false , | state | { state . match_string ("/") . or_else (| state | { state . match_string ("!") }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) }) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#block_comment (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . sequence (| state | { state . match_string ("/*") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { self :: r#block_comment (state) . or_else (| state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("*/") }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { self :: r#block_comment (state) . or_else (| state | { state . sequence (| state | { state . lookahead (false , | state | { state . match_string ("*/") }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) }) }) }) }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . match_string ("*/") }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#COMMENT (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: Atomic , | state | { self :: r#block_comment (state) . or_else (| state | { self :: r#line_comment (state) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#space (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . match_string (" ") . or_else (| state | { state . match_string ("\t") }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#grammar_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#grammar_doc , | state | { state . sequence (| state | { state . match_string ("//!") . and_then (| state | { state . optional (| state | { self :: r#space (state) }) }) . and_then (| state | { self :: r#inner_doc (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#line_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . atomic (:: pest :: Atomicity :: CompoundAtomic , | state | { state . rule (Rule :: r#line_doc , | state | { state . sequence (| state | { state . match_string ("///") . and_then (| state | { state . optional (| state | { self :: r#space (state) }) }) . and_then (| state | { self :: r#inner_doc (state) }) }) }) }) } # [inline] # [allow (non_snake_case , unused_variables)] pub fn r#inner_doc (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: r#inner_doc , | state | { state . atomic (:: pest :: Atomicity :: Atomic , | state | { state . repeat (| state | { state . sequence (| state | { state . lookahead (false , | state | { self :: r#newline (state) }) . and_then (| state | { self :: r#ANY (state) }) }) }) }) }) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn ANY (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . skip (1) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn EOI (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . rule (Rule :: EOI , | state | state . end_of_input ()) } # [inline] # [allow (dead_code , non_snake_case , unused_variables)] pub fn SOI (state : :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >>) -> :: pest :: ParseResult < :: std :: boxed :: Box < :: pest :: ParserState < '_ , Rule >> > { state . start_of_input () } } pub use self :: visible :: * ; } :: pest :: state (input , | state | { match rule { Rule :: r#grammar_rules => rules :: r#grammar_rules (state) , Rule :: r#grammar_rule => rules :: r#grammar_rule (state) , Rule :: r#assignment_operator => rules :: r#assignment_operator (state) , Rule :: r#opening_brace => rules :: r#opening_brace (state) , Rule :: r#closing_brace => rules :: r#closing_brace (state) , Rule :: r#opening_paren => rules :: r#opening_paren (state) , Rule :: r#closing_paren => rules :: r#closing_paren (state) , Rule :: r#opening_brack => rules :: r#opening_brack (state) , Rule :: r#closing_brack => rules :: r#closing_brack (state) , Rule :: r#modifier => rules :: r#modifier (state) , Rule :: r#silent_modifier => rules :: r#silent_modifier (state) , Rule :: r#atomic_modifier => rules :: r#atomic_modifier (state) , Rule :: r#compound_atomic_modifier => rules :: r#compound_atomic_modifier (state) , Rule :: r#non_atomic_modifier => rules :: r#non_atomic_modifier (state) , Rule :: r#tag_id => rules :: r#tag_id (state) , Rule :: r#node_tag => rules :: r#node_tag (state) , Rule :: r#expression => rules :: r#expression (state) , Rule :: r#term => rules :: r#term (state) , Rule :: r#node => rules :: r#node (state) , Rule :: r#terminal => rules :: r#terminal (state) , Rule :: r#prefix_operator => rules :: r#prefix_operator (state) , Rule :: r#infix_operator => rules :: r#infix_operator (state) , Rule :: r#postfix_operator => rules :: r#postfix_operator (state) , Rule :: r#positive_predicate_operator => rules :: r#positive_predicate_operator (state) , Rule :: r#negative_predicate_operator => rules :: r#negative_predicate_operator (state) , Rule :: r#sequence_operator => rules :: r#sequence_operator (state) , Rule :: r#choice_operator => rules :: r#choice_operator (state) , Rule :: r#optional_operator => rules :: r#optional_operator (state) , Rule :: r#repeat_operator => rules :: r#repeat_operator (state) , Rule :: r#repeat_once_operator => rules :: r#repeat_once_operator (state) , Rule :: r#repeat_exact => rules :: r#repeat_exact (state) , Rule :: r#repeat_min => rules :: r#repeat_min (state) , Rule :: r#repeat_max => rules :: r#repeat_max (state) , Rule :: r#repeat_min_max => rules :: r#repeat_min_max (state) , Rule :: r#number => rules :: r#number (state) , Rule :: r#integer => rules :: r#integer (state) , Rule :: r#comma => rules :: r#comma (state) , Rule :: r#_push => rules :: r#_push (state) , Rule :: r#peek_slice => rules :: r#peek_slice (state) , Rule :: r#identifier => rules :: r#identifier (state) , Rule :: r#alpha => rules :: r#alpha (state) , Rule :: r#alpha_num => rules :: r#alpha_num (state) , Rule :: r#string => rules :: r#string (state) , Rule :: r#insensitive_string => rules :: r#insensitive_string (state) , Rule :: r#range => rules :: r#range (state) , Rule :: r#character => rules :: r#character (state) , Rule :: r#inner_str => rules :: r#inner_str (state) , Rule :: r#inner_chr => rules :: r#inner_chr (state) , Rule :: r#escape => rules :: r#escape (state) , Rule :: r#code => rules :: r#code (state) , Rule :: r#unicode => rules :: r#unicode (state) , Rule :: r#hex_digit => rules :: r#hex_digit (state) , Rule :: r#quote => rules :: r#quote (state) , Rule :: r#single_quote => rules :: r#single_quote (state) , Rule :: r#range_operator => rules :: r#range_operator (state) , Rule :: r#newline => rules :: r#newline (state) , Rule :: r#WHITESPACE => rules :: r#WHITESPACE (state) , Rule :: r#line_comment => rules :: r#line_comment (state) , Rule :: r#block_comment => rules :: r#block_comment (state) , Rule :: r#COMMENT => rules :: r#COMMENT (state) , Rule :: r#space => rules :: r#space (state) , Rule :: r#grammar_doc => rules :: r#grammar_doc (state) , Rule :: r#line_doc => rules :: r#line_doc (state) , Rule :: r#inner_doc => rules :: r#inner_doc (state) , Rule :: EOI => rules :: EOI (state) } }) } } diff --git a/src/optimizer/concatenator.rs b/src/optimizer/concatenator.rs index 31d3aa5..c67d363 100644 --- a/src/optimizer/concatenator.rs +++ b/src/optimizer/concatenator.rs @@ -16,7 +16,6 @@ pub fn concatenate(rule: Rule) -> Rule { ty, expr: expr.map_bottom_up(|expr| { if ty == RuleType::Atomic { - // TODO: Use box syntax when it gets stabilized. match expr { Expr::Seq(lhs, rhs) => match (*lhs, *rhs) { (Expr::Str(lhs), Expr::Str(rhs)) => Expr::Str(lhs + &rhs), diff --git a/src/optimizer/factorizer.rs b/src/optimizer/factorizer.rs index cff018b..e6fd8ff 100644 --- a/src/optimizer/factorizer.rs +++ b/src/optimizer/factorizer.rs @@ -15,7 +15,6 @@ pub fn factor(rule: Rule) -> Rule { name, ty, expr: expr.map_top_down(|expr| { - // TODO: Use box syntax when it gets stabilized. match expr { Expr::Choice(lhs, rhs) => match (*lhs, *rhs) { (Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => { diff --git a/src/optimizer/lister.rs b/src/optimizer/lister.rs index e198850..03c9902 100644 --- a/src/optimizer/lister.rs +++ b/src/optimizer/lister.rs @@ -15,7 +15,6 @@ pub fn list(rule: Rule) -> Rule { name, ty, expr: expr.map_bottom_up(|expr| { - // TODO: Use box syntax when it gets stabilized. match expr { Expr::Seq(l, r) => match *l { Expr::Rep(l) => { diff --git a/src/optimizer/mod.rs b/src/optimizer/mod.rs index f9cde83..e1cc263 100644 --- a/src/optimizer/mod.rs +++ b/src/optimizer/mod.rs @@ -68,11 +68,15 @@ fn rule_to_optimized_rule(rule: Rule) -> OptimizedRule { Expr::Rep(expr) => OptimizedExpr::Rep(Box::new(to_optimized(*expr))), Expr::Skip(strings) => OptimizedExpr::Skip(strings), Expr::Push(expr) => OptimizedExpr::Push(Box::new(to_optimized(*expr))), - Expr::RepOnce(_) - | Expr::RepExact(..) - | Expr::RepMin(..) - | Expr::RepMax(..) - | Expr::RepMinMax(..) => unreachable!("No valid transformation to OptimizedRule"), + #[cfg(feature = "grammar-extras")] + Expr::NodeTag(expr, tag) => OptimizedExpr::NodeTag(Box::new(to_optimized(*expr)), tag), + #[cfg(feature = "grammar-extras")] + Expr::RepOnce(expr) => OptimizedExpr::RepOnce(Box::new(to_optimized(*expr))), + #[cfg(not(feature = "grammar-extras"))] + Expr::RepOnce(_) => unreachable!("No valid transformation to OptimizedRule"), + Expr::RepExact(..) | Expr::RepMin(..) | Expr::RepMax(..) | Expr::RepMinMax(..) => { + unreachable!("No valid transformation to OptimizedRule") + } } } @@ -133,10 +137,16 @@ pub enum OptimizedExpr { Opt(Box), /// Matches an expression zero or more times, e.g. `e*` Rep(Box), + /// Matches an expression one or more times, e.g. `e+` + #[cfg(feature = "grammar-extras")] + RepOnce(Box), /// Continues to match expressions until one of the strings in the `Vec` is found Skip(Vec), /// Matches an expression and pushes it to the stack, e.g. `push(e)` Push(Box), + /// Matches an expression and assigns a label to it, e.g. #label = exp + #[cfg(feature = "grammar-extras")] + NodeTag(Box, String), /// Restores an expression's checkpoint RestoreOnErr(Box), } @@ -159,7 +169,6 @@ impl OptimizedExpr { let expr = f(expr); match expr { - // TODO: Use box syntax when it gets stabilized. OptimizedExpr::PosPred(expr) => { let mapped = Box::new(map_internal(*expr, f)); OptimizedExpr::PosPred(mapped) @@ -208,7 +217,6 @@ impl OptimizedExpr { { let mapped = match expr { OptimizedExpr::PosPred(expr) => { - // TODO: Use box syntax when it gets stabilized. let mapped = Box::new(map_internal(*expr, f)); OptimizedExpr::PosPred(mapped) } @@ -248,6 +256,77 @@ impl OptimizedExpr { } } +impl core::fmt::Display for OptimizedExpr { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + OptimizedExpr::Str(s) => write!(f, "{:?}", s), + OptimizedExpr::Insens(s) => write!(f, "^{:?}", s), + OptimizedExpr::Range(start, end) => { + let start = start.chars().next().expect("Empty range start."); + let end = end.chars().next().expect("Empty range end."); + write!(f, "({:?}..{:?})", start, end) + } + OptimizedExpr::Ident(id) => write!(f, "{}", id), + OptimizedExpr::PeekSlice(start, end) => match end { + Some(end) => write!(f, "PEEK[{}..{}]", start, end), + None => write!(f, "PEEK[{}..]", start), + }, + OptimizedExpr::PosPred(expr) => write!(f, "&{}", expr.as_ref()), + OptimizedExpr::NegPred(expr) => write!(f, "!{}", expr.as_ref()), + OptimizedExpr::Seq(lhs, rhs) => { + let mut nodes = Vec::new(); + nodes.push(lhs); + let mut current = rhs; + while let OptimizedExpr::Seq(lhs, rhs) = current.as_ref() { + nodes.push(lhs); + current = rhs; + } + nodes.push(current); + let sequence = nodes + .iter() + .map(|node| format!("{}", node)) + .collect::>() + .join(" ~ "); + write!(f, "({})", sequence) + } + OptimizedExpr::Choice(lhs, rhs) => { + let mut nodes = Vec::new(); + nodes.push(lhs); + let mut current = rhs; + while let OptimizedExpr::Choice(lhs, rhs) = current.as_ref() { + nodes.push(lhs); + current = rhs; + } + nodes.push(current); + let sequence = nodes + .iter() + .map(|node| format!("{}", node)) + .collect::>() + .join(" | "); + write!(f, "({})", sequence) + } + OptimizedExpr::Opt(expr) => write!(f, "{}?", expr), + OptimizedExpr::Rep(expr) => write!(f, "{}*", expr), + #[cfg(feature = "grammar-extras")] + OptimizedExpr::RepOnce(expr) => write!(f, "{}+", expr), + OptimizedExpr::Skip(strings) => { + let strings = strings + .iter() + .map(|s| format!("{:?}", s)) + .collect::>() + .join(" | "); + write!(f, "(!({}) ~ ANY)*", strings) + } + OptimizedExpr::Push(expr) => write!(f, "PUSH({})", expr), + #[cfg(feature = "grammar-extras")] + OptimizedExpr::NodeTag(expr, tag) => { + write!(f, "(#{} = {})", tag, expr) + } + OptimizedExpr::RestoreOnErr(expr) => core::fmt::Display::fmt(expr.as_ref(), f), + } + } +} + /// A top-down iterator over an `OptimizedExpr`. pub struct OptimizedExprTopDownIterator { current: Option, @@ -621,4 +700,393 @@ mod tests { assert_eq!(optimize(rules), optimized); } + + mod display { + use super::super::*; + /// In previous implementation of Display for OptimizedExpr + /// in commit 48e0a8bd3d43a17c1c78f099610b745d18ec0c5f (actually committed by me), + /// Str("\n") will be displayed as + /// " + /// " + /// + /// It will not break the compilation in normal use. + /// + /// But when I use it in automatically generating documents, + /// it will quite confusing and we'll be unable to distinguish \n and \r. + /// + /// And `cargo expand` will emit codes that can't be compiled, + /// for it expand `#[doc("...")]` to `/// ...`, + /// and when the document comment breaks the line, + /// it will be expanded into wrong codes. + #[test] + fn control_character() { + assert_eq!(OptimizedExpr::Str("\n".to_owned()).to_string(), "\"\\n\""); + assert_eq!( + OptimizedExpr::Insens("\n".to_owned()).to_string(), + "^\"\\n\"", + ); + assert_eq!( + OptimizedExpr::Range("\n".to_owned(), "\r".to_owned()).to_string(), + "('\\n'..'\\r')", + ); + assert_eq!( + OptimizedExpr::Skip(vec![ + "\n".to_owned(), + "\r".to_owned(), + "\n\r".to_owned(), + "\0".to_owned(), + ]) + .to_string(), + r#"(!("\n" | "\r" | "\n\r" | "\0") ~ ANY)*"#, + ); + + assert_ne!(OptimizedExpr::Str("\n".to_owned()).to_string(), "\"\n\""); + } + + #[test] + fn str() { + assert_eq!(OptimizedExpr::Str("a".to_owned()).to_string(), r#""a""#); + } + + #[test] + fn insens() { + assert_eq!(OptimizedExpr::Insens("a".to_owned()).to_string(), r#"^"a""#); + } + + #[test] + fn range() { + assert_eq!( + OptimizedExpr::Range("a".to_owned(), "z".to_owned()).to_string(), + r#"('a'..'z')"#, + ); + } + + #[test] + fn ident() { + assert_eq!(OptimizedExpr::Ident("a".to_owned()).to_string(), r#"a"#); + } + + #[test] + fn peek_slice() { + assert_eq!(OptimizedExpr::PeekSlice(0, None).to_string(), "PEEK[0..]"); + assert_eq!( + OptimizedExpr::PeekSlice(0, Some(-1)).to_string(), + "PEEK[0..-1]", + ); + assert_eq!( + OptimizedExpr::PeekSlice(2, Some(3)).to_string(), + "PEEK[2..3]", + ); + assert_eq!( + OptimizedExpr::PeekSlice(2, Some(-1)).to_string(), + "PEEK[2..-1]", + ); + assert_eq!(OptimizedExpr::PeekSlice(0, None).to_string(), "PEEK[0..]"); + } + + #[test] + fn pos_pred() { + assert_eq!( + OptimizedExpr::PosPred(Box::new(OptimizedExpr::NegPred(Box::new( + OptimizedExpr::Ident("a".to_owned()), + )))) + .to_string(), + "&!a", + ); + assert_eq!( + OptimizedExpr::PosPred(Box::new(OptimizedExpr::Choice( + Box::new(OptimizedExpr::Rep(Box::new(OptimizedExpr::Ident( + "a".to_owned(), + )))), + Box::new(OptimizedExpr::Str("a".to_owned())), + ))) + .to_string(), + r#"&(a* | "a")"#, + ); + assert_eq!( + OptimizedExpr::PosPred(Box::new(OptimizedExpr::RestoreOnErr(Box::new( + OptimizedExpr::NegPred(Box::new(OptimizedExpr::Ident("a".to_owned()))), + )))) + .to_string(), + "&!a", + ); + } + + #[test] + fn neg_pred() { + assert_eq!( + OptimizedExpr::NegPred(Box::new(OptimizedExpr::Ident("e".to_owned()))).to_string(), + r#"!e"#, + ); + assert_eq!( + OptimizedExpr::NegPred(Box::new(OptimizedExpr::Choice( + Box::new(OptimizedExpr::Push(Box::new(OptimizedExpr::Ident( + "a".to_owned(), + )))), + Box::new(OptimizedExpr::Str("a".to_owned())), + ))) + .to_string(), + r#"!(PUSH(a) | "a")"#, + ); + } + + #[test] + fn seq() { + assert_eq!( + OptimizedExpr::Seq( + Box::new(OptimizedExpr::Ident("e1".to_owned())), + Box::new(OptimizedExpr::Ident("e2".to_owned())), + ) + .to_string(), + r#"(e1 ~ e2)"#, + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Ident("e3".to_owned())), + )), + ) + .to_string(), + "(e1 ~ e2 ~ e3)", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ e2 ~ e3 ~ e4)", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ (e2 | (e3 ~ e4)))", + ); + assert_eq!( + Expr::Seq( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 ~ e2 ~ (e3 | e4))", + ); + assert_eq!( + OptimizedExpr::Seq( + Box::new(OptimizedExpr::Rep(Box::new(OptimizedExpr::Str( + "a".to_owned(), + )))), + Box::new(OptimizedExpr::Seq( + Box::new(OptimizedExpr::Ident("b".to_owned())), + Box::new(OptimizedExpr::Insens("c".to_owned())), + )), + ) + .to_string(), + r#"("a"* ~ b ~ ^"c")"#, + ); + assert_eq!( + OptimizedExpr::Seq( + Box::new(OptimizedExpr::PosPred(Box::new(OptimizedExpr::Range( + "a".to_owned(), + "z".to_owned(), + )))), + Box::new(OptimizedExpr::NegPred(Box::new(OptimizedExpr::Opt( + Box::new(OptimizedExpr::Range("A".to_owned(), "Z".to_owned())), + )))), + ) + .to_string(), + "(&('a'..'z') ~ !('A'..'Z')?)", + ); + } + + #[test] + fn choice() { + assert_eq!( + OptimizedExpr::Choice( + Box::new(OptimizedExpr::Ident("e1".to_owned())), + Box::new(OptimizedExpr::Ident("e2".to_owned())), + ) + .to_string(), + r#"(e1 | e2)"#, + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Ident("e3".to_owned())), + )), + ) + .to_string(), + "(e1 | e2 | e3)", + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 | e2 | e3 | e4)", + ); + assert_eq!( + Expr::Choice( + Box::new(Expr::Ident("e1".to_owned())), + Box::new(Expr::Seq( + Box::new(Expr::Ident("e2".to_owned())), + Box::new(Expr::Choice( + Box::new(Expr::Ident("e3".to_owned())), + Box::new(Expr::Ident("e4".to_owned())), + )), + )), + ) + .to_string(), + "(e1 | (e2 ~ (e3 | e4)))", + ); + assert_eq!( + OptimizedExpr::Choice( + Box::new(OptimizedExpr::Str("a".to_owned())), + Box::new(OptimizedExpr::Choice( + Box::new(OptimizedExpr::Push(Box::new(OptimizedExpr::Ident( + "b".to_owned(), + )))), + Box::new(OptimizedExpr::Insens("c".to_owned())), + )), + ) + .to_string(), + r#"("a" | PUSH(b) | ^"c")"#, + ); + } + + #[test] + fn opt() { + assert_eq!( + OptimizedExpr::Opt(Box::new(OptimizedExpr::Ident("e".to_owned()))).to_string(), + "e?", + ); + } + + #[test] + fn rep() { + assert_eq!( + OptimizedExpr::Rep(Box::new(OptimizedExpr::Ident("x".to_owned()))).to_string(), + "x*", + ); + assert_eq!( + OptimizedExpr::Rep(Box::new(OptimizedExpr::Range( + "0".to_owned(), + "9".to_owned(), + ))) + .to_string(), + "('0'..'9')*", + ); + } + + #[test] + #[cfg(feature = "grammar-extras")] + fn rep_once() { + assert_eq!( + OptimizedExpr::RepOnce(Box::new(OptimizedExpr::Ident("e".to_owned()))).to_string(), + "e+", + ); + assert_eq!( + OptimizedExpr::RepOnce(Box::new(OptimizedExpr::Range( + "0".to_owned(), + "9".to_owned(), + ))) + .to_string(), + "('0'..'9')+", + ); + } + + #[test] + fn skip() { + assert_eq!( + OptimizedExpr::Skip( + ["a", "bc"] + .into_iter() + .map(|s| s.to_owned()) + .collect::>(), + ) + .to_string(), + r#"(!("a" | "bc") ~ ANY)*"#, + ); + } + + #[test] + fn push() { + assert_eq!( + OptimizedExpr::Push(Box::new(OptimizedExpr::Ident("e".to_owned()))).to_string(), + "PUSH(e)", + ); + } + + #[test] + #[cfg(feature = "grammar-extras")] + fn node_tag() { + assert_eq!( + OptimizedExpr::NodeTag( + Box::new(OptimizedExpr::Ident("expr".to_owned())), + "label".to_owned(), + ) + .to_string(), + r#"(#label = expr)"#, + ); + assert_eq!( + OptimizedExpr::NodeTag( + Box::new(OptimizedExpr::Ident("x".to_owned())), + "X".to_owned(), + ) + .to_string(), + r#"(#X = x)"#, + ); + assert_eq!( + OptimizedExpr::NodeTag( + Box::new(OptimizedExpr::Seq( + Box::new(OptimizedExpr::Ident("x".to_owned())), + Box::new(OptimizedExpr::Str("y".to_owned())), + )), + "X".to_owned(), + ) + .to_string(), + r#"(#X = (x ~ "y"))"#, + ); + } + + #[test] + fn restore_on_err() { + assert_eq!( + OptimizedExpr::RestoreOnErr(Box::new(OptimizedExpr::Ident("e".to_owned()))) + .to_string(), + "e", + ); + } + } } diff --git a/src/optimizer/rotater.rs b/src/optimizer/rotater.rs index 7a7d8fb..b019c80 100644 --- a/src/optimizer/rotater.rs +++ b/src/optimizer/rotater.rs @@ -12,7 +12,6 @@ use crate::ast::*; pub fn rotate(rule: Rule) -> Rule { fn rotate_internal(expr: Expr) -> Expr { match expr { - // TODO: Use box syntax when it gets stabilized. Expr::Seq(lhs, rhs) => { let lhs = *lhs; match lhs { diff --git a/src/optimizer/skipper.rs b/src/optimizer/skipper.rs index 40bc5a1..8300309 100644 --- a/src/optimizer/skipper.rs +++ b/src/optimizer/skipper.rs @@ -34,7 +34,6 @@ pub fn skip(rule: Rule) -> Rule { ty, expr: if ty == RuleType::Atomic { expr.map_top_down(|expr| { - // TODO: Use box syntax when it gets stabilized. if let Expr::Rep(expr) = expr.clone() { if let Expr::Seq(lhs, rhs) = *expr { if let (Expr::NegPred(expr), Expr::Ident(ident)) = (*lhs, *rhs) { diff --git a/src/optimizer/unroller.rs b/src/optimizer/unroller.rs index e3c360d..3c97b1f 100644 --- a/src/optimizer/unroller.rs +++ b/src/optimizer/unroller.rs @@ -15,6 +15,7 @@ pub fn unroll(rule: Rule) -> Rule { name, ty, expr: expr.map_bottom_up(|expr| match expr { + #[cfg(not(feature = "grammar-extras"))] Expr::RepOnce(expr) => Expr::Seq(expr.clone(), Box::new(Expr::Rep(expr))), Expr::RepExact(expr, num) => (1..num + 1) .map(|_| *expr.clone()) diff --git a/src/parser.rs b/src/parser.rs index eb957a1..c1768e3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -15,20 +15,18 @@ use std::iter::Peekable; use pest::error::{Error, ErrorVariant}; use pest::iterators::{Pair, Pairs}; use pest::pratt_parser::{Assoc, Op, PrattParser}; -use pest::{Parser, Span}; +use pest::{Parser, Position, Span}; use crate::ast::{Expr, Rule as AstRule, RuleType}; use crate::validator; -/// TODO: fix the generator to at least add explicit lifetimes -#[allow( - missing_docs, - unused_attributes, - elided_lifetimes_in_paths, - unused_qualifications -)] +#[allow(missing_docs, unused_qualifications)] mod grammar { + #[cfg(not(feature = "not-bootstrap-in-src"))] include!("grammar.rs"); + + #[cfg(feature = "not-bootstrap-in-src")] + include!(concat!(env!("OUT_DIR"), "/__pest_grammar.rs")); } pub use self::grammar::*; @@ -76,7 +74,6 @@ impl<'i> ParserNode<'i> { } match node.expr { - // TODO: Use box syntax when it gets stabilized. ParserExpr::PosPred(node) => { filter_internal(*node, f, result); } @@ -164,6 +161,9 @@ pub enum ParserExpr<'i> { RepMinMax(Box>, u32, u32), /// Matches an expression and pushes it to the stack, e.g. `push(e)` Push(Box>), + /// Matches an expression and assigns a label to it, e.g. #label = exp + #[cfg(feature = "grammar-extras")] + NodeTag(Box>, String), } fn convert_rule(rule: ParserRule<'_>) -> AstRule { @@ -199,6 +199,8 @@ fn convert_node(node: ParserNode<'_>) -> Expr { Expr::RepMinMax(Box::new(convert_node(*node)), min, max) } ParserExpr::Push(node) => Expr::Push(Box::new(convert_node(*node))), + #[cfg(feature = "grammar-extras")] + ParserExpr::NodeTag(node, tag) => Expr::NodeTag(Box::new(convert_node(*node)), tag), } } @@ -305,6 +307,29 @@ fn consume_rules_with_spans( .collect() } +fn get_node_tag<'i>( + pairs: &mut Peekable>, +) -> (Pair<'i, Rule>, Option<(String, Position<'i>)>) { + let pair_or_tag = pairs.next().unwrap(); + if let Some(next_pair) = pairs.peek() { + if next_pair.as_rule() == Rule::assignment_operator { + pairs.next().unwrap(); + let pair = pairs.next().unwrap(); + ( + pair, + Some(( + pair_or_tag.as_str()[1..].to_string(), + pair_or_tag.as_span().start_pos(), + )), + ) + } else { + (pair_or_tag, None) + } + } else { + (pair_or_tag, None) + } +} + fn consume_expr<'i>( pairs: Peekable>, pratt: &PrattParser, @@ -313,7 +338,10 @@ fn consume_expr<'i>( mut pairs: Peekable>, pratt: &PrattParser, ) -> Result, Vec>> { - let pair = pairs.next().unwrap(); + #[cfg(feature = "grammar-extras")] + let (pair, tag_start) = get_node_tag(&mut pairs); + #[cfg(not(feature = "grammar-extras"))] + let (pair, _tag_start) = get_node_tag(&mut pairs); let node = match pair.as_rule() { Rule::opening_paren => { @@ -370,7 +398,7 @@ fn consume_expr<'i>( pairs.next().unwrap(); // .. pair_start.as_str().parse().unwrap() } - _ => unreachable!(), + _ => unreachable!("peek start"), }; let pair_end = pairs.next().unwrap(); // integer or } let end: Option = match pair_end.as_rule() { @@ -379,7 +407,7 @@ fn consume_expr<'i>( pairs.next().unwrap(); // } Some(pair_end.as_str().parse().unwrap()) } - _ => unreachable!(), + _ => unreachable!("peek end"), }; ParserNode { expr: ParserExpr::PeekSlice(start, end), @@ -422,193 +450,198 @@ fn consume_expr<'i>( span: start_pos.span(&end_pos), } } - _ => unreachable!(), + x => unreachable!("other rule: {:?}", x), }; - pairs.fold( - Ok(node), - |node: Result, Vec>>, pair| { - let node = node?; - - let node = match pair.as_rule() { - Rule::optional_operator => { - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::Opt(Box::new(node)), - span: start.span(&pair.as_span().end_pos()), - } + pairs.try_fold(node, |node: ParserNode<'i>, pair: Pair<'i, Rule>| { + let node = match pair.as_rule() { + Rule::optional_operator => { + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::Opt(Box::new(node)), + span: start.span(&pair.as_span().end_pos()), + } + } + Rule::repeat_operator => { + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::Rep(Box::new(node)), + span: start.span(&pair.as_span().end_pos()), + } + } + Rule::repeat_once_operator => { + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::RepOnce(Box::new(node)), + span: start.span(&pair.as_span().end_pos()), } - Rule::repeat_operator => { - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::Rep(Box::new(node)), - span: start.span(&pair.as_span().end_pos()), - } + } + Rule::repeat_exact => { + let mut inner = pair.clone().into_inner(); + + inner.next().unwrap(); // opening_brace + + let number = inner.next().unwrap(); + let num = if let Ok(num) = number.as_str().parse::() { + num + } else { + return Err(vec![Error::new_from_span( + ErrorVariant::CustomError { + message: "number cannot overflow u32".to_owned(), + }, + number.as_span(), + )]); + }; + + if num == 0 { + let error: Error = Error::new_from_span( + ErrorVariant::CustomError { + message: "cannot repeat 0 times".to_owned(), + }, + number.as_span(), + ); + + return Err(vec![error]); } - Rule::repeat_once_operator => { - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::RepOnce(Box::new(node)), - span: start.span(&pair.as_span().end_pos()), - } + + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::RepExact(Box::new(node), num), + span: start.span(&pair.as_span().end_pos()), } - Rule::repeat_exact => { - let mut inner = pair.clone().into_inner(); - - inner.next().unwrap(); // opening_brace - - let number = inner.next().unwrap(); - let num = if let Ok(num) = number.as_str().parse::() { - num - } else { - return Err(vec![Error::new_from_span( - ErrorVariant::CustomError { - message: "number cannot overflow u32".to_owned(), - }, - number.as_span(), - )]); - }; - - if num == 0 { - let error: Error = Error::new_from_span( - ErrorVariant::CustomError { - message: "cannot repeat 0 times".to_owned(), - }, - number.as_span(), - ); - - return Err(vec![error]); - } - - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::RepExact(Box::new(node), num), - span: start.span(&pair.as_span().end_pos()), - } + } + Rule::repeat_min => { + let mut inner = pair.clone().into_inner(); + + inner.next().unwrap(); // opening_brace + + let min_number = inner.next().unwrap(); + let min = if let Ok(min) = min_number.as_str().parse::() { + min + } else { + return Err(vec![Error::new_from_span( + ErrorVariant::CustomError { + message: "number cannot overflow u32".to_owned(), + }, + min_number.as_span(), + )]); + }; + + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::RepMin(Box::new(node), min), + span: start.span(&pair.as_span().end_pos()), } - Rule::repeat_min => { - let mut inner = pair.clone().into_inner(); - - inner.next().unwrap(); // opening_brace - - let min_number = inner.next().unwrap(); - let min = if let Ok(min) = min_number.as_str().parse::() { - min - } else { - return Err(vec![Error::new_from_span( - ErrorVariant::CustomError { - message: "number cannot overflow u32".to_owned(), - }, - min_number.as_span(), - )]); - }; - - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::RepMin(Box::new(node), min), - span: start.span(&pair.as_span().end_pos()), - } + } + Rule::repeat_max => { + let mut inner = pair.clone().into_inner(); + + inner.next().unwrap(); // opening_brace + inner.next().unwrap(); // comma + + let max_number = inner.next().unwrap(); + let max = if let Ok(max) = max_number.as_str().parse::() { + max + } else { + return Err(vec![Error::new_from_span( + ErrorVariant::CustomError { + message: "number cannot overflow u32".to_owned(), + }, + max_number.as_span(), + )]); + }; + + if max == 0 { + let error: Error = Error::new_from_span( + ErrorVariant::CustomError { + message: "cannot repeat 0 times".to_owned(), + }, + max_number.as_span(), + ); + + return Err(vec![error]); } - Rule::repeat_max => { - let mut inner = pair.clone().into_inner(); - - inner.next().unwrap(); // opening_brace - inner.next().unwrap(); // comma - - let max_number = inner.next().unwrap(); - let max = if let Ok(max) = max_number.as_str().parse::() { - max - } else { - return Err(vec![Error::new_from_span( - ErrorVariant::CustomError { - message: "number cannot overflow u32".to_owned(), - }, - max_number.as_span(), - )]); - }; - - if max == 0 { - let error: Error = Error::new_from_span( - ErrorVariant::CustomError { - message: "cannot repeat 0 times".to_owned(), - }, - max_number.as_span(), - ); - - return Err(vec![error]); - } - - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::RepMax(Box::new(node), max), - span: start.span(&pair.as_span().end_pos()), - } + + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::RepMax(Box::new(node), max), + span: start.span(&pair.as_span().end_pos()), } - Rule::repeat_min_max => { - let mut inner = pair.clone().into_inner(); - - inner.next().unwrap(); // opening_brace - - let min_number = inner.next().unwrap(); - let min = if let Ok(min) = min_number.as_str().parse::() { - min - } else { - return Err(vec![Error::new_from_span( - ErrorVariant::CustomError { - message: "number cannot overflow u32".to_owned(), - }, - min_number.as_span(), - )]); - }; - - inner.next().unwrap(); // comma - - let max_number = inner.next().unwrap(); - let max = if let Ok(max) = max_number.as_str().parse::() { - max - } else { - return Err(vec![Error::new_from_span( - ErrorVariant::CustomError { - message: "number cannot overflow u32".to_owned(), - }, - max_number.as_span(), - )]); - }; - - if max == 0 { - let error: Error = Error::new_from_span( - ErrorVariant::CustomError { - message: "cannot repeat 0 times".to_owned(), - }, - max_number.as_span(), - ); - - return Err(vec![error]); - } - - let start = node.span.start_pos(); - ParserNode { - expr: ParserExpr::RepMinMax(Box::new(node), min, max), - span: start.span(&pair.as_span().end_pos()), - } + } + Rule::repeat_min_max => { + let mut inner = pair.clone().into_inner(); + + inner.next().unwrap(); // opening_brace + + let min_number = inner.next().unwrap(); + let min = if let Ok(min) = min_number.as_str().parse::() { + min + } else { + return Err(vec![Error::new_from_span( + ErrorVariant::CustomError { + message: "number cannot overflow u32".to_owned(), + }, + min_number.as_span(), + )]); + }; + + inner.next().unwrap(); // comma + + let max_number = inner.next().unwrap(); + let max = if let Ok(max) = max_number.as_str().parse::() { + max + } else { + return Err(vec![Error::new_from_span( + ErrorVariant::CustomError { + message: "number cannot overflow u32".to_owned(), + }, + max_number.as_span(), + )]); + }; + + if max == 0 { + let error: Error = Error::new_from_span( + ErrorVariant::CustomError { + message: "cannot repeat 0 times".to_owned(), + }, + max_number.as_span(), + ); + + return Err(vec![error]); } - Rule::closing_paren => { - let start = node.span.start_pos(); - ParserNode { - expr: node.expr, - span: start.span(&pair.as_span().end_pos()), - } + let start = node.span.start_pos(); + ParserNode { + expr: ParserExpr::RepMinMax(Box::new(node), min, max), + span: start.span(&pair.as_span().end_pos()), } - _ => unreachable!(), - }; + } + Rule::closing_paren => { + let start = node.span.start_pos(); - Ok(node) - }, - )? + ParserNode { + expr: node.expr, + span: start.span(&pair.as_span().end_pos()), + } + } + rule => unreachable!("node: {:?}", rule), + }; + + Ok(node) + })? } }; - + #[cfg(feature = "grammar-extras")] + if let Some((tag, start)) = tag_start { + let span = start.span(&node.span.end_pos()); + Ok(ParserNode { + expr: ParserExpr::NodeTag(Box::new(node), tag), + span, + }) + } else { + Ok(node) + } + #[cfg(not(feature = "grammar-extras"))] Ok(node) } @@ -640,7 +673,7 @@ fn consume_expr<'i>( span: start.span(&end), }) } - _ => unreachable!(), + _ => unreachable!("infix"), }; pratt.map_primary(term).map_infix(infix).parse(pairs) @@ -1143,7 +1176,7 @@ mod tests { parser: PestParser, input: "0", rule: Rule::grammar_rules, - positives: vec![Rule::grammar_rule, Rule::grammar_doc], + positives: vec![Rule::EOI, Rule::grammar_rule, Rule::grammar_doc], negatives: vec![], pos: 0 }; @@ -1357,13 +1390,87 @@ mod tests { }; } + #[test] + fn node_tag() { + parses_to! { + parser: PestParser, + input: "#a = a", + rule: Rule::expression, + tokens: [ + expression(0, 6, [ + term(0, 6, [ + tag_id(0, 2), + assignment_operator(3, 4), + identifier(5, 6) + ]) + ]) + ] + }; + } + + #[test] + fn incomplete_node_tag() { + fails_with! { + parser: PestParser, + input: "a = { # }", + rule: Rule::grammar_rules, + positives: vec![ + Rule::expression + ], + negatives: vec![], + pos: 6 + }; + } + + #[test] + fn incomplete_node_tag_assignment() { + fails_with! { + parser: PestParser, + input: "a = { #a = }", + rule: Rule::grammar_rules, + positives: vec![ + Rule::opening_paren, + Rule::positive_predicate_operator, + Rule::negative_predicate_operator, + Rule::_push, + Rule::peek_slice, + Rule::identifier, + Rule::insensitive_string, + Rule::quote, + Rule::single_quote + ], + negatives: vec![], + pos: 11 + }; + } + + #[test] + fn incomplete_node_tag_pound_key() { + fails_with! { + parser: PestParser, + input: "a = { a = a }", + rule: Rule::grammar_rules, + positives: vec![ + Rule::opening_brace, + Rule::closing_brace, + Rule::sequence_operator, + Rule::choice_operator, + Rule::optional_operator, + Rule::repeat_operator, + Rule::repeat_once_operator + ], + negatives: vec![], + pos: 8 + }; + } + #[test] fn ast() { - let input = r##" + let input = r#" /// This is line comment /// This is rule rule = _{ a{1} ~ "a"{3,} ~ b{, 2} ~ "b"{1, 2} | !(^"c" | PUSH('d'..'e'))?* } - "##; + "#; let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); let ast = consume_rules_with_spans(pairs).unwrap(); diff --git a/src/validator.rs b/src/validator.rs index d9c2ed3..16d3879 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -216,6 +216,12 @@ pub fn validate_undefined<'i>( pub fn validate_ast<'a, 'i: 'a>(rules: &'a Vec>) -> Vec> { let mut errors = vec![]; + // WARNING: validate_{repetition,choice,whitespace_comment} + // use is_non_failing and is_non_progressing breaking assumptions: + // - for every `ParserExpr::RepMinMax(inner,min,max)`, + // `min<=max` was not checked + // - left recursion was not checked + // - Every expression might not be checked errors.extend(validate_repetition(rules)); errors.extend(validate_choices(rules)); errors.extend(validate_whitespace_comment(rules)); @@ -229,15 +235,32 @@ pub fn validate_ast<'a, 'i: 'a>(rules: &'a Vec>) -> Vec( expr: &ParserExpr<'i>, rules: &HashMap>, trace: &mut Vec, ) -> bool { match *expr { - ParserExpr::Str(ref string) => string.is_empty(), + ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(), ParserExpr::Ident(ref ident) => { - if ident == "soi" || ident == "eoi" { + if ident == "SOI" || ident == "EOI" { return true; } @@ -249,12 +272,27 @@ fn is_non_progressing<'i>( return result; } + // else + // the ident is + // - "POP","PEEK" => false + // the slice being checked is not non_progressing since every + // PUSH is being checked (assumption 4) and the expr + // of a PUSH has to be non_progressing. + // - "POPALL", "PEEKALL" => false + // same as "POP", "PEEK" unless the following: + // BUG: if the stack is empty they are non_progressing + // - "DROP" => false doesn't consume the input but consumes the stack, + // - "ANY", "ASCII_*", UNICODE categories, "NEWLINE" => false + // - referring to another rule that is undefined (breaks assumption) } + // else referring to another rule that was already seen. + // this happens only if there is a left-recursion + // that is only if an assumption is broken, + // WARNING: we can choose to return false, but that might + // cause bugs into the left_recursion check false } - ParserExpr::PosPred(_) => true, - ParserExpr::NegPred(_) => true, ParserExpr::Seq(ref lhs, ref rhs) => { is_non_progressing(&lhs.expr, rules, trace) && is_non_progressing(&rhs.expr, rules, trace) @@ -263,17 +301,58 @@ fn is_non_progressing<'i>( is_non_progressing(&lhs.expr, rules, trace) || is_non_progressing(&rhs.expr, rules, trace) } - _ => false, + // WARNING: the predicate indeed won't make progress on input but it + // might progress on the stack + // ex: @{ PUSH(ANY) ~ (&(DROP))* ~ ANY }, input="AA" + // Notice that this is ex not working as of now, the debugger seems + // to run into an infinite loop on it + ParserExpr::PosPred(_) | ParserExpr::NegPred(_) => true, + ParserExpr::Rep(_) | ParserExpr::Opt(_) | ParserExpr::RepMax(_, _) => true, + // it either always fail (failing is progressing) + // or always match at least a character + ParserExpr::Range(_, _) => false, + ParserExpr::PeekSlice(_, _) => { + // the slice being checked is not non_progressing since every + // PUSH is being checked (assumption 4) and the expr + // of a PUSH has to be non_progressing. + // BUG: if the slice is of size 0, or the stack is not large + // enough it might be non-progressing + false + } + + ParserExpr::RepExact(ref inner, min) + | ParserExpr::RepMin(ref inner, min) + | ParserExpr::RepMinMax(ref inner, min, _) => { + min == 0 || is_non_progressing(&inner.expr, rules, trace) + } + ParserExpr::Push(ref inner) => is_non_progressing(&inner.expr, rules, trace), + ParserExpr::RepOnce(ref inner) => is_non_progressing(&inner.expr, rules, trace), + #[cfg(feature = "grammar-extras")] + ParserExpr::NodeTag(ref inner, _) => is_non_progressing(&inner.expr, rules, trace), } } +/// Checks if `expr` is non-failing, that is it matches any input. +/// +/// # Example +/// +/// ```pest +/// non_failing_1 = { "" } +/// ``` +/// +/// # Assumptions +/// - In `ParserExpr::RepMinMax(inner,min,max)`, `min<=max` +/// - In `ParserExpr::PeekSlice(max,Some(min))`, `max>=min` +/// - All rules identiers have a matching definition +/// - There is no left-recursion +/// - All rules are being checked fn is_non_failing<'i>( expr: &ParserExpr<'i>, rules: &HashMap>, trace: &mut Vec, ) -> bool { match *expr { - ParserExpr::Str(ref string) => string.is_empty(), + ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(), ParserExpr::Ident(ref ident) => { if !trace.contains(ident) { if let Some(node) = rules.get(ident) { @@ -281,21 +360,68 @@ fn is_non_failing<'i>( let result = is_non_failing(&node.expr, rules, trace); trace.pop().unwrap(); - return result; + result + } else { + // else + // the ident is + // - "POP","PEEK" => false + // the slice being checked is not non_failing since every + // PUSH is being checked (assumption 4) and the expr + // of a PUSH has to be non_failing. + // - "POP_ALL", "PEEK_ALL" => false + // same as "POP", "PEEK" unless the following: + // BUG: if the stack is empty they are non_failing + // - "DROP" => false + // - "ANY", "ASCII_*", UNICODE categories, "NEWLINE", + // "SOI", "EOI" => false + // - referring to another rule that is undefined (breaks assumption) + // WARNING: might want to introduce a panic or report the error + false } + } else { + // referring to another rule R that was already seen + // WARNING: this might mean there is a circular non-failing path + // it's not obvious wether this can happen without left-recursion + // and thus breaking the assumption. Until there is answer to + // this, to avoid changing behaviour we return: + false } - - false } ParserExpr::Opt(_) => true, ParserExpr::Rep(_) => true, + ParserExpr::RepMax(_, _) => true, ParserExpr::Seq(ref lhs, ref rhs) => { is_non_failing(&lhs.expr, rules, trace) && is_non_failing(&rhs.expr, rules, trace) } ParserExpr::Choice(ref lhs, ref rhs) => { is_non_failing(&lhs.expr, rules, trace) || is_non_failing(&rhs.expr, rules, trace) } - _ => false, + // it either always fail + // or always match at least a character + ParserExpr::Range(_, _) => false, + ParserExpr::PeekSlice(_, _) => { + // the slice being checked is not non_failing since every + // PUSH is being checked (assumption 4) and the expr + // of a PUSH has to be non_failing. + // BUG: if the slice is of size 0, or the stack is not large + // enough it might be non-failing + false + } + ParserExpr::RepExact(ref inner, min) + | ParserExpr::RepMin(ref inner, min) + | ParserExpr::RepMinMax(ref inner, min, _) => { + min == 0 || is_non_failing(&inner.expr, rules, trace) + } + // BUG: the predicate may always fail, resulting in this expr non_failing + // ex of always failing predicates : + // @{EOI ~ ANY | ANY ~ SOI | &("A") ~ &("B") | 'z'..'a'} + ParserExpr::NegPred(_) => false, + ParserExpr::RepOnce(ref inner) => is_non_failing(&inner.expr, rules, trace), + ParserExpr::Push(ref inner) | ParserExpr::PosPred(ref inner) => { + is_non_failing(&inner.expr, rules, trace) + } + #[cfg(feature = "grammar-extras")] + ParserExpr::NodeTag(ref inner, _) => is_non_failing(&inner.expr, rules, trace), } } @@ -583,17 +709,880 @@ mod tests { --> 1:13 | -1 | COMMENT = { soi } +1 | COMMENT = { SOI } | ^-^ | = COMMENT is non-progressing and will repeat infinitely")] fn non_progressing_comment() { - let input = "COMMENT = { soi }"; + let input = "COMMENT = { SOI }"; unwrap_or_report(consume_rules( PestParser::parse(Rule::grammar_rules, input).unwrap(), )); } + #[test] + fn non_progressing_empty_string() { + assert!(is_non_failing( + &ParserExpr::Insens("".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::Str("".into()), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn progressing_non_empty_string() { + assert!(!is_non_progressing( + &ParserExpr::Insens("non empty".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &ParserExpr::Str("non empty".into()), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_progressing_soi_eoi() { + assert!(is_non_progressing( + &ParserExpr::Ident("SOI".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::Ident("EOI".into()), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_progressing_predicates() { + let progressing = ParserExpr::Str("A".into()); + + assert!(is_non_progressing( + &ParserExpr::PosPred(Box::new(ParserNode { + expr: progressing.clone(), + span: Span::new(" ", 0, 1).unwrap(), + })), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::NegPred(Box::new(ParserNode { + expr: progressing, + span: Span::new(" ", 0, 1).unwrap(), + })), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_progressing_0_length_repetitions() { + let input_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("A".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(!is_non_progressing( + &input_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + assert!(is_non_progressing( + &ParserExpr::Rep(input_progressing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::Opt(input_progressing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::RepExact(input_progressing_node.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::RepMin(input_progressing_node.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::RepMax(input_progressing_node.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::RepMax(input_progressing_node.clone(), 17), + &HashMap::new(), + &mut Vec::new() + )); + + assert!(is_non_progressing( + &ParserExpr::RepMinMax(input_progressing_node.clone(), 0, 12), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_progressing_nonzero_repetitions_with_non_progressing_expr() { + let a = ""; + let non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str(a.into()), + span: Span::new(a, 0, 0).unwrap(), + }); + let exact = ParserExpr::RepExact(non_progressing_node.clone(), 7); + let min = ParserExpr::RepMin(non_progressing_node.clone(), 23); + let minmax = ParserExpr::RepMinMax(non_progressing_node.clone(), 12, 13); + let reponce = ParserExpr::RepOnce(non_progressing_node); + + assert!(is_non_progressing(&exact, &HashMap::new(), &mut Vec::new())); + assert!(is_non_progressing(&min, &HashMap::new(), &mut Vec::new())); + assert!(is_non_progressing( + &minmax, + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &reponce, + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn progressing_repetitions() { + let a = "A"; + let input_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str(a.into()), + span: Span::new(a, 0, 1).unwrap(), + }); + let exact = ParserExpr::RepExact(input_progressing_node.clone(), 1); + let min = ParserExpr::RepMin(input_progressing_node.clone(), 2); + let minmax = ParserExpr::RepMinMax(input_progressing_node.clone(), 4, 5); + let reponce = ParserExpr::RepOnce(input_progressing_node); + + assert!(!is_non_progressing( + &exact, + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing(&min, &HashMap::new(), &mut Vec::new())); + assert!(!is_non_progressing( + &minmax, + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &reponce, + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_progressing_push() { + let a = ""; + let non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str(a.into()), + span: Span::new(a, 0, 0).unwrap(), + }); + let push = ParserExpr::Push(non_progressing_node.clone()); + + assert!(is_non_progressing(&push, &HashMap::new(), &mut Vec::new())); + } + + #[test] + fn progressing_push() { + let a = "i'm make progress"; + let progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str(a.into()), + span: Span::new(a, 0, 1).unwrap(), + }); + let push = ParserExpr::Push(progressing_node.clone()); + + assert!(!is_non_progressing(&push, &HashMap::new(), &mut Vec::new())); + } + + #[test] + fn node_tag_forwards_is_non_progressing() { + let progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm make progress".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_progressing( + &progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + let non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(is_non_progressing( + &non_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + #[cfg(feature = "grammar-extras")] + { + let progressing = ParserExpr::NodeTag(progressing_node.clone(), "TAG".into()); + let non_progressing = ParserExpr::NodeTag(non_progressing_node.clone(), "TAG".into()); + + assert!(!is_non_progressing( + &progressing, + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &non_progressing, + &HashMap::new(), + &mut Vec::new() + )); + } + } + + #[test] + fn progressing_range() { + let progressing = ParserExpr::Range("A".into(), "Z".into()); + let failing_is_progressing = ParserExpr::Range("Z".into(), "A".into()); + + assert!(!is_non_progressing( + &progressing, + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &failing_is_progressing, + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn progressing_choice() { + let left_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm make progress".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_progressing( + &left_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_progressing( + &ParserExpr::Choice(left_progressing_node, right_progressing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_progressing_choices() { + let left_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm make progress".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(!is_non_progressing( + &left_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let left_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_progressing( + &left_non_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_progressing( + &right_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_progressing( + &right_non_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + assert!(is_non_progressing( + &ParserExpr::Choice(left_non_progressing_node.clone(), right_progressing_node), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::Choice(left_progressing_node, right_non_progressing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_progressing( + &ParserExpr::Choice(left_non_progressing_node, right_non_progressing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_progressing_seq() { + let left_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + let right_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_progressing( + &ParserExpr::Seq(left_non_progressing_node, right_non_progressing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn progressing_seqs() { + let left_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm make progress".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(!is_non_progressing( + &left_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let left_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_progressing( + &left_non_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_progressing( + &right_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_non_progressing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_progressing( + &right_non_progressing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + assert!(!is_non_progressing( + &ParserExpr::Seq(left_non_progressing_node, right_progressing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &ParserExpr::Seq(left_progressing_node.clone(), right_non_progressing_node), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &ParserExpr::Seq(left_progressing_node, right_progressing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn progressing_stack_operations() { + assert!(!is_non_progressing( + &ParserExpr::Ident("DROP".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &ParserExpr::Ident("PEEK".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_progressing( + &ParserExpr::Ident("POP".into()), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_failing_string() { + let insens = ParserExpr::Insens("".into()); + let string = ParserExpr::Str("".into()); + + assert!(is_non_failing(&insens, &HashMap::new(), &mut Vec::new())); + + assert!(is_non_failing(&string, &HashMap::new(), &mut Vec::new())) + } + + #[test] + fn failing_string() { + assert!(!is_non_failing( + &ParserExpr::Insens("i may fail!".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::Str("failure is not fatal".into()), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn failing_stack_operations() { + assert!(!is_non_failing( + &ParserExpr::Ident("DROP".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::Ident("POP".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::Ident("PEEK".into()), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_failing_zero_length_repetitions() { + let failing = Box::new(ParserNode { + expr: ParserExpr::Range("A".into(), "B".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_failing( + &failing.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::Opt(failing.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::Rep(failing.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepExact(failing.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMin(failing.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMax(failing.clone(), 0), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMax(failing.clone(), 22), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMinMax(failing.clone(), 0, 73), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn non_failing_non_zero_repetitions_with_non_failing_expr() { + let non_failing = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Range("A".into(), "B".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(is_non_failing( + &non_failing.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepOnce(non_failing.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepExact(non_failing.clone(), 1), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMin(non_failing.clone(), 6), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::RepMinMax(non_failing.clone(), 32, 73), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + #[cfg(feature = "grammar-extras")] + fn failing_non_zero_repetitions() { + let failing = Box::new(ParserNode { + expr: ParserExpr::NodeTag( + Box::new(ParserNode { + expr: ParserExpr::Range("A".into(), "B".into()), + span: Span::new(" ", 0, 1).unwrap(), + }), + "Tag".into(), + ), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_failing( + &failing.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::RepOnce(failing.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::RepExact(failing.clone(), 3), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::RepMin(failing.clone(), 14), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::RepMinMax(failing.clone(), 47, 73), + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn failing_choice() { + let left_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm a failure".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_failing( + &left_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_failing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_failing( + &ParserExpr::Choice(left_failing_node, right_failing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_failing_choices() { + let left_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm a failure".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(!is_non_failing( + &left_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let left_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_failing( + &left_non_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_failing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_failing( + &right_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_failing( + &right_non_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + assert!(is_non_failing( + &ParserExpr::Choice(left_non_failing_node.clone(), right_failing_node), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::Choice(left_failing_node, right_non_failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::Choice(left_non_failing_node, right_non_failing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn non_failing_seq() { + let left_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + let right_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_failing( + &ParserExpr::Seq(left_non_failing_node, right_non_failing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn failing_seqs() { + let left_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm a failure".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(!is_non_failing( + &left_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let left_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_failing( + &left_non_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_failing_node = Box::new(ParserNode { + expr: ParserExpr::Ident("DROP".into()), + span: Span::new("DROP", 0, 3).unwrap(), + }); + + assert!(!is_non_failing( + &right_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + let right_non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Opt(Box::new(ParserNode { + expr: ParserExpr::Str(" ".into()), + span: Span::new(" ", 0, 1).unwrap(), + })), + span: Span::new(" ", 0, 1).unwrap(), + }); + + assert!(is_non_failing( + &right_non_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + assert!(!is_non_failing( + &ParserExpr::Seq(left_non_failing_node, right_failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::Seq(left_failing_node.clone(), right_non_failing_node), + &HashMap::new(), + &mut Vec::new() + )); + assert!(!is_non_failing( + &ParserExpr::Seq(left_failing_node, right_failing_node), + &HashMap::new(), + &mut Vec::new() + )) + } + + #[test] + fn failing_range() { + let failing = ParserExpr::Range("A".into(), "Z".into()); + let always_failing = ParserExpr::Range("Z".into(), "A".into()); + + assert!(!is_non_failing(&failing, &HashMap::new(), &mut Vec::new())); + assert!(!is_non_failing( + &always_failing, + &HashMap::new(), + &mut Vec::new() + )); + } + + #[test] + fn _push_node_tag_pos_pred_forwarding_is_non_failing() { + let failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("i'm a failure".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(!is_non_failing( + &failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + let non_failing_node = Box::new(ParserNode { + expr: ParserExpr::Str("".into()), + span: Span::new(" ", 0, 1).unwrap(), + }); + assert!(is_non_failing( + &non_failing_node.clone().expr, + &HashMap::new(), + &mut Vec::new() + )); + + #[cfg(feature = "grammar-extras")] + { + assert!(!is_non_failing( + &ParserExpr::NodeTag(failing_node.clone(), "TAG".into()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::NodeTag(non_failing_node.clone(), "TAG".into()), + &HashMap::new(), + &mut Vec::new() + )); + } + + assert!(!is_non_failing( + &ParserExpr::Push(failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::Push(non_failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + + assert!(!is_non_failing( + &ParserExpr::PosPred(failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + assert!(is_non_failing( + &ParserExpr::PosPred(non_failing_node.clone()), + &HashMap::new(), + &mut Vec::new() + )); + } + #[test] #[should_panic(expected = "grammar error @@ -647,12 +1636,12 @@ mod tests { --> 1:7 | -1 | a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (soi | eoi))* } +1 | a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* } | ^-------------------------------^ | = expression inside repetition is non-progressing and will repeat infinitely")] fn non_progressing_repetition() { - let input = "a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (soi | eoi))* }"; + let input = "a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* }"; unwrap_or_report(consume_rules( PestParser::parse(Rule::grammar_rules, input).unwrap(), )); -- cgit v1.2.3