1#!/usr/bin/env python3.8 2"""Find the maximum amount of nesting for an expression that can be parsed 3without causing a parse error. 4 5Starting at the INITIAL_NESTING_DEPTH, an expression containing n parenthesis 6around a 0 is generated then tested with both the C and Python parsers. We 7continue incrementing the number of parenthesis by 10 until both parsers have 8failed. As soon as a single parser fails, we stop testing that parser. 9 10The grammar file, initial nesting size, and amount by which the nested size is 11incremented on each success can be controlled by changing the GRAMMAR_FILE, 12INITIAL_NESTING_DEPTH, or NESTED_INCR_AMT variables. 13 14Usage: python -m scripts.find_max_nesting 15""" 16import sys 17import ast 18 19GRAMMAR_FILE = "data/python.gram" 20INITIAL_NESTING_DEPTH = 10 21NESTED_INCR_AMT = 10 22 23 24FAIL = "\033[91m" 25ENDC = "\033[0m" 26 27 28def check_nested_expr(nesting_depth: int) -> bool: 29 expr = f"{'(' * nesting_depth}0{')' * nesting_depth}" 30 try: 31 ast.parse(expr) 32 print(f"Nesting depth of {nesting_depth} is successful") 33 return True 34 except Exception as err: 35 print(f"{FAIL}(Failed with nesting depth of {nesting_depth}{ENDC}") 36 print(f"{FAIL}\t{err}{ENDC}") 37 return False 38 39 40def main() -> None: 41 print(f"Testing {GRAMMAR_FILE} starting at nesting depth of {INITIAL_NESTING_DEPTH}...") 42 43 nesting_depth = INITIAL_NESTING_DEPTH 44 succeeded = True 45 while succeeded: 46 expr = f"{'(' * nesting_depth}0{')' * nesting_depth}" 47 if succeeded: 48 succeeded = check_nested_expr(nesting_depth) 49 nesting_depth += NESTED_INCR_AMT 50 51 sys.exit(1) 52 53 54if __name__ == "__main__": 55 main() 56