redscript-mc 1.2.29 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/.claude/commands/build-test.md +10 -0
  2. package/.claude/commands/deploy-demo.md +12 -0
  3. package/.claude/commands/stage-status.md +13 -0
  4. package/.claude/settings.json +12 -0
  5. package/.github/workflows/ci.yml +1 -0
  6. package/CLAUDE.md +231 -0
  7. package/README.md +29 -28
  8. package/README.zh.md +28 -28
  9. package/demo.gif +0 -0
  10. package/dist/cli.js +2 -554
  11. package/dist/compile.js +2 -266
  12. package/dist/index.js +2 -159
  13. package/dist/lexer/index.js +9 -1
  14. package/dist/lowering/index.js +22 -5
  15. package/dist/src/__tests__/cli.test.d.ts +1 -0
  16. package/dist/src/__tests__/cli.test.js +104 -0
  17. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  18. package/dist/src/__tests__/codegen.test.js +152 -0
  19. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  20. package/dist/src/__tests__/compile-all.test.js +108 -0
  21. package/dist/src/__tests__/dce.test.d.ts +1 -0
  22. package/dist/src/__tests__/dce.test.js +102 -0
  23. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  24. package/dist/src/__tests__/diagnostics.test.js +177 -0
  25. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  26. package/dist/src/__tests__/e2e.test.js +1789 -0
  27. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  28. package/dist/src/__tests__/entity-types.test.js +203 -0
  29. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  30. package/dist/src/__tests__/formatter.test.js +40 -0
  31. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  32. package/dist/src/__tests__/lexer.test.js +343 -0
  33. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  34. package/dist/src/__tests__/lowering.test.js +1015 -0
  35. package/dist/src/__tests__/macro.test.d.ts +8 -0
  36. package/dist/src/__tests__/macro.test.js +306 -0
  37. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  38. package/dist/src/__tests__/mc-integration.test.js +817 -0
  39. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  40. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  41. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  42. package/dist/src/__tests__/nbt.test.js +82 -0
  43. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  44. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  45. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  46. package/dist/src/__tests__/optimizer.test.js +149 -0
  47. package/dist/src/__tests__/parser.test.d.ts +1 -0
  48. package/dist/src/__tests__/parser.test.js +807 -0
  49. package/dist/src/__tests__/repl.test.d.ts +1 -0
  50. package/dist/src/__tests__/repl.test.js +27 -0
  51. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  52. package/dist/src/__tests__/runtime.test.js +289 -0
  53. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  54. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  55. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  56. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  57. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  58. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  59. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  60. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  61. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  62. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  63. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  64. package/dist/src/__tests__/typechecker.test.js +552 -0
  65. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  66. package/dist/src/__tests__/var-allocator.test.js +69 -0
  67. package/dist/src/ast/types.d.ts +515 -0
  68. package/dist/src/ast/types.js +9 -0
  69. package/dist/src/builtins/metadata.d.ts +36 -0
  70. package/dist/src/builtins/metadata.js +1014 -0
  71. package/dist/src/cli.d.ts +11 -0
  72. package/dist/src/cli.js +443 -0
  73. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  74. package/dist/src/codegen/cmdblock/index.js +45 -0
  75. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  76. package/dist/src/codegen/mcfunction/index.js +606 -0
  77. package/dist/src/codegen/structure/index.d.ts +24 -0
  78. package/dist/src/codegen/structure/index.js +279 -0
  79. package/dist/src/codegen/var-allocator.d.ts +45 -0
  80. package/dist/src/codegen/var-allocator.js +104 -0
  81. package/dist/src/compile.d.ts +37 -0
  82. package/dist/src/compile.js +165 -0
  83. package/dist/src/diagnostics/index.d.ts +44 -0
  84. package/dist/src/diagnostics/index.js +140 -0
  85. package/dist/src/events/types.d.ts +35 -0
  86. package/dist/src/events/types.js +59 -0
  87. package/dist/src/formatter/index.d.ts +1 -0
  88. package/dist/src/formatter/index.js +26 -0
  89. package/dist/src/index.d.ts +22 -0
  90. package/dist/src/index.js +45 -0
  91. package/dist/src/ir/builder.d.ts +33 -0
  92. package/dist/src/ir/builder.js +99 -0
  93. package/dist/src/ir/types.d.ts +132 -0
  94. package/dist/src/ir/types.js +15 -0
  95. package/dist/src/lexer/index.d.ts +37 -0
  96. package/dist/src/lexer/index.js +569 -0
  97. package/dist/src/lowering/index.d.ts +188 -0
  98. package/dist/src/lowering/index.js +3405 -0
  99. package/dist/src/mc-test/client.d.ts +128 -0
  100. package/dist/src/mc-test/client.js +174 -0
  101. package/dist/src/mc-test/runner.d.ts +28 -0
  102. package/dist/src/mc-test/runner.js +151 -0
  103. package/dist/src/mc-test/setup.d.ts +11 -0
  104. package/dist/src/mc-test/setup.js +98 -0
  105. package/dist/src/mc-validator/index.d.ts +17 -0
  106. package/dist/src/mc-validator/index.js +322 -0
  107. package/dist/src/nbt/index.d.ts +86 -0
  108. package/dist/src/nbt/index.js +250 -0
  109. package/dist/src/optimizer/commands.d.ts +38 -0
  110. package/dist/src/optimizer/commands.js +451 -0
  111. package/dist/src/optimizer/dce.d.ts +34 -0
  112. package/dist/src/optimizer/dce.js +639 -0
  113. package/dist/src/optimizer/passes.d.ts +34 -0
  114. package/dist/src/optimizer/passes.js +243 -0
  115. package/dist/src/optimizer/structure.d.ts +9 -0
  116. package/dist/src/optimizer/structure.js +356 -0
  117. package/dist/src/parser/index.d.ts +93 -0
  118. package/dist/src/parser/index.js +1687 -0
  119. package/dist/src/repl.d.ts +16 -0
  120. package/dist/src/repl.js +165 -0
  121. package/dist/src/runtime/index.d.ts +107 -0
  122. package/dist/src/runtime/index.js +1409 -0
  123. package/dist/src/typechecker/index.d.ts +61 -0
  124. package/dist/src/typechecker/index.js +1034 -0
  125. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  126. package/dist/src/types/entity-hierarchy.js +107 -0
  127. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  128. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  129. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  130. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  131. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  132. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  133. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  134. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  135. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  136. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  137. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  138. package/dist/src2/__tests__/lir/types.test.js +185 -0
  139. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  140. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  141. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  142. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  143. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  144. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  145. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  146. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  147. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  148. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  149. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  150. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  151. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  152. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  153. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  154. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  155. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  156. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  157. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  158. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  159. package/dist/src2/emit/compile.d.ts +19 -0
  160. package/dist/src2/emit/compile.js +80 -0
  161. package/dist/src2/emit/index.d.ts +17 -0
  162. package/dist/src2/emit/index.js +172 -0
  163. package/dist/src2/hir/lower.d.ts +15 -0
  164. package/dist/src2/hir/lower.js +378 -0
  165. package/dist/src2/hir/types.d.ts +373 -0
  166. package/dist/src2/hir/types.js +16 -0
  167. package/dist/src2/lir/lower.d.ts +15 -0
  168. package/dist/src2/lir/lower.js +453 -0
  169. package/dist/src2/lir/types.d.ts +136 -0
  170. package/dist/src2/lir/types.js +11 -0
  171. package/dist/src2/lir/verify.d.ts +14 -0
  172. package/dist/src2/lir/verify.js +113 -0
  173. package/dist/src2/mir/lower.d.ts +9 -0
  174. package/dist/src2/mir/lower.js +1030 -0
  175. package/dist/src2/mir/macro.d.ts +22 -0
  176. package/dist/src2/mir/macro.js +168 -0
  177. package/dist/src2/mir/types.d.ts +183 -0
  178. package/dist/src2/mir/types.js +11 -0
  179. package/dist/src2/mir/verify.d.ts +16 -0
  180. package/dist/src2/mir/verify.js +216 -0
  181. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  182. package/dist/src2/optimizer/block_merge.js +84 -0
  183. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  184. package/dist/src2/optimizer/branch_simplify.js +28 -0
  185. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  186. package/dist/src2/optimizer/constant_fold.js +85 -0
  187. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  188. package/dist/src2/optimizer/copy_prop.js +113 -0
  189. package/dist/src2/optimizer/dce.d.ts +8 -0
  190. package/dist/src2/optimizer/dce.js +155 -0
  191. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  192. package/dist/src2/optimizer/pipeline.js +42 -0
  193. package/dist/tsconfig.tsbuildinfo +1 -0
  194. package/docs/compiler-pipeline-redesign.md +2243 -0
  195. package/docs/optimization-ideas.md +1076 -0
  196. package/editors/vscode/package-lock.json +3 -3
  197. package/editors/vscode/package.json +1 -1
  198. package/examples/readme-demo.mcrs +44 -66
  199. package/jest.config.js +1 -1
  200. package/package.json +6 -5
  201. package/scripts/postbuild.js +15 -0
  202. package/src/__tests__/cli.test.ts +8 -220
  203. package/src/__tests__/dce.test.ts +11 -56
  204. package/src/__tests__/diagnostics.test.ts +59 -38
  205. package/src/__tests__/mc-integration.test.ts +1 -2
  206. package/src/ast/types.ts +6 -1
  207. package/src/cli.ts +29 -156
  208. package/src/compile.ts +6 -162
  209. package/src/index.ts +14 -178
  210. package/src/lexer/index.ts +9 -1
  211. package/src/mc-test/runner.ts +4 -3
  212. package/src/parser/index.ts +1 -1
  213. package/src/repl.ts +1 -1
  214. package/src/runtime/index.ts +1 -1
  215. package/src2/__tests__/e2e/basic.test.ts +154 -0
  216. package/src2/__tests__/e2e/macros.test.ts +199 -0
  217. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  218. package/src2/__tests__/hir/desugar.test.ts +263 -0
  219. package/src2/__tests__/lir/lower.test.ts +619 -0
  220. package/src2/__tests__/lir/types.test.ts +207 -0
  221. package/src2/__tests__/lir/verify.test.ts +249 -0
  222. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  223. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  224. package/src2/__tests__/mir/verify.test.ts +254 -0
  225. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  226. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  227. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  228. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  229. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  230. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  231. package/src2/emit/compile.ts +99 -0
  232. package/src2/emit/index.ts +222 -0
  233. package/src2/hir/lower.ts +428 -0
  234. package/src2/hir/types.ts +216 -0
  235. package/src2/lir/lower.ts +556 -0
  236. package/src2/lir/types.ts +109 -0
  237. package/src2/lir/verify.ts +129 -0
  238. package/src2/mir/lower.ts +1160 -0
  239. package/src2/mir/macro.ts +167 -0
  240. package/src2/mir/types.ts +106 -0
  241. package/src2/mir/verify.ts +218 -0
  242. package/src2/optimizer/block_merge.ts +93 -0
  243. package/src2/optimizer/branch_simplify.ts +27 -0
  244. package/src2/optimizer/constant_fold.ts +88 -0
  245. package/src2/optimizer/copy_prop.ts +106 -0
  246. package/src2/optimizer/dce.ts +133 -0
  247. package/src2/optimizer/pipeline.ts +44 -0
  248. package/tsconfig.json +2 -2
  249. package/src/__tests__/codegen.test.ts +0 -161
  250. package/src/__tests__/e2e.test.ts +0 -2039
  251. package/src/__tests__/entity-types.test.ts +0 -236
  252. package/src/__tests__/lowering.test.ts +0 -1185
  253. package/src/__tests__/macro.test.ts +0 -343
  254. package/src/__tests__/nbt.test.ts +0 -58
  255. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  256. package/src/__tests__/optimizer.test.ts +0 -162
  257. package/src/__tests__/runtime.test.ts +0 -305
  258. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  259. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  260. package/src/__tests__/stdlib-math.test.ts +0 -374
  261. package/src/__tests__/stdlib-vec.test.ts +0 -259
  262. package/src/__tests__/structure-optimizer.test.ts +0 -38
  263. package/src/__tests__/var-allocator.test.ts +0 -75
  264. package/src/codegen/cmdblock/index.ts +0 -63
  265. package/src/codegen/mcfunction/index.ts +0 -662
  266. package/src/codegen/structure/index.ts +0 -346
  267. package/src/codegen/var-allocator.ts +0 -104
  268. package/src/ir/builder.ts +0 -116
  269. package/src/ir/types.ts +0 -134
  270. package/src/lowering/index.ts +0 -3860
  271. package/src/optimizer/commands.ts +0 -534
  272. package/src/optimizer/dce.ts +0 -679
  273. package/src/optimizer/passes.ts +0 -250
  274. package/src/optimizer/structure.ts +0 -450
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lexer_1 = require("../../../src/lexer");
4
+ const parser_1 = require("../../../src/parser");
5
+ const lower_1 = require("../../hir/lower");
6
+ const lower_2 = require("../../mir/lower");
7
+ const verify_1 = require("../../mir/verify");
8
+ function compile(source) {
9
+ const tokens = new lexer_1.Lexer(source).tokenize();
10
+ const ast = new parser_1.Parser(tokens).parse('test');
11
+ const hir = (0, lower_1.lowerToHIR)(ast);
12
+ return (0, lower_2.lowerToMIR)(hir);
13
+ }
14
+ function getFn(mod, name) {
15
+ if (name)
16
+ return mod.functions.find(f => f.name === name);
17
+ return mod.functions[0];
18
+ }
19
+ function getBlock(fn, id) {
20
+ return fn.blocks.find(b => b.id === id);
21
+ }
22
+ describe('MIR lowering — if/else → branch CFG', () => {
23
+ test('if without else creates branch to then + merge', () => {
24
+ const mod = compile('fn f(x: int): int { if (x > 0) { return x; } return 0; }');
25
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
26
+ const fn = getFn(mod);
27
+ // Entry block should end with a branch
28
+ const entry = getBlock(fn, fn.entry);
29
+ expect(entry.term.kind).toBe('branch');
30
+ const branch = entry.term;
31
+ // Both targets should exist
32
+ expect(fn.blocks.some(b => b.id === branch.then)).toBe(true);
33
+ expect(fn.blocks.some(b => b.id === branch.else)).toBe(true);
34
+ });
35
+ test('if/else creates branch to then + else + merge', () => {
36
+ const mod = compile(`
37
+ fn f(x: int): int {
38
+ if (x > 0) { return 1; }
39
+ else { return -1; }
40
+ }
41
+ `);
42
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
43
+ const fn = getFn(mod);
44
+ const entry = getBlock(fn, fn.entry);
45
+ expect(entry.term.kind).toBe('branch');
46
+ const branch = entry.term;
47
+ const thenBlock = getBlock(fn, branch.then);
48
+ const elseBlock = getBlock(fn, branch.else);
49
+ // Both branches should have return terminators
50
+ expect(thenBlock.term.kind).toBe('return');
51
+ expect(elseBlock.term.kind).toBe('return');
52
+ });
53
+ test('nested if/else produces correct block structure', () => {
54
+ const mod = compile(`
55
+ fn f(x: int): int {
56
+ if (x > 0) {
57
+ if (x > 10) { return 2; }
58
+ return 1;
59
+ }
60
+ return 0;
61
+ }
62
+ `);
63
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
64
+ const fn = getFn(mod);
65
+ // Should have multiple blocks due to nesting
66
+ expect(fn.blocks.length).toBeGreaterThanOrEqual(4);
67
+ });
68
+ });
69
+ describe('MIR lowering — while → loop CFG', () => {
70
+ test('while loop creates header + body + exit blocks', () => {
71
+ const mod = compile(`
72
+ fn f(x: int): int {
73
+ let sum: int = 0;
74
+ while (x > 0) {
75
+ sum = sum + x;
76
+ x = x - 1;
77
+ }
78
+ return sum;
79
+ }
80
+ `);
81
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
82
+ const fn = getFn(mod);
83
+ // Find loop header block (has branch terminator based on condition)
84
+ const headerBlock = fn.blocks.find(b => b.id.startsWith('loop_header') && b.term.kind === 'branch');
85
+ expect(headerBlock).toBeDefined();
86
+ // Find loop body block
87
+ const bodyBlock = fn.blocks.find(b => b.id.startsWith('loop_body'));
88
+ expect(bodyBlock).toBeDefined();
89
+ // Find loop exit block
90
+ const exitBlock = fn.blocks.find(b => b.id.startsWith('loop_exit'));
91
+ expect(exitBlock).toBeDefined();
92
+ // Header should branch to body (then) and exit (else)
93
+ const branch = headerBlock.term;
94
+ expect(branch.then).toBe(bodyBlock.id);
95
+ expect(branch.else).toBe(exitBlock.id);
96
+ });
97
+ test('break jumps to loop exit', () => {
98
+ const mod = compile(`
99
+ fn f(x: int): void {
100
+ while (x > 0) {
101
+ if (x == 5) { break; }
102
+ x = x - 1;
103
+ }
104
+ }
105
+ `);
106
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
107
+ const fn = getFn(mod);
108
+ const exitBlock = fn.blocks.find(b => b.id.startsWith('loop_exit'));
109
+ expect(exitBlock).toBeDefined();
110
+ // Some block should jump directly to the exit (the break)
111
+ const breakBlock = fn.blocks.find(b => b.term.kind === 'jump' && b.term.target === exitBlock.id
112
+ && !b.id.startsWith('loop_header') && !b.id.startsWith('loop_exit')
113
+ && !b.id.startsWith('entry'));
114
+ expect(breakBlock).toBeDefined();
115
+ });
116
+ test('continue jumps to loop header', () => {
117
+ const mod = compile(`
118
+ fn f(x: int): void {
119
+ while (x > 0) {
120
+ x = x - 1;
121
+ if (x == 3) { continue; }
122
+ }
123
+ }
124
+ `);
125
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
126
+ const fn = getFn(mod);
127
+ const headerBlock = fn.blocks.find(b => b.id.startsWith('loop_header'));
128
+ expect(headerBlock).toBeDefined();
129
+ // Some block should jump to header (the continue)
130
+ const continueBlock = fn.blocks.find(b => b.term.kind === 'jump' && b.term.target === headerBlock.id
131
+ && !b.id.startsWith('loop_body') && !b.id.startsWith('entry'));
132
+ expect(continueBlock).toBeDefined();
133
+ });
134
+ });
135
+ describe('MIR lowering — short-circuit operators', () => {
136
+ test('&& produces branch (short-circuit)', () => {
137
+ const mod = compile('fn f(a: bool, b: bool): bool { return a && b; }');
138
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
139
+ const fn = getFn(mod);
140
+ // Should have and_right, and_false, and_merge blocks
141
+ expect(fn.blocks.some(b => b.id.startsWith('and_right'))).toBe(true);
142
+ expect(fn.blocks.some(b => b.id.startsWith('and_false'))).toBe(true);
143
+ expect(fn.blocks.some(b => b.id.startsWith('and_merge'))).toBe(true);
144
+ });
145
+ test('|| produces branch (short-circuit)', () => {
146
+ const mod = compile('fn f(a: bool, b: bool): bool { return a || b; }');
147
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
148
+ const fn = getFn(mod);
149
+ expect(fn.blocks.some(b => b.id.startsWith('or_true'))).toBe(true);
150
+ expect(fn.blocks.some(b => b.id.startsWith('or_right'))).toBe(true);
151
+ expect(fn.blocks.some(b => b.id.startsWith('or_merge'))).toBe(true);
152
+ });
153
+ });
154
+ describe('MIR lowering — return', () => {
155
+ test('void return', () => {
156
+ const mod = compile('fn f(): void { return; }');
157
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
158
+ const fn = getFn(mod);
159
+ const entry = getBlock(fn, fn.entry);
160
+ expect(entry.term.kind).toBe('return');
161
+ expect(entry.term.value).toBeNull();
162
+ });
163
+ test('value return', () => {
164
+ const mod = compile('fn f(): int { return 42; }');
165
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
166
+ const fn = getFn(mod);
167
+ const entry = getBlock(fn, fn.entry);
168
+ expect(entry.term.kind).toBe('return');
169
+ expect(entry.term.value).toEqual({ kind: 'const', value: 42 });
170
+ });
171
+ test('early return creates dead block for subsequent code', () => {
172
+ const mod = compile(`
173
+ fn f(x: int): int {
174
+ return x;
175
+ let y: int = 0;
176
+ }
177
+ `);
178
+ expect((0, verify_1.verifyMIR)(mod)).toEqual([]);
179
+ const fn = getFn(mod);
180
+ const entry = getBlock(fn, fn.entry);
181
+ expect(entry.term.kind).toBe('return');
182
+ });
183
+ });
184
+ describe('MIR lowering — all blocks reachable and well-formed', () => {
185
+ test('complex function verifies clean', () => {
186
+ const mod = compile(`
187
+ fn f(n: int): int {
188
+ let sum: int = 0;
189
+ let i: int = 0;
190
+ while (i < n) {
191
+ if (i % 2 == 0) {
192
+ sum = sum + i;
193
+ } else {
194
+ sum = sum - i;
195
+ }
196
+ i = i + 1;
197
+ }
198
+ return sum;
199
+ }
200
+ `);
201
+ const errors = (0, verify_1.verifyMIR)(mod);
202
+ expect(errors).toEqual([]);
203
+ });
204
+ });
205
+ //# sourceMappingURL=control-flow.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const verify_1 = require("../../mir/verify");
4
+ function makeModule(functions) {
5
+ return { functions, namespace: 'test', objective: '__test' };
6
+ }
7
+ function makeBlock(id, instrs, term, preds = []) {
8
+ return { id, instrs, term, preds };
9
+ }
10
+ describe('MIR verifier — terminator checks', () => {
11
+ test('rejects block without proper terminator', () => {
12
+ const fn = {
13
+ name: 'bad',
14
+ params: [],
15
+ blocks: [
16
+ makeBlock('entry', [], { kind: 'const', dst: 't0', value: 42 }),
17
+ ],
18
+ entry: 'entry',
19
+ isMacro: false,
20
+ };
21
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
22
+ expect(errors.length).toBeGreaterThan(0);
23
+ expect(errors[0].message).toContain('does not end with a terminator');
24
+ });
25
+ test('rejects terminator in non-terminal position', () => {
26
+ const fn = {
27
+ name: 'bad',
28
+ params: [],
29
+ blocks: [
30
+ makeBlock('entry', [{ kind: 'jump', target: 'entry' }], // terminator in instrs
31
+ { kind: 'return', value: null }),
32
+ ],
33
+ entry: 'entry',
34
+ isMacro: false,
35
+ };
36
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
37
+ expect(errors.length).toBeGreaterThan(0);
38
+ expect(errors[0].message).toContain('terminator');
39
+ expect(errors[0].message).toContain('non-terminal position');
40
+ });
41
+ test('accepts valid terminator (return)', () => {
42
+ const fn = {
43
+ name: 'good',
44
+ params: [],
45
+ blocks: [
46
+ makeBlock('entry', [], { kind: 'return', value: null }),
47
+ ],
48
+ entry: 'entry',
49
+ isMacro: false,
50
+ };
51
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
52
+ });
53
+ test('accepts valid terminator (jump)', () => {
54
+ const fn = {
55
+ name: 'good',
56
+ params: [],
57
+ blocks: [
58
+ makeBlock('entry', [], { kind: 'jump', target: 'b1' }),
59
+ makeBlock('b1', [], { kind: 'return', value: null }),
60
+ ],
61
+ entry: 'entry',
62
+ isMacro: false,
63
+ };
64
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
65
+ });
66
+ });
67
+ describe('MIR verifier — target existence', () => {
68
+ test('rejects jump to non-existent block', () => {
69
+ const fn = {
70
+ name: 'bad',
71
+ params: [],
72
+ blocks: [
73
+ makeBlock('entry', [], { kind: 'jump', target: 'nonexistent' }),
74
+ ],
75
+ entry: 'entry',
76
+ isMacro: false,
77
+ };
78
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
79
+ expect(errors.length).toBeGreaterThan(0);
80
+ expect(errors[0].message).toContain('non-existent target');
81
+ });
82
+ test('rejects branch to non-existent block', () => {
83
+ const fn = {
84
+ name: 'bad',
85
+ params: [],
86
+ blocks: [
87
+ makeBlock('entry', [
88
+ { kind: 'const', dst: 't0', value: 1 },
89
+ ], { kind: 'branch', cond: { kind: 'temp', name: 't0' }, then: 'yes', else: 'no' }),
90
+ ],
91
+ entry: 'entry',
92
+ isMacro: false,
93
+ };
94
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
95
+ expect(errors.length).toBe(2); // both targets missing
96
+ expect(errors[0].message).toContain('non-existent target');
97
+ });
98
+ });
99
+ describe('MIR verifier — reachability', () => {
100
+ test('rejects unreachable block', () => {
101
+ const fn = {
102
+ name: 'bad',
103
+ params: [],
104
+ blocks: [
105
+ makeBlock('entry', [], { kind: 'return', value: null }),
106
+ makeBlock('orphan', [], { kind: 'return', value: null }),
107
+ ],
108
+ entry: 'entry',
109
+ isMacro: false,
110
+ };
111
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
112
+ expect(errors.length).toBe(1);
113
+ expect(errors[0].message).toContain('unreachable');
114
+ expect(errors[0].block).toBe('orphan');
115
+ });
116
+ test('accepts all blocks reachable via jumps', () => {
117
+ const fn = {
118
+ name: 'good',
119
+ params: [],
120
+ blocks: [
121
+ makeBlock('entry', [], { kind: 'jump', target: 'b1' }),
122
+ makeBlock('b1', [], { kind: 'jump', target: 'b2' }),
123
+ makeBlock('b2', [], { kind: 'return', value: null }),
124
+ ],
125
+ entry: 'entry',
126
+ isMacro: false,
127
+ };
128
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
129
+ });
130
+ test('accepts blocks reachable via branch', () => {
131
+ const fn = {
132
+ name: 'good',
133
+ params: [],
134
+ blocks: [
135
+ makeBlock('entry', [
136
+ { kind: 'const', dst: 't0', value: 1 },
137
+ ], { kind: 'branch', cond: { kind: 'temp', name: 't0' }, then: 'yes', else: 'no' }),
138
+ makeBlock('yes', [], { kind: 'return', value: null }),
139
+ makeBlock('no', [], { kind: 'return', value: null }),
140
+ ],
141
+ entry: 'entry',
142
+ isMacro: false,
143
+ };
144
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
145
+ });
146
+ });
147
+ describe('MIR verifier — use-before-def', () => {
148
+ test('rejects use of undefined temp', () => {
149
+ const fn = {
150
+ name: 'bad',
151
+ params: [],
152
+ blocks: [
153
+ makeBlock('entry', [
154
+ { kind: 'copy', dst: 't0', src: { kind: 'temp', name: 'undefined_temp' } },
155
+ ], { kind: 'return', value: null }),
156
+ ],
157
+ entry: 'entry',
158
+ isMacro: false,
159
+ };
160
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
161
+ expect(errors.length).toBeGreaterThan(0);
162
+ expect(errors[0].message).toContain('undefined_temp');
163
+ expect(errors[0].message).toContain('never defined');
164
+ });
165
+ test('accepts temps defined as params', () => {
166
+ const fn = {
167
+ name: 'good',
168
+ params: [{ name: 't0', isMacroParam: false }],
169
+ blocks: [
170
+ makeBlock('entry', [], { kind: 'return', value: { kind: 'temp', name: 't0' } }),
171
+ ],
172
+ entry: 'entry',
173
+ isMacro: false,
174
+ };
175
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
176
+ });
177
+ test('accepts temps defined in instructions', () => {
178
+ const fn = {
179
+ name: 'good',
180
+ params: [],
181
+ blocks: [
182
+ makeBlock('entry', [
183
+ { kind: 'const', dst: 't0', value: 42 },
184
+ { kind: 'copy', dst: 't1', src: { kind: 'temp', name: 't0' } },
185
+ ], { kind: 'return', value: { kind: 'temp', name: 't1' } }),
186
+ ],
187
+ entry: 'entry',
188
+ isMacro: false,
189
+ };
190
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
191
+ });
192
+ test('const operands do not require definition', () => {
193
+ const fn = {
194
+ name: 'good',
195
+ params: [],
196
+ blocks: [
197
+ makeBlock('entry', [
198
+ { kind: 'const', dst: 't0', value: 5 },
199
+ { kind: 'add', dst: 't1', a: { kind: 'temp', name: 't0' }, b: { kind: 'const', value: 3 } },
200
+ ], { kind: 'return', value: { kind: 'temp', name: 't1' } }),
201
+ ],
202
+ entry: 'entry',
203
+ isMacro: false,
204
+ };
205
+ expect((0, verify_1.verifyMIR)(makeModule([fn]))).toEqual([]);
206
+ });
207
+ });
208
+ describe('MIR verifier — entry block', () => {
209
+ test('rejects missing entry block', () => {
210
+ const fn = {
211
+ name: 'bad',
212
+ params: [],
213
+ blocks: [
214
+ makeBlock('not_entry', [], { kind: 'return', value: null }),
215
+ ],
216
+ entry: 'entry',
217
+ isMacro: false,
218
+ };
219
+ const errors = (0, verify_1.verifyMIR)(makeModule([fn]));
220
+ expect(errors.some(e => e.message.includes('entry block'))).toBe(true);
221
+ });
222
+ });
223
+ //# sourceMappingURL=verify.test.js.map
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const block_merge_1 = require("../../optimizer/block_merge");
4
+ function mkFn(blocks, entry = 'entry') {
5
+ return { name: 'test', params: [], blocks, entry, isMacro: false };
6
+ }
7
+ function mkBlock(id, instrs, term, preds = []) {
8
+ return { id, instrs, term, preds };
9
+ }
10
+ const c = (v) => ({ kind: 'const', value: v });
11
+ const t = (n) => ({ kind: 'temp', name: n });
12
+ describe('block merging', () => {
13
+ test('merges single-pred successor into predecessor', () => {
14
+ const fn = mkFn([
15
+ mkBlock('entry', [
16
+ { kind: 'const', dst: 't0', value: 1 },
17
+ ], { kind: 'jump', target: 'b1' }),
18
+ mkBlock('b1', [
19
+ { kind: 'const', dst: 't1', value: 2 },
20
+ ], { kind: 'return', value: t('t1') }, ['entry']),
21
+ ]);
22
+ const result = (0, block_merge_1.blockMerge)(fn);
23
+ expect(result.blocks).toHaveLength(1);
24
+ expect(result.blocks[0].id).toBe('entry');
25
+ expect(result.blocks[0].instrs).toHaveLength(2);
26
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: t('t1') });
27
+ });
28
+ test('does not merge when successor has multiple preds', () => {
29
+ const fn = mkFn([
30
+ mkBlock('entry', [], { kind: 'branch', cond: t('c'), then: 'b1', else: 'b2' }),
31
+ mkBlock('b1', [], { kind: 'jump', target: 'merge' }, ['entry']),
32
+ mkBlock('b2', [], { kind: 'jump', target: 'merge' }, ['entry']),
33
+ mkBlock('merge', [], { kind: 'return', value: null }, ['b1', 'b2']),
34
+ ]);
35
+ const result = (0, block_merge_1.blockMerge)(fn);
36
+ // merge has 2 preds → no merging of merge block
37
+ expect(result.blocks.length).toBeGreaterThanOrEqual(3);
38
+ expect(result.blocks.some(b => b.id === 'merge')).toBe(true);
39
+ });
40
+ test('does not merge entry block into predecessor', () => {
41
+ // Entry block should never be merged away
42
+ const fn = mkFn([
43
+ mkBlock('entry', [], { kind: 'jump', target: 'b1' }),
44
+ mkBlock('b1', [], { kind: 'return', value: null }, ['entry']),
45
+ ]);
46
+ const result = (0, block_merge_1.blockMerge)(fn);
47
+ // b1 has single pred → merged into entry
48
+ expect(result.blocks).toHaveLength(1);
49
+ expect(result.blocks[0].id).toBe('entry');
50
+ });
51
+ test('chains merges: A→B→C all single-pred', () => {
52
+ const fn = mkFn([
53
+ mkBlock('entry', [
54
+ { kind: 'const', dst: 't0', value: 1 },
55
+ ], { kind: 'jump', target: 'b1' }),
56
+ mkBlock('b1', [
57
+ { kind: 'const', dst: 't1', value: 2 },
58
+ ], { kind: 'jump', target: 'b2' }, ['entry']),
59
+ mkBlock('b2', [
60
+ { kind: 'const', dst: 't2', value: 3 },
61
+ ], { kind: 'return', value: t('t2') }, ['b1']),
62
+ ]);
63
+ const result = (0, block_merge_1.blockMerge)(fn);
64
+ expect(result.blocks).toHaveLength(1);
65
+ expect(result.blocks[0].instrs).toHaveLength(3);
66
+ });
67
+ test('recomputes preds after merge', () => {
68
+ const fn = mkFn([
69
+ mkBlock('entry', [], { kind: 'jump', target: 'b1' }),
70
+ mkBlock('b1', [], { kind: 'jump', target: 'b2' }, ['entry']),
71
+ mkBlock('b2', [], { kind: 'return', value: null }, ['b1']),
72
+ ]);
73
+ const result = (0, block_merge_1.blockMerge)(fn);
74
+ expect(result.blocks).toHaveLength(1);
75
+ expect(result.blocks[0].preds).toEqual([]);
76
+ });
77
+ });
78
+ //# sourceMappingURL=block_merge.test.js.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const branch_simplify_1 = require("../../optimizer/branch_simplify");
4
+ function mkFn(blocks) {
5
+ return { name: 'test', params: [], blocks, entry: 'entry', isMacro: false };
6
+ }
7
+ function mkBlock(id, instrs, term, preds = []) {
8
+ return { id, instrs, term, preds };
9
+ }
10
+ const c = (v) => ({ kind: 'const', value: v });
11
+ const t = (n) => ({ kind: 'temp', name: n });
12
+ describe('branch simplification', () => {
13
+ test('branch(1, then, else) → jump(then)', () => {
14
+ const fn = mkFn([
15
+ mkBlock('entry', [], { kind: 'branch', cond: c(1), then: 'b1', else: 'b2' }),
16
+ mkBlock('b1', [], { kind: 'return', value: null }, ['entry']),
17
+ mkBlock('b2', [], { kind: 'return', value: null }, ['entry']),
18
+ ]);
19
+ const result = (0, branch_simplify_1.branchSimplify)(fn);
20
+ expect(result.blocks[0].term).toEqual({ kind: 'jump', target: 'b1' });
21
+ });
22
+ test('branch(0, then, else) → jump(else)', () => {
23
+ const fn = mkFn([
24
+ mkBlock('entry', [], { kind: 'branch', cond: c(0), then: 'b1', else: 'b2' }),
25
+ mkBlock('b1', [], { kind: 'return', value: null }, ['entry']),
26
+ mkBlock('b2', [], { kind: 'return', value: null }, ['entry']),
27
+ ]);
28
+ const result = (0, branch_simplify_1.branchSimplify)(fn);
29
+ expect(result.blocks[0].term).toEqual({ kind: 'jump', target: 'b2' });
30
+ });
31
+ test('nonzero const (42) → jump(then)', () => {
32
+ const fn = mkFn([
33
+ mkBlock('entry', [], { kind: 'branch', cond: c(42), then: 'b1', else: 'b2' }),
34
+ mkBlock('b1', [], { kind: 'return', value: null }),
35
+ mkBlock('b2', [], { kind: 'return', value: null }),
36
+ ]);
37
+ const result = (0, branch_simplify_1.branchSimplify)(fn);
38
+ expect(result.blocks[0].term).toEqual({ kind: 'jump', target: 'b1' });
39
+ });
40
+ test('does not simplify branch with temp cond', () => {
41
+ const fn = mkFn([
42
+ mkBlock('entry', [], { kind: 'branch', cond: t('flag'), then: 'b1', else: 'b2' }),
43
+ mkBlock('b1', [], { kind: 'return', value: null }),
44
+ mkBlock('b2', [], { kind: 'return', value: null }),
45
+ ]);
46
+ const result = (0, branch_simplify_1.branchSimplify)(fn);
47
+ expect(result.blocks[0].term.kind).toBe('branch');
48
+ });
49
+ test('does not touch jump terminators', () => {
50
+ const fn = mkFn([
51
+ mkBlock('entry', [], { kind: 'jump', target: 'b1' }),
52
+ mkBlock('b1', [], { kind: 'return', value: null }),
53
+ ]);
54
+ const result = (0, branch_simplify_1.branchSimplify)(fn);
55
+ expect(result.blocks[0].term).toEqual({ kind: 'jump', target: 'b1' });
56
+ });
57
+ });
58
+ //# sourceMappingURL=branch_simplify.test.js.map