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