Skip to content

Commit

Permalink
Restore support for [^ ] inverted pattern syntax.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinmehall committed Feb 15, 2021
1 parent 01440d0 commit 93a327b
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 21 deletions.
28 changes: 9 additions & 19 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,6 @@ fn labeled_seq(context: &Context, exprs: &[TaggedExpr], inner: TokenStream) -> T
})
}

fn cond_swap<T>(swap: bool, tup: (T, T)) -> (T, T) {
let (a, b) = tup;
if swap {
(b, a)
} else {
(a, b)
}
}

fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream {
match e {
LiteralExpr(ref s) => {
Expand All @@ -363,17 +354,16 @@ fn compile_expr(context: &Context, e: &Expr, result_used: bool) -> TokenStream {
}

PatternExpr(ref pattern_group) => {
let invert = false;
let pattern = pattern_group.stream();
let pat_str = pattern.to_string();
let pat_str = pattern_group.to_string();

let (in_set, not_in_set) = cond_swap(
invert,
(
quote! { ::peg::RuleResult::Matched(__next, ()) },
quote! { __err_state.mark_failure(__pos, #pat_str) },
),
);
let success_res = quote! { ::peg::RuleResult::Matched(__next, ()) };
let failure_res = quote! { __err_state.mark_failure(__pos, #pat_str) };

let (pattern, in_set, not_in_set) = if let Some(pattern) = group_check_prefix(pattern_group, '^') {
(pattern, failure_res, success_res)
} else {
(pattern_group.stream(), success_res, failure_res)
};

let in_set_arm = quote!( #pattern => #in_set, );

Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
//!
//! * `"keyword"` - _Literal:_ match a literal string.
//! * `['0'..='9']` - _Pattern:_ match a single element that matches a Rust `match`-style
//! pattern. [(details)](#match-expressions)
//! pattern. [(details)](#pattern-expressions)
//! * `[^ '0'..='9']` - _Inverted pattern:_ match a single element that does not match a Rust `match`-style
//! pattern. [(details)](#pattern-expressions)
//! * `some_rule()` - _Rule:_ match a rule defined elsewhere in the grammar and return its
//! result. Arguments in the parentheses are Rust expressions.
//! * `_` or `__` or `___` - _Rule (underscore):_ As a special case, rule names
Expand Down Expand Up @@ -130,7 +132,8 @@
//!
//! 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.
//! (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.
//!
//! 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
Expand Down
12 changes: 12 additions & 0 deletions tests/run-pass/pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
peg::parser!( grammar test() for str {
pub rule alphanumeric() = ['a'..='z' | 'A'..='Z' | '0'..='9']*
pub rule inverted_pat() -> &'input str = "(" s:$([^')']*) ")" {s}
});

fn main() {
assert!(test::alphanumeric("azAZ09").is_ok());
assert!(test::alphanumeric("@").is_err());

assert_eq!(test::inverted_pat("(asdf)"), Ok("asdf"));
}

0 comments on commit 93a327b

Please sign in to comment.