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
diff --git a/Android.bp b/Android.bp
index 239744f..4e69e02 100644
--- a/Android.bp
+++ b/Android.bp
@@ -41,9 +41,10 @@
     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 <dragostiselice@gmail.com>"]
 exclude = ["src/grammar.pest"]
 include = [
@@ -34,15 +34,24 @@
     "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 <dragostiselice@gmail.com>"]
 homepage = "https://pest.rs/"
@@ -9,15 +9,21 @@
 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)
-<a href="https://blog.rust-lang.org/2021/11/01/Rust-1.56.1.html"><img alt="Rustc Version 1.56.1+" src="https://img.shields.io/badge/rustc-1.56.1%2B-lightgrey.svg"/></a>
+<a href="https://blog.rust-lang.org/2021/11/01/Rust-1.61.0.html"><img alt="Rustc Version 1.61.0+" src="https://img.shields.io/badge/rustc-1.61.0%2B-lightgrey.svg"/></a>
 
 [![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 @@
 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 @@
 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 @@
 
 ## 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 @@
 * [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 @@
     Skip(Vec<String>),
     /// Matches an expression and pushes it to the stack, e.g. `push(e)`
     Push(Box<Expr>),
+    /// Matches an expression and assigns a label to it, e.g. #label = exp
+    #[cfg(feature = "grammar-extras")]
+    NodeTag(Box<Expr>, String),
 }
 
 impl Expr {
@@ -114,7 +117,6 @@
             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 @@
                     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 @@
         {
             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 @@
                     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 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::<Vec<_>>()
+                    .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::<Vec<_>>()
+                    .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::<Vec<_>>()
+                    .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<Expr>,
@@ -285,6 +369,10 @@
             | 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 @@
             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::<Vec<_>>(),
+                )
+                .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
 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 @@
 
 /// 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 @@
         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 @@
         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 @@
         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 @@
             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 @@
     Opt(Box<OptimizedExpr>),
     /// Matches an expression zero or more times, e.g. `e*`
     Rep(Box<OptimizedExpr>),
+    /// Matches an expression one or more times, e.g. `e+`
+    #[cfg(feature = "grammar-extras")]
+    RepOnce(Box<OptimizedExpr>),
     /// Continues to match expressions until one of the strings in the `Vec` is found
     Skip(Vec<String>),
     /// Matches an expression and pushes it to the stack, e.g. `push(e)`
     Push(Box<OptimizedExpr>),
+    /// Matches an expression and assigns a label to it, e.g. #label = exp
+    #[cfg(feature = "grammar-extras")]
+    NodeTag(Box<OptimizedExpr>, String),
     /// Restores an expression's checkpoint
     RestoreOnErr(Box<OptimizedExpr>),
 }
@@ -159,7 +169,6 @@
             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 @@
         {
             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 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::<Vec<_>>()
+                    .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::<Vec<_>>()
+                    .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::<Vec<_>>()
+                    .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<OptimizedExpr>,
@@ -621,4 +700,393 @@
 
         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::<Vec<_>>(),
+                )
+                .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 @@
 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 @@
         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 @@
         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 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 @@
             }
 
             match node.expr {
-                // TODO: Use box syntax when it gets stabilized.
                 ParserExpr::PosPred(node) => {
                     filter_internal(*node, f, result);
                 }
@@ -164,6 +161,9 @@
     RepMinMax(Box<ParserNode<'i>>, u32, u32),
     /// Matches an expression and pushes it to the stack, e.g. `push(e)`
     Push(Box<ParserNode<'i>>),
+    /// Matches an expression and assigns a label to it, e.g. #label = exp
+    #[cfg(feature = "grammar-extras")]
+    NodeTag(Box<ParserNode<'i>>, String),
 }
 
 fn convert_rule(rule: ParserRule<'_>) -> AstRule {
@@ -199,6 +199,8 @@
             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 @@
         .collect()
 }
 
+fn get_node_tag<'i>(
+    pairs: &mut Peekable<Pairs<'i, Rule>>,
+) -> (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<Pairs<'i, Rule>>,
     pratt: &PrattParser<Rule>,
@@ -313,7 +338,10 @@
         mut pairs: Peekable<Pairs<'i, Rule>>,
         pratt: &PrattParser<Rule>,
     ) -> Result<ParserNode<'i>, Vec<Error<Rule>>> {
-        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 @@
                                 pairs.next().unwrap(); // ..
                                 pair_start.as_str().parse().unwrap()
                             }
-                            _ => unreachable!(),
+                            _ => unreachable!("peek start"),
                         };
                         let pair_end = pairs.next().unwrap(); // integer or }
                         let end: Option<i32> = match pair_end.as_rule() {
@@ -379,7 +407,7 @@
                                 pairs.next().unwrap(); // }
                                 Some(pair_end.as_str().parse().unwrap())
                             }
-                            _ => unreachable!(),
+                            _ => unreachable!("peek end"),
                         };
                         ParserNode {
                             expr: ParserExpr::PeekSlice(start, end),
@@ -422,193 +450,198 @@
                             span: start_pos.span(&end_pos),
                         }
                     }
