Skip to content

bpo-41044: generate a valid python parser for opt+seq rules #20995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Lib/test/test_peg_generator/test_pegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,14 @@ def test_start_leader(self) -> None:
# Would assert False without a special case in compute_left_recursives().
make_parser(grammar)

def test_opt_sequence(self) -> None:
grammar = """
start: [NAME*]
"""
# This case was failing because of a double trailing comma at the end
# of a line in the generated source. See bpo-41044
make_parser(grammar)

def test_left_recursion_too_complex(self) -> None:
grammar = """
start: foo
Expand Down
8 changes: 7 additions & 1 deletion Tools/peg_generator/pegen/python_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ def visit_NegativeLookahead(self, node: NegativeLookahead) -> Tuple[None, str]:

def visit_Opt(self, node: Opt) -> Tuple[str, str]:
name, call = self.visit(node.node)
return "opt", f"{call}," # Note trailing comma!
# Note trailing comma (the call may already have one comma
# at the end, for example when rules have both repeat0 and optional
# markers, e.g: [rule*])
if call.endswith(","):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hummmm, not a find on relying on the generated code to reason about the grammar structure (I know that we do it in other places but we have been removing those as it makes it more difficult to reason about). In this case I have to say that is pretty straightforward so it may be fine.

return "opt", call
else:
return "opt", f"{call},"

def visit_Repeat0(self, node: Repeat0) -> Tuple[str, str]:
if node in self.cache:
Expand Down