1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/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<T>() {{ return sizeof(T); }}\nint {name}_two<T>() {{ return sizeof(T) + 1; }}\n'
source += f'fn main() {{ put_n({name}_one<int>() + {name}_two<int>()); put_c(10); return 0; }}\n'
run(source, '3\n')
print('ok parser tables, analyzer paths, queued regions, and generated names grow')
|