From 9dbd3ce5bb272d2caa2dfb8143497ace0d51360a Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Sat, 27 Apr 2024 10:57:12 -0600 Subject: [PATCH] Test and document pattern `if` guards --- src/lib.rs | 15 ++++++++++++--- tests/run-pass/pattern.rs | 6 ++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2405f11..7e71755 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,8 +132,11 @@ //! //! The `[pat]` syntax expands into a [Rust `match` //! pattern](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) against the next character -//! (or element) of the input. When the pattern begins with `^`, the matching behavior is inverted: +//! (or element) of the input. +//! +//! When the pattern begins with `^`, the matching behavior is inverted: //! the expression succeeds only if the pattern does *not* match. +//! `[^' ']` matches any character other than a space. //! //! To match sets of characters, use Rust's `..=` inclusive range pattern //! syntax and `|` to match multiple patterns. For example `['a'..='z' | 'A'..='Z']` matches an @@ -143,11 +146,17 @@ //! `[Token::Operator('+')]`. //! //! Variables captured by the pattern are accessible in a subsequent action -//! block: `[Token::Integer(i)] { i }` +//! block: `[Token::Integer(i)] { i }`. +//! +//! The pattern expression also evaluates to the matched element, which can be +//! captured into a variable or used as the return value of a rule: `c:['+'|'-']`. +//! +//! Like Rust `match`, pattern expressions support guard expressions: +//! `[c if c.is_ascii_digit()]`. //! //! `[_]` matches any single element. As this always matches except at end-of-file, combining it //! with negative lookahead as `![_]` is the idiom for matching EOF in PEG. -//! +//! //! ### Repeat ranges //! //! The repeat operators `*` and `**` can be followed by an optional range specification of the diff --git a/tests/run-pass/pattern.rs b/tests/run-pass/pattern.rs index e9f9192..db5d8c3 100644 --- a/tests/run-pass/pattern.rs +++ b/tests/run-pass/pattern.rs @@ -6,6 +6,8 @@ peg::parser!( grammar test() for str { pub rule capture2() -> (char, char) = a:['a'..='z'] b:['0'..='9'] { (a, b) } pub rule open_range() -> char = ['a'..] + + pub rule if_guard() -> char = [x if x.is_ascii_digit()] }); fn main() { @@ -16,5 +18,9 @@ fn main() { assert_eq!(test::capture("x"), Ok('x')); assert_eq!(test::capture2("a1"), Ok(('a', '1'))); + + assert_eq!(test::if_guard("1"), Ok('1')); + assert!(test::if_guard("a").is_err()); + }