parsimonious icon indicating copy to clipboard operation
parsimonious copied to clipboard

RecursionError

Open Martmists-GH opened this issue 8 years ago • 2 comments
trafficstars

I'm writing a custom language, and a friend recommended to use this library. Grammar:

grammar = Grammar(r"""
    program    = stmt*
    class      = "class" params? compound
    while      = "while" cond compound
    function   = "function" params f_compound
    cond       = ("(" value (comp value)* ")") / (value (comp value)*)
    assign     = var "=" value
    if         = "if" cond compound else?
    else       = "else" compound
    try        = "try" compound except?
    except     = "except" compound
    params     = "(" comma_args? ")"
    f_stmt     = stmt / return
    stmt       = (assign / if / while / function / class)
    f_compound = "{" f_stmt* "}"
    compound   = "{" stmt* "}"
    return     = "return" stmt?
    array      = "[" comma_args? "]"
    comma_args = value ("," value)*
    value      = string / integer / float / var / array / binop / call / comp
    float      = integer "." integer
    attr       = var "." varname
    string     = ('"' ~'[^"]*' '"') / ("'" ~"[^']*" "'")
    binop      = value op value
    op         = ~"[\+\-\/\*]"
    comp       = "==" / "!=" / ">=" / "<=" / ">" / "<"
    call       = var params
    var        = varname / attr
    varname    = ~"[A-Z_][A-Z0-9_]*"i
    integer    = ~"[0-9]+"
    _          = ~r'\s'*
    """)

when using print(grammar.parse("x = 1 + 1")), I get the following error:

Traceback (most recent call last):
  File "test_lexer.py", line 36, in <module>
    res = grammar.parse("x=1+1")
  File "/usr/lib/python3.6/site-packages/parsimonious/grammar.py", line 115, in parse
    return self.default_rule.parse(text, pos=pos)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 120, in parse
    node = self.match(text, pos=pos)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 135, in match
    node = self.match_core(text, pos, {}, error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 178, in match_core
    error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 458, in _uncached_match
    node = self.members[0].match_core(text, new_pos, cache, error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 178, in match_core
    error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 356, in _uncached_match
    node = m.match_core(text, pos, cache, error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 178, in match_core
    error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 333, in _uncached_match
    node = m.match_core(text, new_pos, cache, error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 178, in match_core
    error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 356, in _uncached_match
    node = m.match_core(text, pos, cache, error)
  File "/usr/lib/python3.6/site-packages/parsimonious/expressions.py", line 178, in match_core
    error)

and this repeated until it says RecursionError: maximum recursion depth exceeded

Is it my grammar at fault, or is there something else I'm doing wrong?

Martmists-GH avatar Sep 24 '17 18:09 Martmists-GH

Right now, all I can find wrong is

value = string / integer / float / var / array / binop / call / comp
binop = value op value

They seem to be self-referential, and might be the source of the recursion.

I'm not sure how to fix the grammar, but am quite sure that it's not an issue with the parser.

oxy avatar Sep 25 '17 07:09 oxy

I tried to reproduce your bug with a simpler version of the grammar:

>>> g = Grammar(r'''
...    expr = value EOF
...    value = integer / binop
...    integer = ~"[0-9]+"
...    binop   = value spaces op spaces value
...    op = ~"[\+\-]"
...    EOF = ~"$"
...    spaces = ~"\s*"
... ''')

But when trying to parse '1 + 1', the problem is that parsimonious stops after matching the 'integer':

>>> g.parse('1 + 1')
....
ParseError: Rule 'EOF' didn't match at ' + 1' (line 1, column 2).

Only after switching the order of binop and integer in the value rule, I get the RecursionError.

mvaled avatar Sep 07 '18 20:09 mvaled