erikrose / parsimonious

The fastest pure-Python PEG parser I can muster
MIT License
1.79k stars 126 forks source link

Repetition doesn't seem to work #213

Closed tyilo closed 1 year ago

tyilo commented 1 year ago

This code works:

from parsimonious.grammar import Grammar

grammar = Grammar(
    """
    exactly_three_as = A A A
    A = "A"
    """
)

print(grammar.parse("AAA"))

But after rewriting it to use repetition it doesn't:

from parsimonious.grammar import Grammar

grammar = Grammar(
    """
    exactly_three_as = A{3}
    A = "A"
    """
)

print(grammar.parse("AAA"))

It raises the following exception:

Traceback (most recent call last):
  File "/home/tyilo/parse_test.py", line 3, in <module>
    grammar = Grammar(
  File "/home/tyilo/.local/lib/python3.10/site-packages/parsimonious/grammar.py", line 65, in __init__
    exprs, first = self._expressions_from_rules(rules, decorated_custom_rules)
  File "/home/tyilo/.local/lib/python3.10/site-packages/parsimonious/grammar.py", line 101, in _expressions_from_rules
    tree = rule_grammar.parse(rules)
  File "/home/tyilo/.local/lib/python3.10/site-packages/parsimonious/grammar.py", line 111, in parse
    return self.default_rule.parse(text, pos=pos)
  File "/home/tyilo/.local/lib/python3.10/site-packages/parsimonious/expressions.py", line 132, in parse
    raise IncompleteParseError(text, node.end, self)
parsimonious.exceptions.IncompleteParseError: Rule 'rules' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with '{3}
    A = "A"
    ' (line 2, column 25).

I'm using version 0.9.0.

lucaswiman commented 1 year ago

Sorry about this. Hadn't done a deploy in a while so that feature wasn't available on the version deployed on pypi. I deployed the new version. Please do pip install parsimonious==0.10.0 and your problem should be fixed. I just tested it in a virtualenv:

>>> from parsimonious.grammar import Grammar
>>>
>>> grammar = Grammar(
...     """
...     exactly_three_as = A{3}
...     A = "A"
...     """
... )
>>>
>>> print(grammar.parse("AAA"))
<Node called "exactly_three_as" matching "AAA">
    <Node called "A" matching "A">
    <Node called "A" matching "A">
    <Node called "A" matching "A">