kevinmehall/rust-peg

"rule" but not when

Closed this issue · 2 comments

Hi I use peg for a project and I have a grammar like this:

peg::parser! {
    grammar parser() for str {
        rule raw_identifier() -> &'input str
            = i:$(['a'..='z'|'A'..='Z'|'0'..='9'|'_']*) { i }
        pub rule my_custom_rule() -> Vec<&'input str>
            = "test" i:raw_identifier()* "test" { i }
    }
}

but when I try to do parser::my_custom_rule("test test") or parser::my_custom_rule("test hello test") I get an error and not the expected result. How I can do this without doing a thing like that:

pub rule my_custom_rule() -> Vec<&'input str>
    = "test" i:("test" { Vec::new() } / i:raw_identifier()+ "test" { i }) { i }

and in more, how I can say to raw_identifier parse that as long as it's not "test" ?

Just express what you say in natural language in PEG DSL:

rule raw_identifier() -> &'input str
  = !"test" i:$(['a'..='z'|'A'..='Z'|'0'..='9'|'_']*) { i }

Unlike regex, PEGs backtrack only on match failures in a loop or ordered choice, so once the raw_identifier()* matches the second test, the parser will be at the end of input and "test" will fail.

As @Mingun said, you can use the negative lookahead ! operator for this: !"test" will fail to match if "test" would match at the current position, or match and consume no input if "test" would not match.

Also, might be just how you simplified your code for the issue, but it looks like your examples would fail because nothing would match the spaces.