| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | import argparse | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2021-09-05 14:58:52 +01:00
										 |  |  | from typing import Any, Callable, Iterator | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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() |