mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			65 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			65 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import argparse
 | 
						|
import sys
 | 
						|
 | 
						|
from typing import Any, Iterator, Callable
 | 
						|
 | 
						|
from pegen.build import build_parser
 | 
						|
from pegen.grammar import Grammar, Rule
 | 
						|
 | 
						|
argparser = argparse.ArgumentParser(
 | 
						|
    prog="pegen", description="Pretty print the AST for a given PEG grammar"
 | 
						|
)
 | 
						|
argparser.add_argument("filename", help="Grammar description")
 | 
						|
 | 
						|
 | 
						|
class ASTGrammarPrinter:
 | 
						|
    def children(self, node: Rule) -> Iterator[Any]:
 | 
						|
        for value in node:
 | 
						|
            if isinstance(value, list):
 | 
						|
                yield from value
 | 
						|
            else:
 | 
						|
                yield value
 | 
						|
 | 
						|
    def name(self, node: Rule) -> str:
 | 
						|
        if not list(self.children(node)):
 | 
						|
            return repr(node)
 | 
						|
        return node.__class__.__name__
 | 
						|
 | 
						|
    def print_grammar_ast(self, grammar: Grammar, printer: Callable[..., None] = print) -> None:
 | 
						|
        for rule in grammar.rules.values():
 | 
						|
            printer(self.print_nodes_recursively(rule))
 | 
						|
 | 
						|
    def print_nodes_recursively(self, node: Rule, prefix: str = "", istail: bool = True) -> str:
 | 
						|
 | 
						|
        children = list(self.children(node))
 | 
						|
        value = self.name(node)
 | 
						|
 | 
						|
        line = prefix + ("└──" if istail else "├──") + value + "\n"
 | 
						|
        sufix = "   " if istail else "│  "
 | 
						|
 | 
						|
        if not children:
 | 
						|
            return line
 | 
						|
 | 
						|
        *children, last = children
 | 
						|
        for child in children:
 | 
						|
            line += self.print_nodes_recursively(child, prefix + sufix, False)
 | 
						|
        line += self.print_nodes_recursively(last, prefix + sufix, True)
 | 
						|
 | 
						|
        return line
 | 
						|
 | 
						|
 | 
						|
def main() -> None:
 | 
						|
    args = argparser.parse_args()
 | 
						|
 | 
						|
    try:
 | 
						|
        grammar, parser, tokenizer = build_parser(args.filename)
 | 
						|
    except Exception as err:
 | 
						|
        print("ERROR: Failed to parse grammar file", file=sys.stderr)
 | 
						|
        sys.exit(1)
 | 
						|
 | 
						|
    visitor = ASTGrammarPrinter()
 | 
						|
    visitor.print_grammar_ast(grammar)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    main()
 |