Skip to content

Commit

Permalink
one-or-more rule fix based on #397 (#878)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomtau committed Jun 30, 2023
1 parent 047c27e commit d9bfdde
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 24 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ You can find more projects and ecosystem tools in the [awesome-pest](https://git
* [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)

Expand Down
8 changes: 4 additions & 4 deletions debugger/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_debugger"
description = "pest grammar debugger"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>", "Tomas Tauber <me@tomtau.be>"]
homepage = "https://pest.rs/"
Expand All @@ -14,9 +14,9 @@ readme = "_README.md"
rust-version = "1.60"

[dependencies]
pest = { path = "../pest", version = "2.7.0" }
pest_meta = { path = "../meta", version = "2.7.0" }
pest_vm = { path = "../vm", version = "2.7.0" }
pest = { path = "../pest", version = "2.7.1" }
pest_meta = { path = "../meta", version = "2.7.1" }
pest_vm = { path = "../vm", version = "2.7.1" }
reqwest = { version = "= 0.11.13", default-features = false, features = ["blocking", "json", "default-tls"] }
rustyline = "10"
serde_json = "1"
Expand Down
6 changes: 3 additions & 3 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_derive"
description = "pest's derive macro"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand All @@ -25,5 +25,5 @@ grammar-extras = ["pest_generator/grammar-extras"]

[dependencies]
# for tests, included transitively anyway
pest = { path = "../pest", version = "2.7.0", default-features = false }
pest_generator = { path = "../generator", version = "2.7.0", default-features = false }
pest = { path = "../pest", version = "2.7.1", default-features = false }
pest_generator = { path = "../generator", version = "2.7.1", default-features = false }
5 changes: 5 additions & 0 deletions derive/tests/oneormore.pest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
WHITESPACE = _{ " " | "\r" | "\n" | "\t" }


identifier = { (ASCII_ALPHA | "_")+ }
assign = { identifier ~ "<-" ~ identifier }
29 changes: 29 additions & 0 deletions derive/tests/oneormore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{format, vec::Vec};

#[cfg(feature = "grammar-extras")]
use pest::Parser;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "../tests/oneormore.pest"]
pub struct OneOrMoreParser;

#[test]
#[cfg(feature = "grammar-extras")]
pub fn test_one_or_more() {
let result = OneOrMoreParser::parse(Rule::assign, "k <- b\n");
assert!(result.is_ok());
let mut pairs = result.unwrap();
let pair = pairs.next().unwrap();
assert_eq!(pair.as_rule(), Rule::assign);
let mut inner = pair.into_inner();
let lhs = inner.next().unwrap();
assert_eq!(lhs.as_rule(), Rule::identifier);
assert_eq!(lhs.as_str(), "k");
let rhs = inner.next().unwrap();
assert_eq!(rhs.as_rule(), Rule::identifier);
assert_eq!(rhs.as_str(), "b");
}
6 changes: 3 additions & 3 deletions generator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_generator"
description = "pest code generator"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand All @@ -20,8 +20,8 @@ not-bootstrap-in-src = ["pest_meta/not-bootstrap-in-src"]
grammar-extras = ["pest_meta/grammar-extras"]

