#!/usr/bin/env python3 # parser storage grows across enum members, tagged enums, methods, and generated text. import subprocess import sys command = sys.argv[1:] def run(source, expected): result = subprocess.run(command, input=source, text=True, capture_output=True, timeout=30) assert result.returncode == 0, (result.stdout, result.stderr) assert result.stdout == expected, result.stdout[:1000] source = 'enum values { ' + ', '.join(f'member_{i}' for i in range(300)) + ' };\n' source += 'fn main() { gc(); put_n(member_299); put_c(10); return 0; }\n' run(source, '299\n') source = ''.join(f'enum tagged_{i} {{ item_{i} {{ int value; }}, empty_{i} }};\n' for i in range(25)) source += 'fn main() { tagged_24*.m item = tagged_24.item_24(7); gc(); put_n(item.item_24_value); put_c(10); return 0; }\n' run(source, '7\n') source = 'struct methods { int value;\n' source += ''.join(f'int get_{i}() {{ return this.value + {i}; }}\n' for i in range(100)) source += '}\nfn main() { methods item; item.value = 7; gc(); put_n(item.get_99()); put_c(10); return 0; }\n' run(source, '106\n') # grabfn owns a single token buffer while repeated growth moves replacements # into its released slot; the replayed method must survive compilation and gc. source = 'struct long_method { int seed; int count() { int value = 0;\n' source += 'value += 1;\n' * 400 source += 'return value + this.seed; } };\n' source += 'fn main() { long_method item; item.seed = 7; gc(); put_n(item.count()); put_c(10); return 0; }\n' run(source, '407\n') source = 'enum expanded {\n' source += ',\n'.join(f'member_with_long_generated_name_{i} {{ ' + ''.join(f'int field_with_long_generated_name_{j}; ' for j in range(8)) + '}' for i in range(40)) source += '\n};\nfn main() { gc(); put_n(ebcap > 8192); put_c(10); return 0; }\n' run(source, '1\n') source = 'fn main() { int result = 0; switch (127) {\n' source += ''.join(f'case {i}: result = {i};\n' for i in range(128)) source += '} gc(); put_n(result); put_c(32); put_n(jpscap > 64); put_c(10); return 0; }\n' run(source, '127 1\n') source = 'fn main() { int result = 0;\n' source += ''.join('o3 { result += 1; }\n' for _ in range(40)) source += 'gc(); put_n(result); put_c(32); put_n(o3pendcap > 10); put_c(10); return 0; }\n' run(source, '40 1\n') source = 'fn main() { int i = 0; while (i < 120) { putfact(i, i, 1); i++; } gc(); put_n(factcap > 32); put_c(32); put_n(getlo(119)); put_c(10); return 0; }\n' run(source, '1 119\n') long_type = 'structure_' + 't' * 180 long_method = 'method_' + 'm' * 180 source = f'struct {long_type} {{ int {long_method}() {{ return 7; }} }};\n' source += f'fn main() {{ {long_type} value; put_n(value.{long_method}()); put_c(10); return 0; }}\n' run(source, '7\n') name = 'generic_' + 'g' * 180 source = f'int {name}_one() {{ return sizeof(T); }}\nint {name}_two() {{ return sizeof(T) + 1; }}\n' source += f'fn main() {{ put_n({name}_one() + {name}_two()); put_c(10); return 0; }}\n' run(source, '3\n') print('ok parser tables, analyzer paths, queued regions, and generated names grow')