Skip to content

Commit

Permalink
Make [] pattern syntax return the matched token/character
Browse files Browse the repository at this point in the history
Fixes #234
  • Loading branch information
kevinmehall committed Jan 2, 2022
1 parent 6838d5d commit cd3044a
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 10 deletions.
15 changes: 9 additions & 6 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,9 @@ fn compile_expr_continuation(context: &Context, e: &SpannedExpr, result_name: Op
}

PatternExpr(ref pattern) => {
compile_pattern_expr(pattern, quote_spanned!{ span =>
{ let __pos = __next; let #result_pat = (); { #continuation } }
let result_name = result_name.cloned().unwrap_or_else(|| Ident::new("__ch", span));
compile_pattern_expr(pattern, result_name, quote_spanned!{ span =>
{ let __pos = __next; { #continuation } }
})
}

Expand Down Expand Up @@ -430,7 +431,7 @@ fn compile_literal_expr(s: &Literal, continuation: TokenStream) -> TokenStream {
}
}

fn compile_pattern_expr(pattern_group: &Group, success_res: TokenStream) -> TokenStream {
fn compile_pattern_expr(pattern_group: &Group, result_name: Ident, success_res: TokenStream) -> TokenStream {
let span = pattern_group.span().resolved_at(Span::mixed_site());
let pat_str = pattern_group.to_string();
let failure_res = quote_spanned! { span => { __err_state.mark_failure(__pos, #pat_str); ::peg::RuleResult::Failed } };
Expand All @@ -443,7 +444,7 @@ fn compile_pattern_expr(pattern_group: &Group, success_res: TokenStream) -> Toke

quote_spanned! { span =>
match ::peg::ParseElem::parse_elem(__input, __pos) {
::peg::RuleResult::Matched(__next, __ch) => match __ch {
::peg::RuleResult::Matched(__next, #result_name) => match #result_name {
#pattern => #in_set,
_ => #not_in_set,
}
Expand All @@ -463,8 +464,10 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
}

PatternExpr(ref pattern_group) => {
compile_pattern_expr(pattern_group, quote_spanned! { span =>
::peg::RuleResult::Matched(__next, ())
let res_name = Ident::new("__ch", span);
let res = if result_used { quote!(#res_name) } else { quote_spanned!{ span => () }};
compile_pattern_expr(pattern_group, res_name, quote_spanned! { span =>
::peg::RuleResult::Matched(__next, #res)
})
}

Expand Down
4 changes: 2 additions & 2 deletions tests/compile-fail/rule_args_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ extern crate peg;

peg::parser!(grammar foo() for str {
rule foo(x: i32, y: rule<()>) = "foo"
rule ok() = foo(1, <[_]>)
rule ok() = foo(1, <[_] {}>)

rule too_few() = foo(1) //~ ERROR
rule too_many() = foo(1, <[_]>, 2) //~ ERROR
rule too_many() = foo(1, <[_] {}>, 2) //~ ERROR

pub rule pub_rule_arg(x: rule<()>) = "foo" //~ ERROR
});
Expand Down
2 changes: 1 addition & 1 deletion tests/compile-fail/rule_args_errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ error: this rule takes 2 parameters but 1 parameters were supplied
error: this rule takes 2 parameters but 3 parameters were supplied
--> $DIR/rule_args_errors.rs:8:23
|
8 | rule too_many() = foo(1, <[_]>, 2) //~ ERROR
8 | rule too_many() = foo(1, <[_] {}>, 2) //~ ERROR
| ^^^

error: parameters on `pub rule` must be Rust types
Expand Down
2 changes: 1 addition & 1 deletion tests/run-pass/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate peg;

peg::parser!{ grammar parser() for str {
pub rule one_letter() -> () = ['a'..='z']
pub rule one_letter() = ['a'..='z']

pub rule parse() -> usize
= v:( "a" / "\n" )* { v.len() }
Expand Down
6 changes: 6 additions & 0 deletions tests/run-pass/pattern.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
peg::parser!( grammar test() for str {
pub rule alphanumeric() = ['a'..='z' | 'A'..='Z' | '0'..='9']*
pub rule inverted_pat() -> &'input str = "(" s:$([^')']*) ")" {s}

pub rule capture() -> char = ['a'..='z']
pub rule capture2() -> (char, char) = a:['a'..='z'] b:['0'..='9'] { (a, b) }
});

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

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

assert_eq!(test::capture("x"), Ok('x'));
assert_eq!(test::capture2("a1"), Ok(('a', '1')));
}

0 comments on commit cd3044a

Please sign in to comment.