-                    _ => unreachable!(),
+                    x => unreachable!("other rule: {:?}", x),
                 };
 
-                pairs.fold(
-                    Ok(node),
-                    |node: Result<ParserNode<'i>, Vec<Error<Rule>>>, 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_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_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_exact => {
-                                let mut inner = pair.clone().into_inner();
+                        }
+                        Rule::repeat_exact => {
+                            let mut inner = pair.clone().into_inner();
 
-                                inner.next().unwrap(); // opening_brace
+                            inner.next().unwrap(); // opening_brace
 
-                                let number = inner.next().unwrap();
-                                let num = if let Ok(num) = number.as_str().parse::<u32>() {
-                                    num
-                                } else {
-                                    return Err(vec![Error::new_from_span(
-                                        ErrorVariant::CustomError {
-                                            message: "number cannot overflow u32".to_owned(),
-                                        },
-                                        number.as_span(),
-                                    )]);
-                                };
+                            let number = inner.next().unwrap();
+                            let num = if let Ok(num) = number.as_str().parse::<u32>() {
+                                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<Rule> = Error::new_from_span(
-                                        ErrorVariant::CustomError {
-                                            message: "cannot repeat 0 times".to_owned(),
-                                        },
-                                        number.as_span(),
-                                    );
+                            if num == 0 {
+                                let error: Error<Rule> = 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()),
-                                }
+                                return Err(vec![error]);
                             }
-                            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::<u32>() {
-                                    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()),
-                                }
+                            let start = node.span.start_pos();
+                            ParserNode {
+                                expr: ParserExpr::RepExact(Box::new(node), num),
+                                span: start.span(&pair.as_span().end_pos()),
                             }
