redscript-mc 1.2.30 → 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 (269) 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/demo.gif +0 -0
  8. package/dist/cli.js +2 -554
  9. package/dist/compile.js +2 -266
  10. package/dist/index.js +2 -159
  11. package/dist/lowering/index.js +5 -3
  12. package/dist/src/__tests__/cli.test.d.ts +1 -0
  13. package/dist/src/__tests__/cli.test.js +104 -0
  14. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  15. package/dist/src/__tests__/codegen.test.js +152 -0
  16. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  17. package/dist/src/__tests__/compile-all.test.js +108 -0
  18. package/dist/src/__tests__/dce.test.d.ts +1 -0
  19. package/dist/src/__tests__/dce.test.js +102 -0
  20. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  21. package/dist/src/__tests__/diagnostics.test.js +177 -0
  22. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  23. package/dist/src/__tests__/e2e.test.js +1789 -0
  24. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  25. package/dist/src/__tests__/entity-types.test.js +203 -0
  26. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  27. package/dist/src/__tests__/formatter.test.js +40 -0
  28. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  29. package/dist/src/__tests__/lexer.test.js +343 -0
  30. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  31. package/dist/src/__tests__/lowering.test.js +1015 -0
  32. package/dist/src/__tests__/macro.test.d.ts +8 -0
  33. package/dist/src/__tests__/macro.test.js +306 -0
  34. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  35. package/dist/src/__tests__/mc-integration.test.js +817 -0
  36. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  37. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  38. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  39. package/dist/src/__tests__/nbt.test.js +82 -0
  40. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  41. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  42. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  43. package/dist/src/__tests__/optimizer.test.js +149 -0
  44. package/dist/src/__tests__/parser.test.d.ts +1 -0
  45. package/dist/src/__tests__/parser.test.js +807 -0
  46. package/dist/src/__tests__/repl.test.d.ts +1 -0
  47. package/dist/src/__tests__/repl.test.js +27 -0
  48. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  49. package/dist/src/__tests__/runtime.test.js +289 -0
  50. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  51. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  52. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  53. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  54. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  55. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  56. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  57. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  58. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  59. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  60. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  61. package/dist/src/__tests__/typechecker.test.js +552 -0
  62. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  63. package/dist/src/__tests__/var-allocator.test.js +69 -0
  64. package/dist/src/ast/types.d.ts +515 -0
  65. package/dist/src/ast/types.js +9 -0
  66. package/dist/src/builtins/metadata.d.ts +36 -0
  67. package/dist/src/builtins/metadata.js +1014 -0
  68. package/dist/src/cli.d.ts +11 -0
  69. package/dist/src/cli.js +443 -0
  70. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  71. package/dist/src/codegen/cmdblock/index.js +45 -0
  72. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  73. package/dist/src/codegen/mcfunction/index.js +606 -0
  74. package/dist/src/codegen/structure/index.d.ts +24 -0
  75. package/dist/src/codegen/structure/index.js +279 -0
  76. package/dist/src/codegen/var-allocator.d.ts +45 -0
  77. package/dist/src/codegen/var-allocator.js +104 -0
  78. package/dist/src/compile.d.ts +37 -0
  79. package/dist/src/compile.js +165 -0
  80. package/dist/src/diagnostics/index.d.ts +44 -0
  81. package/dist/src/diagnostics/index.js +140 -0
  82. package/dist/src/events/types.d.ts +35 -0
  83. package/dist/src/events/types.js +59 -0
  84. package/dist/src/formatter/index.d.ts +1 -0
  85. package/dist/src/formatter/index.js +26 -0
  86. package/dist/src/index.d.ts +22 -0
  87. package/dist/src/index.js +45 -0
  88. package/dist/src/ir/builder.d.ts +33 -0
  89. package/dist/src/ir/builder.js +99 -0
  90. package/dist/src/ir/types.d.ts +132 -0
  91. package/dist/src/ir/types.js +15 -0
  92. package/dist/src/lexer/index.d.ts +37 -0
  93. package/dist/src/lexer/index.js +569 -0
  94. package/dist/src/lowering/index.d.ts +188 -0
  95. package/dist/src/lowering/index.js +3405 -0
  96. package/dist/src/mc-test/client.d.ts +128 -0
  97. package/dist/src/mc-test/client.js +174 -0
  98. package/dist/src/mc-test/runner.d.ts +28 -0
  99. package/dist/src/mc-test/runner.js +151 -0
  100. package/dist/src/mc-test/setup.d.ts +11 -0
  101. package/dist/src/mc-test/setup.js +98 -0
  102. package/dist/src/mc-validator/index.d.ts +17 -0
  103. package/dist/src/mc-validator/index.js +322 -0
  104. package/dist/src/nbt/index.d.ts +86 -0
  105. package/dist/src/nbt/index.js +250 -0
  106. package/dist/src/optimizer/commands.d.ts +38 -0
  107. package/dist/src/optimizer/commands.js +451 -0
  108. package/dist/src/optimizer/dce.d.ts +34 -0
  109. package/dist/src/optimizer/dce.js +639 -0
  110. package/dist/src/optimizer/passes.d.ts +34 -0
  111. package/dist/src/optimizer/passes.js +243 -0
  112. package/dist/src/optimizer/structure.d.ts +9 -0
  113. package/dist/src/optimizer/structure.js +356 -0
  114. package/dist/src/parser/index.d.ts +93 -0
  115. package/dist/src/parser/index.js +1687 -0
  116. package/dist/src/repl.d.ts +16 -0
  117. package/dist/src/repl.js +165 -0
  118. package/dist/src/runtime/index.d.ts +107 -0
  119. package/dist/src/runtime/index.js +1409 -0
  120. package/dist/src/typechecker/index.d.ts +61 -0
  121. package/dist/src/typechecker/index.js +1034 -0
  122. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  123. package/dist/src/types/entity-hierarchy.js +107 -0
  124. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  125. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  126. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  127. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  128. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  129. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  130. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  131. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  132. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  133. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  134. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  135. package/dist/src2/__tests__/lir/types.test.js +185 -0
  136. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  137. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  138. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  139. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  140. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  141. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  142. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  143. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  144. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  145. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  146. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  147. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  148. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  149. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  150. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  151. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  152. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  153. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  154. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  155. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  156. package/dist/src2/emit/compile.d.ts +19 -0
  157. package/dist/src2/emit/compile.js +80 -0
  158. package/dist/src2/emit/index.d.ts +17 -0
  159. package/dist/src2/emit/index.js +172 -0
  160. package/dist/src2/hir/lower.d.ts +15 -0
  161. package/dist/src2/hir/lower.js +378 -0
  162. package/dist/src2/hir/types.d.ts +373 -0
  163. package/dist/src2/hir/types.js +16 -0
  164. package/dist/src2/lir/lower.d.ts +15 -0
  165. package/dist/src2/lir/lower.js +453 -0
  166. package/dist/src2/lir/types.d.ts +136 -0
  167. package/dist/src2/lir/types.js +11 -0
  168. package/dist/src2/lir/verify.d.ts +14 -0
  169. package/dist/src2/lir/verify.js +113 -0
  170. package/dist/src2/mir/lower.d.ts +9 -0
  171. package/dist/src2/mir/lower.js +1030 -0
  172. package/dist/src2/mir/macro.d.ts +22 -0
  173. package/dist/src2/mir/macro.js +168 -0
  174. package/dist/src2/mir/types.d.ts +183 -0
  175. package/dist/src2/mir/types.js +11 -0
  176. package/dist/src2/mir/verify.d.ts +16 -0
  177. package/dist/src2/mir/verify.js +216 -0
  178. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  179. package/dist/src2/optimizer/block_merge.js +84 -0
  180. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  181. package/dist/src2/optimizer/branch_simplify.js +28 -0
  182. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  183. package/dist/src2/optimizer/constant_fold.js +85 -0
  184. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  185. package/dist/src2/optimizer/copy_prop.js +113 -0
  186. package/dist/src2/optimizer/dce.d.ts +8 -0
  187. package/dist/src2/optimizer/dce.js +155 -0
  188. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  189. package/dist/src2/optimizer/pipeline.js +42 -0
  190. package/dist/tsconfig.tsbuildinfo +1 -0
  191. package/docs/compiler-pipeline-redesign.md +2243 -0
  192. package/docs/optimization-ideas.md +1076 -0
  193. package/editors/vscode/package-lock.json +3 -3
  194. package/editors/vscode/package.json +1 -1
  195. package/jest.config.js +1 -1
  196. package/package.json +6 -5
  197. package/scripts/postbuild.js +15 -0
  198. package/src/__tests__/cli.test.ts +8 -220
  199. package/src/__tests__/dce.test.ts +11 -56
  200. package/src/__tests__/diagnostics.test.ts +59 -38
  201. package/src/__tests__/mc-integration.test.ts +1 -2
  202. package/src/ast/types.ts +6 -1
  203. package/src/cli.ts +29 -156
  204. package/src/compile.ts +6 -162
  205. package/src/index.ts +14 -178
  206. package/src/mc-test/runner.ts +4 -3
  207. package/src/parser/index.ts +1 -1
  208. package/src/repl.ts +1 -1
  209. package/src/runtime/index.ts +1 -1
  210. package/src2/__tests__/e2e/basic.test.ts +154 -0
  211. package/src2/__tests__/e2e/macros.test.ts +199 -0
  212. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  213. package/src2/__tests__/hir/desugar.test.ts +263 -0
  214. package/src2/__tests__/lir/lower.test.ts +619 -0
  215. package/src2/__tests__/lir/types.test.ts +207 -0
  216. package/src2/__tests__/lir/verify.test.ts +249 -0
  217. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  218. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  219. package/src2/__tests__/mir/verify.test.ts +254 -0
  220. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  221. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  222. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  223. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  224. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  225. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  226. package/src2/emit/compile.ts +99 -0
  227. package/src2/emit/index.ts +222 -0
  228. package/src2/hir/lower.ts +428 -0
  229. package/src2/hir/types.ts +216 -0
  230. package/src2/lir/lower.ts +556 -0
  231. package/src2/lir/types.ts +109 -0
  232. package/src2/lir/verify.ts +129 -0
  233. package/src2/mir/lower.ts +1160 -0
  234. package/src2/mir/macro.ts +167 -0
  235. package/src2/mir/types.ts +106 -0
  236. package/src2/mir/verify.ts +218 -0
  237. package/src2/optimizer/block_merge.ts +93 -0
  238. package/src2/optimizer/branch_simplify.ts +27 -0
  239. package/src2/optimizer/constant_fold.ts +88 -0
  240. package/src2/optimizer/copy_prop.ts +106 -0
  241. package/src2/optimizer/dce.ts +133 -0
  242. package/src2/optimizer/pipeline.ts +44 -0
  243. package/tsconfig.json +2 -2
  244. package/src/__tests__/codegen.test.ts +0 -161
  245. package/src/__tests__/e2e.test.ts +0 -2039
  246. package/src/__tests__/entity-types.test.ts +0 -236
  247. package/src/__tests__/lowering.test.ts +0 -1185
  248. package/src/__tests__/macro.test.ts +0 -343
  249. package/src/__tests__/nbt.test.ts +0 -58
  250. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  251. package/src/__tests__/optimizer.test.ts +0 -162
  252. package/src/__tests__/runtime.test.ts +0 -305
  253. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  254. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  255. package/src/__tests__/stdlib-math.test.ts +0 -374
  256. package/src/__tests__/stdlib-vec.test.ts +0 -259
  257. package/src/__tests__/structure-optimizer.test.ts +0 -38
  258. package/src/__tests__/var-allocator.test.ts +0 -75
  259. package/src/codegen/cmdblock/index.ts +0 -63
  260. package/src/codegen/mcfunction/index.ts +0 -662
  261. package/src/codegen/structure/index.ts +0 -346
  262. package/src/codegen/var-allocator.ts +0 -104
  263. package/src/ir/builder.ts +0 -116
  264. package/src/ir/types.ts +0 -134
  265. package/src/lowering/index.ts +0 -3876
  266. package/src/optimizer/commands.ts +0 -534
  267. package/src/optimizer/dce.ts +0 -679
  268. package/src/optimizer/passes.ts +0 -250
  269. package/src/optimizer/structure.ts +0 -450