[dependencies]
pest = { path = "../pest", version = "2.7.0", default-features = false }
pest_meta = { path = "../meta", version = "2.7.0" }
pest = { path = "../pest", version = "2.7.1", default-features = false }
pest_meta = { path = "../meta", version = "2.7.1" }
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"
36 changes: 36 additions & 0 deletions generator/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,26 @@ fn generate_expr(expr: OptimizedExpr) -> TokenStream {
})
}
}
#[cfg(feature = "grammar-extras")]
OptimizedExpr::RepOnce(expr) => {
let expr = generate_expr(*expr);

quote! {
state.sequence(|state| {
#expr.and_then(|state| {
state.repeat(|state| {
state.sequence(|state| {
super::hidden::skip(
state
).and_then(|state| {
#expr
})
})
})
})
})
}
}
OptimizedExpr::Skip(strings) => {
quote! {
let strings = [#(#strings),*];
Expand Down Expand Up @@ -635,6 +655,22 @@ fn generate_expr_atomic(expr: OptimizedExpr) -> TokenStream {
})
}
}
#[cfg(feature = "grammar-extras")]
OptimizedExpr::RepOnce(expr) => {
let expr = generate_expr_atomic(*expr);

quote! {
state.sequence(|state| {
#expr.and_then(|state| {
state.repeat(|state| {
state.sequence(|state| {
#expr
})
})
})
})
}
}
OptimizedExpr::Skip(strings) => {
quote! {
let strings = [#(#strings),*];
Expand Down
6 changes: 3 additions & 3 deletions grammars/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_grammars"
description = "pest popular grammar implementations"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand All @@ -14,8 +14,8 @@ readme = "_README.md"
rust-version = "1.60"

[dependencies]
pest = { path = "../pest", version = "2.7.0" }
pest_derive = { path = "../derive", version = "2.7.0" }
pest = { path = "../pest", version = "2.7.1" }
pest_derive = { path = "../derive", version = "2.7.1" }

[dev-dependencies]
criterion = "0.5"
Expand Down
4 changes: 2 additions & 2 deletions meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_meta"
description = "pest meta language parser and validator"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand All @@ -16,7 +16,7 @@ include = ["Cargo.toml", "src/**/*", "src/grammar.rs", "_README.md", "LICENSE-*"
rust-version = "1.60"

[dependencies]
pest = { path = "../pest", version = "2.7.0" }
pest = { path = "../pest", version = "2.7.1" }
once_cell = "1.8.0"

[build-dependencies]
Expand Down
15 changes: 10 additions & 5 deletions meta/src/optimizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,13 @@ fn rule_to_optimized_rule(rule: Rule) -> OptimizedRule {
Expr::Push(expr) => OptimizedExpr::Push(Box::new(to_optimized(*expr))),
#[cfg(feature = "grammar-extras")]
Expr::NodeTag(expr, tag) => OptimizedExpr::NodeTag(Box::new(to_optimized(*expr)), tag),
Expr::RepOnce(_)
| Expr::RepExact(..)
| Expr::RepMin(..)
| Expr::RepMax(..)
| Expr::RepMinMax(..) => unreachable!("No valid transformation to OptimizedRule"),
#[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")
}
}
}

Expand Down Expand Up @@ -135,6 +137,9 @@ 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)`
Expand Down
1 change: 1 addition & 0 deletions meta/src/optimizer/unroller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion pest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest"
description = "The Elegant Parser"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand Down
6 changes: 3 additions & 3 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pest_vm"
description = "pest grammar virtual machine"
version = "2.7.0"
version = "2.7.1"
edition = "2021"
authors = ["Dragoș Tiselice <dragostiselice@gmail.com>"]
homepage = "https://pest.rs/"
Expand All @@ -14,8 +14,8 @@ readme = "_README.md"
rust-version = "1.60"

[dependencies]
pest = { path = "../pest", version = "2.7.0" }
pest_meta = { path = "../meta", version = "2.7.0" }
pest = { path = "../pest", version = "2.7.1" }
pest_meta = { path = "../meta", version = "2.7.1" }

[features]
grammar-extras = ["pest_meta/grammar-extras"]
11 changes: 11 additions & 0 deletions vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,17 @@ impl Vm {
})
})
}),
#[cfg(feature = "grammar-extras")]
OptimizedExpr::RepOnce(ref expr) => state.sequence(|state| {
self.parse_expr(expr, state).and_then(|state| {
state.repeat(|state| {
state.sequence(|state| {
self.skip(state)
.and_then(|state| self.parse_expr(expr, state))
})
})
})
}),
OptimizedExpr::Push(ref expr) => state.stack_push(|state| self.parse_expr(expr, state)),
OptimizedExpr::Skip(ref strings) => state.skip_until(
&strings
Expand Down

0 comments on commit d9bfdde

Please sign in to comment.