mirror of
https://github.com/python/cpython.git
synced 2025-07-29 06:05:00 +00:00

Simplify the peg generator logic by extracting as much visitors as possible to disentangle the flow and separate concerns.
64 lines
1.8 KiB
Python
64 lines
1.8 KiB
Python
import argparse
|
|
import sys
|
|
from typing import Any, Callable, Iterator
|
|
|
|
from pegen.build import build_parser
|
|
from pegen.grammar import Grammar, Rule
|
|
|
|
argparser = argparse.ArgumentParser(
|
|
prog="pegen", description="Pretty print the AST for a given PEG grammar"
|
|
)
|
|
argparser.add_argument("filename", help="Grammar description")
|
|
|
|
|
|
class ASTGrammarPrinter:
|
|
def children(self, node: Rule) -> Iterator[Any]:
|
|
for value in node:
|
|
if isinstance(value, list):
|
|
yield from value
|
|
else:
|
|
yield value
|
|
|
|
def name(self, node: Rule) -> str:
|
|
if not list(self.children(node)):
|
|
return repr(node)
|
|
return node.__class__.__name__
|
|
|
|
def print_grammar_ast(self, grammar: Grammar, printer: Callable[..., None] = print) -> None:
|
|
for rule in grammar.rules.values():
|
|
printer(self.print_nodes_recursively(rule))
|
|
|
|
def print_nodes_recursively(self, node: Rule, prefix: str = "", istail: bool = True) -> str:
|
|
|
|
children = list(self.children(node))
|
|
value = self.name(node)
|
|
|
|
line = prefix + ("└──" if istail else "├──") + value + "\n"
|
|
sufix = " " if istail else "│ "
|
|
|
|
if not children:
|
|
return line
|
|
|
|
*children, last = children
|
|
for child in children:
|
|
line += self.print_nodes_recursively(child, prefix + sufix, False)
|
|
line += self.print_nodes_recursively(last, prefix + sufix, True)
|
|
|
|
return line
|
|
|
|
|
|
def main() -> None:
|
|
args = argparser.parse_args()
|
|
|
|
try:
|
|
grammar, parser, tokenizer = build_parser(args.filename)
|
|
except Exception as err:
|
|
print("ERROR: Failed to parse grammar file", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
visitor = ASTGrammarPrinter()
|
|
visitor.print_grammar_ast(grammar)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|