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