Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/peg_generator/pegen/grammar_visualizer.py
12 views
1
import argparse
2
import sys
3
from typing import Any, Callable, Iterator
4
5
from pegen.build import build_parser
6
from pegen.grammar import Grammar, Rule
7
8
argparser = argparse.ArgumentParser(
9
prog="pegen", description="Pretty print the AST for a given PEG grammar"
10
)
11
argparser.add_argument("filename", help="Grammar description")
12
13
14
class ASTGrammarPrinter:
15
def children(self, node: Rule) -> Iterator[Any]:
16
for value in node:
17
if isinstance(value, list):
18
yield from value
19
else:
20
yield value
21
22
def name(self, node: Rule) -> str:
23
if not list(self.children(node)):
24
return repr(node)
25
return node.__class__.__name__
26
27
def print_grammar_ast(self, grammar: Grammar, printer: Callable[..., None] = print) -> None:
28
for rule in grammar.rules.values():
29
printer(self.print_nodes_recursively(rule))
30
31
def print_nodes_recursively(self, node: Rule, prefix: str = "", istail: bool = True) -> str:
32
children = list(self.children(node))
33
value = self.name(node)
34
35
line = prefix + ("└──" if istail else "├──") + value + "\n"
36
sufix = " " if istail else "│ "
37
38
if not children:
39
return line
40
41
*children, last = children
42
for child in children:
43
line += self.print_nodes_recursively(child, prefix + sufix, False)
44
line += self.print_nodes_recursively(last, prefix + sufix, True)
45
46
return line
47
48
49
def main() -> None:
50
args = argparser.parse_args()
51
52
try:
53
grammar, parser, tokenizer = build_parser(args.filename)
54
except Exception as err:
55
print("ERROR: Failed to parse grammar file", file=sys.stderr)
56
sys.exit(1)
57
58
visitor = ASTGrammarPrinter()
59
visitor.print_grammar_ast(grammar)
60
61
62
if __name__ == "__main__":
63
main()
64
65