2020-04-22 19:29:27 -03:00
|
|
|
#!/usr/bin/env python3.8
|
|
|
|
"""Find the maximum amount of nesting for an expression that can be parsed
|
|
|
|
without causing a parse error.
|
|
|
|
|
|
|
|
Starting at the INITIAL_NESTING_DEPTH, an expression containing n parenthesis
|
|
|
|
around a 0 is generated then tested with both the C and Python parsers. We
|
|
|
|
continue incrementing the number of parenthesis by 10 until both parsers have
|
|
|
|
failed. As soon as a single parser fails, we stop testing that parser.
|
|
|
|
|
|
|
|
The grammar file, initial nesting size, and amount by which the nested size is
|
|
|
|
incremented on each success can be controlled by changing the GRAMMAR_FILE,
|
|
|
|
INITIAL_NESTING_DEPTH, or NESTED_INCR_AMT variables.
|
|
|
|
|
|
|
|
Usage: python -m scripts.find_max_nesting
|
|
|
|
"""
|
|
|
|
import sys
|
2020-06-11 21:55:35 -03:00
|
|
|
import ast
|
2020-04-22 19:29:27 -03:00
|
|
|
|
|
|
|
GRAMMAR_FILE = "data/python.gram"
|
|
|
|
INITIAL_NESTING_DEPTH = 10
|
|
|
|
NESTED_INCR_AMT = 10
|
|
|
|
|
|
|
|
|
|
|
|
FAIL = "\033[91m"
|
|
|
|
ENDC = "\033[0m"
|
|
|
|
|
|
|
|
|
|
|
|
def check_nested_expr(nesting_depth: int) -> bool:
|
|
|
|
expr = f"{'(' * nesting_depth}0{')' * nesting_depth}"
|
|
|
|
try:
|
2020-06-11 21:55:35 -03:00
|
|
|
ast.parse(expr)
|
2020-04-22 19:29:27 -03:00
|
|
|
print(f"Nesting depth of {nesting_depth} is successful")
|
|
|
|
return True
|
|
|
|
except Exception as err:
|
|
|
|
print(f"{FAIL}(Failed with nesting depth of {nesting_depth}{ENDC}")
|
|
|
|
print(f"{FAIL}\t{err}{ENDC}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
print(f"Testing {GRAMMAR_FILE} starting at nesting depth of {INITIAL_NESTING_DEPTH}...")
|
|
|
|
|
|
|
|
nesting_depth = INITIAL_NESTING_DEPTH
|
|
|
|
succeeded = True
|
|
|
|
while succeeded:
|
|
|
|
expr = f"{'(' * nesting_depth}0{')' * nesting_depth}"
|
|
|
|
if succeeded:
|
|
|
|
succeeded = check_nested_expr(nesting_depth)
|
|
|
|
nesting_depth += NESTED_INCR_AMT
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|