aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Tools/peg_generator/pegen/grammar_visualizer.py
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2020-04-22 23:29:27 +0100
committerGitHub <noreply@github.com>2020-04-22 23:29:27 +0100
commitc5fc15685202cda73f7c3f5c6f299b0945f58508 (patch)
tree7624ae45b95f2812e801c5879bdbdcb796f570a6 /Tools/peg_generator/pegen/grammar_visualizer.py
parenta81849b0315277bb3937271174aaaa5059c0b445 (diff)
downloadcpython-c5fc15685202cda73f7c3f5c6f299b0945f58508.tar.gz
cpython-c5fc15685202cda73f7c3f5c6f299b0945f58508.zip
bpo-40334: PEP 617 implementation: New PEG parser for CPython (GH-19503)
Co-authored-by: Guido van Rossum <guido@python.org> Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Diffstat (limited to 'Tools/peg_generator/pegen/grammar_visualizer.py')
-rw-r--r--Tools/peg_generator/pegen/grammar_visualizer.py65
1 files changed, 65 insertions, 0 deletions
diff --git a/Tools/peg_generator/pegen/grammar_visualizer.py b/Tools/peg_generator/pegen/grammar_visualizer.py
new file mode 100644
index 00000000000..b1d51d2cdb2
--- /dev/null
+++ b/Tools/peg_generator/pegen/grammar_visualizer.py
@@ -0,0 +1,65 @@
+import argparse
+import sys
+
+from typing import Any, Iterator, Iterable, 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()