17db96d56Sopenharmony_ciimport argparse
27db96d56Sopenharmony_ciimport sys
37db96d56Sopenharmony_cifrom typing import Any, Callable, Iterator
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_cifrom pegen.build import build_parser
67db96d56Sopenharmony_cifrom pegen.grammar import Grammar, Rule
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ciargparser = argparse.ArgumentParser(
97db96d56Sopenharmony_ci    prog="pegen", description="Pretty print the AST for a given PEG grammar"
107db96d56Sopenharmony_ci)
117db96d56Sopenharmony_ciargparser.add_argument("filename", help="Grammar description")
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciclass ASTGrammarPrinter:
157db96d56Sopenharmony_ci    def children(self, node: Rule) -> Iterator[Any]:
167db96d56Sopenharmony_ci        for value in node:
177db96d56Sopenharmony_ci            if isinstance(value, list):
187db96d56Sopenharmony_ci                yield from value
197db96d56Sopenharmony_ci            else:
207db96d56Sopenharmony_ci                yield value
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci    def name(self, node: Rule) -> str:
237db96d56Sopenharmony_ci        if not list(self.children(node)):
247db96d56Sopenharmony_ci            return repr(node)
257db96d56Sopenharmony_ci        return node.__class__.__name__
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci    def print_grammar_ast(self, grammar: Grammar, printer: Callable[..., None] = print) -> None:
287db96d56Sopenharmony_ci        for rule in grammar.rules.values():
297db96d56Sopenharmony_ci            printer(self.print_nodes_recursively(rule))
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci    def print_nodes_recursively(self, node: Rule, prefix: str = "", istail: bool = True) -> str:
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci        children = list(self.children(node))
347db96d56Sopenharmony_ci        value = self.name(node)
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci        line = prefix + ("└──" if istail else "├──") + value + "\n"
377db96d56Sopenharmony_ci        sufix = "   " if istail else "│  "
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci        if not children:
407db96d56Sopenharmony_ci            return line
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci        *children, last = children
437db96d56Sopenharmony_ci        for child in children:
447db96d56Sopenharmony_ci            line += self.print_nodes_recursively(child, prefix + sufix, False)
457db96d56Sopenharmony_ci        line += self.print_nodes_recursively(last, prefix + sufix, True)
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci        return line
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_cidef main() -> None:
517db96d56Sopenharmony_ci    args = argparser.parse_args()
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    try:
547db96d56Sopenharmony_ci        grammar, parser, tokenizer = build_parser(args.filename)
557db96d56Sopenharmony_ci    except Exception as err:
567db96d56Sopenharmony_ci        print("ERROR: Failed to parse grammar file", file=sys.stderr)
577db96d56Sopenharmony_ci        sys.exit(1)
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci    visitor = ASTGrammarPrinter()
607db96d56Sopenharmony_ci    visitor.print_grammar_ast(grammar)
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ciif __name__ == "__main__":
647db96d56Sopenharmony_ci    main()
65