-                            Rule::repeat_max => {
-                                let mut inner = pair.clone().into_inner();
+                        }
+                        Rule::repeat_min => {
+                            let mut inner = pair.clone().into_inner();
 
-                                inner.next().unwrap(); // opening_brace
-                                inner.next().unwrap(); // comma
+                            inner.next().unwrap(); // opening_brace
 
-                                let max_number = inner.next().unwrap();
-                                let max = if let Ok(max) = max_number.as_str().parse::<u32>() {
-                                    max
-                                } else {
-                                    return Err(vec![Error::new_from_span(
-                                        ErrorVariant::CustomError {
-                                            message: "number cannot overflow u32".to_owned(),
-                                        },
-                                        max_number.as_span(),
-                                    )]);
-                                };
+                            let min_number = inner.next().unwrap();
+                            let min = if let Ok(min) = min_number.as_str().parse::<u32>() {
+                                min
+                            } else {
+                                return Err(vec![Error::new_from_span(
+                                    ErrorVariant::CustomError {
+                                        message: "number cannot overflow u32".to_owned(),
+                                    },
+                                    min_number.as_span(),
+                                )]);
+                            };
 
-                                if max == 0 {
-                                    let error: Error<Rule> = 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::RepMin(Box::new(node), min),
+                                span: start.span(&pair.as_span().end_pos()),
                             }
-                            Rule::repeat_min_max => {
-                                let mut inner = pair.clone().into_inner();
+                        }
+                        Rule::repeat_max => {
+                            let mut inner = pair.clone().into_inner();
 
-                                inner.next().unwrap(); // opening_brace
+                            inner.next().unwrap(); // opening_brace
+                            inner.next().unwrap(); // comma
 
-                                let min_number = inner.next().unwrap();
-                                let min = if let Ok(min) = min_number.as_str().parse::<u32>() {
-                                    min
-                                } else {
-                                    return Err(vec![Error::new_from_span(
-                                        ErrorVariant::CustomError {
-                                            message: "number cannot overflow u32".to_owned(),
-                                        },
-                                        min_number.as_span(),
-                                    )]);
-                                };
+                            let max_number = inner.next().unwrap();
+                            let max = if let Ok(max) = max_number.as_str().parse::<u32>() {
+                                max
+                            } else {
+                                return Err(vec![Error::new_from_span(
+                                    ErrorVariant::CustomError {
+                                        message: "number cannot overflow u32".to_owned(),
+                                    },
+                                    max_number.as_span(),
+                                )]);
+                            };
 
-                                inner.next().unwrap(); // comma
+                            if max == 0 {
+                                let error: Error<Rule> = Error::new_from_span(
+                                    ErrorVariant::CustomError {
+                                        message: "cannot repeat 0 times".to_owned(),
+                                    },
+                                    max_number.as_span(),
+                                );
 
-                                let max_number = inner.next().unwrap();
-                                let max = if let Ok(max) = max_number.as_str().parse::<u32>() {
-                                    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<Rule> = 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()),
-                                }
+                                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::RepMax(Box::new(node), max),
+                                span: start.span(&pair.as_span().end_pos()),
                             }
-                            _ => unreachable!(),
-                        };
+                        }
+                        Rule::repeat_min_max => {
+                            let mut inner = pair.clone().into_inner();
 
-                        Ok(node)
-                    },
-                )?
+                            inner.next().unwrap(); // opening_brace
+
+                            let min_number = inner.next().unwrap();
+                            let min = if let Ok(min) = min_number.as_str().parse::<u32>() {
+                                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::<u32>() {
+                                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<Rule> = 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::closing_paren => {
+                            let start = node.span.start_pos();
+
+                            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 @@
                 span: start.span(&end),
             })
         }
-        _ => unreachable!(),
+        _ => unreachable!("infix"),
     };
 
     pratt.map_primary(term).map_infix(infix).parse(pairs)
@@ -1143,7 +1176,7 @@
             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
         };
@@ -1358,12 +1391,86 @@
     }
 
     #[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_ast<'a, 'i: 'a>(rules: &'a Vec<ParserRule<'i>>) -> Vec<Error<Rule>> {
     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 @@
     errors
 }
 
+/// Checks if `expr` is non-progressing, that is the expression does not
+/// consume any input or any stack. This includes expressions matching the empty input,
+/// `SOI` and ̀ `EOI`, predicates and repetitions.
+///
+/// # Example
+///
+/// ```pest
+/// not_progressing_1 = { "" }
+/// not_progressing_2 = { "a"? }
+/// not_progressing_3 = { !"a" }
+/// ```
+///
+/// # Assumptions
+/// - In `ParserExpr::RepMinMax(inner,min,max)`, `min<=max`
+/// - All rules identiers have a matching definition
+/// - There is no left-recursion (if only this one is broken returns false)
+/// - Every expression is being checked
 fn is_non_progressing<'i>(
     expr: &ParserExpr<'i>,
     rules: &HashMap<String, &ParserNode<'i>>,
     trace: &mut Vec<String>,
 ) -> 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 @@
 
                     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 @@
             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<String, &ParserNode<'i>>,
     trace: &mut Vec<String>,
 ) -> 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 @@
                     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,18 +709,881 @@
 
  --> 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
 
  --> 1:7
@@ -647,12 +1636,12 @@
 
  --> 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(),
         ));