17db96d56Sopenharmony_ciimport importlib.util 27db96d56Sopenharmony_ciimport io 37db96d56Sopenharmony_ciimport os 47db96d56Sopenharmony_ciimport pathlib 57db96d56Sopenharmony_ciimport sys 67db96d56Sopenharmony_ciimport textwrap 77db96d56Sopenharmony_ciimport token 87db96d56Sopenharmony_ciimport tokenize 97db96d56Sopenharmony_cifrom typing import IO, Any, Dict, Final, Optional, Type, cast 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_cifrom pegen.build import compile_c_extension 127db96d56Sopenharmony_cifrom pegen.c_generator import CParserGenerator 137db96d56Sopenharmony_cifrom pegen.grammar import Grammar 147db96d56Sopenharmony_cifrom pegen.grammar_parser import GeneratedParser as GrammarParser 157db96d56Sopenharmony_cifrom pegen.parser import Parser 167db96d56Sopenharmony_cifrom pegen.python_generator import PythonParserGenerator 177db96d56Sopenharmony_cifrom pegen.tokenizer import Tokenizer 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ciALL_TOKENS = token.tok_name 207db96d56Sopenharmony_ciEXACT_TOKENS = token.EXACT_TOKEN_TYPES 217db96d56Sopenharmony_ciNON_EXACT_TOKENS = { 227db96d56Sopenharmony_ci name for index, name in token.tok_name.items() if index not in EXACT_TOKENS.values() 237db96d56Sopenharmony_ci} 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_cidef generate_parser(grammar: Grammar) -> Type[Parser]: 277db96d56Sopenharmony_ci # Generate a parser. 287db96d56Sopenharmony_ci out = io.StringIO() 297db96d56Sopenharmony_ci genr = PythonParserGenerator(grammar, out) 307db96d56Sopenharmony_ci genr.generate("<string>") 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci # Load the generated parser class. 337db96d56Sopenharmony_ci ns: Dict[str, Any] = {} 347db96d56Sopenharmony_ci exec(out.getvalue(), ns) 357db96d56Sopenharmony_ci return ns["GeneratedParser"] 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_cidef run_parser(file: IO[bytes], parser_class: Type[Parser], *, verbose: bool = False) -> Any: 397db96d56Sopenharmony_ci # Run a parser on a file (stream). 407db96d56Sopenharmony_ci tokenizer = Tokenizer(tokenize.generate_tokens(file.readline)) # type: ignore # typeshed issue #3515 417db96d56Sopenharmony_ci parser = parser_class(tokenizer, verbose=verbose) 427db96d56Sopenharmony_ci result = parser.start() 437db96d56Sopenharmony_ci if result is None: 447db96d56Sopenharmony_ci raise parser.make_syntax_error("invalid syntax") 457db96d56Sopenharmony_ci return result 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cidef parse_string( 497db96d56Sopenharmony_ci source: str, parser_class: Type[Parser], *, dedent: bool = True, verbose: bool = False 507db96d56Sopenharmony_ci) -> Any: 517db96d56Sopenharmony_ci # Run the parser on a string. 527db96d56Sopenharmony_ci if dedent: 537db96d56Sopenharmony_ci source = textwrap.dedent(source) 547db96d56Sopenharmony_ci file = io.StringIO(source) 557db96d56Sopenharmony_ci return run_parser(file, parser_class, verbose=verbose) # type: ignore # typeshed issue #3515 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_cidef make_parser(source: str) -> Type[Parser]: 597db96d56Sopenharmony_ci # Combine parse_string() and generate_parser(). 607db96d56Sopenharmony_ci grammar = parse_string(source, GrammarParser) 617db96d56Sopenharmony_ci return generate_parser(grammar) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_cidef import_file(full_name: str, path: str) -> Any: 657db96d56Sopenharmony_ci """Import a python module from a path""" 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ci spec = importlib.util.spec_from_file_location(full_name, path) 687db96d56Sopenharmony_ci assert spec is not None 697db96d56Sopenharmony_ci mod = importlib.util.module_from_spec(spec) 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci # We assume this is not None and has an exec_module() method. 727db96d56Sopenharmony_ci # See https://docs.python.org/3/reference/import.html?highlight=exec_module#loading 737db96d56Sopenharmony_ci loader = cast(Any, spec.loader) 747db96d56Sopenharmony_ci loader.exec_module(mod) 757db96d56Sopenharmony_ci return mod 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_cidef generate_c_parser_source(grammar: Grammar) -> str: 797db96d56Sopenharmony_ci out = io.StringIO() 807db96d56Sopenharmony_ci genr = CParserGenerator(grammar, ALL_TOKENS, EXACT_TOKENS, NON_EXACT_TOKENS, out) 817db96d56Sopenharmony_ci genr.generate("<string>") 827db96d56Sopenharmony_ci return out.getvalue() 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_cidef generate_parser_c_extension( 867db96d56Sopenharmony_ci grammar: Grammar, path: pathlib.PurePath, debug: bool = False, 877db96d56Sopenharmony_ci library_dir: Optional[str] = None, 887db96d56Sopenharmony_ci) -> Any: 897db96d56Sopenharmony_ci """Generate a parser c extension for the given grammar in the given path 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci Returns a module object with a parse_string() method. 927db96d56Sopenharmony_ci TODO: express that using a Protocol. 937db96d56Sopenharmony_ci """ 947db96d56Sopenharmony_ci # Make sure that the working directory is empty: reusing non-empty temporary 957db96d56Sopenharmony_ci # directories when generating extensions can lead to segmentation faults. 967db96d56Sopenharmony_ci # Check issue #95 (https://github.com/gvanrossum/pegen/issues/95) for more 977db96d56Sopenharmony_ci # context. 987db96d56Sopenharmony_ci assert not os.listdir(path) 997db96d56Sopenharmony_ci source = path / "parse.c" 1007db96d56Sopenharmony_ci with open(source, "w", encoding="utf-8") as file: 1017db96d56Sopenharmony_ci genr = CParserGenerator( 1027db96d56Sopenharmony_ci grammar, ALL_TOKENS, EXACT_TOKENS, NON_EXACT_TOKENS, file, debug=debug 1037db96d56Sopenharmony_ci ) 1047db96d56Sopenharmony_ci genr.generate("parse.c") 1057db96d56Sopenharmony_ci compile_c_extension( 1067db96d56Sopenharmony_ci str(source), 1077db96d56Sopenharmony_ci build_dir=str(path), 1087db96d56Sopenharmony_ci # Significant test_peg_generator speedups 1097db96d56Sopenharmony_ci disable_optimization=True, 1107db96d56Sopenharmony_ci library_dir=library_dir, 1117db96d56Sopenharmony_ci ) 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_cidef print_memstats() -> bool: 1157db96d56Sopenharmony_ci MiB: Final = 2 ** 20 1167db96d56Sopenharmony_ci try: 1177db96d56Sopenharmony_ci import psutil # type: ignore 1187db96d56Sopenharmony_ci except ImportError: 1197db96d56Sopenharmony_ci return False 1207db96d56Sopenharmony_ci print("Memory stats:") 1217db96d56Sopenharmony_ci process = psutil.Process() 1227db96d56Sopenharmony_ci meminfo = process.memory_info() 1237db96d56Sopenharmony_ci res = {} 1247db96d56Sopenharmony_ci res["rss"] = meminfo.rss / MiB 1257db96d56Sopenharmony_ci res["vms"] = meminfo.vms / MiB 1267db96d56Sopenharmony_ci if sys.platform == "win32": 1277db96d56Sopenharmony_ci res["maxrss"] = meminfo.peak_wset / MiB 1287db96d56Sopenharmony_ci else: 1297db96d56Sopenharmony_ci # See https://stackoverflow.com/questions/938733/total-memory-used-by-python-process 1307db96d56Sopenharmony_ci import resource # Since it doesn't exist on Windows. 1317db96d56Sopenharmony_ci 1327db96d56Sopenharmony_ci rusage = resource.getrusage(resource.RUSAGE_SELF) 1337db96d56Sopenharmony_ci if sys.platform == "darwin": 1347db96d56Sopenharmony_ci factor = 1 1357db96d56Sopenharmony_ci else: 1367db96d56Sopenharmony_ci factor = 1024 # Linux 1377db96d56Sopenharmony_ci res["maxrss"] = rusage.ru_maxrss * factor / MiB 1387db96d56Sopenharmony_ci for key, value in res.items(): 1397db96d56Sopenharmony_ci print(f" {key:12.12s}: {value:10.0f} MiB") 1407db96d56Sopenharmony_ci return True 141