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,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const constant_fold_1 = require("../../optimizer/constant_fold");
4
+ function mkFn(blocks) {
5
+ return { name: 'test', params: [], blocks, entry: 'entry', isMacro: false };
6
+ }
7
+ function mkBlock(id, instrs, term) {
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('constant folding', () => {
13
+ test('folds add(const, const)', () => {
14
+ const fn = mkFn([
15
+ mkBlock('entry', [
16
+ { kind: 'add', dst: 't0', a: c(3), b: c(4) },
17
+ ], { kind: 'return', value: t('t0') }),
18
+ ]);
19
+ const result = (0, constant_fold_1.constantFold)(fn);
20
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 7 });
21
+ });
22
+ test('folds sub(const, const)', () => {
23
+ const fn = mkFn([
24
+ mkBlock('entry', [
25
+ { kind: 'sub', dst: 't0', a: c(10), b: c(3) },
26
+ ], { kind: 'return', value: t('t0') }),
27
+ ]);
28
+ const result = (0, constant_fold_1.constantFold)(fn);
29
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 7 });
30
+ });
31
+ test('folds mul(const, const)', () => {
32
+ const fn = mkFn([
33
+ mkBlock('entry', [
34
+ { kind: 'mul', dst: 't0', a: c(3), b: c(5) },
35
+ ], { kind: 'return', value: t('t0') }),
36
+ ]);
37
+ const result = (0, constant_fold_1.constantFold)(fn);
38
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 15 });
39
+ });
40
+ test('folds div(const, const) with truncation', () => {
41
+ const fn = mkFn([
42
+ mkBlock('entry', [
43
+ { kind: 'div', dst: 't0', a: c(7), b: c(2) },
44
+ ], { kind: 'return', value: t('t0') }),
45
+ ]);
46
+ const result = (0, constant_fold_1.constantFold)(fn);
47
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 3 });
48
+ });
49
+ test('does not fold div by zero', () => {
50
+ const fn = mkFn([
51
+ mkBlock('entry', [
52
+ { kind: 'div', dst: 't0', a: c(7), b: c(0) },
53
+ ], { kind: 'return', value: t('t0') }),
54
+ ]);
55
+ const result = (0, constant_fold_1.constantFold)(fn);
56
+ expect(result.blocks[0].instrs[0].kind).toBe('div');
57
+ });
58
+ test('folds mod(const, const)', () => {
59
+ const fn = mkFn([
60
+ mkBlock('entry', [
61
+ { kind: 'mod', dst: 't0', a: c(7), b: c(3) },
62
+ ], { kind: 'return', value: t('t0') }),
63
+ ]);
64
+ const result = (0, constant_fold_1.constantFold)(fn);
65
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 1 });
66
+ });
67
+ test('folds neg(const)', () => {
68
+ const fn = mkFn([
69
+ mkBlock('entry', [
70
+ { kind: 'neg', dst: 't0', src: c(5) },
71
+ ], { kind: 'return', value: t('t0') }),
72
+ ]);
73
+ const result = (0, constant_fold_1.constantFold)(fn);
74
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: -5 });
75
+ });
76
+ test('folds not(0) → 1', () => {
77
+ const fn = mkFn([
78
+ mkBlock('entry', [
79
+ { kind: 'not', dst: 't0', src: c(0) },
80
+ ], { kind: 'return', value: t('t0') }),
81
+ ]);
82
+ const result = (0, constant_fold_1.constantFold)(fn);
83
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 1 });
84
+ });
85
+ test('folds cmp(lt, 3, 4) → 1', () => {
86
+ const fn = mkFn([
87
+ mkBlock('entry', [
88
+ { kind: 'cmp', dst: 't0', op: 'lt', a: c(3), b: c(4) },
89
+ ], { kind: 'return', value: t('t0') }),
90
+ ]);
91
+ const result = (0, constant_fold_1.constantFold)(fn);
92
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 1 });
93
+ });
94
+ test('folds cmp(eq, 5, 5) → 1', () => {
95
+ const fn = mkFn([
96
+ mkBlock('entry', [
97
+ { kind: 'cmp', dst: 't0', op: 'eq', a: c(5), b: c(5) },
98
+ ], { kind: 'return', value: t('t0') }),
99
+ ]);
100
+ const result = (0, constant_fold_1.constantFold)(fn);
101
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 1 });
102
+ });
103
+ test('folds and(1, 0) → 0', () => {
104
+ const fn = mkFn([
105
+ mkBlock('entry', [
106
+ { kind: 'and', dst: 't0', a: c(1), b: c(0) },
107
+ ], { kind: 'return', value: t('t0') }),
108
+ ]);
109
+ const result = (0, constant_fold_1.constantFold)(fn);
110
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 0 });
111
+ });
112
+ test('folds or(0, 1) → 1', () => {
113
+ const fn = mkFn([
114
+ mkBlock('entry', [
115
+ { kind: 'or', dst: 't0', a: c(0), b: c(1) },
116
+ ], { kind: 'return', value: t('t0') }),
117
+ ]);
118
+ const result = (0, constant_fold_1.constantFold)(fn);
119
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 't0', value: 1 });
120
+ });
121
+ test('does not fold when operand is temp', () => {
122
+ const fn = mkFn([
123
+ mkBlock('entry', [
124
+ { kind: 'add', dst: 't0', a: t('a'), b: c(4) },
125
+ ], { kind: 'return', value: t('t0') }),
126
+ ]);
127
+ const result = (0, constant_fold_1.constantFold)(fn);
128
+ expect(result.blocks[0].instrs[0].kind).toBe('add');
129
+ });
130
+ });
131
+ //# sourceMappingURL=constant_fold.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const copy_prop_1 = require("../../optimizer/copy_prop");
4
+ function mkFn(blocks) {
5
+ return { name: 'test', params: [], blocks, entry: 'entry', isMacro: false };
6
+ }
7
+ function mkBlock(id, instrs, term) {
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('copy propagation', () => {
13
+ test('propagates copy into subsequent use', () => {
14
+ const fn = mkFn([
15
+ mkBlock('entry', [
16
+ { kind: 'copy', dst: 'x', src: t('y') },
17
+ { kind: 'add', dst: 'z', a: t('x'), b: c(1) },
18
+ ], { kind: 'return', value: t('z') }),
19
+ ]);
20
+ const result = (0, copy_prop_1.copyProp)(fn);
21
+ const add = result.blocks[0].instrs[1];
22
+ expect(add.kind).toBe('add');
23
+ expect(add.a).toEqual(t('y'));
24
+ });
25
+ test('propagates into terminator', () => {
26
+ const fn = mkFn([
27
+ mkBlock('entry', [
28
+ { kind: 'copy', dst: 'x', src: t('y') },
29
+ ], { kind: 'return', value: t('x') }),
30
+ ]);
31
+ const result = (0, copy_prop_1.copyProp)(fn);
32
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: t('y') });
33
+ });
34
+ test('invalidates mapping when source is redefined', () => {
35
+ const fn = mkFn([
36
+ mkBlock('entry', [
37
+ { kind: 'copy', dst: 'x', src: t('y') },
38
+ { kind: 'const', dst: 'y', value: 99 },
39
+ { kind: 'add', dst: 'z', a: t('x'), b: c(1) },
40
+ ], { kind: 'return', value: t('z') }),
41
+ ]);
42
+ const result = (0, copy_prop_1.copyProp)(fn);
43
+ // x's mapping was invalidated because y was redefined
44
+ const add = result.blocks[0].instrs[2];
45
+ expect(add.a).toEqual(t('x'));
46
+ });
47
+ test('propagates const definitions into uses', () => {
48
+ const fn = mkFn([
49
+ mkBlock('entry', [
50
+ { kind: 'const', dst: 'x', value: 42 },
51
+ { kind: 'add', dst: 'z', a: t('x'), b: c(1) },
52
+ ], { kind: 'return', value: t('z') }),
53
+ ]);
54
+ const result = (0, copy_prop_1.copyProp)(fn);
55
+ const add = result.blocks[0].instrs[1];
56
+ expect(add.a).toEqual(c(42));
57
+ });
58
+ test('propagates copy-of-const into uses', () => {
59
+ const fn = mkFn([
60
+ mkBlock('entry', [
61
+ { kind: 'copy', dst: 'x', src: c(42) },
62
+ { kind: 'add', dst: 'z', a: t('x'), b: c(1) },
63
+ ], { kind: 'return', value: t('z') }),
64
+ ]);
65
+ const result = (0, copy_prop_1.copyProp)(fn);
66
+ const add = result.blocks[0].instrs[1];
67
+ expect(add.a).toEqual(c(42));
68
+ });
69
+ test('chains propagation: x=y, z=x → z uses y', () => {
70
+ const fn = mkFn([
71
+ mkBlock('entry', [
72
+ { kind: 'copy', dst: 'x', src: t('y') },
73
+ { kind: 'copy', dst: 'z', src: t('x') },
74
+ ], { kind: 'return', value: t('z') }),
75
+ ]);
76
+ const result = (0, copy_prop_1.copyProp)(fn);
77
+ // z = copy x → rewritten to z = copy y
78
+ // then return z → rewritten to return y
79
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: t('y') });
80
+ });
81
+ test('propagates into branch condition', () => {
82
+ const fn = mkFn([
83
+ mkBlock('entry', [
84
+ { kind: 'copy', dst: 'c', src: t('flag') },
85
+ ], { kind: 'branch', cond: t('c'), then: 'b1', else: 'b2' }),
86
+ ]);
87
+ const result = (0, copy_prop_1.copyProp)(fn);
88
+ expect(result.blocks[0].term).toEqual({ kind: 'branch', cond: t('flag'), then: 'b1', else: 'b2' });
89
+ });
90
+ });
91
+ //# sourceMappingURL=copy_prop.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const dce_1 = require("../../optimizer/dce");
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('dead code elimination', () => {
13
+ test('removes unused temp definition', () => {
14
+ const fn = mkFn([
15
+ mkBlock('entry', [
16
+ { kind: 'const', dst: 'dead', value: 42 },
17
+ { kind: 'const', dst: 'live', value: 1 },
18
+ ], { kind: 'return', value: t('live') }),
19
+ ]);
20
+ const result = (0, dce_1.dce)(fn);
21
+ expect(result.blocks[0].instrs).toHaveLength(1);
22
+ expect(result.blocks[0].instrs[0]).toEqual({ kind: 'const', dst: 'live', value: 1 });
23
+ });
24
+ test('keeps side-effectful instructions even if dst unused', () => {
25
+ const fn = mkFn([
26
+ mkBlock('entry', [
27
+ { kind: 'call', dst: 'unused', fn: 'sideEffect', args: [] },
28
+ ], { kind: 'return', value: null }),
29
+ ]);
30
+ const result = (0, dce_1.dce)(fn);
31
+ expect(result.blocks[0].instrs).toHaveLength(1);
32
+ });
33
+ test('removes unreachable blocks', () => {
34
+ const fn = mkFn([
35
+ mkBlock('entry', [], { kind: 'return', value: null }),
36
+ mkBlock('dead_block', [
37
+ { kind: 'const', dst: 't0', value: 99 },
38
+ ], { kind: 'return', value: t('t0') }),
39
+ ]);
40
+ const result = (0, dce_1.dce)(fn);
41
+ expect(result.blocks).toHaveLength(1);
42
+ expect(result.blocks[0].id).toBe('entry');
43
+ });
44
+ test('keeps reachable blocks', () => {
45
+ const fn = mkFn([
46
+ mkBlock('entry', [
47
+ { kind: 'const', dst: 't0', value: 1 },
48
+ ], { kind: 'branch', cond: t('t0'), then: 'b1', else: 'b2' }),
49
+ mkBlock('b1', [], { kind: 'return', value: null }, ['entry']),
50
+ mkBlock('b2', [], { kind: 'return', value: null }, ['entry']),
51
+ ]);
52
+ const result = (0, dce_1.dce)(fn);
53
+ expect(result.blocks).toHaveLength(3);
54
+ });
55
+ test('recomputes preds after block removal', () => {
56
+ const fn = mkFn([
57
+ mkBlock('entry', [], { kind: 'jump', target: 'b1' }),
58
+ mkBlock('b1', [], { kind: 'return', value: null }, ['entry']),
59
+ mkBlock('dead', [], { kind: 'jump', target: 'b1' }),
60
+ ]);
61
+ const result = (0, dce_1.dce)(fn);
62
+ expect(result.blocks).toHaveLength(2);
63
+ const b1 = result.blocks.find(b => b.id === 'b1');
64
+ expect(b1.preds).toEqual(['entry']);
65
+ });
66
+ test('keeps nbt_write even though it has no dst', () => {
67
+ const fn = mkFn([
68
+ mkBlock('entry', [
69
+ { kind: 'nbt_write', ns: 'rs:data', path: 'x', type: 'int', scale: 1, src: c(5) },
70
+ ], { kind: 'return', value: null }),
71
+ ]);
72
+ const result = (0, dce_1.dce)(fn);
73
+ expect(result.blocks[0].instrs).toHaveLength(1);
74
+ });
75
+ });
76
+ //# sourceMappingURL=dce.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const pipeline_1 = require("../../optimizer/pipeline");
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('optimization pipeline', () => {
13
+ test('constant fold + branch simplify + DCE removes dead branch', () => {
14
+ // cmp(lt, 1, 2) → 1 → branch(1, then, else) → jump(then) → else is dead
15
+ const fn = mkFn([
16
+ mkBlock('entry', [
17
+ { kind: 'cmp', dst: 't0', op: 'lt', a: c(1), b: c(2) },
18
+ ], { kind: 'branch', cond: t('t0'), then: 'then', else: 'else' }),
19
+ mkBlock('then', [], { kind: 'return', value: c(1) }, ['entry']),
20
+ mkBlock('else', [], { kind: 'return', value: c(0) }, ['entry']),
21
+ ]);
22
+ const result = (0, pipeline_1.optimizeFunction)(fn);
23
+ // After optimization: entry should return 1 directly, else block removed
24
+ // The cmp folds to const 1, branch simplifies to jump(then),
25
+ // else block becomes unreachable and is removed,
26
+ // then block merges into entry
27
+ expect(result.blocks).toHaveLength(1);
28
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: c(1) });
29
+ });
30
+ test('copy prop + const fold + DCE eliminates dead copy and folds', () => {
31
+ const fn = mkFn([
32
+ mkBlock('entry', [
33
+ { kind: 'const', dst: 'a', value: 5 },
34
+ { kind: 'copy', dst: 'b', src: t('a') },
35
+ { kind: 'add', dst: 'c', a: t('b'), b: c(1) },
36
+ ], { kind: 'return', value: t('c') }),
37
+ ]);
38
+ const result = (0, pipeline_1.optimizeFunction)(fn);
39
+ // const a=5 propagated into copy and add, add(5,1) folded to 6
40
+ // all dead defs removed, returns const 6
41
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: c(6) });
42
+ });
43
+ test('full pipeline: fold + simplify + merge + dce', () => {
44
+ // if (3 > 2) { return 10 + 20; } else { return 0; }
45
+ const fn = mkFn([
46
+ mkBlock('entry', [
47
+ { kind: 'cmp', dst: 't0', op: 'gt', a: c(3), b: c(2) },
48
+ ], { kind: 'branch', cond: t('t0'), then: 'then', else: 'else' }),
49
+ mkBlock('then', [
50
+ { kind: 'add', dst: 't1', a: c(10), b: c(20) },
51
+ ], { kind: 'return', value: t('t1') }, ['entry']),
52
+ mkBlock('else', [], { kind: 'return', value: c(0) }, ['entry']),
53
+ ]);
54
+ const result = (0, pipeline_1.optimizeFunction)(fn);
55
+ // Everything folds away: single block returning const 30
56
+ expect(result.blocks).toHaveLength(1);
57
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: c(30) });
58
+ });
59
+ test('optimizeModule applies to all functions', () => {
60
+ const mod = {
61
+ namespace: 'test',
62
+ objective: '__test',
63
+ functions: [
64
+ mkFn([
65
+ mkBlock('entry', [
66
+ { kind: 'add', dst: 't0', a: c(1), b: c(2) },
67
+ ], { kind: 'return', value: t('t0') }),
68
+ ]),
69
+ mkFn([
70
+ mkBlock('entry', [
71
+ { kind: 'mul', dst: 't0', a: c(3), b: c(4) },
72
+ ], { kind: 'return', value: t('t0') }),
73
+ ]),
74
+ ],
75
+ };
76
+ const result = (0, pipeline_1.optimizeModule)(mod);
77
+ // Both functions should have their constants folded
78
+ for (const fn of result.functions) {
79
+ const instrs = fn.blocks[0].instrs;
80
+ const hasArith = instrs.some(i => i.kind === 'add' || i.kind === 'mul');
81
+ expect(hasArith).toBe(false);
82
+ }
83
+ });
84
+ test('fixpoint: multiple iterations needed', () => {
85
+ // First iteration: fold add → const, fold cmp → const
86
+ // Second iteration: branch simplify on newly-const cond
87
+ // Third iteration: DCE removes dead block, merge
88
+ const fn = mkFn([
89
+ mkBlock('entry', [
90
+ { kind: 'add', dst: 't0', a: c(1), b: c(1) },
91
+ { kind: 'cmp', dst: 't1', op: 'eq', a: t('t0'), b: c(2) },
92
+ ], { kind: 'branch', cond: t('t1'), then: 'yes', else: 'no' }),
93
+ mkBlock('yes', [], { kind: 'return', value: c(1) }, ['entry']),
94
+ mkBlock('no', [], { kind: 'return', value: c(0) }, ['entry']),
95
+ ]);
96
+ const result = (0, pipeline_1.optimizeFunction)(fn);
97
+ // 1+1=2, 2==2 → 1, branch(1) → jump(yes), dead block removed, merged
98
+ expect(result.blocks).toHaveLength(1);
99
+ expect(result.blocks[0].term).toEqual({ kind: 'return', value: c(1) });
100
+ });
101
+ });
102
+ //# sourceMappingURL=pipeline.test.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Top-level compile function for the v2 pipeline.
3
+ *
4
+ * Pipeline: source → Lexer → Parser → HIR → MIR → optimize → LIR → emit
5
+ */
6
+ import { type DatapackFile } from './index';
7
+ export interface CompileOptions {
8
+ namespace?: string;
9
+ filePath?: string;
10
+ /** v1 compat: inline library sources (treated as `module library;` imports) */
11
+ librarySources?: string[];
12
+ }
13
+ export interface CompileResult {
14
+ files: DatapackFile[];
15
+ warnings: string[];
16
+ /** Always true — v1 compat shim (compile() throws on error) */
17
+ readonly success: true;
18
+ }
19
+ export declare function compile(source: string, options?: CompileOptions): CompileResult;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * Top-level compile function for the v2 pipeline.
4
+ *
5
+ * Pipeline: source → Lexer → Parser → HIR → MIR → optimize → LIR → emit
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.compile = compile;
9
+ const lexer_1 = require("../../src/lexer");
10
+ const parser_1 = require("../../src/parser");
11
+ const compile_1 = require("../../src/compile");
12
+ const lower_1 = require("../hir/lower");
13
+ const lower_2 = require("../mir/lower");
14
+ const pipeline_1 = require("../optimizer/pipeline");
15
+ const lower_3 = require("../lir/lower");
16
+ const index_1 = require("./index");
17
+ function compile(source, options = {}) {
18
+ const { namespace = 'redscript', filePath } = options;
19
+ const warnings = [];
20
+ // Preprocess: resolve import directives, merge imported sources
21
+ const preprocessed = (0, compile_1.preprocessSourceWithMetadata)(source, { filePath });
22
+ const processedSource = preprocessed.source;
23
+ // Stage 1: Lex + Parse → AST
24
+ const lexer = new lexer_1.Lexer(processedSource);
25
+ const tokens = lexer.tokenize();
26
+ const parser = new parser_1.Parser(tokens, processedSource, filePath);
27
+ const ast = parser.parse(namespace);
28
+ // Merge library imports (files with `module library;`) into AST
29
+ for (const li of preprocessed.libraryImports ?? []) {
30
+ const libPreprocessed = (0, compile_1.preprocessSourceWithMetadata)(li.source, { filePath: li.filePath });
31
+ const libTokens = new lexer_1.Lexer(libPreprocessed.source, li.filePath).tokenize();
32
+ const libAst = new parser_1.Parser(libTokens, libPreprocessed.source, li.filePath).parse(namespace);
33
+ for (const fn of libAst.declarations)
34
+ fn.isLibraryFn = true;
35
+ ast.declarations.push(...libAst.declarations);
36
+ ast.structs.push(...libAst.structs);
37
+ ast.implBlocks.push(...libAst.implBlocks);
38
+ ast.enums.push(...libAst.enums);
39
+ ast.consts.push(...libAst.consts);
40
+ ast.globals.push(...libAst.globals);
41
+ }
42
+ // Merge librarySources (v1 compat: inline library strings) before HIR
43
+ if (options.librarySources) {
44
+ for (const libSrc of options.librarySources) {
45
+ const libTokens = new lexer_1.Lexer(libSrc).tokenize();
46
+ const libAst = new parser_1.Parser(libTokens, libSrc).parse(namespace);
47
+ for (const fn of libAst.declarations)
48
+ fn.isLibraryFn = true;
49
+ ast.declarations.push(...libAst.declarations);
50
+ ast.structs.push(...libAst.structs);
51
+ ast.implBlocks.push(...libAst.implBlocks);
52
+ ast.enums.push(...libAst.enums);
53
+ ast.consts.push(...libAst.consts);
54
+ ast.globals.push(...libAst.globals);
55
+ }
56
+ }
57
+ // Stage 2: AST → HIR
58
+ const hir = (0, lower_1.lowerToHIR)(ast);
59
+ // Extract @tick and @load functions from HIR (before decorator info is lost)
60
+ const tickFunctions = [];
61
+ const loadFunctions = [];
62
+ for (const fn of hir.functions) {
63
+ for (const dec of fn.decorators) {
64
+ if (dec.name === 'tick')
65
+ tickFunctions.push(fn.name);
66
+ if (dec.name === 'load')
67
+ loadFunctions.push(fn.name);
68
+ }
69
+ }
70
+ // Stage 3: HIR → MIR
71
+ const mir = (0, lower_2.lowerToMIR)(hir);
72
+ // Stage 4: MIR optimization
73
+ const mirOpt = (0, pipeline_1.optimizeModule)(mir);
74
+ // Stage 5: MIR → LIR
75
+ const lir = (0, lower_3.lowerToLIR)(mirOpt);
76
+ // Stage 7: LIR → .mcfunction
77
+ const files = (0, index_1.emit)(lir, { namespace, tickFunctions, loadFunctions });
78
+ return { files, warnings, success: true };
79
+ }
80
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Stage 7 — LIR → .mcfunction Emission
3
+ *
4
+ * Converts a LIRModule into DatapackFile[] representing a Minecraft datapack.
5
+ * Each LIRFunction becomes a .mcfunction file under data/<ns>/function/.
6
+ */
7
+ import type { LIRModule } from '../lir/types';
8
+ export interface DatapackFile {
9
+ path: string;
10
+ content: string;
11
+ }
12
+ export interface EmitOptions {
13
+ namespace: string;
14
+ tickFunctions?: string[];
15
+ loadFunctions?: string[];
16
+ }
17
+ export declare function emit(module: LIRModule, options: EmitOptions): DatapackFile[];