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