mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	The scripts in `Tools/peg_generator/scripts` mostly assume that `ast.parse` and `compile` use the old parser, since this was the state of things, while we were developing them. They need to be updated to always use the correct parser. `_peg_parser` is being extended to support both parsing and compiling with both parsers.
		
			
				
	
	
		
			116 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env python3.8
 | 
						|
 | 
						|
"""Show the parse tree for a given program, nicely formatted.
 | 
						|
 | 
						|
Example:
 | 
						|
 | 
						|
$ scripts/show_parse.py a+b
 | 
						|
Module(
 | 
						|
    body=[
 | 
						|
        Expr(
 | 
						|
            value=BinOp(
 | 
						|
                left=Name(id="a", ctx=Load()), op=Add(), right=Name(id="b", ctx=Load())
 | 
						|
            )
 | 
						|
        )
 | 
						|
    ],
 | 
						|
    type_ignores=[],
 | 
						|
)
 | 
						|
$
 | 
						|
 | 
						|
Use -v to show line numbers and column offsets.
 | 
						|
 | 
						|
The formatting is done using black.  You can also import this module
 | 
						|
and call one of its functions.
 | 
						|
"""
 | 
						|
 | 
						|
import argparse
 | 
						|
import ast
 | 
						|
import difflib
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import tempfile
 | 
						|
 | 
						|
import _peg_parser
 | 
						|
 | 
						|
from typing import List
 | 
						|
 | 
						|
sys.path.insert(0, os.getcwd())
 | 
						|
from pegen.ast_dump import ast_dump
 | 
						|
 | 
						|
parser = argparse.ArgumentParser()
 | 
						|
parser.add_argument(
 | 
						|
    "-d", "--diff", action="store_true", help="show diff between grammar and ast (requires -g)"
 | 
						|
)
 | 
						|
parser.add_argument("-g", "--grammar-file", help="grammar to use (default: use the ast module)")
 | 
						|
parser.add_argument(
 | 
						|
    "-m",
 | 
						|
    "--multiline",
 | 
						|
    action="store_true",
 | 
						|
    help="concatenate program arguments using newline instead of space",
 | 
						|
)
 | 
						|
parser.add_argument("-v", "--verbose", action="store_true", help="show line/column numbers")
 | 
						|
parser.add_argument("program", nargs="+", help="program to parse (will be concatenated)")
 | 
						|
 | 
						|
 | 
						|
def format_tree(tree: ast.AST, verbose: bool = False) -> str:
 | 
						|
    with tempfile.NamedTemporaryFile("w+") as tf:
 | 
						|
        tf.write(ast_dump(tree, include_attributes=verbose))
 | 
						|
        tf.write("\n")
 | 
						|
        tf.flush()
 | 
						|
        cmd = f"black -q {tf.name}"
 | 
						|
        sts = os.system(cmd)
 | 
						|
        if sts:
 | 
						|
            raise RuntimeError(f"Command {cmd!r} failed with status 0x{sts:x}")
 | 
						|
        tf.seek(0)
 | 
						|
        return tf.read()
 | 
						|
 | 
						|
 | 
						|
def diff_trees(a: ast.AST, b: ast.AST, verbose: bool = False) -> List[str]:
 | 
						|
    sa = format_tree(a, verbose)
 | 
						|
    sb = format_tree(b, verbose)
 | 
						|
    la = sa.splitlines()
 | 
						|
    lb = sb.splitlines()
 | 
						|
    return list(difflib.unified_diff(la, lb, "a", "b", lineterm=""))
 | 
						|
 | 
						|
 | 
						|
def show_parse(source: str, verbose: bool = False) -> str:
 | 
						|
    tree = _peg_parser.parse_string(source, oldparser=True)
 | 
						|
    return format_tree(tree, verbose).rstrip("\n")
 | 
						|
 | 
						|
 | 
						|
def print_parse(source: str, verbose: bool = False) -> None:
 | 
						|
    print(show_parse(source, verbose))
 | 
						|
 | 
						|
 | 
						|
def main() -> None:
 | 
						|
    args = parser.parse_args()
 | 
						|
    if args.diff and not args.grammar_file:
 | 
						|
        parser.error("-d/--diff requires -g/--grammar-file")
 | 
						|
    if args.multiline:
 | 
						|
        sep = "\n"
 | 
						|
    else:
 | 
						|
        sep = " "
 | 
						|
    program = sep.join(args.program)
 | 
						|
    if args.grammar_file:
 | 
						|
        tree = _peg_parser.parse_string(program)
 | 
						|
 | 
						|
        if args.diff:
 | 
						|
            a = tree
 | 
						|
            b = _peg_parser.parse_string(program, oldparser=True)
 | 
						|
            diff = diff_trees(a, b, args.verbose)
 | 
						|
            if diff:
 | 
						|
                for line in diff:
 | 
						|
                    print(line)
 | 
						|
            else:
 | 
						|
                print("# Trees are the same")
 | 
						|
        else:
 | 
						|
            print(f"# Parsed using {args.grammar_file}")
 | 
						|
            print(format_tree(tree, args.verbose))
 | 
						|
    else:
 | 
						|
        tree = _peg_parser.parse_string(program, oldparser=True)
 | 
						|
        print("# Parse using the old parser")
 | 
						|
        print(format_tree(tree, args.verbose))
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    main()
 |