diff --git a/parso/pgen2/grammar_parser.py b/parso/pgen2/grammar_parser.py index 623a455..0be7209 100644 --- a/parso/pgen2/grammar_parser.py +++ b/parso/pgen2/grammar_parser.py @@ -141,6 +141,9 @@ class NFAArc(object): self.next = next_ self.nonterminal_or_string = nonterminal_or_string + def __repr__(self): + return '<%s: %s>' % (self.__class__.__name__, self.nonterminal_or_string) + class NFAState(object): def __init__(self, from_rule): diff --git a/test/test_pgen2.py b/test/test_pgen2.py index 6ec081b..30b0c23 100644 --- a/test/test_pgen2.py +++ b/test/test_pgen2.py @@ -292,41 +292,22 @@ def test_left_recursion(): generate_grammar('foo: foo NAME\n', tokenize.PythonTokenTypes) -def test_ambiguities(): - with pytest.raises( - ValueError, - match=r"foo is ambiguous.*given a TokenType\(NAME\).*bar or baz" - ): - generate_grammar('foo: bar | baz\nbar: NAME\nbaz: NAME\n', tokenize.PythonTokenTypes) - - with pytest.raises( - ValueError, - match=r"foo is ambiguous.*given a ReservedString\(x\).*bar or baz" - ): - generate_grammar('''foo: bar | baz\nbar: 'x'\nbaz: "x"\n''', tokenize.PythonTokenTypes) - - with pytest.raises( - ValueError, - match=r"foo is ambiguous.*given a ReservedString\(x\).*bar or foo" - ): - generate_grammar('''foo: bar | 'x'\nbar: 'x'\n''', tokenize.PythonTokenTypes) - - # an ambiguity with the second (not the first) child of a production - with pytest.raises( - ValueError, - match=r"outer is ambiguous.*given a ReservedString\(b\).*inner or outer" - ): - generate_grammar( - 'outer: "a" [inner] "b" "c"\ninner: "b" "c" [inner]\n', - tokenize.PythonTokenTypes, - ) - - # an ambiguity hidden by a level of indirection (middle) - with pytest.raises( - ValueError, - match=r"outer is ambiguous.*given a ReservedString\(b\).*middle or outer" - ): - generate_grammar( - 'outer: "a" [middle] "b" "c"\nmiddle: inner\ninner: "b" "c" [inner]\n', - tokenize.PythonTokenTypes, - ) +@pytest.mark.parametrize( + 'grammar, error_match', [ + ['foo: bar | baz\nbar: NAME\nbaz: NAME\n', + r"foo is ambiguous.*given a TokenType\(NAME\).*bar or baz"], + ['''foo: bar | baz\nbar: 'x'\nbaz: "x"\n''', + r"foo is ambiguous.*given a ReservedString\(x\).*bar or baz"], + ['''foo: bar | 'x'\nbar: 'x'\n''', + r"foo is ambiguous.*given a ReservedString\(x\).*bar or foo"], + # An ambiguity with the second (not the first) child of a production + ['outer: "a" [inner] "b" "c"\ninner: "b" "c" [inner]\n', + r"outer is ambiguous.*given a ReservedString\(b\).*inner or outer"], + # An ambiguity hidden by a level of indirection (middle) + ['outer: "a" [middle] "b" "c"\nmiddle: inner\ninner: "b" "c" [inner]\n', + r"outer is ambiguous.*given a ReservedString\(b\).*middle or outer"], + ] +) +def test_ambiguities(grammar, error_match): + with pytest.raises(ValueError, match=error_match): + generate_grammar(grammar, tokenize.PythonTokenTypes)