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
@@ -0,0 +1,587 @@
1
+ /**
2
+ * MIR → LIR Lowering — Stage 5 of the RedScript compiler pipeline.
3
+ *
4
+ * Converts 3-address MIR (CFG with basic blocks) to 2-address LIR
5
+ * (flat instruction lists with MC scoreboard semantics).
6
+ *
7
+ * Key transformations:
8
+ * - Each MIR Temp → a Slot (player = $tempname, obj = module.objective)
9
+ * - 3-address arithmetic → score_copy dst←a, then score_op dst←b
10
+ * - CFG control flow → call_if_matches / call_unless_matches to extracted functions
11
+ * - MIR calls → parameter slot setup + call instruction
12
+ */
13
+
14
+ import type {
15
+ MIRModule, MIRFunction, MIRBlock, MIRInstr, Operand, Temp, BlockId,
16
+ } from '../mir/types'
17
+ import type {
18
+ LIRModule, LIRFunction, LIRInstr, Slot, SourceLoc,
19
+ } from './types'
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Public API
23
+ // ---------------------------------------------------------------------------
24
+
25
+ export function lowerToLIR(mir: MIRModule): LIRModule {
26
+ const ctx = new LoweringContext(mir.namespace, mir.objective)
27
+ for (const fn of mir.functions) {
28
+ lowerFunction(fn, ctx)
29
+ }
30
+ return {
31
+ functions: ctx.functions,
32
+ namespace: mir.namespace,
33
+ objective: mir.objective,
34
+ }
35
+ }
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Lowering context
39
+ // ---------------------------------------------------------------------------
40
+
41
+ class LoweringContext {
42
+ readonly functions: LIRFunction[] = []
43
+ readonly namespace: string
44
+ readonly objective: string
45
+ /** Track which blocks have multiple predecessors (need their own function) */
46
+ private multiPredBlocks = new Set<BlockId>()
47
+ /** Map block id → generated LIR function name for multi-pred blocks */
48
+ private blockFnNames = new Map<BlockId, string>()
49
+ /** Current MIR function being lowered */
50
+ private currentMIRFn: MIRFunction | null = null
51
+ /** Block map for quick lookup */
52
+ private blockMap = new Map<BlockId, MIRBlock>()
53
+
54
+ constructor(namespace: string, objective: string) {
55
+ this.namespace = namespace
56
+ this.objective = objective
57
+ }
58
+
59
+ slot(temp: Temp): Slot {
60
+ // Return field temps are global (shared between caller/callee)
61
+ if (temp.startsWith('__rf_')) {
62
+ return { player: `$ret_${temp.slice(5)}`, obj: this.objective }
63
+ }
64
+ // Prefix temp names with function name to avoid caller/callee collision
65
+ const fn = this.currentMIRFn
66
+ const prefix = fn ? fn.name : ''
67
+ return { player: `$${prefix}_${temp}`, obj: this.objective }
68
+ }
69
+
70
+ qualifiedName(fnName: string): string {
71
+ // Convert :: to / and lowercase for MC function paths
72
+ const mcName = fnName.replace(/::/g, '/').toLowerCase()
73
+ return `${this.namespace}:${mcName}`
74
+ }
75
+
76
+ addFunction(fn: LIRFunction): void {
77
+ this.functions.push(fn)
78
+ }
79
+
80
+ /** Attach sourceLoc to newly added instructions (from the given start index onward) */
81
+ tagSourceLoc(instrs: LIRInstr[], fromIndex: number, sourceLoc: SourceLoc | undefined): void {
82
+ if (!sourceLoc) return
83
+ for (let i = fromIndex; i < instrs.length; i++) {
84
+ if (!instrs[i].sourceLoc) instrs[i].sourceLoc = sourceLoc
85
+ }
86
+ }
87
+
88
+ analyzeBlocks(fn: MIRFunction): void {
89
+ this.currentMIRFn = fn
90
+ this.multiPredBlocks.clear()
91
+ this.blockFnNames.clear()
92
+ this.blockMap.clear()
93
+
94
+ for (const block of fn.blocks) {
95
+ this.blockMap.set(block.id, block)
96
+ }
97
+
98
+ // Count predecessors for each block
99
+ const predCount = new Map<BlockId, number>()
100
+ for (const block of fn.blocks) {
101
+ const targets = getTermTargets(block.term)
102
+ for (const target of targets) {
103
+ predCount.set(target, (predCount.get(target) || 0) + 1)
104
+ }
105
+ }
106
+
107
+ // Blocks with >1 predecessors or that are branch targets need their own function
108
+ for (const [blockId, count] of predCount) {
109
+ if (count > 1 && blockId !== fn.entry) {
110
+ this.multiPredBlocks.add(blockId)
111
+ this.blockFnNames.set(blockId, `${fn.name}__${blockId}`)
112
+ }
113
+ }
114
+ }
115
+
116
+ isMultiPred(blockId: BlockId): boolean {
117
+ return this.multiPredBlocks.has(blockId)
118
+ }
119
+
120
+ getBlockFnName(blockId: BlockId): string {
121
+ const name = this.blockFnNames.get(blockId)
122
+ if (name) return name
123
+ // Generate one on demand
124
+ const generated = `${this.currentMIRFn!.name}__${blockId}`
125
+ this.blockFnNames.set(blockId, generated)
126
+ return generated
127
+ }
128
+
129
+ getBlock(id: BlockId): MIRBlock | undefined {
130
+ return this.blockMap.get(id)
131
+ }
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Function lowering
136
+ // ---------------------------------------------------------------------------
137
+
138
+ function lowerFunction(fn: MIRFunction, ctx: LoweringContext): void {
139
+ ctx.analyzeBlocks(fn)
140
+
141
+ // Lower the entry block as the main function body
142
+ const instrs: LIRInstr[] = []
143
+ const visited = new Set<BlockId>()
144
+
145
+ // Copy parameter slots ($p0, $p1, ...) into the callee's temp slots
146
+ for (let i = 0; i < fn.params.length; i++) {
147
+ const paramSlot: Slot = { player: `$p${i}`, obj: ctx.objective }
148
+ const tempSlot = ctx.slot(fn.params[i].name)
149
+ instrs.push({ kind: 'score_copy', dst: tempSlot, src: paramSlot })
150
+ }
151
+
152
+ lowerBlock(fn.entry, fn, ctx, instrs, visited)
153
+
154
+ ctx.addFunction({
155
+ name: fn.name,
156
+ instructions: instrs,
157
+ isMacro: fn.isMacro,
158
+ macroParams: fn.params.filter(p => p.isMacroParam).map(p => p.name),
159
+ })
160
+
161
+ // Emit separate functions for multi-pred blocks
162
+ for (const blockId of ctx['multiPredBlocks']) {
163
+ if (!visited.has(blockId)) {
164
+ const blockInstrs: LIRInstr[] = []
165
+ const blockVisited = new Set<BlockId>()
166
+ lowerBlock(blockId, fn, ctx, blockInstrs, blockVisited)
167
+ ctx.addFunction({
168
+ name: ctx.getBlockFnName(blockId),
169
+ instructions: blockInstrs,
170
+ isMacro: false,
171
+ macroParams: [],
172
+ })
173
+ }
174
+ }
175
+ }
176
+
177
+ function lowerBlock(
178
+ blockId: BlockId,
179
+ fn: MIRFunction,
180
+ ctx: LoweringContext,
181
+ instrs: LIRInstr[],
182
+ visited: Set<BlockId>,
183
+ ): void {
184
+ if (visited.has(blockId)) return
185
+ visited.add(blockId)
186
+
187
+ const block = ctx.getBlock(blockId)
188
+ if (!block) return
189
+
190
+ // Lower all non-terminator instructions
191
+ for (const instr of block.instrs) {
192
+ lowerInstr(instr, fn, ctx, instrs)
193
+ }
194
+
195
+ // Lower the terminator
196
+ lowerTerminator(block.term, fn, ctx, instrs, visited)
197
+ }
198
+
199
+ // ---------------------------------------------------------------------------
200
+ // Instruction lowering
201
+ // ---------------------------------------------------------------------------
202
+
203
+ function lowerInstr(
204
+ instr: MIRInstr,
205
+ fn: MIRFunction,
206
+ ctx: LoweringContext,
207
+ instrs: LIRInstr[],
208
+ ): void {
209
+ const beforeLen = instrs.length
210
+ lowerInstrInner(instr, fn, ctx, instrs)
211
+ ctx.tagSourceLoc(instrs, beforeLen, instr.sourceLoc)
212
+ }
213
+
214
+ function lowerInstrInner(
215
+ instr: MIRInstr,
216
+ fn: MIRFunction,
217
+ ctx: LoweringContext,
218
+ instrs: LIRInstr[],
219
+ ): void {
220
+ switch (instr.kind) {
221
+ case 'const': {
222
+ instrs.push({ kind: 'score_set', dst: ctx.slot(instr.dst), value: instr.value })
223
+ break
224
+ }
225
+
226
+ case 'copy': {
227
+ lowerOperandToSlot(instr.dst, instr.src, ctx, instrs)
228
+ break
229
+ }
230
+
231
+ case 'add':
232
+ case 'sub':
233
+ case 'mul':
234
+ case 'div':
235
+ case 'mod': {
236
+ // 3-address → 2-address: copy a to dst, then op dst with b
237
+ lowerOperandToSlot(instr.dst, instr.a, ctx, instrs)
238
+ const scoreOp = {
239
+ add: 'score_add',
240
+ sub: 'score_sub',
241
+ mul: 'score_mul',
242
+ div: 'score_div',
243
+ mod: 'score_mod',
244
+ } as const
245
+ lowerBinOp(instr.dst, instr.b, scoreOp[instr.kind], ctx, instrs)
246
+ break
247
+ }
248
+
249
+ case 'neg': {
250
+ // 0 - src: set tmp to 0, then subtract src
251
+ const dst = ctx.slot(instr.dst)
252
+ instrs.push({ kind: 'score_set', dst, value: 0 })
253
+ const srcSlot = operandToSlot(instr.src, ctx, instrs)
254
+ instrs.push({ kind: 'score_sub', dst, src: srcSlot })
255
+ break
256
+ }
257
+
258
+ case 'cmp': {
259
+ // Strategy: set dst=0, then conditionally set to 1
260
+ // MC pattern: execute if score $a <op> $b run scoreboard players set $dst 1
261
+ const dst = ctx.slot(instr.dst)
262
+ const aSlot = operandToSlot(instr.a, ctx, instrs)
263
+ const bSlot = operandToSlot(instr.b, ctx, instrs)
264
+
265
+ instrs.push({ kind: 'score_set', dst, value: 0 })
266
+
267
+ const cmpOps: Record<string, string> = {
268
+ eq: '=', ne: '=', lt: '<', le: '<=', gt: '>', ge: '>=',
269
+ }
270
+ const op = cmpOps[instr.op]
271
+ const guard = instr.op === 'ne' ? 'unless' : 'if'
272
+ const dstStr = `${dst.player} ${dst.obj}`
273
+ const aStr = `${aSlot.player} ${aSlot.obj}`
274
+ const bStr = `${bSlot.player} ${bSlot.obj}`
275
+ instrs.push({
276
+ kind: 'raw',
277
+ cmd: `execute ${guard} score ${aStr} ${op} ${bStr} run scoreboard players set ${dstStr} 1`,
278
+ })
279
+ break
280
+ }
281
+
282
+ case 'and': {
283
+ // Bitwise/logical AND: both are 0/1, so multiply works
284
+ // But more accurately: dst = (a != 0) && (b != 0)
285
+ // Simple approach: copy a, then score_mul with b (since both are 0/1)
286
+ lowerOperandToSlot(instr.dst, instr.a, ctx, instrs)
287
+ lowerBinOp(instr.dst, instr.b, 'score_mul', ctx, instrs)
288
+ break
289
+ }
290
+
291
+ case 'or': {
292
+ // OR for 0/1 values: add then clamp to 1
293
+ // dst = a + b; if dst > 1, dst = 1
294
+ const dst = ctx.slot(instr.dst)
295
+ lowerOperandToSlot(instr.dst, instr.a, ctx, instrs)
296
+ lowerBinOp(instr.dst, instr.b, 'score_add', ctx, instrs)
297
+ // Clamp: use score_min with a const slot set to 1
298
+ const oneSlot = constSlot(1, ctx, instrs)
299
+ instrs.push({ kind: 'score_min', dst, src: oneSlot })
300
+ break
301
+ }
302
+
303
+ case 'not': {
304
+ // NOT for 0/1: dst = 1 - src
305
+ const dst = ctx.slot(instr.dst)
306
+ instrs.push({ kind: 'score_set', dst, value: 1 })
307
+ const srcSlot = operandToSlot(instr.src, ctx, instrs)
308
+ instrs.push({ kind: 'score_sub', dst, src: srcSlot })
309
+ break
310
+ }
311
+
312
+ case 'nbt_read': {
313
+ const dst = ctx.slot(instr.dst)
314
+ instrs.push({
315
+ kind: 'store_nbt_to_score',
316
+ dst,
317
+ ns: instr.ns,
318
+ path: instr.path,
319
+ scale: instr.scale,
320
+ })
321
+ break
322
+ }
323
+
324
+ case 'nbt_write': {
325
+ const srcSlot = operandToSlot(instr.src, ctx, instrs)
326
+ instrs.push({
327
+ kind: 'store_score_to_nbt',
328
+ ns: instr.ns,
329
+ path: instr.path,
330
+ type: instr.type,
331
+ scale: instr.scale,
332
+ src: srcSlot,
333
+ })
334
+ break
335
+ }
336
+
337
+ case 'call': {
338
+ // Set parameter slots $p0, $p1, ...
339
+ for (let i = 0; i < instr.args.length; i++) {
340
+ const paramSlot: Slot = { player: `$p${i}`, obj: ctx.objective }
341
+ lowerOperandToSlotDirect(paramSlot, instr.args[i], ctx, instrs)
342
+ }
343
+
344
+ // Handle raw commands embedded in call
345
+ if (instr.fn.startsWith('__raw:')) {
346
+ const cmd = instr.fn.slice(6)
347
+ if (cmd.startsWith('\x01')) {
348
+ // Macro sentinel → emit as macro_line ($ prefix added by emit)
349
+ instrs.push({ kind: 'macro_line', template: cmd.slice(1) })
350
+ } else {
351
+ instrs.push({ kind: 'raw', cmd })
352
+ }
353
+ } else {
354
+ instrs.push({ kind: 'call', fn: ctx.qualifiedName(instr.fn) })
355
+ }
356
+
357
+ // Copy return value to dst if needed
358
+ if (instr.dst) {
359
+ const retSlot: Slot = { player: '$ret', obj: ctx.objective }
360
+ instrs.push({ kind: 'score_copy', dst: ctx.slot(instr.dst), src: retSlot })
361
+ }
362
+ break
363
+ }
364
+
365
+ case 'call_macro': {
366
+ const macroStorage = `rs:macro_args`
367
+ // Store each arg to NBT
368
+ for (const arg of instr.args) {
369
+ const srcSlot = operandToSlot(arg.value, ctx, instrs)
370
+ instrs.push({
371
+ kind: 'store_score_to_nbt',
372
+ ns: 'rs:macro_args',
373
+ path: arg.name,
374
+ type: arg.type,
375
+ scale: arg.scale,
376
+ src: srcSlot,
377
+ })
378
+ }
379
+ instrs.push({ kind: 'call_macro', fn: ctx.qualifiedName(instr.fn), storage: macroStorage })
380
+
381
+ // Copy return value to dst if needed
382
+ if (instr.dst) {
383
+ const retSlot: Slot = { player: '$ret', obj: ctx.objective }
384
+ instrs.push({ kind: 'score_copy', dst: ctx.slot(instr.dst), src: retSlot })
385
+ }
386
+ break
387
+ }
388
+
389
+ case 'call_context': {
390
+ instrs.push({
391
+ kind: 'call_context',
392
+ fn: ctx.qualifiedName(instr.fn),
393
+ subcommands: instr.subcommands,
394
+ })
395
+ break
396
+ }
397
+
398
+ default:
399
+ break
400
+ }
401
+ }
402
+
403
+ // ---------------------------------------------------------------------------
404
+ // Terminator lowering
405
+ // ---------------------------------------------------------------------------
406
+
407
+ function lowerTerminator(
408
+ term: MIRInstr,
409
+ fn: MIRFunction,
410
+ ctx: LoweringContext,
411
+ instrs: LIRInstr[],
412
+ visited: Set<BlockId>,
413
+ ): void {
414
+ const beforeLen = instrs.length
415
+ lowerTerminatorInner(term, fn, ctx, instrs, visited)
416
+ ctx.tagSourceLoc(instrs, beforeLen, term.sourceLoc)
417
+ }
418
+
419
+ function lowerTerminatorInner(
420
+ term: MIRInstr,
421
+ fn: MIRFunction,
422
+ ctx: LoweringContext,
423
+ instrs: LIRInstr[],
424
+ visited: Set<BlockId>,
425
+ ): void {
426
+ switch (term.kind) {
427
+ case 'return': {
428
+ if (term.value) {
429
+ const retSlot: Slot = { player: '$ret', obj: ctx.objective }
430
+ const srcSlot = operandToSlot(term.value, ctx, instrs)
431
+ instrs.push({ kind: 'return_value', slot: srcSlot })
432
+ }
433
+ break
434
+ }
435
+
436
+ case 'jump': {
437
+ if (ctx.isMultiPred(term.target)) {
438
+ // Target has multiple predecessors — call the extracted function
439
+ instrs.push({ kind: 'call', fn: ctx.qualifiedName(ctx.getBlockFnName(term.target)) })
440
+ } else {
441
+ // Inline the target block's instructions
442
+ lowerBlock(term.target, fn, ctx, instrs, visited)
443
+ }
444
+ break
445
+ }
446
+
447
+ case 'branch': {
448
+ const condSlot = operandToSlot(term.cond, ctx, instrs)
449
+
450
+ // Then branch: use `return run function` to atomically call and exit.
451
+ // This prevents fallthrough to the else-branch even when recursive calls
452
+ // (e.g. continue → loop header → loop body) clobber the condition slot.
453
+ const thenFnName = emitBranchTarget(term.then, fn, ctx, visited)
454
+ instrs.push({
455
+ kind: 'raw',
456
+ cmd: `execute if score ${condSlot.player} ${condSlot.obj} matches 1 run return run function ${ctx.qualifiedName(thenFnName)}`,
457
+ })
458
+
459
+ // Else branch: if we reach here, cond was not 1 (the then-path returned).
460
+ const elseFnName = emitBranchTarget(term.else, fn, ctx, visited)
461
+ instrs.push({ kind: 'call', fn: ctx.qualifiedName(elseFnName) })
462
+ break
463
+ }
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Emit a branch target as a separate LIR function and return its name.
469
+ * If the target is already a multi-pred block with a function, reuse it.
470
+ */
471
+ function emitBranchTarget(
472
+ blockId: BlockId,
473
+ fn: MIRFunction,
474
+ ctx: LoweringContext,
475
+ parentVisited: Set<BlockId>,
476
+ ): string {
477
+ // If already has a function (multi-pred), return its name
478
+ if (ctx.isMultiPred(blockId)) {
479
+ // Make sure the block gets emitted
480
+ if (!parentVisited.has(blockId)) {
481
+ const blockInstrs: LIRInstr[] = []
482
+ const blockVisited = new Set<BlockId>()
483
+ lowerBlock(blockId, fn, ctx, blockInstrs, blockVisited)
484
+ ctx.addFunction({
485
+ name: ctx.getBlockFnName(blockId),
486
+ instructions: blockInstrs,
487
+ isMacro: false,
488
+ macroParams: [],
489
+ })
490
+ parentVisited.add(blockId)
491
+ }
492
+ return ctx.getBlockFnName(blockId)
493
+ }
494
+
495
+ // Create a new function for this branch target
496
+ const branchFnName = ctx.getBlockFnName(blockId)
497
+ const blockInstrs: LIRInstr[] = []
498
+ const blockVisited = new Set<BlockId>()
499
+ lowerBlock(blockId, fn, ctx, blockInstrs, blockVisited)
500
+
501
+ ctx.addFunction({
502
+ name: branchFnName,
503
+ instructions: blockInstrs,
504
+ isMacro: false,
505
+ macroParams: [],
506
+ })
507
+
508
+ // Mark visited so parent doesn't re-inline
509
+ parentVisited.add(blockId)
510
+
511
+ return branchFnName
512
+ }
513
+
514
+ // ---------------------------------------------------------------------------
515
+ // Helpers
516
+ // ---------------------------------------------------------------------------
517
+
518
+ /** Lower an operand into a named temp slot (copy const or score_copy) */
519
+ function lowerOperandToSlot(
520
+ dstTemp: Temp,
521
+ src: Operand,
522
+ ctx: LoweringContext,
523
+ instrs: LIRInstr[],
524
+ ): void {
525
+ const dst = ctx.slot(dstTemp)
526
+ if (src.kind === 'const') {
527
+ instrs.push({ kind: 'score_set', dst, value: src.value })
528
+ } else {
529
+ instrs.push({ kind: 'score_copy', dst, src: ctx.slot(src.name) })
530
+ }
531
+ }
532
+
533
+ /** Lower an operand into a specific slot (not by temp name) */
534
+ function lowerOperandToSlotDirect(
535
+ dst: Slot,
536
+ src: Operand,
537
+ ctx: LoweringContext,
538
+ instrs: LIRInstr[],
539
+ ): void {
540
+ if (src.kind === 'const') {
541
+ instrs.push({ kind: 'score_set', dst, value: src.value })
542
+ } else {
543
+ instrs.push({ kind: 'score_copy', dst, src: ctx.slot(src.name) })
544
+ }
545
+ }
546
+
547
+ /** Get a slot for an operand, emitting a score_set for constants into a temp */
548
+ function operandToSlot(
549
+ op: Operand,
550
+ ctx: LoweringContext,
551
+ instrs: LIRInstr[],
552
+ ): Slot {
553
+ if (op.kind === 'temp') {
554
+ return ctx.slot(op.name)
555
+ }
556
+ // Constant → need a temporary slot
557
+ return constSlot(op.value, ctx, instrs)
558
+ }
559
+
560
+ /** Create a constant slot with a given value */
561
+ function constSlot(value: number, ctx: LoweringContext, instrs: LIRInstr[]): Slot {
562
+ const slot: Slot = { player: `$__const_${value}`, obj: ctx.objective }
563
+ instrs.push({ kind: 'score_set', dst: slot, value })
564
+ return slot
565
+ }
566
+
567
+ /** Apply a binary score operation: dst op= src */
568
+ function lowerBinOp(
569
+ dstTemp: Temp,
570
+ b: Operand,
571
+ scoreKind: 'score_add' | 'score_sub' | 'score_mul' | 'score_div' | 'score_mod',
572
+ ctx: LoweringContext,
573
+ instrs: LIRInstr[],
574
+ ): void {
575
+ const dst = ctx.slot(dstTemp)
576
+ const srcSlot = operandToSlot(b, ctx, instrs)
577
+ instrs.push({ kind: scoreKind, dst, src: srcSlot })
578
+ }
579
+
580
+ function getTermTargets(term: MIRInstr): BlockId[] {
581
+ switch (term.kind) {
582
+ case 'jump': return [term.target]
583
+ case 'branch': return [term.then, term.else]
584
+ case 'return': return []
585
+ default: return []
586
+ }
587
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * LIR (Low-level IR) Types — Stage 5 of the RedScript compiler pipeline.
3
+ *
4
+ * LIR is 2-address, MC-specific, typed nodes — no raw strings.
5
+ * Each LIR instruction maps 1:1 (or near) to one MC command.
6
+ *
7
+ * Spec: docs/compiler-pipeline-redesign.md § "LIR Instruction Set"
8
+ */
9
+
10
+ import type { CmpOp, NBTType, ExecuteSubcmd, SourceLoc } from '../mir/types'
11
+
12
+ // A scoreboard slot: fake-player name + objective
13
+ export interface Slot {
14
+ player: string
15
+ obj: string
16
+ }
17
+
18
+ // Re-export types used in LIR from MIR
19
+ export type { CmpOp, NBTType, ExecuteSubcmd, SourceLoc }
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // LIR Instructions
23
+ // ---------------------------------------------------------------------------
24
+
25
+ // Base type for all LIR instructions — carries optional source location
26
+ export type LIRInstrBase = { sourceLoc?: SourceLoc }
27
+
28
+ export type LIRInstr = LIRInstrBase & (
29
+ // ── Scoreboard ───────────────────────────────────────────────────────────
30
+ | { kind: 'score_set'; dst: Slot; value: number }
31
+ // scoreboard players set <dst.player> <dst.obj> value
32
+
33
+ | { kind: 'score_copy'; dst: Slot; src: Slot }
34
+ // scoreboard players operation <dst> = <src>
35
+
36
+ | { kind: 'score_add'; dst: Slot; src: Slot } // +=
37
+ | { kind: 'score_sub'; dst: Slot; src: Slot } // -=
38
+ | { kind: 'score_mul'; dst: Slot; src: Slot } // *=
39
+ | { kind: 'score_div'; dst: Slot; src: Slot } // /=
40
+ | { kind: 'score_mod'; dst: Slot; src: Slot } // %=
41
+ | { kind: 'score_min'; dst: Slot; src: Slot } // < (min)
42
+ | { kind: 'score_max'; dst: Slot; src: Slot } // > (max)
43
+ | { kind: 'score_swap'; a: Slot; b: Slot } // ><
44
+
45
+ // ── Execute store ────────────────────────────────────────────────────────
46
+ | { kind: 'store_cmd_to_score'; dst: Slot; cmd: LIRInstr }
47
+ // execute store result score <dst> run <cmd>
48
+
49
+ | { kind: 'store_score_to_nbt';
50
+ ns: string; path: string; type: NBTType; scale: number;
51
+ src: Slot }
52
+ // execute store result storage <ns> <path> <type> <scale> run scoreboard players get <src>
53
+
54
+ | { kind: 'store_nbt_to_score';
55
+ dst: Slot; ns: string; path: string; scale: number }
56
+ // execute store result score <dst> run data get storage <ns> <path> <scale>
57
+
58
+ // ── NBT ──────────────────────────────────────────────────────────────────
59
+ | { kind: 'nbt_set_literal'; ns: string; path: string; value: string }
60
+ // data modify storage <ns> <path> set value <value>
61
+
62
+ | { kind: 'nbt_copy'; srcNs: string; srcPath: string; dstNs: string; dstPath: string }
63
+ // data modify storage <dstNs> <dstPath> set from storage <srcNs> <srcPath>
64
+
65
+ // ── Control flow ─────────────────────────────────────────────────────────
66
+ | { kind: 'call'; fn: string }
67
+ // function <fn>
68
+
69
+ | { kind: 'call_macro'; fn: string; storage: string }
70
+ // function <fn> with storage <storage>
71
+
72
+ | { kind: 'call_if_matches'; fn: string; slot: Slot; range: string }
73
+ // execute if score <slot> matches <range> run function <fn>
74
+
75
+ | { kind: 'call_unless_matches'; fn: string; slot: Slot; range: string }
76
+
77
+ | { kind: 'call_if_score'; fn: string; a: Slot; op: CmpOp; b: Slot }
78
+ // execute if score <a> <op> <b> run function <fn>
79
+
80
+ | { kind: 'call_unless_score'; fn: string; a: Slot; op: CmpOp; b: Slot }
81
+
82
+ | { kind: 'call_context'; fn: string; subcommands: ExecuteSubcmd[] }
83
+ // execute [subcommands] run function <fn>
84
+
85
+ | { kind: 'return_value'; slot: Slot }
86
+ // scoreboard players operation $ret <obj> = <slot> (then implicit return)
87
+
88
+ // ── Macro line ────────────────────────────────────────────────────────────
89
+ | { kind: 'macro_line'; template: string }
90
+ // A line starting with $ in a macro function.
91
+ // template uses $(param) substitutions
92
+
93
+ // ── Arbitrary MC command ─────────────────────────────────────────────────
94
+ | { kind: 'raw'; cmd: string }
95
+ // Emitted verbatim. Use sparingly — prefer typed instructions.
96
+ )
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // LIR function and module structure
100
+ // ---------------------------------------------------------------------------
101
+
102
+ export interface LIRFunction {
103
+ name: string
104
+ instructions: LIRInstr[] // flat list (no blocks; control flow is via call_if_*)
105
+ isMacro: boolean
106
+ macroParams: string[] // names of $(param) substitution keys
107
+ }
108
+
109
+ export interface LIRModule {
110
+ functions: LIRFunction[]
111
+ namespace: string
112
+ objective: string
113
+ }