@@ -1,162 +0,0 @@
1
- import { constantFolding, copyPropagation, deadCodeElimination, optimize } from '../optimizer/passes'
2
- import type { IRFunction } from '../ir/types'
3
-
4
- function makeFn(instrs: any[], term: any = { op: 'return' }): IRFunction {
5
- return {
6
- name: 'test',
7
- params: [],
8
- locals: [],
9
- blocks: [{ label: 'entry', instrs, term }],
10
- }
11
- }
12
-
13
- describe('constantFolding', () => {
14
- it('folds 2 + 3 → 5', () => {
15
- const fn = makeFn([
16
- { op: 'binop', dst: '$x', lhs: { kind: 'const', value: 2 }, bop: '+', rhs: { kind: 'const', value: 3 } },
17
- ])
18
- const opt = constantFolding(fn)
19
- expect(opt.blocks[0].instrs[0]).toEqual({
20
- op: 'assign', dst: '$x', src: { kind: 'const', value: 5 },
21
- })
22
- })
23
-
24
- it('folds 10 / 3 → 3 (truncated int division)', () => {
25
- const fn = makeFn([
26
- { op: 'binop', dst: '$x', lhs: { kind: 'const', value: 10 }, bop: '/', rhs: { kind: 'const', value: 3 } },
27
- ])
28
- const opt = constantFolding(fn)
29
- expect((opt.blocks[0].instrs[0] as any).src.value).toBe(3)
30
- })
31
-
32
- it('folds cmp 5 == 5 → 1', () => {
33
- const fn = makeFn([
34
- { op: 'cmp', dst: '$r', lhs: { kind: 'const', value: 5 }, cop: '==', rhs: { kind: 'const', value: 5 } },
35
- ])
36
- const opt = constantFolding(fn)
37
- expect((opt.blocks[0].instrs[0] as any).src.value).toBe(1)
38
- })
39
-
40
- it('folds cmp 5 > 10 → 0', () => {
41
- const fn = makeFn([
42
- { op: 'cmp', dst: '$r', lhs: { kind: 'const', value: 5 }, cop: '>', rhs: { kind: 'const', value: 10 } },
43
- ])
44
- const opt = constantFolding(fn)
45
- expect((opt.blocks[0].instrs[0] as any).src.value).toBe(0)
46
- })
47
-
48
- it('does not fold division by zero', () => {
49
- const fn = makeFn([
50
- { op: 'binop', dst: '$x', lhs: { kind: 'const', value: 5 }, bop: '/', rhs: { kind: 'const', value: 0 } },
51
- ])
52
- const opt = constantFolding(fn)
53
- expect(opt.blocks[0].instrs[0].op).toBe('binop')
54
- })
55
- })
56
-
57
- describe('copyPropagation', () => {
58
- it('propagates simple copy', () => {
59
- const fn = makeFn([
60
- { op: 'assign', dst: '$t0', src: { kind: 'var', name: '$x' } },
61
- { op: 'binop', dst: '$y', lhs: { kind: 'var', name: '$t0' }, bop: '+', rhs: { kind: 'const', value: 1 } },
62
- ])
63
- const opt = copyPropagation(fn)
64
- const binop = opt.blocks[0].instrs[1] as any
65
- expect(binop.lhs).toEqual({ kind: 'var', name: '$x' })
66
- })
67
-
68
- it('propagates constant copies', () => {
69
- const fn = makeFn([
70
- { op: 'assign', dst: '$t0', src: { kind: 'const', value: 42 } },
71
- { op: 'assign', dst: '$y', src: { kind: 'var', name: '$t0' } },
72
- ])
73
- const opt = copyPropagation(fn)
74
- const second = opt.blocks[0].instrs[1] as any
75
- expect(second.src).toEqual({ kind: 'const', value: 42 })
76
- })
77
- })
78
-
79
- describe('deadCodeElimination', () => {
80
- it('removes unused assignment', () => {
81
- const fn = makeFn([
82
- { op: 'assign', dst: '$t0', src: { kind: 'const', value: 99 } }, // unused temp
83
- { op: 'assign', dst: '$t1', src: { kind: 'const', value: 1 } }, // used temp
84
- ], { op: 'return', value: { kind: 'var', name: '$t1' } })
85
- const opt = deadCodeElimination(fn)
86
- expect(opt.blocks[0].instrs).toHaveLength(1)
87
- expect((opt.blocks[0].instrs[0] as any).dst).toBe('$t1')
88
- })
89
-
90
- it('keeps call even if return value unused (side effects)', () => {
91
- const fn = makeFn([
92
- { op: 'call', fn: 'foo', args: [], dst: '$unused' },
93
- ])
94
- const opt = deadCodeElimination(fn)
95
- expect(opt.blocks[0].instrs).toHaveLength(1)
96
- })
97
-
98
- it('keeps assignments referenced by raw commands', () => {
99
- const fn = makeFn([
100
- { op: 'assign', dst: '$used_by_raw', src: { kind: 'const', value: 7 } },
101
- { op: 'raw', cmd: 'execute store result score player obj run scoreboard players get $used_by_raw rs' },
102
- ])
103
- const opt = deadCodeElimination(fn)
104
- expect(opt.blocks[0].instrs).toHaveLength(2)
105
- expect((opt.blocks[0].instrs[0] as any).dst).toBe('$used_by_raw')
106
- })
107
- })
108
-
109
- describe('copyPropagation – stale alias invalidation', () => {
110
- it('does not propagate $tmp = $y after $y is overwritten (swap pattern)', () => {
111
- // Simulates: let tmp = y; y = x % y; x = tmp
112
- // The copy $tmp = $y must be invalidated when $y is reassigned.
113
- // Before fix: x = tmp was propagated to x = y (new y, wrong value).
114
- const fn = makeFn([
115
- { op: 'assign', dst: '$tmp', src: { kind: 'var', name: '$y' } }, // tmp = y
116
- { op: 'binop', dst: '$r', lhs: { kind: 'var', name: '$x' }, bop: '%', rhs: { kind: 'var', name: '$y' } }, // r = x%y
117
- { op: 'assign', dst: '$y', src: { kind: 'var', name: '$r' } }, // y = r ← stale: tmp still points to OLD y
118
- { op: 'assign', dst: '$x', src: { kind: 'var', name: '$tmp' } }, // x = tmp (should NOT be x = y)
119
- ])
120
- const opt = copyPropagation(fn)
121
- const instrs = opt.blocks[0].instrs
122
- const xAssign = instrs.find((i: any) => i.dst === '$x') as any
123
- // x = tmp must NOT be optimised to x = $y (stale) or x = $r (new y).
124
- // It should stay as x = $tmp (the original copy).
125
- expect(xAssign.src).toEqual({ kind: 'var', name: '$tmp' })
126
- })
127
-
128
- it('still propagates simple non-conflicting copies', () => {
129
- // a = 5; b = a; c = b → after propagation b and c should both be const 5
130
- const fn = makeFn([
131
- { op: 'assign', dst: '$a', src: { kind: 'const', value: 5 } },
132
- { op: 'assign', dst: '$b', src: { kind: 'var', name: '$a' } },
133
- { op: 'assign', dst: '$c', src: { kind: 'var', name: '$b' } },
134
- ])
135
- const opt = copyPropagation(fn)
136
- const instrs = opt.blocks[0].instrs
137
- const cAssign = instrs.find((i: any) => i.dst === '$c') as any
138
- expect(cAssign.src).toEqual({ kind: 'const', value: 5 })
139
- })
140
- })
141
-
142
- describe('optimize pipeline', () => {
143
- it('combines all passes', () => {
144
- // t0 = 2 + 3 (→ constant fold → t0 = 5)
145
- // x = t0 (→ copy prop → x = 5)
146
- // unused = 0 (→ DCE → removed)
147
- // return x
148
- const fn = makeFn([
149
- { op: 'binop', dst: '$t0', lhs: { kind: 'const', value: 2 }, bop: '+', rhs: { kind: 'const', value: 3 } },
150
- { op: 'assign', dst: '$x', src: { kind: 'var', name: '$t0' } },
151
- { op: 'assign', dst: '$t1', src: { kind: 'const', value: 0 } }, // unused temp, should be removed
152
- ], { op: 'return', value: { kind: 'var', name: '$x' } })
153
-
154
- const opt = optimize(fn)
155
- const instrs = opt.blocks[0].instrs
156
- // $t1 (unused temp) should be gone
157
- expect(instrs.some((i: any) => i.dst === '$t1')).toBe(false)
158
- // $x should be const 5 (after folding + propagation)
159
- const xInstr = instrs.find((i: any) => i.dst === '$x') as any
160
- expect(xInstr?.src).toEqual({ kind: 'const', value: 5 })
161
- })
162
- })
@@ -1,305 +0,0 @@
1
- import * as fs from 'fs'
2
- import * as path from 'path'
3
-
4
- import { compile } from '../compile'
5
- import { MCRuntime, Entity } from '../runtime'
6
-
7
- function loadCompiledProgram(source: string, namespace = 'runtime'): MCRuntime {
8
- const result = compile(source, { namespace })
9
- expect(result.success).toBe(true)
10
- expect(result.files).toBeDefined()
11
-
12
- const runtime = new MCRuntime(namespace)
13
- for (const file of result.files ?? []) {
14
- if (!file.path.endsWith('.mcfunction')) continue
15
-
16
- const match = file.path.match(/data\/([^/]+)\/function\/(.+)\.mcfunction$/)
17
- if (!match) continue
18
-
19
- const [, ns, fnPath] = match
20
- runtime.loadFunction(`${ns}:${fnPath}`, file.content.split('\n'))
21
- }
22
-
23
- return runtime
24
- }
25
-
26
- function loadExample(name: string): string {
27
- return fs.readFileSync(path.join(__dirname, '..', 'examples', name), 'utf-8')
28
- }
29
-
30
- describe('MCRuntime behavioral integration', () => {
31
- it('runs the counter example and increments the scoreboard across ticks', () => {
32
- const runtime = loadCompiledProgram(loadExample('counter.mcrs'))
33
-
34
- runtime.load()
35
- runtime.ticks(5)
36
-
37
- expect(runtime.getScore('counter', 'ticks')).toBe(5)
38
- expect(runtime.tickCount).toBe(5)
39
- })
40
-
41
- it('executes compiled math control flow and stores the expected result', () => {
42
- const runtime = loadCompiledProgram(`
43
- fn compute() {
44
- let x: int = 3;
45
- let result: int = 0;
46
-
47
- if (x > 2) {
48
- result = 11;
49
- } else {
50
- result = 29;
51
- }
52
-
53
- scoreboard_set("math", "result", result);
54
- }
55
- `)
56
-
57
- runtime.load()
58
- runtime.execFunction('compute')
59
-
60
- expect(runtime.getScore('math', 'runtime.result')).toBe(11)
61
- })
62
-
63
- it('captures say, announce, actionbar, and title output in the chat log', () => {
64
- const runtime = loadCompiledProgram(`
65
- fn chat() {
66
- say("hello");
67
- announce("broadcast");
68
- actionbar(@a, "warning");
69
- title(@a, "Boss Wave");
70
- }
71
- `)
72
-
73
- runtime.load()
74
- runtime.execFunction('chat')
75
-
76
- expect(runtime.getChatLog()).toEqual([
77
- '[Server] hello',
78
- 'broadcast',
79
- '[ACTIONBAR] warning',
80
- '[TITLE] Boss Wave',
81
- ])
82
- })
83
-
84
- it('renders interpolated strings through tellraw score components', () => {
85
- const runtime = loadCompiledProgram(`
86
- fn chat() {
87
- let score: int = 7;
88
- say("You have \${score} points");
89
- }
90
- `)
91
-
92
- runtime.load()
93
- runtime.execFunction('chat')
94
-
95
- expect(runtime.getChatLog()).toEqual([
96
- 'You have 7 points',
97
- ])
98
- })
99
-
100
- it('renders f-strings through tellraw score components', () => {
101
- const runtime = loadCompiledProgram(`
102
- fn chat() {
103
- let score: int = 7;
104
- say(f"You have {score} points");
105
- }
106
- `)
107
-
108
- runtime.load()
109
- runtime.execFunction('chat')
110
-
111
- expect(runtime.getChatLog()).toEqual([
112
- 'You have 7 points',
113
- ])
114
- })
115
-
116
- it('kills only entities matched by a foreach selector', () => {
117
- const runtime = loadCompiledProgram(`
118
- fn purge_zombies() {
119
- foreach (z in @e[type=zombie]) {
120
- kill(z);
121
- }
122
- }
123
- `)
124
-
125
- const zombieA = runtime.spawnEntity(['hostile'], 'minecraft:zombie')
126
- const zombieB = runtime.spawnEntity(['hostile'], 'zombie')
127
- const skeleton = runtime.spawnEntity(['hostile'], 'minecraft:skeleton')
128
-
129
- runtime.load()
130
- runtime.execFunction('purge_zombies')
131
-
132
- expect(runtime.entities.map(entity => entity.id)).toEqual([skeleton.id])
133
- expect(runtime.entities.find(entity => entity.id === zombieA.id)).toBeUndefined()
134
- expect(runtime.entities.find(entity => entity.id === zombieB.id)).toBeUndefined()
135
- })
136
-
137
- it('executes array push, pop, and len through storage operations', () => {
138
- const runtime = loadCompiledProgram(`
139
- fn arrays() {
140
- let arr: int[] = [];
141
- arr.push(4);
142
- arr.push(9);
143
- let popped: int = arr.pop();
144
- let len: int = arr.len;
145
-
146
- scoreboard_set("arrays", "len", len);
147
- scoreboard_set("arrays", "last", popped);
148
- }
149
- `)
150
-
151
- runtime.load()
152
- runtime.execFunction('arrays')
153
-
154
- expect(runtime.getScore('arrays', 'runtime.len')).toBe(1)
155
- expect(runtime.getScore('arrays', 'runtime.last')).toBe(9)
156
- expect(runtime.getStorage('rs:heap.arr')).toEqual([4])
157
- })
158
-
159
- it('tracks world state, weather, and time from compiled world commands', () => {
160
- const runtime = loadCompiledProgram(`
161
- fn reset_world() {
162
- let floor_start: BlockPos = (0, 64, 0);
163
- let floor_end: BlockPos = (1, 64, 1);
164
- let centerpiece: BlockPos = (1, 64, 1);
165
- fill(floor_start, floor_end, "minecraft:stone");
166
- setblock(centerpiece, "minecraft:gold_block");
167
- weather("rain");
168
- time_set("noon");
169
- }
170
- `)
171
-
172
- runtime.load()
173
- runtime.execFunction('reset_world')
174
-
175
- expect(runtime.world.get('0,64,0')).toBe('minecraft:stone')
176
- expect(runtime.world.get('0,64,1')).toBe('minecraft:stone')
177
- expect(runtime.world.get('1,64,0')).toBe('minecraft:stone')
178
- expect(runtime.world.get('1,64,1')).toBe('minecraft:gold_block')
179
- expect(runtime.weather).toBe('rain')
180
- expect(runtime.worldTime).toBe(6000)
181
- })
182
-
183
- it('respects @tick(rate=5) scheduling when ticking the runtime', () => {
184
- const runtime = loadCompiledProgram(`
185
- @tick(rate=5)
186
- fn pulse() {
187
- let count: int = scoreboard_get("pulse", "count");
188
- count = count + 1;
189
- scoreboard_set("pulse", "count", count);
190
- }
191
- `)
192
-
193
- runtime.load()
194
- runtime.ticks(10)
195
-
196
- expect(runtime.getScore('pulse', 'runtime.count')).toBe(2)
197
- })
198
-
199
- it('executes only the matching match arm', () => {
200
- const runtime = loadCompiledProgram(`
201
- fn choose() {
202
- let choice: int = 2;
203
- match (choice) {
204
- 1 => { say("one"); }
205
- 2 => { say("two"); }
206
- _ => { say("other"); }
207
- }
208
- }
209
- `)
210
-
211
- runtime.load()
212
- runtime.execFunction('choose')
213
-
214
- expect(runtime.getChatLog()).toEqual([
215
- '[Server] two',
216
- ])
217
- })
218
-
219
- it('updates position, effects, and xp for executor-targeted builtins', () => {
220
- const runtime = loadCompiledProgram(`
221
- fn buff_player() {
222
- tp(@s, (5, 70, -2));
223
- effect(@s, "speed", 15, 2);
224
- xp_add(@s, 5);
225
- xp_set(@s, 12, "levels");
226
- }
227
- `)
228
-
229
- const player: Entity = runtime.spawnEntity(['player'], 'minecraft:player')
230
-
231
- runtime.load()
232
- runtime.execFunction('buff_player', player)
233
-
234
- expect(player.position).toEqual({ x: 5, y: 70, z: -2 })
235
- expect(runtime.effects.get(player.id)).toEqual([
236
- { effect: 'speed', duration: 15, amplifier: 2 },
237
- ])
238
- expect(runtime.xp.get(player.id)).toBe(12)
239
- })
240
-
241
- it('executes lambda variables through generated sub-functions', () => {
242
- const runtime = loadCompiledProgram(`
243
- fn test() {
244
- let double: (int) -> int = (x: int) => x * 2;
245
- let result: int = double(5);
246
- scoreboard_set("lambda", "direct", result);
247
- }
248
- `)
249
-
250
- runtime.load()
251
- runtime.execFunction('test')
252
-
253
- expect(runtime.getScore('lambda', 'runtime.direct')).toBe(10)
254
- })
255
-
256
- it('executes lambdas passed as callback arguments', () => {
257
- const runtime = loadCompiledProgram(`
258
- fn apply(val: int, cb: (int) -> int) -> int {
259
- return cb(val);
260
- }
261
-
262
- fn test() {
263
- let result: int = apply(5, (x: int) => x * 3);
264
- scoreboard_set("lambda", "callback", result);
265
- }
266
- `)
267
-
268
- runtime.load()
269
- runtime.execFunction('test')
270
-
271
- expect(runtime.getScore('lambda', 'runtime.callback')).toBe(15)
272
- })
273
-
274
- it('executes block-body lambdas', () => {
275
- const runtime = loadCompiledProgram(`
276
- fn test() {
277
- let process: (int) -> int = (x: int) => {
278
- let doubled: int = x * 2;
279
- return doubled + 1;
280
- };
281
- let result: int = process(5);
282
- scoreboard_set("lambda", "block", result);
283
- }
284
- `)
285
-
286
- runtime.load()
287
- runtime.execFunction('test')
288
-
289
- expect(runtime.getScore('lambda', 'runtime.block')).toBe(11)
290
- })
291
-
292
- it('executes immediately-invoked expression-body lambdas', () => {
293
- const runtime = loadCompiledProgram(`
294
- fn test() {
295
- let result: int = ((x: int) => x * 2)(5);
296
- scoreboard_set("lambda", "iife", result);
297
- }
298
- `)
299
-
300
- runtime.load()
301
- runtime.execFunction('test')
302
-
303
- expect(runtime.getScore('lambda', 'runtime.iife')).toBe(10)
304
- })
305
- })