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