redscript-mc 1.2.30 → 2.1.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 (593) hide show
  1. package/.claudeignore +21 -0
  2. package/.github/workflows/ci.yml +1 -0
  3. package/README.md +12 -16
  4. package/README.zh.md +2 -2
  5. package/demo.gif +0 -0
  6. package/dist/cli.js +2 -554
  7. package/dist/compile.js +2 -266
  8. package/dist/index.js +2 -159
  9. package/dist/src/__tests__/budget.test.js +261 -0
  10. package/dist/src/__tests__/cli.test.js +104 -0
  11. package/dist/{__tests__ → src/__tests__}/dce.test.js +11 -47
  12. package/dist/{__tests__ → src/__tests__}/diagnostics.test.js +67 -40
  13. package/dist/src/__tests__/e2e/basic.test.d.ts +8 -0
  14. package/dist/src/__tests__/e2e/basic.test.js +140 -0
  15. package/dist/src/__tests__/e2e/coroutine.test.d.ts +7 -0
  16. package/dist/src/__tests__/e2e/coroutine.test.js +132 -0
  17. package/dist/src/__tests__/e2e/macros.test.d.ts +9 -0
  18. package/dist/src/__tests__/e2e/macros.test.js +182 -0
  19. package/dist/src/__tests__/e2e/migrate.test.d.ts +13 -0
  20. package/dist/src/__tests__/e2e/migrate.test.js +2739 -0
  21. package/dist/src/__tests__/e2e/stdlib-e2e.test.d.ts +10 -0
  22. package/dist/src/__tests__/e2e/stdlib-e2e.test.js +324 -0
  23. package/dist/src/__tests__/enum.test.d.ts +10 -0
  24. package/dist/src/__tests__/enum.test.js +389 -0
  25. package/dist/src/__tests__/generics.test.d.ts +14 -0
  26. package/dist/src/__tests__/generics.test.js +367 -0
  27. package/dist/src/__tests__/hir/desugar.test.js +234 -0
  28. package/dist/src/__tests__/incremental.test.d.ts +5 -0
  29. package/dist/src/__tests__/incremental.test.js +308 -0
  30. package/dist/src/__tests__/lir/lower.test.js +559 -0
  31. package/dist/src/__tests__/lir/types.test.js +185 -0
  32. package/dist/src/__tests__/lir/verify.test.js +221 -0
  33. package/dist/src/__tests__/lsp.test.d.ts +7 -0
  34. package/dist/src/__tests__/lsp.test.js +245 -0
  35. package/dist/{__tests__ → src/__tests__}/mc-integration.test.js +1 -3
  36. package/dist/src/__tests__/mc-version.test.d.ts +10 -0
  37. package/dist/src/__tests__/mc-version.test.js +154 -0
  38. package/dist/src/__tests__/mir/arithmetic.test.js +130 -0
  39. package/dist/src/__tests__/mir/control-flow.test.js +205 -0
  40. package/dist/src/__tests__/mir/verify.test.js +223 -0
  41. package/dist/src/__tests__/modules.test.d.ts +7 -0
  42. package/dist/src/__tests__/modules.test.js +333 -0
  43. package/dist/src/__tests__/optimizer/block_merge.test.js +78 -0
  44. package/dist/src/__tests__/optimizer/branch_simplify.test.js +58 -0
  45. package/dist/src/__tests__/optimizer/constant_fold.test.js +131 -0
  46. package/dist/src/__tests__/optimizer/copy_prop.test.js +91 -0
  47. package/dist/src/__tests__/optimizer/coroutine.test.d.ts +12 -0
  48. package/dist/src/__tests__/optimizer/coroutine.test.js +251 -0
  49. package/dist/src/__tests__/optimizer/dce.test.d.ts +1 -0
  50. package/dist/src/__tests__/optimizer/dce.test.js +76 -0
  51. package/dist/src/__tests__/optimizer/interprocedural.test.d.ts +1 -0
  52. package/dist/src/__tests__/optimizer/interprocedural.test.js +145 -0
  53. package/dist/src/__tests__/optimizer/lir/const_imm.test.d.ts +1 -0
  54. package/dist/src/__tests__/optimizer/lir/const_imm.test.js +138 -0
  55. package/dist/src/__tests__/optimizer/lir/dead_slot.test.d.ts +1 -0
  56. package/dist/src/__tests__/optimizer/lir/dead_slot.test.js +141 -0
  57. package/dist/src/__tests__/optimizer/lir/peephole.test.d.ts +1 -0
  58. package/dist/src/__tests__/optimizer/lir/peephole.test.js +126 -0
  59. package/dist/src/__tests__/optimizer/lir/pipeline.test.d.ts +1 -0
  60. package/dist/src/__tests__/optimizer/lir/pipeline.test.js +84 -0
  61. package/dist/src/__tests__/optimizer/nbt-batch.test.d.ts +1 -0
  62. package/dist/src/__tests__/optimizer/nbt-batch.test.js +110 -0
  63. package/dist/src/__tests__/optimizer/pipeline.test.d.ts +1 -0
  64. package/dist/src/__tests__/optimizer/pipeline.test.js +102 -0
  65. package/dist/src/__tests__/optimizer/selector-cache.test.d.ts +1 -0
  66. package/dist/src/__tests__/optimizer/selector-cache.test.js +103 -0
  67. package/dist/src/__tests__/optimizer/unroll.test.d.ts +1 -0
  68. package/dist/src/__tests__/optimizer/unroll.test.js +206 -0
  69. package/dist/src/__tests__/option.test.d.ts +14 -0
  70. package/dist/src/__tests__/option.test.js +275 -0
  71. package/dist/src/__tests__/parser.test.d.ts +1 -0
  72. package/dist/src/__tests__/repl.test.d.ts +1 -0
  73. package/dist/src/__tests__/schedule.test.d.ts +7 -0
  74. package/dist/src/__tests__/schedule.test.js +98 -0
  75. package/dist/src/__tests__/sourcemap.test.d.ts +7 -0
  76. package/dist/src/__tests__/sourcemap.test.js +227 -0
  77. package/dist/src/__tests__/tuple.test.d.ts +11 -0
  78. package/dist/src/__tests__/tuple.test.js +202 -0
  79. package/dist/src/__tests__/typechecker-strict.test.d.ts +10 -0
  80. package/dist/src/__tests__/typechecker-strict.test.js +197 -0
  81. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  82. package/dist/{ast → src/ast}/types.d.ts +58 -3
  83. package/dist/src/cache/deps.d.ts +41 -0
  84. package/dist/src/cache/deps.js +158 -0
  85. package/dist/src/cache/incremental.d.ts +35 -0
  86. package/dist/src/cache/incremental.js +165 -0
  87. package/dist/src/cache/index.d.ts +37 -0
  88. package/dist/src/cache/index.js +152 -0
  89. package/dist/{cli.d.ts → src/cli.d.ts} +1 -1
  90. package/dist/src/cli.js +474 -0
  91. package/dist/src/compile.d.ts +37 -0
  92. package/dist/src/compile.js +165 -0
  93. package/dist/{diagnostics → src/diagnostics}/index.d.ts +1 -1
  94. package/dist/{diagnostics → src/diagnostics}/index.js +8 -11
  95. package/dist/src/emit/compile.d.ts +29 -0
  96. package/dist/src/emit/compile.js +143 -0
  97. package/dist/src/emit/index.d.ts +26 -0
  98. package/dist/src/emit/index.js +223 -0
  99. package/dist/src/emit/modules.d.ts +29 -0
  100. package/dist/src/emit/modules.js +492 -0
  101. package/dist/src/emit/sourcemap.d.ts +53 -0
  102. package/dist/src/emit/sourcemap.js +73 -0
  103. package/dist/src/hir/lower.d.ts +15 -0
  104. package/dist/src/hir/lower.js +399 -0
  105. package/dist/src/hir/monomorphize.d.ts +22 -0
  106. package/dist/src/hir/monomorphize.js +379 -0
  107. package/dist/src/hir/types.d.ts +406 -0
  108. package/dist/src/hir/types.js +16 -0
  109. package/dist/src/index.d.ts +39 -0
  110. package/dist/src/index.js +67 -0
  111. package/dist/{lexer → src/lexer}/index.d.ts +1 -1
  112. package/dist/{lexer → src/lexer}/index.js +1 -0
  113. package/dist/src/lir/budget.d.ts +37 -0
  114. package/dist/src/lir/budget.js +280 -0
  115. package/dist/src/lir/lower.d.ts +15 -0
  116. package/dist/src/lir/lower.js +472 -0
  117. package/dist/src/lir/types.d.ts +139 -0
  118. package/dist/src/lir/types.js +11 -0
  119. package/dist/src/lir/verify.d.ts +14 -0
  120. package/dist/src/lir/verify.js +113 -0
  121. package/dist/src/lsp/main.d.ts +8 -0
  122. package/dist/src/lsp/main.js +11 -0
  123. package/dist/src/lsp/server.d.ts +11 -0
  124. package/dist/src/lsp/server.js +352 -0
  125. package/dist/{mc-test → src/mc-test}/runner.js +4 -3
  126. package/dist/src/mir/lower.d.ts +9 -0
  127. package/dist/src/mir/lower.js +1264 -0
  128. package/dist/src/mir/macro.d.ts +22 -0
  129. package/dist/src/mir/macro.js +168 -0
  130. package/dist/src/mir/types.d.ts +191 -0
  131. package/dist/src/mir/types.js +11 -0
  132. package/dist/src/mir/verify.d.ts +16 -0
  133. package/dist/src/mir/verify.js +216 -0
  134. package/dist/src/optimizer/block_merge.d.ts +12 -0
  135. package/dist/src/optimizer/block_merge.js +84 -0
  136. package/dist/src/optimizer/branch_simplify.d.ts +9 -0
  137. package/dist/src/optimizer/branch_simplify.js +28 -0
  138. package/dist/src/optimizer/constant_fold.d.ts +10 -0
  139. package/dist/src/optimizer/constant_fold.js +85 -0
  140. package/dist/src/optimizer/copy_prop.d.ts +9 -0
  141. package/dist/src/optimizer/copy_prop.js +113 -0
  142. package/dist/src/optimizer/coroutine.d.ts +34 -0
  143. package/dist/src/optimizer/coroutine.js +789 -0
  144. package/dist/src/optimizer/dce.d.ts +8 -0
  145. package/dist/src/optimizer/dce.js +156 -0
  146. package/dist/src/optimizer/interprocedural.d.ts +14 -0
  147. package/dist/src/optimizer/interprocedural.js +186 -0
  148. package/dist/src/optimizer/lir/const_imm.d.ts +12 -0
  149. package/dist/src/optimizer/lir/const_imm.js +139 -0
  150. package/dist/src/optimizer/lir/dead_slot.d.ts +14 -0
  151. package/dist/src/optimizer/lir/dead_slot.js +130 -0
  152. package/dist/src/optimizer/lir/peephole.d.ts +21 -0
  153. package/dist/src/optimizer/lir/peephole.js +52 -0
  154. package/dist/src/optimizer/lir/pipeline.d.ts +10 -0
  155. package/dist/src/optimizer/lir/pipeline.js +34 -0
  156. package/dist/src/optimizer/nbt-batch.d.ts +11 -0
  157. package/dist/src/optimizer/nbt-batch.js +51 -0
  158. package/dist/src/optimizer/pipeline.d.ts +14 -0
  159. package/dist/src/optimizer/pipeline.js +58 -0
  160. package/dist/src/optimizer/selector-cache.d.ts +22 -0
  161. package/dist/src/optimizer/selector-cache.js +100 -0
  162. package/dist/src/optimizer/unroll.d.ts +32 -0
  163. package/dist/src/optimizer/unroll.js +348 -0
  164. package/dist/{parser → src/parser}/index.d.ts +8 -0
  165. package/dist/{parser → src/parser}/index.js +204 -14
  166. package/dist/{repl.d.ts → src/repl.d.ts} +1 -1
  167. package/dist/{runtime → src/runtime}/index.js +1 -1
  168. package/dist/{typechecker → src/typechecker}/index.d.ts +4 -0
  169. package/dist/{typechecker → src/typechecker}/index.js +198 -13
  170. package/dist/src/types/mc-version.d.ts +24 -0
  171. package/dist/src/types/mc-version.js +49 -0
  172. package/docs/ROADMAP.md +395 -0
  173. package/docs/compiler-pipeline-redesign.md +2260 -0
  174. package/docs/optimization-ideas.md +1076 -0
  175. package/editors/vscode/out/extension.js +25176 -8000
  176. package/editors/vscode/package-lock.json +90 -6
  177. package/editors/vscode/package.json +3 -2
  178. package/editors/vscode/src/extension.ts +97 -67
  179. package/examples/showcase.mcrs +3 -3
  180. package/package.json +13 -6
  181. package/scripts/postbuild.js +15 -0
  182. package/src/__tests__/budget.test.ts +297 -0
  183. package/src/__tests__/cli.test.ts +8 -220
  184. package/src/__tests__/dce.test.ts +11 -56
  185. package/src/__tests__/diagnostics.test.ts +61 -41
  186. package/src/__tests__/e2e/basic.test.ts +154 -0
  187. package/src/__tests__/e2e/coroutine.test.ts +142 -0
  188. package/src/__tests__/e2e/macros.test.ts +199 -0
  189. package/src/__tests__/e2e/migrate.test.ts +3008 -0
  190. package/src/__tests__/e2e/stdlib-e2e.test.ts +348 -0
  191. package/src/__tests__/enum.test.ts +425 -0
  192. package/src/__tests__/generics.test.ts +390 -0
  193. package/src/__tests__/hir/desugar.test.ts +263 -0
  194. package/src/__tests__/incremental.test.ts +337 -0
  195. package/src/__tests__/lir/lower.test.ts +619 -0
  196. package/src/__tests__/lir/types.test.ts +207 -0
  197. package/src/__tests__/lir/verify.test.ts +249 -0
  198. package/src/__tests__/lsp.test.ts +270 -0
  199. package/src/__tests__/mc-integration.test.ts +1 -2
  200. package/src/__tests__/mc-version.test.ts +178 -0
  201. package/src/__tests__/mir/arithmetic.test.ts +156 -0
  202. package/src/__tests__/mir/control-flow.test.ts +242 -0
  203. package/src/__tests__/mir/verify.test.ts +254 -0
  204. package/src/__tests__/modules.test.ts +365 -0
  205. package/src/__tests__/optimizer/block_merge.test.ts +84 -0
  206. package/src/__tests__/optimizer/branch_simplify.test.ts +64 -0
  207. package/src/__tests__/optimizer/constant_fold.test.ts +145 -0
  208. package/src/__tests__/optimizer/copy_prop.test.ts +99 -0
  209. package/src/__tests__/optimizer/coroutine.test.ts +312 -0
  210. package/src/__tests__/optimizer/dce.test.ts +83 -0
  211. package/src/__tests__/optimizer/interprocedural.test.ts +174 -0
  212. package/src/__tests__/optimizer/lir/const_imm.test.ts +151 -0
  213. package/src/__tests__/optimizer/lir/dead_slot.test.ts +156 -0
  214. package/src/__tests__/optimizer/lir/peephole.test.ts +136 -0
  215. package/src/__tests__/optimizer/lir/pipeline.test.ts +113 -0
  216. package/src/__tests__/optimizer/nbt-batch.test.ts +119 -0
  217. package/src/__tests__/optimizer/pipeline.test.ts +116 -0
  218. package/src/__tests__/optimizer/selector-cache.test.ts +112 -0
  219. package/src/__tests__/optimizer/unroll.test.ts +231 -0
  220. package/src/__tests__/option.test.ts +299 -0
  221. package/src/__tests__/schedule.test.ts +105 -0
  222. package/src/__tests__/sourcemap.test.ts +254 -0
  223. package/src/__tests__/tuple.test.ts +220 -0
  224. package/src/__tests__/typechecker-strict.test.ts +216 -0
  225. package/src/ast/types.ts +39 -3
  226. package/src/cache/deps.ts +132 -0
  227. package/src/cache/incremental.ts +173 -0
  228. package/src/cache/index.ts +135 -0
  229. package/src/cli.ts +111 -195
  230. package/src/compile.ts +6 -162
  231. package/src/diagnostics/index.ts +8 -11
  232. package/src/emit/compile.ts +177 -0
  233. package/src/emit/index.ts +286 -0
  234. package/src/emit/modules.ts +581 -0
  235. package/src/emit/sourcemap.ts +101 -0
  236. package/src/hir/lower.ts +455 -0
  237. package/src/hir/monomorphize.ts +416 -0
  238. package/src/hir/types.ts +228 -0
  239. package/src/index.ts +37 -182
  240. package/src/lexer/index.ts +2 -1
  241. package/src/lir/budget.ts +321 -0
  242. package/src/lir/lower.ts +587 -0
  243. package/src/lir/types.ts +113 -0
  244. package/src/lir/verify.ts +129 -0
  245. package/src/lsp/main.ts +9 -0
  246. package/src/lsp/server.ts +414 -0
  247. package/src/mc-test/runner.ts +4 -3
  248. package/src/mir/lower.ts +1403 -0
  249. package/src/mir/macro.ts +167 -0
  250. package/src/mir/types.ts +117 -0
  251. package/src/mir/verify.ts +218 -0
  252. package/src/optimizer/block_merge.ts +93 -0
  253. package/src/optimizer/branch_simplify.ts +27 -0
  254. package/src/optimizer/constant_fold.ts +88 -0
  255. package/src/optimizer/copy_prop.ts +106 -0
  256. package/src/optimizer/coroutine.ts +996 -0
  257. package/src/optimizer/dce.ts +108 -653
  258. package/src/optimizer/interprocedural.ts +177 -0
  259. package/src/optimizer/lir/const_imm.ts +143 -0
  260. package/src/optimizer/lir/dead_slot.ts +123 -0
  261. package/src/optimizer/lir/peephole.ts +57 -0
  262. package/src/optimizer/lir/pipeline.ts +37 -0
  263. package/src/optimizer/nbt-batch.ts +50 -0
  264. package/src/optimizer/pipeline.ts +59 -0
  265. package/src/optimizer/selector-cache.ts +103 -0
  266. package/src/optimizer/unroll.ts +386 -0
  267. package/src/parser/index.ts +213 -16
  268. package/src/repl.ts +1 -1
  269. package/src/runtime/index.ts +1 -1
  270. package/src/stdlib/math.mcrs +4 -4
  271. package/src/templates/quest.mcrs +4 -4
  272. package/src/typechecker/index.ts +215 -15
  273. package/src/types/mc-version.ts +46 -0
  274. package/tsconfig.json +1 -1
  275. package/dist/__tests__/cli.test.js +0 -278
  276. package/dist/__tests__/codegen.test.js +0 -152
  277. package/dist/__tests__/e2e.test.d.ts +0 -6
  278. package/dist/__tests__/e2e.test.js +0 -1847
  279. package/dist/__tests__/entity-types.test.js +0 -203
  280. package/dist/__tests__/lowering.test.js +0 -1015
  281. package/dist/__tests__/macro.test.d.ts +0 -8
  282. package/dist/__tests__/macro.test.js +0 -305
  283. package/dist/__tests__/nbt.test.js +0 -82
  284. package/dist/__tests__/optimizer-advanced.test.js +0 -124
  285. package/dist/__tests__/optimizer.test.js +0 -149
  286. package/dist/__tests__/runtime.test.js +0 -289
  287. package/dist/__tests__/stdlib-advanced.test.d.ts +0 -4
  288. package/dist/__tests__/stdlib-advanced.test.js +0 -378
  289. package/dist/__tests__/stdlib-bigint.test.d.ts +0 -7
  290. package/dist/__tests__/stdlib-bigint.test.js +0 -428
  291. package/dist/__tests__/stdlib-math.test.d.ts +0 -7
  292. package/dist/__tests__/stdlib-math.test.js +0 -352
  293. package/dist/__tests__/stdlib-vec.test.d.ts +0 -4
  294. package/dist/__tests__/stdlib-vec.test.js +0 -264
  295. package/dist/__tests__/structure-optimizer.test.js +0 -33
  296. package/dist/__tests__/var-allocator.test.js +0 -69
  297. package/dist/codegen/cmdblock/index.d.ts +0 -26
  298. package/dist/codegen/cmdblock/index.js +0 -45
  299. package/dist/codegen/mcfunction/index.d.ts +0 -40
  300. package/dist/codegen/mcfunction/index.js +0 -606
  301. package/dist/codegen/structure/index.d.ts +0 -24
  302. package/dist/codegen/structure/index.js +0 -279
  303. package/dist/codegen/var-allocator.d.ts +0 -45
  304. package/dist/codegen/var-allocator.js +0 -104
  305. package/dist/compile.d.ts +0 -68
  306. package/dist/data/arena/function/__load.mcfunction +0 -6
  307. package/dist/data/arena/function/__tick.mcfunction +0 -2
  308. package/dist/data/arena/function/announce_leaders/else_1.mcfunction +0 -3
  309. package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +0 -1
  310. package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +0 -3
  311. package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +0 -7
  312. package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +0 -1
  313. package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +0 -4
  314. package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +0 -6
  315. package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +0 -1
  316. package/dist/data/arena/function/announce_leaders/then_0.mcfunction +0 -4
  317. package/dist/data/arena/function/announce_leaders.mcfunction +0 -6
  318. package/dist/data/arena/function/arena_tick/merge_2.mcfunction +0 -1
  319. package/dist/data/arena/function/arena_tick/then_0.mcfunction +0 -4
  320. package/dist/data/arena/function/arena_tick.mcfunction +0 -11
  321. package/dist/data/counter/function/__load.mcfunction +0 -5
  322. package/dist/data/counter/function/__tick.mcfunction +0 -2
  323. package/dist/data/counter/function/counter_tick/merge_2.mcfunction +0 -1
  324. package/dist/data/counter/function/counter_tick/then_0.mcfunction +0 -3
  325. package/dist/data/counter/function/counter_tick.mcfunction +0 -11
  326. package/dist/data/gcd2/function/__load.mcfunction +0 -3
  327. package/dist/data/gcd2/function/abs/merge_2.mcfunction +0 -3
  328. package/dist/data/gcd2/function/abs/then_0.mcfunction +0 -5
  329. package/dist/data/gcd2/function/abs.mcfunction +0 -7
  330. package/dist/data/gcd2/function/gcd/loop_body_1.mcfunction +0 -7
  331. package/dist/data/gcd2/function/gcd/loop_check_0.mcfunction +0 -5
  332. package/dist/data/gcd2/function/gcd/loop_exit_2.mcfunction +0 -3
  333. package/dist/data/gcd2/function/gcd.mcfunction +0 -14
  334. package/dist/data/gcd3/function/__load.mcfunction +0 -3
  335. package/dist/data/gcd3/function/abs/merge_2.mcfunction +0 -3
  336. package/dist/data/gcd3/function/abs/then_0.mcfunction +0 -5
  337. package/dist/data/gcd3/function/abs.mcfunction +0 -7
  338. package/dist/data/gcd3/function/gcd/loop_body_1.mcfunction +0 -7
  339. package/dist/data/gcd3/function/gcd/loop_check_0.mcfunction +0 -5
  340. package/dist/data/gcd3/function/gcd/loop_exit_2.mcfunction +0 -3
  341. package/dist/data/gcd3/function/gcd.mcfunction +0 -14
  342. package/dist/data/gcd3/function/test.mcfunction +0 -7
  343. package/dist/data/gcd3nm/function/__load.mcfunction +0 -3
  344. package/dist/data/gcd3nm/function/abs/merge_2.mcfunction +0 -3
  345. package/dist/data/gcd3nm/function/abs/then_0.mcfunction +0 -5
  346. package/dist/data/gcd3nm/function/abs.mcfunction +0 -7
  347. package/dist/data/gcd3nm/function/gcd/loop_body_1.mcfunction +0 -7
  348. package/dist/data/gcd3nm/function/gcd/loop_check_0.mcfunction +0 -5
  349. package/dist/data/gcd3nm/function/gcd/loop_exit_2.mcfunction +0 -3
  350. package/dist/data/gcd3nm/function/gcd.mcfunction +0 -14
  351. package/dist/data/gcd3nm/function/test.mcfunction +0 -7
  352. package/dist/data/gcd_test/function/__load.mcfunction +0 -3
  353. package/dist/data/gcd_test/function/abs/merge_2.mcfunction +0 -3
  354. package/dist/data/gcd_test/function/abs/then_0.mcfunction +0 -5
  355. package/dist/data/gcd_test/function/abs.mcfunction +0 -7
  356. package/dist/data/gcd_test/function/gcd/loop_body_1.mcfunction +0 -7
  357. package/dist/data/gcd_test/function/gcd/loop_check_0.mcfunction +0 -5
  358. package/dist/data/gcd_test/function/gcd/loop_exit_2.mcfunction +0 -3
  359. package/dist/data/gcd_test/function/gcd.mcfunction +0 -14
  360. package/dist/data/isqrttest/function/__load.mcfunction +0 -6
  361. package/dist/data/isqrttest/function/isqrt/loop_body_4.mcfunction +0 -12
  362. package/dist/data/isqrttest/function/isqrt/loop_check_3.mcfunction +0 -5
  363. package/dist/data/isqrttest/function/isqrt/loop_exit_5.mcfunction +0 -3
  364. package/dist/data/isqrttest/function/isqrt/merge_2.mcfunction +0 -4
  365. package/dist/data/isqrttest/function/isqrt/merge_8.mcfunction +0 -6
  366. package/dist/data/isqrttest/function/isqrt/then_0.mcfunction +0 -3
  367. package/dist/data/isqrttest/function/isqrt/then_6.mcfunction +0 -3
  368. package/dist/data/isqrttest/function/isqrt.mcfunction +0 -7
  369. package/dist/data/isqrttest/function/test.mcfunction +0 -6
  370. package/dist/data/mathtest/function/__load.mcfunction +0 -3
  371. package/dist/data/mathtest/function/abs/merge_2.mcfunction +0 -3
  372. package/dist/data/mathtest/function/abs/then_0.mcfunction +0 -5
  373. package/dist/data/mathtest/function/abs.mcfunction +0 -6
  374. package/dist/data/mathtest/function/test.mcfunction +0 -5
  375. package/dist/data/minecraft/tags/function/load.json +0 -5
  376. package/dist/data/minecraft/tags/function/tick.json +0 -5
  377. package/dist/data/mypack/function/__load.mcfunction +0 -13
  378. package/dist/data/mypack/function/_atan_init.mcfunction +0 -2
  379. package/dist/data/mypack/function/abs/merge_2.mcfunction +0 -3
  380. package/dist/data/mypack/function/abs/then_0.mcfunction +0 -5
  381. package/dist/data/mypack/function/abs.mcfunction +0 -6
  382. package/dist/data/mypack/function/atan2_fixed/__sgi_1.mcfunction +0 -2
  383. package/dist/data/mypack/function/atan2_fixed/else_34.mcfunction +0 -3
  384. package/dist/data/mypack/function/atan2_fixed/loop_body_31.mcfunction +0 -19
  385. package/dist/data/mypack/function/atan2_fixed/loop_check_30.mcfunction +0 -5
  386. package/dist/data/mypack/function/atan2_fixed/loop_exit_32.mcfunction +0 -6
  387. package/dist/data/mypack/function/atan2_fixed/merge_11.mcfunction +0 -6
  388. package/dist/data/mypack/function/atan2_fixed/merge_14.mcfunction +0 -3
  389. package/dist/data/mypack/function/atan2_fixed/merge_17.mcfunction +0 -6
  390. package/dist/data/mypack/function/atan2_fixed/merge_2.mcfunction +0 -5
  391. package/dist/data/mypack/function/atan2_fixed/merge_20.mcfunction +0 -5
  392. package/dist/data/mypack/function/atan2_fixed/merge_23.mcfunction +0 -5
  393. package/dist/data/mypack/function/atan2_fixed/merge_26.mcfunction +0 -6
  394. package/dist/data/mypack/function/atan2_fixed/merge_29.mcfunction +0 -4
  395. package/dist/data/mypack/function/atan2_fixed/merge_38.mcfunction +0 -5
  396. package/dist/data/mypack/function/atan2_fixed/merge_41.mcfunction +0 -5
  397. package/dist/data/mypack/function/atan2_fixed/merge_44.mcfunction +0 -5
  398. package/dist/data/mypack/function/atan2_fixed/merge_47.mcfunction +0 -5
  399. package/dist/data/mypack/function/atan2_fixed/merge_5.mcfunction +0 -5
  400. package/dist/data/mypack/function/atan2_fixed/merge_8.mcfunction +0 -3
  401. package/dist/data/mypack/function/atan2_fixed/then_0.mcfunction +0 -5
  402. package/dist/data/mypack/function/atan2_fixed/then_12.mcfunction +0 -3
  403. package/dist/data/mypack/function/atan2_fixed/then_15.mcfunction +0 -5
  404. package/dist/data/mypack/function/atan2_fixed/then_18.mcfunction +0 -5
  405. package/dist/data/mypack/function/atan2_fixed/then_21.mcfunction +0 -3
  406. package/dist/data/mypack/function/atan2_fixed/then_24.mcfunction +0 -3
  407. package/dist/data/mypack/function/atan2_fixed/then_27.mcfunction +0 -6
  408. package/dist/data/mypack/function/atan2_fixed/then_3.mcfunction +0 -3
  409. package/dist/data/mypack/function/atan2_fixed/then_33.mcfunction +0 -5
  410. package/dist/data/mypack/function/atan2_fixed/then_36.mcfunction +0 -5
  411. package/dist/data/mypack/function/atan2_fixed/then_39.mcfunction +0 -5
  412. package/dist/data/mypack/function/atan2_fixed/then_42.mcfunction +0 -3
  413. package/dist/data/mypack/function/atan2_fixed/then_45.mcfunction +0 -5
  414. package/dist/data/mypack/function/atan2_fixed/then_6.mcfunction +0 -3
  415. package/dist/data/mypack/function/atan2_fixed/then_9.mcfunction +0 -5
  416. package/dist/data/mypack/function/atan2_fixed.mcfunction +0 -7
  417. package/dist/data/mypack/function/my_game.mcfunction +0 -10
  418. package/dist/data/quiz/function/__load.mcfunction +0 -16
  419. package/dist/data/quiz/function/__tick.mcfunction +0 -6
  420. package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +0 -4
  421. package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +0 -4
  422. package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +0 -4
  423. package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +0 -4
  424. package/dist/data/quiz/function/answer_a.mcfunction +0 -4
  425. package/dist/data/quiz/function/answer_b.mcfunction +0 -4
  426. package/dist/data/quiz/function/answer_c.mcfunction +0 -4
  427. package/dist/data/quiz/function/ask_question/else_1.mcfunction +0 -5
  428. package/dist/data/quiz/function/ask_question/else_4.mcfunction +0 -5
  429. package/dist/data/quiz/function/ask_question/else_7.mcfunction +0 -4
  430. package/dist/data/quiz/function/ask_question/merge_2.mcfunction +0 -1
  431. package/dist/data/quiz/function/ask_question/merge_5.mcfunction +0 -2
  432. package/dist/data/quiz/function/ask_question/merge_8.mcfunction +0 -2
  433. package/dist/data/quiz/function/ask_question/then_0.mcfunction +0 -4
  434. package/dist/data/quiz/function/ask_question/then_3.mcfunction +0 -4
  435. package/dist/data/quiz/function/ask_question/then_6.mcfunction +0 -4
  436. package/dist/data/quiz/function/ask_question.mcfunction +0 -7
  437. package/dist/data/quiz/function/finish_quiz.mcfunction +0 -6
  438. package/dist/data/quiz/function/handle_answer/else_1.mcfunction +0 -5
  439. package/dist/data/quiz/function/handle_answer/else_10.mcfunction +0 -3
  440. package/dist/data/quiz/function/handle_answer/else_16.mcfunction +0 -3
  441. package/dist/data/quiz/function/handle_answer/else_4.mcfunction +0 -3
  442. package/dist/data/quiz/function/handle_answer/else_7.mcfunction +0 -5
  443. package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +0 -2
  444. package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +0 -2
  445. package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +0 -2
  446. package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +0 -8
  447. package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +0 -2
  448. package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +0 -2
  449. package/dist/data/quiz/function/handle_answer/then_0.mcfunction +0 -5
  450. package/dist/data/quiz/function/handle_answer/then_12.mcfunction +0 -5
  451. package/dist/data/quiz/function/handle_answer/then_15.mcfunction +0 -6
  452. package/dist/data/quiz/function/handle_answer/then_3.mcfunction +0 -6
  453. package/dist/data/quiz/function/handle_answer/then_6.mcfunction +0 -5
  454. package/dist/data/quiz/function/handle_answer/then_9.mcfunction +0 -6
  455. package/dist/data/quiz/function/handle_answer.mcfunction +0 -11
  456. package/dist/data/quiz/function/start_quiz.mcfunction +0 -5
  457. package/dist/data/reqtest/function/__load.mcfunction +0 -4
  458. package/dist/data/reqtest/function/_table_init.mcfunction +0 -2
  459. package/dist/data/reqtest/function/no_trig.mcfunction +0 -3
  460. package/dist/data/reqtest/function/use_table.mcfunction +0 -4
  461. package/dist/data/reqtest2/function/__load.mcfunction +0 -3
  462. package/dist/data/reqtest2/function/no_trig.mcfunction +0 -3
  463. package/dist/data/runtime/function/__load.mcfunction +0 -5
  464. package/dist/data/runtime/function/__tick.mcfunction +0 -2
  465. package/dist/data/runtime/function/counter_tick/then_0.mcfunction +0 -3
  466. package/dist/data/runtime/function/counter_tick.mcfunction +0 -13
  467. package/dist/data/shop/function/__load.mcfunction +0 -7
  468. package/dist/data/shop/function/__tick.mcfunction +0 -3
  469. package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +0 -4
  470. package/dist/data/shop/function/complete_purchase/else_1.mcfunction +0 -5
  471. package/dist/data/shop/function/complete_purchase/else_4.mcfunction +0 -5
  472. package/dist/data/shop/function/complete_purchase/else_7.mcfunction +0 -3
  473. package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +0 -2
  474. package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +0 -2
  475. package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +0 -2
  476. package/dist/data/shop/function/complete_purchase/then_0.mcfunction +0 -4
  477. package/dist/data/shop/function/complete_purchase/then_3.mcfunction +0 -4
  478. package/dist/data/shop/function/complete_purchase/then_6.mcfunction +0 -4
  479. package/dist/data/shop/function/complete_purchase.mcfunction +0 -7
  480. package/dist/data/shop/function/handle_shop_trigger.mcfunction +0 -3
  481. package/dist/data/swap_test/function/__load.mcfunction +0 -3
  482. package/dist/data/swap_test/function/gcd_old/loop_body_1.mcfunction +0 -7
  483. package/dist/data/swap_test/function/gcd_old/loop_check_0.mcfunction +0 -5
  484. package/dist/data/swap_test/function/gcd_old/loop_exit_2.mcfunction +0 -3
  485. package/dist/data/swap_test/function/gcd_old.mcfunction +0 -8
  486. package/dist/data/turret/function/__load.mcfunction +0 -5
  487. package/dist/data/turret/function/__tick.mcfunction +0 -4
  488. package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +0 -4
  489. package/dist/data/turret/function/deploy_turret.mcfunction +0 -8
  490. package/dist/data/turret/function/turret_tick/at_1.mcfunction +0 -2
  491. package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +0 -2
  492. package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +0 -2
  493. package/dist/data/turret/function/turret_tick/tick_body.mcfunction +0 -3
  494. package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +0 -1
  495. package/dist/data/turret/function/turret_tick.mcfunction +0 -5
  496. package/dist/gcd2.map.json +0 -15
  497. package/dist/gcd3.map.json +0 -17
  498. package/dist/gcd_test.map.json +0 -15
  499. package/dist/index.d.ts +0 -62
  500. package/dist/ir/builder.d.ts +0 -33
  501. package/dist/ir/builder.js +0 -99
  502. package/dist/ir/types.d.ts +0 -132
  503. package/dist/ir/types.js +0 -15
  504. package/dist/isqrttest.map.json +0 -15
  505. package/dist/lowering/index.d.ts +0 -188
  506. package/dist/lowering/index.js +0 -3403
  507. package/dist/mathtest.map.json +0 -6
  508. package/dist/mypack.map.json +0 -27
  509. package/dist/optimizer/commands.d.ts +0 -38
  510. package/dist/optimizer/commands.js +0 -451
  511. package/dist/optimizer/dce.d.ts +0 -34
  512. package/dist/optimizer/dce.js +0 -639
  513. package/dist/optimizer/passes.d.ts +0 -34
  514. package/dist/optimizer/passes.js +0 -243
  515. package/dist/optimizer/structure.d.ts +0 -9
  516. package/dist/optimizer/structure.js +0 -356
  517. package/dist/pack.mcmeta +0 -6
  518. package/dist/reqtest.map.json +0 -4
  519. package/dist/reqtest2.map.json +0 -4
  520. package/dist/runtime.map.json +0 -7
  521. package/dist/swap_test.map.json +0 -14
  522. package/src/__tests__/codegen.test.ts +0 -161
  523. package/src/__tests__/e2e.test.ts +0 -2039
  524. package/src/__tests__/entity-types.test.ts +0 -236
  525. package/src/__tests__/lowering.test.ts +0 -1185
  526. package/src/__tests__/macro.test.ts +0 -343
  527. package/src/__tests__/nbt.test.ts +0 -58
  528. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  529. package/src/__tests__/optimizer.test.ts +0 -162
  530. package/src/__tests__/runtime.test.ts +0 -305
  531. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  532. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  533. package/src/__tests__/stdlib-math.test.ts +0 -374
  534. package/src/__tests__/stdlib-vec.test.ts +0 -259
  535. package/src/__tests__/structure-optimizer.test.ts +0 -38
  536. package/src/__tests__/var-allocator.test.ts +0 -75
  537. package/src/codegen/cmdblock/index.ts +0 -63
  538. package/src/codegen/mcfunction/index.ts +0 -662
  539. package/src/codegen/structure/index.ts +0 -346
  540. package/src/codegen/var-allocator.ts +0 -104
  541. package/src/ir/builder.ts +0 -116
  542. package/src/ir/types.ts +0 -134
  543. package/src/lowering/index.ts +0 -3876
  544. package/src/optimizer/commands.ts +0 -534
  545. package/src/optimizer/passes.ts +0 -250
  546. package/src/optimizer/structure.ts +0 -450
  547. /package/dist/{__tests__/cli.test.d.ts → src/__tests__/budget.test.d.ts} +0 -0
  548. /package/dist/{__tests__/codegen.test.d.ts → src/__tests__/cli.test.d.ts} +0 -0
  549. /package/dist/{__tests__ → src/__tests__}/compile-all.test.d.ts +0 -0
  550. /package/dist/{__tests__ → src/__tests__}/compile-all.test.js +0 -0
  551. /package/dist/{__tests__ → src/__tests__}/dce.test.d.ts +0 -0
  552. /package/dist/{__tests__ → src/__tests__}/diagnostics.test.d.ts +0 -0
  553. /package/dist/{__tests__ → src/__tests__}/formatter.test.d.ts +0 -0
  554. /package/dist/{__tests__ → src/__tests__}/formatter.test.js +0 -0
  555. /package/dist/{__tests__/entity-types.test.d.ts → src/__tests__/hir/desugar.test.d.ts} +0 -0
  556. /package/dist/{__tests__ → src/__tests__}/lexer.test.d.ts +0 -0
  557. /package/dist/{__tests__ → src/__tests__}/lexer.test.js +0 -0
  558. /package/dist/{__tests__/lowering.test.d.ts → src/__tests__/lir/lower.test.d.ts} +0 -0
  559. /package/dist/{__tests__/mc-syntax.test.d.ts → src/__tests__/lir/types.test.d.ts} +0 -0
  560. /package/dist/{__tests__/nbt.test.d.ts → src/__tests__/lir/verify.test.d.ts} +0 -0
  561. /package/dist/{__tests__ → src/__tests__}/mc-integration.test.d.ts +0 -0
  562. /package/dist/{__tests__/optimizer-advanced.test.d.ts → src/__tests__/mc-syntax.test.d.ts} +0 -0
  563. /package/dist/{__tests__ → src/__tests__}/mc-syntax.test.js +0 -0
  564. /package/dist/{__tests__/optimizer.test.d.ts → src/__tests__/mir/arithmetic.test.d.ts} +0 -0
  565. /package/dist/{__tests__/parser.test.d.ts → src/__tests__/mir/control-flow.test.d.ts} +0 -0
  566. /package/dist/{__tests__/repl.test.d.ts → src/__tests__/mir/verify.test.d.ts} +0 -0
  567. /package/dist/{__tests__/runtime.test.d.ts → src/__tests__/optimizer/block_merge.test.d.ts} +0 -0
  568. /package/dist/{__tests__/structure-optimizer.test.d.ts → src/__tests__/optimizer/branch_simplify.test.d.ts} +0 -0
  569. /package/dist/{__tests__/typechecker.test.d.ts → src/__tests__/optimizer/constant_fold.test.d.ts} +0 -0
  570. /package/dist/{__tests__/var-allocator.test.d.ts → src/__tests__/optimizer/copy_prop.test.d.ts} +0 -0
  571. /package/dist/{__tests__ → src/__tests__}/parser.test.js +0 -0
  572. /package/dist/{__tests__ → src/__tests__}/repl.test.js +0 -0
  573. /package/dist/{__tests__ → src/__tests__}/typechecker.test.js +0 -0
  574. /package/dist/{ast → src/ast}/types.js +0 -0
  575. /package/dist/{builtins → src/builtins}/metadata.d.ts +0 -0
  576. /package/dist/{builtins → src/builtins}/metadata.js +0 -0
  577. /package/dist/{events → src/events}/types.d.ts +0 -0
  578. /package/dist/{events → src/events}/types.js +0 -0
  579. /package/dist/{formatter → src/formatter}/index.d.ts +0 -0
  580. /package/dist/{formatter → src/formatter}/index.js +0 -0
  581. /package/dist/{mc-test → src/mc-test}/client.d.ts +0 -0
  582. /package/dist/{mc-test → src/mc-test}/client.js +0 -0
  583. /package/dist/{mc-test → src/mc-test}/runner.d.ts +0 -0
  584. /package/dist/{mc-test → src/mc-test}/setup.d.ts +0 -0
  585. /package/dist/{mc-test → src/mc-test}/setup.js +0 -0
  586. /package/dist/{mc-validator → src/mc-validator}/index.d.ts +0 -0
  587. /package/dist/{mc-validator → src/mc-validator}/index.js +0 -0
  588. /package/dist/{nbt → src/nbt}/index.d.ts +0 -0
  589. /package/dist/{nbt → src/nbt}/index.js +0 -0
  590. /package/dist/{repl.js → src/repl.js} +0 -0
  591. /package/dist/{runtime → src/runtime}/index.d.ts +0 -0
  592. /package/dist/{types → src/types}/entity-hierarchy.d.ts +0 -0
  593. /package/dist/{types → src/types}/entity-hierarchy.js +0 -0
@@ -1,250 +0,0 @@
1
- /**
2
- * Optimization passes over IR.
3
- *
4
- * Each pass: IRFunction → IRFunction (pure transformation)
5
- *
6
- * Pipeline order:
7
- * 1. constantFolding — evaluate constant expressions at compile time
8
- * 2. copyPropagation — eliminate redundant copies
9
- * 3. deadCodeElimination — remove unused assignments
10
- * 4. commandMerging — MC-specific: merge chained execute conditions
11
- */
12
-
13
- import type { IRBlock, IRFunction, IRInstr, Operand } from '../ir/types'
14
- import { createEmptyOptimizationStats, mergeOptimizationStats, type OptimizationStats } from './commands'
15
-
16
- // ---------------------------------------------------------------------------
17
- // Helpers
18
- // ---------------------------------------------------------------------------
19
-
20
- function isConst(op: Operand): op is { kind: 'const'; value: number } {
21
- return op.kind === 'const'
22
- }
23
-
24
- function evalBinop(lhs: number, bop: string, rhs: number): number | null {
25
- switch (bop) {
26
- case '+': return lhs + rhs
27
- case '-': return lhs - rhs
28
- case '*': return lhs * rhs
29
- case '/': return rhs === 0 ? null : Math.trunc(lhs / rhs) // MC uses truncated int division
30
- case '%': return rhs === 0 ? null : lhs % rhs
31
- default: return null
32
- }
33
- }
34
-
35
- function evalCmp(lhs: number, cop: string, rhs: number): number {
36
- switch (cop) {
37
- case '==': return lhs === rhs ? 1 : 0
38
- case '!=': return lhs !== rhs ? 1 : 0
39
- case '<': return lhs < rhs ? 1 : 0
40
- case '<=': return lhs <= rhs ? 1 : 0
41
- case '>': return lhs > rhs ? 1 : 0
42
- case '>=': return lhs >= rhs ? 1 : 0
43
- default: return 0
44
- }
45
- }
46
-
47
- // ---------------------------------------------------------------------------
48
- // Pass 1: Constant Folding
49
- // Evaluates expressions with all-constant operands at compile time.
50
- // ---------------------------------------------------------------------------
51
-
52
- export function constantFolding(fn: IRFunction): IRFunction {
53
- return constantFoldingWithStats(fn).fn
54
- }
55
-
56
- export function constantFoldingWithStats(fn: IRFunction): { fn: IRFunction; stats: Partial<OptimizationStats> } {
57
- let folded = 0
58
- const newBlocks = fn.blocks.map(block => {
59
- const newInstrs: IRInstr[] = []
60
- for (const instr of block.instrs) {
61
- if (instr.op === 'binop' && isConst(instr.lhs) && isConst(instr.rhs)) {
62
- const result = evalBinop(instr.lhs.value, instr.bop, instr.rhs.value)
63
- if (result !== null) {
64
- folded++
65
- newInstrs.push({ op: 'assign', dst: instr.dst, src: { kind: 'const', value: result } })
66
- continue
67
- }
68
- }
69
- if (instr.op === 'cmp' && isConst(instr.lhs) && isConst(instr.rhs)) {
70
- const result = evalCmp(instr.lhs.value, instr.cop, instr.rhs.value)
71
- folded++
72
- newInstrs.push({ op: 'assign', dst: instr.dst, src: { kind: 'const', value: result } })
73
- continue
74
- }
75
- newInstrs.push(instr)
76
- }
77
- return { ...block, instrs: newInstrs }
78
- })
79
- return { fn: { ...fn, blocks: newBlocks }, stats: { constantFolds: folded } }
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Pass 2: Copy Propagation
84
- // Replaces uses of variables that are just copies with their source.
85
- // e.g. t0 = x; y = t0 + 1 → y = x + 1
86
- // ---------------------------------------------------------------------------
87
-
88
- export function copyPropagation(fn: IRFunction): IRFunction {
89
- // Build copy map within each block (single-block analysis for simplicity)
90
- const newBlocks = fn.blocks.map(block => {
91
- const copies = new Map<string, Operand>() // var → its source if it's a copy
92
-
93
- function resolve(op: Operand): Operand {
94
- if (op.kind !== 'var') return op
95
- return copies.get(op.name) ?? op
96
- }
97
-
98
- /**
99
- * Invalidate all copies that became stale because `written` was modified.
100
- * When $y is overwritten, any mapping copies[$tmp] = $y is now stale:
101
- * reading $tmp would return the OLD $y value via the copy, but $y now holds
102
- * a different value. Remove both the direct entry (copies[$y]) and every
103
- * reverse entry that points at $y.
104
- */
105
- function invalidate(written: string): void {
106
- copies.delete(written)
107
- for (const [k, v] of copies) {
108
- if (v.kind === 'var' && v.name === written) copies.delete(k)
109
- }
110
- }
111
-
112
- const newInstrs: IRInstr[] = []
113
- for (const instr of block.instrs) {
114
- switch (instr.op) {
115
- case 'assign': {
116
- const src = resolve(instr.src)
117
- invalidate(instr.dst)
118
- // Only propagate scalars (var or const), not storage
119
- if (src.kind === 'var' || src.kind === 'const') {
120
- copies.set(instr.dst, src)
121
- }
122
- newInstrs.push({ ...instr, src })
123
- break
124
- }
125
- case 'binop':
126
- invalidate(instr.dst)
127
- newInstrs.push({ ...instr, lhs: resolve(instr.lhs), rhs: resolve(instr.rhs) })
128
- break
129
- case 'cmp':
130
- invalidate(instr.dst)
131
- newInstrs.push({ ...instr, lhs: resolve(instr.lhs), rhs: resolve(instr.rhs) })
132
- break
133
- case 'call':
134
- if (instr.dst) invalidate(instr.dst)
135
- newInstrs.push({ ...instr, args: instr.args.map(resolve) })
136
- break
137
- default:
138
- newInstrs.push(instr)
139
- }
140
- }
141
- return { ...block, instrs: newInstrs }
142
- })
143
- return { ...fn, blocks: newBlocks }
144
- }
145
-
146
- // ---------------------------------------------------------------------------
147
- // Pass 3: Dead Code Elimination
148
- // Removes assignments to variables that are never read afterward.
149
- // ---------------------------------------------------------------------------
150
-
151
- export function deadCodeElimination(fn: IRFunction): IRFunction {
152
- return deadCodeEliminationWithStats(fn).fn
153
- }
154
-
155
- export function deadCodeEliminationWithStats(fn: IRFunction): { fn: IRFunction; stats: Partial<OptimizationStats> } {
156
- // Collect all reads across all blocks
157
- const readVars = new Set<string>()
158
-
159
- function markRead(op: Operand) {
160
- if (op.kind === 'var') readVars.add(op.name)
161
- }
162
-
163
- function markRawReads(cmd: string) {
164
- for (const match of cmd.matchAll(/\$[A-Za-z0-9_]+/g)) {
165
- readVars.add(match[0])
166
- }
167
- }
168
-
169
- for (const block of fn.blocks) {
170
- for (const instr of block.instrs) {
171
- if (instr.op === 'binop') { markRead(instr.lhs); markRead(instr.rhs) }
172
- if (instr.op === 'cmp') { markRead(instr.lhs); markRead(instr.rhs) }
173
- if (instr.op === 'call') { instr.args.forEach(markRead) }
174
- if (instr.op === 'assign') { markRead(instr.src) }
175
- if (instr.op === 'raw') { markRawReads(instr.cmd) }
176
- }
177
- // Terminator reads
178
- const t = block.term
179
- if (t.op === 'jump_if' || t.op === 'jump_unless') readVars.add(t.cond)
180
- if (t.op === 'return' && t.value) markRead(t.value)
181
- if (t.op === 'tick_yield') { /* no reads */ }
182
- }
183
-
184
- // Also keep params and globals
185
- fn.params.forEach(p => readVars.add(p))
186
-
187
- let removed = 0
188
- const newBlocks = fn.blocks.map(block => ({
189
- ...block,
190
- instrs: block.instrs.filter(instr => {
191
- // Only assignments/binops/cmps with an unused dst are candidates for removal
192
- if (instr.op === 'assign' || instr.op === 'binop' || instr.op === 'cmp') {
193
- // Always keep assignments to global variables (they may be read by other functions)
194
- // Temps are $t0, $t1, ...; params are $p0, $p1, ...; locals are $_0, $_1, ...
195
- // Everything else is a potential global
196
- const isTemp = /^\$t\d+$/.test(instr.dst) || /^\$p\d+$/.test(instr.dst) || /^\$_\d+$/.test(instr.dst)
197
- const keep = !isTemp || readVars.has(instr.dst)
198
- if (!keep) removed++
199
- return keep
200
- }
201
- // calls may have side effects — keep them always
202
- return true
203
- }),
204
- }))
205
-
206
- return { fn: { ...fn, blocks: newBlocks }, stats: { deadCodeRemoved: removed } }
207
- }
208
-
209
- // ---------------------------------------------------------------------------
210
- // Pipeline
211
- // ---------------------------------------------------------------------------
212
-
213
- export interface OptimizationPass {
214
- name: string
215
- run: (fn: IRFunction) => IRFunction
216
- }
217
-
218
- export const defaultPipeline: OptimizationPass[] = [
219
- { name: 'constant-folding', run: constantFolding },
220
- { name: 'copy-propagation', run: copyPropagation },
221
- { name: 'dead-code-elimination', run: deadCodeElimination },
222
- // commandMerging is applied during codegen (MC-specific)
223
- ]
224
-
225
- export function optimize(fn: IRFunction, passes = defaultPipeline): IRFunction {
226
- return optimizeWithStats(fn, passes).fn
227
- }
228
-
229
- export function optimizeWithStats(fn: IRFunction, passes = defaultPipeline): { fn: IRFunction; stats: OptimizationStats } {
230
- let current = fn
231
- const stats = createEmptyOptimizationStats()
232
-
233
- for (const pass of passes) {
234
- if (pass.name === 'constant-folding') {
235
- const result = constantFoldingWithStats(current)
236
- current = result.fn
237
- mergeOptimizationStats(stats, result.stats)
238
- continue
239
- }
240
- if (pass.name === 'dead-code-elimination') {
241
- const result = deadCodeEliminationWithStats(current)
242
- current = result.fn
243
- mergeOptimizationStats(stats, result.stats)
244
- continue
245
- }
246
- current = pass.run(current)
247
- }
248
-
249
- return { fn: current, stats }
250
- }
@@ -1,450 +0,0 @@
1
- import type { IRBlock, IRCommand, IRFunction, IRInstr, Operand, Terminator } from '../ir/types'
2
- import { createEmptyOptimizationStats, mergeOptimizationStats, optimizeCommandFunctions, setOptimizerObjective, type OptimizationStats } from './commands'
3
-
4
- let OBJ = 'rs'
5
- export function setStructureObjective(obj: string): void {
6
- OBJ = obj
7
- setOptimizerObjective(obj)
8
- }
9
- const INLINE_THRESHOLD = 8
10
-
11
- const BOP_OP: Record<string, string> = {
12
- '+': '+=',
13
- '-': '-=',
14
- '*': '*=',
15
- '/': '/=',
16
- '%': '%=',
17
- }
18
-
19
- interface InlineBlock {
20
- commands: IRCommand[]
21
- continuation?: string
22
- }
23
-
24
- function varRef(name: string): string {
25
- return name.startsWith('$') ? name : `$${name}`
26
- }
27
-
28
- function operandToScore(op: Operand): string {
29
- if (op.kind === 'var') return `${varRef(op.name)} ${OBJ}`
30
- if (op.kind === 'const') return `$const_${op.value} ${OBJ}`
31
- if (op.kind === 'param') return `$p${op.index} ${OBJ}`
32
- throw new Error(`Cannot convert storage operand to score: ${(op as any).path}`)
33
- }
34
-
35
- function emitInstr(instr: IRInstr, namespace: string): IRCommand[] {
36
- const commands: IRCommand[] = []
37
-
38
- switch (instr.op) {
39
- case 'assign':
40
- if (instr.src.kind === 'const') {
41
- commands.push({ cmd: `scoreboard players set ${varRef(instr.dst)} ${OBJ} ${instr.src.value}` })
42
- } else if (instr.src.kind === 'var') {
43
- commands.push({
44
- cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} = ${varRef(instr.src.name)} ${OBJ}`,
45
- })
46
- } else if (instr.src.kind === 'param') {
47
- commands.push({
48
- cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} = $p${instr.src.index} ${OBJ}`,
49
- })
50
- } else {
51
- commands.push({
52
- cmd: `execute store result score ${varRef(instr.dst)} ${OBJ} run data get storage ${instr.src.path}`,
53
- })
54
- }
55
- break
56
-
57
- case 'binop':
58
- commands.push(...emitInstr({ op: 'assign', dst: instr.dst, src: instr.lhs }, namespace))
59
- commands.push({
60
- cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} ${BOP_OP[instr.bop]} ${operandToScore(instr.rhs)}`,
61
- })
62
- break
63
-
64
- case 'cmp': {
65
- const dst = varRef(instr.dst)
66
- const lhs = operandToScore(instr.lhs)
67
- const rhs = operandToScore(instr.rhs)
68
- commands.push({ cmd: `scoreboard players set ${dst} ${OBJ} 0` })
69
- const op =
70
- instr.cop === '==' ? 'if score' :
71
- instr.cop === '!=' ? 'unless score' :
72
- instr.cop === '<' ? 'if score' :
73
- instr.cop === '<=' ? 'if score' :
74
- instr.cop === '>' ? 'if score' :
75
- 'if score'
76
- const cmp =
77
- instr.cop === '==' || instr.cop === '!=' ? '=' :
78
- instr.cop
79
- commands.push({
80
- cmd: `execute ${op} ${lhs} ${cmp} ${rhs} run scoreboard players set ${dst} ${OBJ} 1`,
81
- })
82
- break
83
- }
84
-
85
- case 'call':
86
- for (let i = 0; i < instr.args.length; i++) {
87
- commands.push(...emitInstr({ op: 'assign', dst: `$p${i}`, src: instr.args[i] }, namespace))
88
- }
89
- commands.push({ cmd: `function ${namespace}:${instr.fn}` })
90
- if (instr.dst) {
91
- commands.push({
92
- cmd: `scoreboard players operation ${varRef(instr.dst)} ${OBJ} = $ret ${OBJ}`,
93
- })
94
- }
95
- break
96
-
97
- case 'raw':
98
- commands.push({ cmd: instr.cmd })
99
- break
100
- }
101
-
102
- return commands
103
- }
104
-
105
- function emitReturn(term: Extract<Terminator, { op: 'return' }>): IRCommand[] {
106
- const commands: IRCommand[] = []
107
- if (term.value) {
108
- commands.push(...emitInstr({ op: 'assign', dst: '$ret', src: term.value }, ''))
109
- }
110
- if (term.value?.kind === 'const') {
111
- commands.push({ cmd: `return ${term.value.value}` })
112
- } else if (term.value?.kind === 'var') {
113
- commands.push({ cmd: `return run scoreboard players get ${varRef(term.value.name)} ${OBJ}` })
114
- }
115
- return commands
116
- }
117
-
118
- function markConditional(commands: IRCommand[]): IRCommand[] {
119
- return commands.map(command => ({
120
- ...command,
121
- conditional: true,
122
- }))
123
- }
124
-
125
- function cloneVisited(visited: Set<string>): Set<string> {
126
- return new Set(visited)
127
- }
128
-
129
- function isRecursiveCommand(command: string, currentFn: string, namespace: string): boolean {
130
- return command.includes(`function ${namespace}:${currentFn}`)
131
- }
132
-
133
- function getInlineableBlock(
134
- block: IRBlock | undefined,
135
- currentFn: string,
136
- namespace: string
137
- ): InlineBlock | null {
138
- if (!block) return null
139
- if (block.term.op === 'jump_if' || block.term.op === 'jump_unless' || block.term.op === 'tick_yield') {
140
- return null
141
- }
142
-
143
- const commands = block.instrs.flatMap(instr => emitInstr(instr, namespace))
144
- if (commands.some(command => isRecursiveCommand(command.cmd, currentFn, namespace))) {
145
- return null
146
- }
147
-
148
- if (block.term.op === 'return') {
149
- commands.push(...emitReturn(block.term))
150
- }
151
-
152
- if (commands.length > INLINE_THRESHOLD) {
153
- return null
154
- }
155
-
156
- return {
157
- commands,
158
- continuation: block.term.op === 'jump' ? block.term.target : undefined,
159
- }
160
- }
161
-
162
- function flattenBlock(
163
- fn: IRFunction,
164
- label: string,
165
- namespace: string,
166
- visited: Set<string>
167
- ): IRCommand[] {
168
- const blockMap = new Map(fn.blocks.map(block => [block.label, block]))
169
- const block = blockMap.get(label)
170
- if (!block) {
171
- return []
172
- }
173
-
174
- if (visited.has(label)) {
175
- return [{ cmd: `function ${namespace}:${fn.name}/${label}`, label }]
176
- }
177
-
178
- visited.add(label)
179
-
180
- const commands: IRCommand[] = []
181
- if (label === fn.blocks[0]?.label) {
182
- for (let i = 0; i < fn.params.length; i++) {
183
- commands.push({
184
- cmd: `scoreboard players operation ${varRef(fn.params[i])} ${OBJ} = $p${i} ${OBJ}`,
185
- })
186
- }
187
- }
188
- commands.push(...block.instrs.flatMap(instr => emitInstr(instr, namespace)))
189
- const term = block.term
190
-
191
- switch (term.op) {
192
- case 'jump':
193
- commands.push(...flattenBlock(fn, term.target, namespace, visited))
194
- return commands
195
-
196
- case 'jump_if':
197
- case 'jump_unless': {
198
- const trueLabel = term.op === 'jump_if' ? term.then : term.else_
199
- const falseLabel = term.op === 'jump_if' ? term.else_ : term.then
200
- const trueRange = term.op === 'jump_if' ? '1..' : '..0'
201
- const falseRange = term.op === 'jump_if' ? '..0' : '1..'
202
- const trueBlock = getInlineableBlock(blockMap.get(trueLabel), fn.name, namespace)
203
- const falseBlock = getInlineableBlock(blockMap.get(falseLabel), fn.name, namespace)
204
-
205
- if (trueBlock && falseBlock) {
206
- if (trueBlock.commands.length > 0) {
207
- commands.push({ cmd: `execute if score ${varRef(term.cond)} ${OBJ} matches ${trueRange}`, label: trueLabel })
208
- commands.push(...markConditional(trueBlock.commands))
209
- }
210
- if (falseBlock.commands.length > 0) {
211
- commands.push({ cmd: `execute if score ${varRef(term.cond)} ${OBJ} matches ${falseRange}`, label: falseLabel })
212
- commands.push(...markConditional(falseBlock.commands))
213
- }
214
-
215
- const continuation = trueBlock.continuation && trueBlock.continuation === falseBlock.continuation
216
- ? trueBlock.continuation
217
- : undefined
218
- if (continuation) {
219
- commands.push(...flattenBlock(fn, continuation, namespace, cloneVisited(visited)))
220
- }
221
- return commands
222
- }
223
-
224
- commands.push({ cmd: `execute if score ${varRef(term.cond)} ${OBJ} matches ${trueRange} run function ${namespace}:${fn.name}/${trueLabel}` })
225
- commands.push({ cmd: `execute if score ${varRef(term.cond)} ${OBJ} matches ${falseRange} run function ${namespace}:${fn.name}/${falseLabel}` })
226
- return commands
227
- }
228
-
229
- case 'return':
230
- commands.push(...emitReturn(term))
231
- return commands
232
-
233
- case 'tick_yield':
234
- commands.push({ cmd: `schedule function ${namespace}:${fn.name}/${term.continuation} 1t replace` })
235
- return commands
236
- }
237
- }
238
-
239
- function findVars(command: string): string[] {
240
- return Array.from(command.matchAll(/\$[A-Za-z0-9_]+/g), match => match[0])
241
- }
242
-
243
- function parsePureWrite(command: string): { dst: string; reads: string[] } | null {
244
- let match = command.match(/^scoreboard players set (\$[A-Za-z0-9_]+) rs -?\d+$/)
245
- if (match) {
246
- return { dst: match[1], reads: [] }
247
- }
248
-
249
- match = command.match(/^scoreboard players operation (\$[A-Za-z0-9_]+) rs = (\$[A-Za-z0-9_]+) rs$/)
250
- if (match) {
251
- return { dst: match[1], reads: [match[2]] }
252
- }
253
-
254
- match = command.match(/^execute .* run scoreboard players set (\$[A-Za-z0-9_]+) rs -?\d+$/)
255
- if (match) {
256
- return {
257
- dst: match[1],
258
- reads: findVars(command).filter(name => name !== match![1]),
259
- }
260
- }
261
-
262
- return null
263
- }
264
-
265
- function deadStoreEliminate(commands: IRCommand[]): IRCommand[] {
266
- const live = new Set<string>()
267
- const kept: IRCommand[] = []
268
-
269
- for (let i = commands.length - 1; i >= 0; i--) {
270
- const command = commands[i]
271
- const pureWrite = parsePureWrite(command.cmd)
272
-
273
- if (pureWrite) {
274
- pureWrite.reads.forEach(name => live.add(name))
275
- if (!live.has(pureWrite.dst)) {
276
- continue
277
- }
278
- live.delete(pureWrite.dst)
279
- kept.push(command)
280
- continue
281
- }
282
-
283
- findVars(command.cmd).forEach(name => live.add(name))
284
- kept.push(command)
285
- }
286
-
287
- return kept.reverse()
288
- }
289
-
290
- function isInlineableFunction(
291
- fn: IRFunction | undefined,
292
- currentFn: string,
293
- namespace: string
294
- ): fn is IRFunction & { commands: IRCommand[] } {
295
- if (!fn?.commands || fn.name === currentFn || fn.commands.length > INLINE_THRESHOLD) {
296
- return false
297
- }
298
-
299
- return !fn.commands.some(command =>
300
- isRecursiveCommand(command.cmd, currentFn, namespace) ||
301
- isRecursiveCommand(command.cmd, fn.name, namespace)
302
- )
303
- }
304
-
305
- function inlineConditionalCalls(
306
- commands: IRCommand[],
307
- functions: Map<string, IRFunction>,
308
- currentFn: string,
309
- namespace: string
310
- ): IRCommand[] {
311
- const optimized: IRCommand[] = []
312
-
313
- for (const command of commands) {
314
- const match = command.cmd.match(/^(execute .+) run function ([^:]+):(.+)$/)
315
- if (!match || match[2] !== namespace) {
316
- optimized.push(command)
317
- continue
318
- }
319
-
320
- const target = functions.get(match[3])
321
- if (!isInlineableFunction(target, currentFn, namespace)) {
322
- optimized.push(command)
323
- continue
324
- }
325
-
326
- optimized.push({ cmd: match[1], label: command.label })
327
- optimized.push(...markConditional(target.commands))
328
- }
329
-
330
- return optimized
331
- }
332
-
333
- function invertExecuteCondition(command: string): string | null {
334
- if (command.startsWith('execute if ')) {
335
- return command.replace(/^execute if /, 'execute unless ')
336
- }
337
- if (command.startsWith('execute unless ')) {
338
- return command.replace(/^execute unless /, 'execute if ')
339
- }
340
- return null
341
- }
342
-
343
- function eliminateBranchVariables(
344
- commands: IRCommand[],
345
- functions: Map<string, IRFunction>,
346
- currentFn: string,
347
- namespace: string
348
- ): IRCommand[] {
349
- const optimized: IRCommand[] = []
350
-
351
- for (let i = 0; i < commands.length; i++) {
352
- const init = commands[i]
353
- const set = commands[i + 1]
354
- const thenCmd = commands[i + 2]
355
- const elseCmd = commands[i + 3]
356
-
357
- const initMatch = init?.cmd.match(/^scoreboard players set (\$[A-Za-z0-9_]+) rs 0$/)
358
- const setMatch = set?.cmd.match(/^((?:execute if|execute unless) .+) run scoreboard players set (\$[A-Za-z0-9_]+) rs 1$/)
359
- const thenMatch = thenCmd?.cmd.match(/^execute if score (\$[A-Za-z0-9_]+) rs matches 1\.\. run function [^:]+:(.+)$/)
360
- const elseMatch =
361
- elseCmd?.cmd.match(/^execute if score (\$[A-Za-z0-9_]+) rs matches ..0 run function [^:]+:(.+)$/) ??
362
- elseCmd?.cmd.match(/^execute unless score (\$[A-Za-z0-9_]+) rs matches 1\.\. run function [^:]+:(.+)$/)
363
-
364
- if (!initMatch || !setMatch || !thenMatch || !elseMatch) {
365
- optimized.push(init)
366
- continue
367
- }
368
-
369
- const branchVar = initMatch[1]
370
- if (setMatch[2] !== branchVar || thenMatch[1] !== branchVar || elseMatch[1] !== branchVar) {
371
- optimized.push(init)
372
- continue
373
- }
374
-
375
- const thenFn = functions.get(thenMatch[2])
376
- const elseFn = functions.get(elseMatch[2])
377
- if (!isInlineableFunction(thenFn, currentFn, namespace) || !isInlineableFunction(elseFn, currentFn, namespace)) {
378
- optimized.push(init)
379
- continue
380
- }
381
-
382
- const thenCondition = setMatch[1]
383
- const elseCondition = invertExecuteCondition(thenCondition)
384
- if (!elseCondition) {
385
- optimized.push(init)
386
- continue
387
- }
388
-
389
- optimized.push({ cmd: thenCondition })
390
- optimized.push(...markConditional(thenFn.commands))
391
- if (elseFn.commands.length > 0) {
392
- optimized.push({ cmd: elseCondition })
393
- optimized.push(...markConditional(elseFn.commands))
394
- }
395
- i += 3
396
- }
397
-
398
- return optimized
399
- }
400
-
401
- export function optimizeFunctionForStructure(
402
- fn: IRFunction,
403
- functions: Map<string, IRFunction>,
404
- namespace: string
405
- ): IRCommand[] {
406
- if (fn.blocks.length === 0) {
407
- return []
408
- }
409
-
410
- const linear = flattenBlock(fn, fn.blocks[0].label, namespace, new Set<string>())
411
- const branchEliminated = eliminateBranchVariables(linear, functions, fn.name, namespace)
412
- const inlined = inlineConditionalCalls(branchEliminated, functions, fn.name, namespace)
413
- return deadStoreEliminate(inlined)
414
- }
415
-
416
- export function optimizeForStructure(functions: IRFunction[], namespace = 'redscript'): IRFunction[] {
417
- return optimizeForStructureWithStats(functions, namespace).functions
418
- }
419
-
420
- export function optimizeForStructureWithStats(
421
- functions: IRFunction[],
422
- namespace = 'redscript'
423
- ): { functions: IRFunction[]; stats: OptimizationStats } {
424
- const staged = new Map(functions.map(fn => [fn.name, { ...fn }]))
425
-
426
- for (const fn of staged.values()) {
427
- fn.commands = flattenBlock(fn, fn.blocks[0]?.label ?? 'entry', namespace, new Set<string>())
428
- }
429
-
430
- for (const fn of staged.values()) {
431
- fn.commands = optimizeFunctionForStructure(fn, staged, namespace)
432
- }
433
-
434
- const optimizedCommands = optimizeCommandFunctions(
435
- Array.from(staged.values()).map(fn => ({
436
- name: fn.name,
437
- commands: fn.commands ?? [],
438
- }))
439
- )
440
- const stats = createEmptyOptimizationStats()
441
- mergeOptimizationStats(stats, optimizedCommands.stats)
442
-
443
- return {
444
- functions: Array.from(staged.values()).map(fn => ({
445
- ...fn,
446
- commands: optimizedCommands.functions.find(candidate => candidate.name === fn.name)?.commands ?? fn.commands,
447
- })),
448
- stats,
449
- }
450
- }