I want to be able to parse simple rule expressions that can be joined together using conjunction words like and
and or
within parsimonious.
I've tried a very rudimentary grammar, which parses a simple expression, but fails as soon as I start introducing conjunctions.
import parsimonious
grammar = parsimonious.grammar.Grammar( """
rule = (rule)+
rule = (fieldname function parameters) / (rule conjunction rule)
fieldname = space? ("field1" / "field2" / "field3") space?
function = space? ("equal to" / "not equal to") space?
parameters = space? "()" space?
conjunction = space? ("and" / "or") space?
space = ~r"\s+"
""")
Testing for a simple case:
grammar.parse("field1 equal to ()")
Successfully parses (at least it appears to build a node-tree - I've not gone into depth figuring out how well it's split the content - but appears fine at first glance)
But then for a more complex case:
grammar.parse("field1 equal to () and field2 not equal to ()")
It returns IncompleteParseError: Rule 'rule' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with 'and field2 not equal' (line 1, column 20).
The grammar I've set out is trying to allow for arbitrarily conjoined statements, but I must be missing something.
I tried tweaking the grammar to make explicit the difference between the top-level class and lower ones:
grammar = parsimonious.grammar.Grammar( """
rule = expr+
expr = (fieldname function parameters) / (expr conjunction expr)
fieldname = space? ("field1" / "field2" / "field3") space?
function = space? ("equal to" / "not equal to") space?
parameters = space? "()" space?
conjunction = space? ("and" / "or") space?
space = ~r"\s+"
""")
And now, when running the 2-part phrase:
grammar.parse("field1 equal to () and field2 not equal to ()")
instead of the IncompleteParseError
, I get a RecursionError: maximum recursion depth exceeded in comparison
.
In the
(expr conjunction expr)
part ofexpr
you have a left recursion problem. So, you'll need to break it up into separate rules something like this: