rubyparsingparslet

Parslet : exclusion clause


I am currently writting a Ruby parser using Ruby, and more precisely Parslet, since I think it is far more easier to use than Treetop or Citrus. I create my rules using the official specifications, but there are some statements I can not write, since they "exclude" some syntax, and I do not know how to do that... Well, here is an example for you to understand...

Here is a basic rule :

foo::=
any-character+ BUT NOT (foo* escape_character barbar*)
# Knowing that (foo* escape_character barbar*) is included in any-character

How could I translate that using Parslet ? Maybe the absent?/present? stuff ?

Thank you very much, hope someone has an idea....

Have a nice day!

EDIT: I tried what you said, so here's my translation into Ruby language using parslet:

  rule(:line_comment){(source_character.repeat >> line_terminator >> source_character.repeat).absent? >> source_character.repeat(1)}

However, it does not seem to work (the sequence in parens). I did some tests, and came to the conclusion that what's written in my parens is wrong.

Here is a very easier example, let's consider these rules:

# Parslet rules
rule(:source_character) {any}
rule(:line_terminator){ str("\n") >> str("\r").maybe }  

rule(:not){source_character.repeat >> line_terminator }
# Which looks like what I try to "detect" up there

I these these rules with this code:

# Code to test : 
code = "test
"

But I get that:

Failed to match sequence (SOURCE_CHARACTER{0, } LINE_TERMINATOR) at line 2 char 1. - Failed to match sequence (SOURCE_CHARACTER{0, } LINE_TERMINATOR) at line 2 char 1.- Failed to match sequence (' ' ' '?) at line 2 char 1. `- Premature end of input at line 2 char 1. nil

If this sequence doesn't work, my 'complete' rule up there won't ever work... If anyone has an idea, it would be great.

Thank you !


Solution

  • You can do something like this:

    rule(:word) { match['^")(\\s'].repeat(1) } # normal word
    rule(:op) { str('AND') | str('OR') | str('NOT') }
    rule(:keyword) { str('all:') | str('any:') }
    rule(:searchterm) { keyword.absent? >> op.absent? >>  word }
    

    In this case, the absent? does a lookahead to make sure the next token is not a keyword; if not, then it checks to make sure it's not an operator; if not, finally see if it's a valid word.

    An equivalent rule would be:

    rule(:searchterm) { (keyword | op).absent? >> word }