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,1264 @@
1
+ "use strict";
2
+ /**
3
+ * HIR → MIR Lowering — Stage 3 of the RedScript compiler pipeline.
4
+ *
5
+ * Converts structured HIR (if/while/break/continue) into an explicit CFG
6
+ * with 3-address instructions and unlimited fresh temporaries.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.lowerToMIR = lowerToMIR;
10
+ const macro_1 = require("./macro");
11
+ // ---------------------------------------------------------------------------
12
+ // Public API
13
+ // ---------------------------------------------------------------------------
14
+ function lowerToMIR(hir, sourceFile) {
15
+ // Build struct definitions: name → field names
16
+ const structDefs = new Map();
17
+ for (const s of hir.structs) {
18
+ structDefs.set(s.name, s.fields.map(f => f.name));
19
+ }
20
+ // Build enum definitions: enumName → variantName → integer value
21
+ const enumDefs = new Map();
22
+ for (const e of hir.enums) {
23
+ const variants = new Map();
24
+ for (const v of e.variants) {
25
+ variants.set(v.name, v.value ?? 0);
26
+ }
27
+ enumDefs.set(e.name, variants);
28
+ }
29
+ // Build impl method info: typeName → methodName → { hasSelf }
30
+ const implMethods = new Map();
31
+ for (const ib of hir.implBlocks) {
32
+ const methods = new Map();
33
+ for (const m of ib.methods) {
34
+ const hasSelf = m.params.length > 0 && m.params[0].name === 'self';
35
+ methods.set(m.name, { hasSelf });
36
+ }
37
+ implMethods.set(ib.typeName, methods);
38
+ }
39
+ // Pre-scan for macro functions
40
+ const macroInfo = (0, macro_1.detectMacroFunctions)(hir);
41
+ // Build function param info for call_macro generation at call sites
42
+ const fnParamInfo = new Map();
43
+ for (const f of hir.functions) {
44
+ fnParamInfo.set(f.name, f.params);
45
+ }
46
+ for (const ib of hir.implBlocks) {
47
+ for (const m of ib.methods) {
48
+ fnParamInfo.set(`${ib.typeName}::${m.name}`, m.params);
49
+ }
50
+ }
51
+ const allFunctions = [];
52
+ for (const f of hir.functions) {
53
+ const { fn, helpers } = lowerFunction(f, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile);
54
+ allFunctions.push(fn, ...helpers);
55
+ }
56
+ // Lower impl block methods
57
+ for (const ib of hir.implBlocks) {
58
+ for (const m of ib.methods) {
59
+ const { fn, helpers } = lowerImplMethod(m, ib.typeName, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile);
60
+ allFunctions.push(fn, ...helpers);
61
+ }
62
+ }
63
+ return {
64
+ functions: allFunctions,
65
+ namespace: hir.namespace,
66
+ objective: `__${hir.namespace}`,
67
+ };
68
+ }
69
+ // ---------------------------------------------------------------------------
70
+ // Function lowering context
71
+ // ---------------------------------------------------------------------------
72
+ class FnContext {
73
+ constructor(namespace, fnName, structDefs = new Map(), implMethods = new Map(), macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map()) {
74
+ this.tempCounter = 0;
75
+ this.blockCounter = 0;
76
+ this.blocks = [];
77
+ /** Stack of (loopHeader, loopExit, continueTo) for break/continue */
78
+ this.loopStack = [];
79
+ /** Extracted helper functions for execute blocks */
80
+ this.helperFunctions = [];
81
+ /** Struct variable tracking: varName → { typeName, fields: fieldName → temp } */
82
+ this.structVars = new Map();
83
+ /** Tuple variable tracking: varName → array of element temps (index = slot) */
84
+ this.tupleVars = new Map();
85
+ /** Current source location (set during statement lowering) */
86
+ this.currentSourceLoc = undefined;
87
+ /** Source file path for the module being compiled */
88
+ this.sourceFile = undefined;
89
+ this.namespace = namespace;
90
+ this.fnName = fnName;
91
+ this.structDefs = structDefs;
92
+ this.implMethods = implMethods;
93
+ this.macroInfo = macroInfo;
94
+ this.fnParamInfo = fnParamInfo;
95
+ this.currentMacroParams = macroInfo.get(fnName)?.macroParams ?? new Set();
96
+ this.enumDefs = enumDefs;
97
+ const entry = this.makeBlock('entry');
98
+ this.currentBlock = entry;
99
+ }
100
+ freshTemp() {
101
+ return `t${this.tempCounter++}`;
102
+ }
103
+ makeBlock(id) {
104
+ const block = {
105
+ id: id ?? `bb${this.blockCounter++}`,
106
+ instrs: [],
107
+ term: { kind: 'return', value: null }, // placeholder
108
+ preds: [],
109
+ };
110
+ this.blocks.push(block);
111
+ return block;
112
+ }
113
+ newBlock(prefix) {
114
+ return this.makeBlock(prefix ? `${prefix}_${this.blockCounter++}` : undefined);
115
+ }
116
+ emit(instr) {
117
+ if (this.currentSourceLoc && !instr.sourceLoc) {
118
+ instr.sourceLoc = this.currentSourceLoc;
119
+ }
120
+ this.currentBlock.instrs.push(instr);
121
+ }
122
+ terminate(term) {
123
+ if (this.currentSourceLoc && !term.sourceLoc) {
124
+ term.sourceLoc = this.currentSourceLoc;
125
+ }
126
+ this.currentBlock.term = term;
127
+ }
128
+ switchTo(block) {
129
+ this.currentBlock = block;
130
+ }
131
+ current() {
132
+ return this.currentBlock;
133
+ }
134
+ pushLoop(header, exit, continueTo) {
135
+ this.loopStack.push({ header, exit, continueTo: continueTo ?? header });
136
+ }
137
+ popLoop() {
138
+ this.loopStack.pop();
139
+ }
140
+ currentLoop() {
141
+ return this.loopStack[this.loopStack.length - 1];
142
+ }
143
+ getNamespace() {
144
+ return this.namespace;
145
+ }
146
+ getFnName() {
147
+ return this.fnName;
148
+ }
149
+ }
150
+ // ---------------------------------------------------------------------------
151
+ // Function lowering
152
+ // ---------------------------------------------------------------------------
153
+ function lowerFunction(fn, namespace, structDefs = new Map(), implMethods = new Map(), macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), sourceFile) {
154
+ const ctx = new FnContext(namespace, fn.name, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs);
155
+ ctx.sourceFile = sourceFile;
156
+ const fnMacroInfo = macroInfo.get(fn.name);
157
+ // Create temps for parameters
158
+ const params = fn.params.map(p => {
159
+ const t = ctx.freshTemp();
160
+ return { name: t, isMacroParam: fnMacroInfo?.macroParams.has(p.name) ?? false };
161
+ });
162
+ // Map parameter names to their temps
163
+ const scope = new Map();
164
+ fn.params.forEach((p, i) => {
165
+ scope.set(p.name, params[i].name);
166
+ });
167
+ lowerBlock(fn.body, ctx, scope);
168
+ // If the current block doesn't have a real terminator, add void return
169
+ const cur = ctx.current();
170
+ if (isPlaceholderTerm(cur.term)) {
171
+ ctx.terminate({ kind: 'return', value: null });
172
+ }
173
+ // Remove unreachable blocks (dead continuations after return/break/continue)
174
+ const reachable = computeReachable(ctx.blocks, 'entry');
175
+ const liveBlocks = ctx.blocks.filter(b => reachable.has(b.id));
176
+ // Fill predecessor lists
177
+ computePreds(liveBlocks);
178
+ const result = {
179
+ name: fn.name,
180
+ params,
181
+ blocks: liveBlocks,
182
+ entry: 'entry',
183
+ isMacro: fnMacroInfo != null,
184
+ };
185
+ return { fn: result, helpers: ctx.helperFunctions };
186
+ }
187
+ function lowerImplMethod(method, typeName, namespace, structDefs, implMethods, macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), sourceFile) {
188
+ const fnName = `${typeName}::${method.name}`;
189
+ const ctx = new FnContext(namespace, fnName, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs);
190
+ ctx.sourceFile = sourceFile;
191
+ const fields = structDefs.get(typeName) ?? [];
192
+ const hasSelf = method.params.length > 0 && method.params[0].name === 'self';
193
+ const params = [];
194
+ const scope = new Map();
195
+ if (hasSelf) {
196
+ // Self fields become the first N params (one per struct field)
197
+ const selfFields = new Map();
198
+ for (const fieldName of fields) {
199
+ const t = ctx.freshTemp();
200
+ params.push({ name: t, isMacroParam: false });
201
+ selfFields.set(fieldName, t);
202
+ }
203
+ ctx.structVars.set('self', { typeName, fields: selfFields });
204
+ // Remaining params (after self)
205
+ for (let i = 1; i < method.params.length; i++) {
206
+ const t = ctx.freshTemp();
207
+ params.push({ name: t, isMacroParam: false });
208
+ scope.set(method.params[i].name, t);
209
+ }
210
+ }
211
+ else {
212
+ // Static method — regular params
213
+ for (const p of method.params) {
214
+ const t = ctx.freshTemp();
215
+ params.push({ name: t, isMacroParam: false });
216
+ scope.set(p.name, t);
217
+ }
218
+ }
219
+ lowerBlock(method.body, ctx, scope);
220
+ const cur = ctx.current();
221
+ if (isPlaceholderTerm(cur.term)) {
222
+ ctx.terminate({ kind: 'return', value: null });
223
+ }
224
+ const reachable = computeReachable(ctx.blocks, 'entry');
225
+ const liveBlocks = ctx.blocks.filter(b => reachable.has(b.id));
226
+ computePreds(liveBlocks);
227
+ const result = {
228
+ name: fnName,
229
+ params,
230
+ blocks: liveBlocks,
231
+ entry: 'entry',
232
+ isMacro: macroInfo.has(fnName),
233
+ };
234
+ return { fn: result, helpers: ctx.helperFunctions };
235
+ }
236
+ function isPlaceholderTerm(term) {
237
+ // Our placeholder is a return null that was set in makeBlock
238
+ return term.kind === 'return' && term.value === null;
239
+ }
240
+ function computeReachable(blocks, entry) {
241
+ const reachable = new Set();
242
+ const queue = [entry];
243
+ while (queue.length > 0) {
244
+ const id = queue.shift();
245
+ if (reachable.has(id))
246
+ continue;
247
+ reachable.add(id);
248
+ const block = blocks.find(b => b.id === id);
249
+ if (block) {
250
+ for (const t of getTermTargets(block.term)) {
251
+ if (!reachable.has(t))
252
+ queue.push(t);
253
+ }
254
+ }
255
+ }
256
+ return reachable;
257
+ }
258
+ function computePreds(blocks) {
259
+ // Clear all preds
260
+ for (const b of blocks)
261
+ b.preds = [];
262
+ for (const b of blocks) {
263
+ const targets = getTermTargets(b.term);
264
+ for (const t of targets) {
265
+ const target = blocks.find(bb => bb.id === t);
266
+ if (target && !target.preds.includes(b.id)) {
267
+ target.preds.push(b.id);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ function getTermTargets(term) {
273
+ switch (term.kind) {
274
+ case 'jump': return [term.target];
275
+ case 'branch': return [term.then, term.else];
276
+ case 'return': return [];
277
+ default: return [];
278
+ }
279
+ }
280
+ // ---------------------------------------------------------------------------
281
+ // Block / statement lowering
282
+ // ---------------------------------------------------------------------------
283
+ function lowerBlock(stmts, ctx, scope) {
284
+ for (const stmt of stmts) {
285
+ lowerStmt(stmt, ctx, scope);
286
+ }
287
+ }
288
+ function lowerStmt(stmt, ctx, scope) {
289
+ // Propagate source location from HIR statement span
290
+ if (stmt.span && ctx.sourceFile) {
291
+ ctx.currentSourceLoc = { file: ctx.sourceFile, line: stmt.span.line, col: stmt.span.col };
292
+ }
293
+ switch (stmt.kind) {
294
+ case 'let': {
295
+ if (stmt.init.kind === 'some_lit') {
296
+ // Some(expr) — create option struct vars: has=1, val=expr
297
+ // Use __opt_ prefix so DCE treats these as side-effectful scoreboard writes
298
+ const hasTemp = `__opt_${stmt.name}_has`;
299
+ const valTemp = `__opt_${stmt.name}_val`;
300
+ ctx.emit({ kind: 'const', dst: hasTemp, value: 1 });
301
+ const valOp = lowerExpr(stmt.init.value, ctx, scope);
302
+ ctx.emit({ kind: 'copy', dst: valTemp, src: valOp });
303
+ const fieldTemps = new Map([['has', hasTemp], ['val', valTemp]]);
304
+ ctx.structVars.set(stmt.name, { typeName: '__option', fields: fieldTemps });
305
+ }
306
+ else if (stmt.init.kind === 'none_lit') {
307
+ // None — create option struct vars: has=0, val=0
308
+ const hasTemp = `__opt_${stmt.name}_has`;
309
+ const valTemp = `__opt_${stmt.name}_val`;
310
+ ctx.emit({ kind: 'const', dst: hasTemp, value: 0 });
311
+ ctx.emit({ kind: 'const', dst: valTemp, value: 0 });
312
+ const fieldTemps = new Map([['has', hasTemp], ['val', valTemp]]);
313
+ ctx.structVars.set(stmt.name, { typeName: '__option', fields: fieldTemps });
314
+ }
315
+ else if (stmt.init.kind === 'struct_lit') {
316
+ // Struct literal: create per-field temps
317
+ const typeName = (stmt.type?.kind === 'struct') ? stmt.type.name : '__anon';
318
+ const fieldTemps = new Map();
319
+ for (const field of stmt.init.fields) {
320
+ const val = lowerExpr(field.value, ctx, scope);
321
+ const t = ctx.freshTemp();
322
+ ctx.emit({ kind: 'copy', dst: t, src: val });
323
+ fieldTemps.set(field.name, t);
324
+ }
325
+ ctx.structVars.set(stmt.name, { typeName, fields: fieldTemps });
326
+ }
327
+ else if (stmt.type?.kind === 'option') {
328
+ // Option<T>-typed let with function call result — use __rf_has/__rf_val convention
329
+ lowerExpr(stmt.init, ctx, scope);
330
+ const hasTemp = `__opt_${stmt.name}_has`;
331
+ const valTemp = `__opt_${stmt.name}_val`;
332
+ ctx.emit({ kind: 'copy', dst: hasTemp, src: { kind: 'temp', name: '__rf_has' } });
333
+ ctx.emit({ kind: 'copy', dst: valTemp, src: { kind: 'temp', name: '__rf_val' } });
334
+ const fieldTemps = new Map([['has', hasTemp], ['val', valTemp]]);
335
+ ctx.structVars.set(stmt.name, { typeName: '__option', fields: fieldTemps });
336
+ }
337
+ else if (stmt.type?.kind === 'struct') {
338
+ // Struct-typed let with non-literal init (e.g., call returning struct)
339
+ const fields = ctx.structDefs.get(stmt.type.name);
340
+ if (fields) {
341
+ lowerExpr(stmt.init, ctx, scope);
342
+ // Copy from return field slots into struct variable temps
343
+ const fieldTemps = new Map();
344
+ for (const fieldName of fields) {
345
+ const t = ctx.freshTemp();
346
+ ctx.emit({ kind: 'copy', dst: t, src: { kind: 'temp', name: `__rf_${fieldName}` } });
347
+ fieldTemps.set(fieldName, t);
348
+ }
349
+ ctx.structVars.set(stmt.name, { typeName: stmt.type.name, fields: fieldTemps });
350
+ }
351
+ else {
352
+ const valOp = lowerExpr(stmt.init, ctx, scope);
353
+ const t = ctx.freshTemp();
354
+ ctx.emit({ kind: 'copy', dst: t, src: valOp });
355
+ scope.set(stmt.name, t);
356
+ }
357
+ }
358
+ else {
359
+ const valOp = lowerExpr(stmt.init, ctx, scope);
360
+ const t = ctx.freshTemp();
361
+ ctx.emit({ kind: 'copy', dst: t, src: valOp });
362
+ scope.set(stmt.name, t);
363
+ }
364
+ break;
365
+ }
366
+ case 'let_destruct': {
367
+ // Tuple destructuring: let (a, b, c) = expr
368
+ const n = stmt.names.length;
369
+ if (stmt.init.kind === 'tuple_lit') {
370
+ // Direct tuple literal: evaluate each element into its own temp
371
+ const elemTemps = [];
372
+ for (let i = 0; i < stmt.init.elements.length && i < n; i++) {
373
+ const val = lowerExpr(stmt.init.elements[i], ctx, scope);
374
+ const t = ctx.freshTemp();
375
+ ctx.emit({ kind: 'copy', dst: t, src: val });
376
+ elemTemps.push(t);
377
+ scope.set(stmt.names[i], t);
378
+ }
379
+ }
380
+ else if (stmt.init.kind === 'ident') {
381
+ // Could be referencing a known tuple var
382
+ const tv = ctx.tupleVars.get(stmt.init.name);
383
+ if (tv) {
384
+ for (let i = 0; i < n && i < tv.length; i++) {
385
+ scope.set(stmt.names[i], tv[i]);
386
+ }
387
+ break;
388
+ }
389
+ // Otherwise treat as a call result stored in __rf_ slots
390
+ lowerExpr(stmt.init, ctx, scope);
391
+ const elemTemps = [];
392
+ for (let i = 0; i < n; i++) {
393
+ const t = ctx.freshTemp();
394
+ ctx.emit({ kind: 'copy', dst: t, src: { kind: 'temp', name: `__rf_${i}` } });
395
+ elemTemps.push(t);
396
+ scope.set(stmt.names[i], t);
397
+ }
398
+ // Register as tuple var so it can be passed around
399
+ const varName = stmt.names.join('_') + '_tup';
400
+ ctx.tupleVars.set(varName, elemTemps);
401
+ }
402
+ else {
403
+ // General expression (e.g. function call) — evaluate, read __rf_ slots
404
+ lowerExpr(stmt.init, ctx, scope);
405
+ const elemTemps = [];
406
+ for (let i = 0; i < n; i++) {
407
+ const t = ctx.freshTemp();
408
+ ctx.emit({ kind: 'copy', dst: t, src: { kind: 'temp', name: `__rf_${i}` } });
409
+ elemTemps.push(t);
410
+ scope.set(stmt.names[i], t);
411
+ }
412
+ }
413
+ break;
414
+ }
415
+ case 'expr': {
416
+ lowerExpr(stmt.expr, ctx, scope);
417
+ break;
418
+ }
419
+ case 'return': {
420
+ if (stmt.value?.kind === 'some_lit') {
421
+ // Option return: Some(expr) → set __rf_has=1, __rf_val=expr
422
+ const valOp = lowerExpr(stmt.value.value, ctx, scope);
423
+ ctx.emit({ kind: 'copy', dst: '__rf_has', src: { kind: 'const', value: 1 } });
424
+ ctx.emit({ kind: 'copy', dst: '__rf_val', src: valOp });
425
+ ctx.terminate({ kind: 'return', value: null });
426
+ }
427
+ else if (stmt.value?.kind === 'none_lit') {
428
+ // Option return: None → set __rf_has=0, __rf_val=0
429
+ ctx.emit({ kind: 'copy', dst: '__rf_has', src: { kind: 'const', value: 0 } });
430
+ ctx.emit({ kind: 'copy', dst: '__rf_val', src: { kind: 'const', value: 0 } });
431
+ ctx.terminate({ kind: 'return', value: null });
432
+ }
433
+ else if (stmt.value?.kind === 'struct_lit') {
434
+ // Struct return — copy each field to return field slots
435
+ for (const field of stmt.value.fields) {
436
+ const val = lowerExpr(field.value, ctx, scope);
437
+ ctx.emit({ kind: 'copy', dst: `__rf_${field.name}`, src: val });
438
+ }
439
+ ctx.terminate({ kind: 'return', value: null });
440
+ }
441
+ else if (stmt.value?.kind === 'tuple_lit') {
442
+ // Tuple return — copy each element to __rf_0, __rf_1, ...
443
+ for (let i = 0; i < stmt.value.elements.length; i++) {
444
+ const val = lowerExpr(stmt.value.elements[i], ctx, scope);
445
+ ctx.emit({ kind: 'copy', dst: `__rf_${i}`, src: val });
446
+ }
447
+ ctx.terminate({ kind: 'return', value: null });
448
+ }
449
+ else if (stmt.value?.kind === 'ident') {
450
+ // Check if returning an option struct var
451
+ const sv = ctx.structVars.get(stmt.value.name);
452
+ if (sv && sv.typeName === '__option') {
453
+ const hasT = sv.fields.get('has');
454
+ const valT = sv.fields.get('val');
455
+ ctx.emit({ kind: 'copy', dst: '__rf_has', src: { kind: 'temp', name: hasT } });
456
+ ctx.emit({ kind: 'copy', dst: '__rf_val', src: { kind: 'temp', name: valT } });
457
+ ctx.terminate({ kind: 'return', value: null });
458
+ }
459
+ else {
460
+ const val = lowerExpr(stmt.value, ctx, scope);
461
+ ctx.terminate({ kind: 'return', value: val });
462
+ }
463
+ }
464
+ else {
465
+ const val = stmt.value ? lowerExpr(stmt.value, ctx, scope) : null;
466
+ ctx.terminate({ kind: 'return', value: val });
467
+ }
468
+ // Create a dead block for any subsequent statements
469
+ const dead = ctx.newBlock('post_ret');
470
+ ctx.switchTo(dead);
471
+ break;
472
+ }
473
+ case 'break': {
474
+ const loop = ctx.currentLoop();
475
+ if (!loop)
476
+ throw new Error('break outside loop');
477
+ ctx.terminate({ kind: 'jump', target: loop.exit });
478
+ const dead = ctx.newBlock('post_break');
479
+ ctx.switchTo(dead);
480
+ break;
481
+ }
482
+ case 'continue': {
483
+ const loop = ctx.currentLoop();
484
+ if (!loop)
485
+ throw new Error('continue outside loop');
486
+ ctx.terminate({ kind: 'jump', target: loop.continueTo });
487
+ const dead = ctx.newBlock('post_continue');
488
+ ctx.switchTo(dead);
489
+ break;
490
+ }
491
+ case 'if': {
492
+ const condOp = lowerExpr(stmt.cond, ctx, scope);
493
+ const thenBlock = ctx.newBlock('then');
494
+ const mergeBlock = ctx.newBlock('merge');
495
+ const elseBlock = stmt.else_ ? ctx.newBlock('else') : mergeBlock;
496
+ ctx.terminate({ kind: 'branch', cond: condOp, then: thenBlock.id, else: elseBlock.id });
497
+ // Then branch
498
+ ctx.switchTo(thenBlock);
499
+ lowerBlock(stmt.then, ctx, new Map(scope));
500
+ if (isPlaceholderTerm(ctx.current().term)) {
501
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
502
+ }
503
+ // Else branch
504
+ if (stmt.else_) {
505
+ ctx.switchTo(elseBlock);
506
+ lowerBlock(stmt.else_, ctx, new Map(scope));
507
+ if (isPlaceholderTerm(ctx.current().term)) {
508
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
509
+ }
510
+ }
511
+ ctx.switchTo(mergeBlock);
512
+ break;
513
+ }
514
+ case 'while': {
515
+ const headerBlock = ctx.newBlock('loop_header');
516
+ const bodyBlock = ctx.newBlock('loop_body');
517
+ const exitBlock = ctx.newBlock('loop_exit');
518
+ // If there's a step block (for/for_range), create a latch block that
519
+ // executes the step and then jumps to the header. Continue targets the
520
+ // latch so the increment always runs.
521
+ let latchBlock = null;
522
+ if (stmt.step && stmt.step.length > 0) {
523
+ latchBlock = ctx.newBlock('loop_latch');
524
+ }
525
+ const continueTarget = latchBlock ? latchBlock.id : headerBlock.id;
526
+ // Jump from current block to header
527
+ ctx.terminate({ kind: 'jump', target: headerBlock.id });
528
+ // Header: evaluate condition
529
+ ctx.switchTo(headerBlock);
530
+ const condOp = lowerExpr(stmt.cond, ctx, scope);
531
+ ctx.terminate({ kind: 'branch', cond: condOp, then: bodyBlock.id, else: exitBlock.id });
532
+ // Body
533
+ ctx.switchTo(bodyBlock);
534
+ ctx.pushLoop(headerBlock.id, exitBlock.id, continueTarget);
535
+ lowerBlock(stmt.body, ctx, new Map(scope));
536
+ ctx.popLoop();
537
+ if (isPlaceholderTerm(ctx.current().term)) {
538
+ ctx.terminate({ kind: 'jump', target: continueTarget });
539
+ }
540
+ // Latch block (step): execute increment, then jump to header
541
+ if (latchBlock && stmt.step) {
542
+ ctx.switchTo(latchBlock);
543
+ lowerBlock(stmt.step, ctx, new Map(scope));
544
+ if (isPlaceholderTerm(ctx.current().term)) {
545
+ ctx.terminate({ kind: 'jump', target: headerBlock.id });
546
+ }
547
+ }
548
+ ctx.switchTo(exitBlock);
549
+ break;
550
+ }
551
+ case 'foreach': {
552
+ // foreach is MC-specific entity iteration — lower to call_context
553
+ // For now, extract body into a helper and emit call_context
554
+ const helperName = `${ctx.getFnName()}__foreach_${ctx.freshTemp()}`;
555
+ const subcommands = [];
556
+ // The iterable should be a selector expression
557
+ if (stmt.iterable.kind === 'selector') {
558
+ subcommands.push({ kind: 'as', selector: stmt.iterable.raw });
559
+ }
560
+ if (stmt.executeContext === '@s') {
561
+ subcommands.push({ kind: 'at_self' });
562
+ }
563
+ // Build helper function body as MIR
564
+ const helperCtx = new FnContext(ctx.getNamespace(), helperName, ctx.structDefs, ctx.implMethods);
565
+ const helperScope = new Map(scope);
566
+ lowerBlock(stmt.body, helperCtx, helperScope);
567
+ if (isPlaceholderTerm(helperCtx.current().term)) {
568
+ helperCtx.terminate({ kind: 'return', value: null });
569
+ }
570
+ const helperReachable = computeReachable(helperCtx.blocks, 'entry');
571
+ const helperBlocks = helperCtx.blocks.filter(b => helperReachable.has(b.id));
572
+ computePreds(helperBlocks);
573
+ ctx.helperFunctions.push({
574
+ name: helperName,
575
+ params: [],
576
+ blocks: helperBlocks,
577
+ entry: 'entry',
578
+ isMacro: false,
579
+ });
580
+ ctx.emit({ kind: 'call_context', fn: helperName, subcommands });
581
+ break;
582
+ }
583
+ case 'execute': {
584
+ // Extract body into a helper function, emit call_context
585
+ const helperName = `${ctx.getFnName()}__exec_${ctx.freshTemp()}`;
586
+ const subcommands = stmt.subcommands.map(lowerExecuteSubcmd);
587
+ const helperCtx = new FnContext(ctx.getNamespace(), helperName, ctx.structDefs, ctx.implMethods);
588
+ const helperScope = new Map(scope);
589
+ lowerBlock(stmt.body, helperCtx, helperScope);
590
+ if (isPlaceholderTerm(helperCtx.current().term)) {
591
+ helperCtx.terminate({ kind: 'return', value: null });
592
+ }
593
+ const execReachable = computeReachable(helperCtx.blocks, 'entry');
594
+ const execBlocks = helperCtx.blocks.filter(b => execReachable.has(b.id));
595
+ computePreds(execBlocks);
596
+ ctx.helperFunctions.push({
597
+ name: helperName,
598
+ params: [],
599
+ blocks: execBlocks,
600
+ entry: 'entry',
601
+ isMacro: false,
602
+ });
603
+ ctx.emit({ kind: 'call_context', fn: helperName, subcommands });
604
+ break;
605
+ }
606
+ case 'match': {
607
+ // Lower match as chained if/else
608
+ const matchVal = lowerExpr(stmt.expr, ctx, scope);
609
+ const mergeBlock = ctx.newBlock('match_merge');
610
+ for (let i = 0; i < stmt.arms.length; i++) {
611
+ const arm = stmt.arms[i];
612
+ if (arm.pattern === null) {
613
+ // Default arm — just emit the body
614
+ lowerBlock(arm.body, ctx, new Map(scope));
615
+ if (isPlaceholderTerm(ctx.current().term)) {
616
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
617
+ }
618
+ }
619
+ else {
620
+ const patOp = lowerExpr(arm.pattern, ctx, scope);
621
+ const cmpTemp = ctx.freshTemp();
622
+ ctx.emit({ kind: 'cmp', dst: cmpTemp, op: 'eq', a: matchVal, b: patOp });
623
+ const armBody = ctx.newBlock('match_arm');
624
+ const nextArm = ctx.newBlock('match_next');
625
+ ctx.terminate({ kind: 'branch', cond: { kind: 'temp', name: cmpTemp }, then: armBody.id, else: nextArm.id });
626
+ ctx.switchTo(armBody);
627
+ lowerBlock(arm.body, ctx, new Map(scope));
628
+ if (isPlaceholderTerm(ctx.current().term)) {
629
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
630
+ }
631
+ ctx.switchTo(nextArm);
632
+ }
633
+ }
634
+ // If no default arm matched, jump to merge
635
+ if (isPlaceholderTerm(ctx.current().term)) {
636
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
637
+ }
638
+ ctx.switchTo(mergeBlock);
639
+ break;
640
+ }
641
+ case 'raw': {
642
+ // Raw commands are opaque at MIR level — emit as a call to a synthetic raw function
643
+ // For now, pass through as a call with no args (will be handled in LIR)
644
+ ctx.emit({ kind: 'call', dst: null, fn: `__raw:${stmt.cmd}`, args: [] });
645
+ break;
646
+ }
647
+ case 'if_let_some': {
648
+ // if let Some(x) = opt { ... }
649
+ // Lower: check opt.has, if 1 then bind x = opt.val and run then-block
650
+ const sv = (() => {
651
+ if (stmt.init.kind === 'ident')
652
+ return ctx.structVars.get(stmt.init.name);
653
+ return undefined;
654
+ })();
655
+ let hasOp;
656
+ let valTemp;
657
+ if (sv && sv.typeName === '__option') {
658
+ const hasT = sv.fields.get('has');
659
+ const valT = sv.fields.get('val');
660
+ hasOp = { kind: 'temp', name: hasT };
661
+ valTemp = valT;
662
+ }
663
+ else {
664
+ // General: evaluate init (e.g. function call returning option via __rf_has/__rf_val)
665
+ lowerExpr(stmt.init, ctx, scope);
666
+ const hasT = ctx.freshTemp();
667
+ const valT = ctx.freshTemp();
668
+ ctx.emit({ kind: 'copy', dst: hasT, src: { kind: 'temp', name: '__rf_has' } });
669
+ ctx.emit({ kind: 'copy', dst: valT, src: { kind: 'temp', name: '__rf_val' } });
670
+ hasOp = { kind: 'temp', name: hasT };
671
+ valTemp = valT;
672
+ }
673
+ const thenBlock = ctx.newBlock('ifl_then');
674
+ const mergeBlock = ctx.newBlock('ifl_merge');
675
+ const elseBlock = stmt.else_ ? ctx.newBlock('ifl_else') : mergeBlock;
676
+ ctx.terminate({ kind: 'branch', cond: hasOp, then: thenBlock.id, else: elseBlock.id });
677
+ // Then branch: bind x = val temp
678
+ ctx.switchTo(thenBlock);
679
+ const thenScope = new Map(scope);
680
+ if (valTemp)
681
+ thenScope.set(stmt.binding, valTemp);
682
+ lowerBlock(stmt.then, ctx, thenScope);
683
+ if (isPlaceholderTerm(ctx.current().term)) {
684
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
685
+ }
686
+ // Else branch
687
+ if (stmt.else_) {
688
+ ctx.switchTo(elseBlock);
689
+ lowerBlock(stmt.else_, ctx, new Map(scope));
690
+ if (isPlaceholderTerm(ctx.current().term)) {
691
+ ctx.terminate({ kind: 'jump', target: mergeBlock.id });
692
+ }
693
+ }
694
+ ctx.switchTo(mergeBlock);
695
+ break;
696
+ }
697
+ default: {
698
+ const _exhaustive = stmt;
699
+ throw new Error(`Unknown HIR statement kind: ${_exhaustive.kind}`);
700
+ }
701
+ }
702
+ }
703
+ // ---------------------------------------------------------------------------
704
+ // Expression lowering → produces an Operand (temp or const)
705
+ // ---------------------------------------------------------------------------
706
+ function lowerExpr(expr, ctx, scope) {
707
+ switch (expr.kind) {
708
+ case 'int_lit':
709
+ return { kind: 'const', value: expr.value };
710
+ case 'float_lit':
711
+ // float is ×1000 fixed-point in RedScript
712
+ return { kind: 'const', value: expr.value };
713
+ case 'byte_lit':
714
+ case 'short_lit':
715
+ case 'long_lit':
716
+ case 'double_lit':
717
+ return { kind: 'const', value: expr.value };
718
+ case 'bool_lit': {
719
+ return { kind: 'const', value: expr.value ? 1 : 0 };
720
+ }
721
+ case 'struct_lit': {
722
+ // Struct literal in expression context (not let/return — those handle it directly).
723
+ // Lower each field value but return a placeholder since the struct
724
+ // is tracked via structVars at the statement level.
725
+ for (const field of expr.fields) {
726
+ lowerExpr(field.value, ctx, scope);
727
+ }
728
+ const t = ctx.freshTemp();
729
+ ctx.emit({ kind: 'const', dst: t, value: 0 });
730
+ return { kind: 'temp', name: t };
731
+ }
732
+ case 'str_lit':
733
+ case 'range_lit':
734
+ case 'array_lit':
735
+ case 'rel_coord':
736
+ case 'local_coord':
737
+ case 'mc_name':
738
+ case 'blockpos':
739
+ case 'selector':
740
+ case 'str_interp':
741
+ case 'f_string':
742
+ case 'is_check':
743
+ case 'lambda': {
744
+ // MC-specific / complex types — opaque at MIR level
745
+ // Emit as const 0 placeholder; these are handled in LIR lowering
746
+ const t = ctx.freshTemp();
747
+ ctx.emit({ kind: 'const', dst: t, value: 0 });
748
+ return { kind: 'temp', name: t };
749
+ }
750
+ case 'ident': {
751
+ const temp = scope.get(expr.name);
752
+ if (temp)
753
+ return { kind: 'temp', name: temp };
754
+ // Unresolved ident — could be a global or external reference
755
+ const t = ctx.freshTemp();
756
+ ctx.emit({ kind: 'copy', dst: t, src: { kind: 'const', value: 0 } });
757
+ scope.set(expr.name, t);
758
+ return { kind: 'temp', name: t };
759
+ }
760
+ case 'binary': {
761
+ // Handle short-circuit && and ||
762
+ if (expr.op === '&&') {
763
+ return lowerShortCircuitAnd(expr, ctx, scope);
764
+ }
765
+ if (expr.op === '||') {
766
+ return lowerShortCircuitOr(expr, ctx, scope);
767
+ }
768
+ const left = lowerExpr(expr.left, ctx, scope);
769
+ const right = lowerExpr(expr.right, ctx, scope);
770
+ const t = ctx.freshTemp();
771
+ // Map HIR binary ops to MIR instructions
772
+ const arithmeticOps = {
773
+ '+': 'add', '-': 'sub', '*': 'mul', '/': 'div', '%': 'mod',
774
+ };
775
+ const cmpOps = {
776
+ '==': 'eq', '!=': 'ne', '<': 'lt', '<=': 'le', '>': 'gt', '>=': 'ge',
777
+ };
778
+ if (expr.op in arithmeticOps) {
779
+ ctx.emit({ kind: arithmeticOps[expr.op], dst: t, a: left, b: right });
780
+ }
781
+ else if (expr.op in cmpOps) {
782
+ ctx.emit({ kind: 'cmp', dst: t, op: cmpOps[expr.op], a: left, b: right });
783
+ }
784
+ else {
785
+ throw new Error(`Unknown binary op: ${expr.op}`);
786
+ }
787
+ return { kind: 'temp', name: t };
788
+ }
789
+ case 'unary': {
790
+ const operand = lowerExpr(expr.operand, ctx, scope);
791
+ const t = ctx.freshTemp();
792
+ if (expr.op === '-') {
793
+ ctx.emit({ kind: 'neg', dst: t, src: operand });
794
+ }
795
+ else if (expr.op === '!') {
796
+ ctx.emit({ kind: 'not', dst: t, src: operand });
797
+ }
798
+ return { kind: 'temp', name: t };
799
+ }
800
+ case 'assign': {
801
+ const val = lowerExpr(expr.value, ctx, scope);
802
+ // Reuse the existing temp for this variable so that updates inside
803
+ // if/while bodies are visible to outer code (we target mutable
804
+ // scoreboard slots, not true SSA registers).
805
+ const existing = scope.get(expr.target);
806
+ const t = existing ?? ctx.freshTemp();
807
+ ctx.emit({ kind: 'copy', dst: t, src: val });
808
+ scope.set(expr.target, t);
809
+ return val;
810
+ }
811
+ case 'member_assign': {
812
+ const val = lowerExpr(expr.value, ctx, scope);
813
+ // Struct field assignment: v.x = val → copy val to v's x temp
814
+ if (expr.obj.kind === 'ident') {
815
+ const sv = ctx.structVars.get(expr.obj.name);
816
+ if (sv) {
817
+ const fieldTemp = sv.fields.get(expr.field);
818
+ if (fieldTemp) {
819
+ ctx.emit({ kind: 'copy', dst: fieldTemp, src: val });
820
+ return val;
821
+ }
822
+ }
823
+ }
824
+ return val;
825
+ }
826
+ case 'path_expr': {
827
+ // Enum variant access: Phase::Idle → integer constant
828
+ const variants = ctx.enumDefs.get(expr.enumName);
829
+ const value = variants?.get(expr.variant) ?? 0;
830
+ return { kind: 'const', value };
831
+ }
832
+ case 'member': {
833
+ // Enum variant access via dot syntax: Phase.Idle → integer constant
834
+ if (expr.obj.kind === 'ident') {
835
+ const enumVariants = ctx.enumDefs.get(expr.obj.name);
836
+ if (enumVariants && enumVariants.has(expr.field)) {
837
+ return { kind: 'const', value: enumVariants.get(expr.field) };
838
+ }
839
+ }
840
+ // Struct field access: v.x → return v's x temp
841
+ if (expr.obj.kind === 'ident') {
842
+ const sv = ctx.structVars.get(expr.obj.name);
843
+ if (sv) {
844
+ const fieldTemp = sv.fields.get(expr.field);
845
+ if (fieldTemp)
846
+ return { kind: 'temp', name: fieldTemp };
847
+ }
848
+ }
849
+ // Fallback: opaque
850
+ const obj = lowerExpr(expr.obj, ctx, scope);
851
+ const t = ctx.freshTemp();
852
+ ctx.emit({ kind: 'copy', dst: t, src: obj });
853
+ return { kind: 'temp', name: t };
854
+ }
855
+ case 'index': {
856
+ const obj = lowerExpr(expr.obj, ctx, scope);
857
+ const idx = lowerExpr(expr.index, ctx, scope);
858
+ const t = ctx.freshTemp();
859
+ ctx.emit({ kind: 'copy', dst: t, src: obj });
860
+ return { kind: 'temp', name: t };
861
+ }
862
+ case 'call': {
863
+ // Handle builtin calls → raw MC commands
864
+ if (macro_1.BUILTIN_SET.has(expr.fn)) {
865
+ const cmd = formatBuiltinCall(expr.fn, expr.args, ctx.currentMacroParams);
866
+ ctx.emit({ kind: 'call', dst: null, fn: `__raw:${cmd}`, args: [] });
867
+ const t = ctx.freshTemp();
868
+ ctx.emit({ kind: 'const', dst: t, value: 0 });
869
+ return { kind: 'temp', name: t };
870
+ }
871
+ // Check for struct instance method call: parser desugars v.method() → call('method', [v, ...])
872
+ if (expr.args.length > 0 && expr.args[0].kind === 'ident') {
873
+ const sv = ctx.structVars.get(expr.args[0].name);
874
+ if (sv) {
875
+ const methodInfo = ctx.implMethods.get(sv.typeName)?.get(expr.fn);
876
+ if (methodInfo?.hasSelf) {
877
+ // Build args: self fields first, then remaining explicit args
878
+ const fields = ctx.structDefs.get(sv.typeName) ?? [];
879
+ const selfArgs = fields.map(f => {
880
+ const temp = sv.fields.get(f);
881
+ return temp ? { kind: 'temp', name: temp } : { kind: 'const', value: 0 };
882
+ });
883
+ const explicitArgs = expr.args.slice(1).map(a => lowerExpr(a, ctx, scope));
884
+ const allArgs = [...selfArgs, ...explicitArgs];
885
+ const t = ctx.freshTemp();
886
+ ctx.emit({ kind: 'call', dst: t, fn: `${sv.typeName}::${expr.fn}`, args: allArgs });
887
+ return { kind: 'temp', name: t };
888
+ }
889
+ }
890
+ }
891
+ // Check if calling a macro function → emit call_macro
892
+ const targetMacro = ctx.macroInfo.get(expr.fn);
893
+ if (targetMacro) {
894
+ const args = expr.args.map(a => lowerExpr(a, ctx, scope));
895
+ const targetParams = ctx.fnParamInfo.get(expr.fn) ?? [];
896
+ const macroArgs = [];
897
+ for (let i = 0; i < targetParams.length && i < args.length; i++) {
898
+ const paramName = targetParams[i].name;
899
+ if (targetMacro.macroParams.has(paramName)) {
900
+ const paramTypeName = targetMacro.paramTypes.get(paramName) ?? 'int';
901
+ const isFloat = paramTypeName === 'float';
902
+ macroArgs.push({
903
+ name: paramName,
904
+ value: args[i],
905
+ type: isFloat ? 'double' : 'int',
906
+ scale: isFloat ? 0.01 : 1,
907
+ });
908
+ }
909
+ }
910
+ const t = ctx.freshTemp();
911
+ ctx.emit({ kind: 'call_macro', dst: t, fn: expr.fn, args: macroArgs });
912
+ return { kind: 'temp', name: t };
913
+ }
914
+ const args = expr.args.map(a => lowerExpr(a, ctx, scope));
915
+ const t = ctx.freshTemp();
916
+ ctx.emit({ kind: 'call', dst: t, fn: expr.fn, args });
917
+ return { kind: 'temp', name: t };
918
+ }
919
+ case 'invoke': {
920
+ // Check for struct method call: v.method(args)
921
+ if (expr.callee.kind === 'member' && expr.callee.obj.kind === 'ident') {
922
+ const sv = ctx.structVars.get(expr.callee.obj.name);
923
+ if (sv) {
924
+ const methodInfo = ctx.implMethods.get(sv.typeName)?.get(expr.callee.field);
925
+ if (methodInfo?.hasSelf) {
926
+ // Build args: self fields first, then explicit args
927
+ const fields = ctx.structDefs.get(sv.typeName) ?? [];
928
+ const selfArgs = fields.map(f => {
929
+ const temp = sv.fields.get(f);
930
+ return temp ? { kind: 'temp', name: temp } : { kind: 'const', value: 0 };
931
+ });
932
+ const explicitArgs = expr.args.map(a => lowerExpr(a, ctx, scope));
933
+ const allArgs = [...selfArgs, ...explicitArgs];
934
+ const t = ctx.freshTemp();
935
+ ctx.emit({ kind: 'call', dst: t, fn: `${sv.typeName}::${expr.callee.field}`, args: allArgs });
936
+ return { kind: 'temp', name: t };
937
+ }
938
+ }
939
+ }
940
+ // Fallback: generic invoke
941
+ const calleeOp = lowerExpr(expr.callee, ctx, scope);
942
+ const args = expr.args.map(a => lowerExpr(a, ctx, scope));
943
+ const t = ctx.freshTemp();
944
+ ctx.emit({ kind: 'call', dst: t, fn: '__invoke', args: [calleeOp, ...args] });
945
+ return { kind: 'temp', name: t };
946
+ }
947
+ case 'static_call': {
948
+ const args = expr.args.map(a => lowerExpr(a, ctx, scope));
949
+ const t = ctx.freshTemp();
950
+ ctx.emit({ kind: 'call', dst: t, fn: `${expr.type}::${expr.method}`, args });
951
+ return { kind: 'temp', name: t };
952
+ }
953
+ case 'tuple_lit': {
954
+ // Inline tuple literal as expression: store elements into __rf_ slots and return a dummy temp
955
+ // This happens when a tuple literal appears as an expression (e.g., passed to a function)
956
+ for (let i = 0; i < expr.elements.length; i++) {
957
+ const val = lowerExpr(expr.elements[i], ctx, scope);
958
+ ctx.emit({ kind: 'copy', dst: `__rf_${i}`, src: val });
959
+ }
960
+ const t = ctx.freshTemp();
961
+ ctx.emit({ kind: 'const', dst: t, value: 0 });
962
+ return { kind: 'temp', name: t };
963
+ }
964
+ case 'some_lit': {
965
+ // Some(expr) in expression context: store has=1,val into __rf_has/__rf_val slots
966
+ const valOp = lowerExpr(expr.value, ctx, scope);
967
+ ctx.emit({ kind: 'copy', dst: '__rf_has', src: { kind: 'const', value: 1 } });
968
+ ctx.emit({ kind: 'copy', dst: '__rf_val', src: valOp });
969
+ const t = ctx.freshTemp();
970
+ ctx.emit({ kind: 'const', dst: t, value: 1 });
971
+ return { kind: 'temp', name: t };
972
+ }
973
+ case 'none_lit': {
974
+ // None in expression context: store has=0,val=0 into __rf_has/__rf_val slots
975
+ ctx.emit({ kind: 'copy', dst: '__rf_has', src: { kind: 'const', value: 0 } });
976
+ ctx.emit({ kind: 'copy', dst: '__rf_val', src: { kind: 'const', value: 0 } });
977
+ const t = ctx.freshTemp();
978
+ ctx.emit({ kind: 'const', dst: t, value: 0 });
979
+ return { kind: 'temp', name: t };
980
+ }
981
+ default: {
982
+ const _exhaustive = expr;
983
+ throw new Error(`Unknown HIR expression kind: ${_exhaustive.kind}`);
984
+ }
985
+ }
986
+ }
987
+ // ---------------------------------------------------------------------------
988
+ // Short-circuit lowering
989
+ // ---------------------------------------------------------------------------
990
+ function lowerShortCircuitAnd(expr, ctx, scope) {
991
+ // a && b → if(a) { b } else { 0 }
992
+ const left = lowerExpr(expr.left, ctx, scope);
993
+ const result = ctx.freshTemp();
994
+ const evalRight = ctx.newBlock('and_right');
995
+ const merge = ctx.newBlock('and_merge');
996
+ const falseBlock = ctx.newBlock('and_false');
997
+ ctx.terminate({ kind: 'branch', cond: left, then: evalRight.id, else: falseBlock.id });
998
+ ctx.switchTo(evalRight);
999
+ const right = lowerExpr(expr.right, ctx, scope);
1000
+ ctx.emit({ kind: 'copy', dst: result, src: right });
1001
+ ctx.terminate({ kind: 'jump', target: merge.id });
1002
+ ctx.switchTo(falseBlock);
1003
+ ctx.emit({ kind: 'const', dst: result, value: 0 });
1004
+ ctx.terminate({ kind: 'jump', target: merge.id });
1005
+ ctx.switchTo(merge);
1006
+ return { kind: 'temp', name: result };
1007
+ }
1008
+ function lowerShortCircuitOr(expr, ctx, scope) {
1009
+ // a || b → if(a) { 1 } else { b }
1010
+ const left = lowerExpr(expr.left, ctx, scope);
1011
+ const result = ctx.freshTemp();
1012
+ const trueBlock = ctx.newBlock('or_true');
1013
+ const evalRight = ctx.newBlock('or_right');
1014
+ const merge = ctx.newBlock('or_merge');
1015
+ ctx.terminate({ kind: 'branch', cond: left, then: trueBlock.id, else: evalRight.id });
1016
+ ctx.switchTo(trueBlock);
1017
+ ctx.emit({ kind: 'const', dst: result, value: 1 });
1018
+ ctx.terminate({ kind: 'jump', target: merge.id });
1019
+ ctx.switchTo(evalRight);
1020
+ const right = lowerExpr(expr.right, ctx, scope);
1021
+ ctx.emit({ kind: 'copy', dst: result, src: right });
1022
+ ctx.terminate({ kind: 'jump', target: merge.id });
1023
+ ctx.switchTo(merge);
1024
+ return { kind: 'temp', name: result };
1025
+ }
1026
+ // ---------------------------------------------------------------------------
1027
+ // Execute subcommand lowering
1028
+ // ---------------------------------------------------------------------------
1029
+ function lowerExecuteSubcmd(sub) {
1030
+ switch (sub.kind) {
1031
+ case 'as':
1032
+ return { kind: 'as', selector: selectorToString(sub.selector) };
1033
+ case 'at':
1034
+ return { kind: 'at', selector: selectorToString(sub.selector) };
1035
+ case 'positioned':
1036
+ return { kind: 'positioned', x: sub.x, y: sub.y, z: sub.z };
1037
+ case 'rotated':
1038
+ return { kind: 'rotated', yaw: sub.yaw, pitch: sub.pitch };
1039
+ case 'in':
1040
+ return { kind: 'in', dimension: sub.dimension };
1041
+ case 'anchored':
1042
+ return { kind: 'anchored', anchor: sub.anchor };
1043
+ case 'positioned_as':
1044
+ return { kind: 'at', selector: selectorToString(sub.selector) };
1045
+ case 'rotated_as':
1046
+ return { kind: 'rotated', yaw: '0', pitch: '0' };
1047
+ case 'facing':
1048
+ return { kind: 'positioned', x: sub.x, y: sub.y, z: sub.z };
1049
+ case 'facing_entity':
1050
+ return { kind: 'at', selector: selectorToString(sub.selector) };
1051
+ case 'align':
1052
+ return { kind: 'positioned', x: '0', y: '0', z: '0' };
1053
+ case 'on':
1054
+ return { kind: 'at_self' };
1055
+ case 'summon':
1056
+ return { kind: 'at_self' };
1057
+ case 'if_entity':
1058
+ case 'unless_entity':
1059
+ case 'if_block':
1060
+ case 'unless_block':
1061
+ case 'if_score':
1062
+ case 'unless_score':
1063
+ case 'if_score_range':
1064
+ case 'unless_score_range':
1065
+ case 'store_result':
1066
+ case 'store_success':
1067
+ // These are condition subcommands — pass through as-is for now
1068
+ return { kind: 'at_self' };
1069
+ default: {
1070
+ const _exhaustive = sub;
1071
+ throw new Error(`Unknown execute subcommand kind: ${_exhaustive.kind}`);
1072
+ }
1073
+ }
1074
+ }
1075
+ function selectorToString(sel) {
1076
+ // EntitySelector has kind like '@a', '@e', '@s', etc.
1077
+ // Filters are key=value pairs that become [key=value,key=value]
1078
+ if (!sel.filters || Object.keys(sel.filters).length === 0) {
1079
+ return sel.kind;
1080
+ }
1081
+ const parts = [];
1082
+ for (const [key, value] of Object.entries(sel.filters)) {
1083
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
1084
+ // Range filter: { min, max } → key=min..max
1085
+ const rangeObj = value;
1086
+ if (rangeObj.min !== undefined && rangeObj.max !== undefined) {
1087
+ parts.push(`${key}=${rangeObj.min}..${rangeObj.max}`);
1088
+ }
1089
+ else if (rangeObj.max !== undefined) {
1090
+ parts.push(`${key}=..${rangeObj.max}`);
1091
+ }
1092
+ else if (rangeObj.min !== undefined) {
1093
+ parts.push(`${key}=${rangeObj.min}..`);
1094
+ }
1095
+ }
1096
+ else {
1097
+ parts.push(`${key}=${value}`);
1098
+ }
1099
+ }
1100
+ return `${sel.kind}[${parts.join(',')}]`;
1101
+ }
1102
+ // ---------------------------------------------------------------------------
1103
+ // Builtin call formatting → raw MC command strings
1104
+ // ---------------------------------------------------------------------------
1105
+ const MACRO_SENTINEL = '\x01';
1106
+ /**
1107
+ * Format a builtin call as a raw MC command string.
1108
+ * If any argument uses a macro param, the command is prefixed with \x01
1109
+ * (converted to $ in LIR emission).
1110
+ */
1111
+ function formatBuiltinCall(fn, args, macroParams) {
1112
+ const fmtArgs = args.map(a => exprToCommandArg(a, macroParams));
1113
+ const strs = fmtArgs.map(a => a.str);
1114
+ const hasMacro = fmtArgs.some(a => a.isMacro);
1115
+ let cmd;
1116
+ switch (fn) {
1117
+ case 'summon': {
1118
+ const [type, x, y, z, nbt] = strs;
1119
+ const pos = [x ?? '~', y ?? '~', z ?? '~'].join(' ');
1120
+ cmd = nbt ? `summon ${type} ${pos} ${nbt}` : `summon ${type} ${pos}`;
1121
+ break;
1122
+ }
1123
+ case 'particle': {
1124
+ const [name, x, y, z, ...rest] = strs;
1125
+ const pos = [x ?? '~', y ?? '~', z ?? '~'].join(' ');
1126
+ const extra = rest.filter(v => v !== undefined);
1127
+ cmd = extra.length > 0 ? `particle ${name} ${pos} ${extra.join(' ')}` : `particle ${name} ${pos}`;
1128
+ break;
1129
+ }
1130
+ case 'setblock': {
1131
+ const [x, y, z, block] = strs;
1132
+ cmd = `setblock ${x} ${y} ${z} ${block}`;
1133
+ break;
1134
+ }
1135
+ case 'fill': {
1136
+ const [x1, y1, z1, x2, y2, z2, block] = strs;
1137
+ cmd = `fill ${x1} ${y1} ${z1} ${x2} ${y2} ${z2} ${block}`;
1138
+ break;
1139
+ }
1140
+ case 'say':
1141
+ cmd = `say ${strs[0] ?? ''}`;
1142
+ break;
1143
+ case 'tell':
1144
+ case 'tellraw':
1145
+ cmd = `tellraw ${strs[0]} {"text":"${strs[1]}"}`;
1146
+ break;
1147
+ case 'title':
1148
+ cmd = `title ${strs[0]} title {"text":"${strs[1]}"}`;
1149
+ break;
1150
+ case 'actionbar':
1151
+ cmd = `title ${strs[0]} actionbar {"text":"${strs[1]}"}`;
1152
+ break;
1153
+ case 'subtitle':
1154
+ cmd = `title ${strs[0]} subtitle {"text":"${strs[1]}"}`;
1155
+ break;
1156
+ case 'title_times':
1157
+ cmd = `title ${strs[0]} times ${strs[1]} ${strs[2]} ${strs[3]}`;
1158
+ break;
1159
+ case 'announce':
1160
+ cmd = `tellraw @a {"text":"${strs[0]}"}`;
1161
+ break;
1162
+ case 'give': {
1163
+ const nbt = strs[3] ? strs[3] : '';
1164
+ cmd = `give ${strs[0]} ${strs[1]}${nbt} ${strs[2] ?? '1'}`;
1165
+ break;
1166
+ }
1167
+ case 'kill':
1168
+ cmd = `kill ${strs[0] ?? '@s'}`;
1169
+ break;
1170
+ case 'effect':
1171
+ cmd = `effect give ${strs[0]} ${strs[1]} ${strs[2] ?? '30'} ${strs[3] ?? '0'}`;
1172
+ break;
1173
+ case 'effect_clear':
1174
+ cmd = strs[1] ? `effect clear ${strs[0]} ${strs[1]}` : `effect clear ${strs[0]}`;
1175
+ break;
1176
+ case 'playsound':
1177
+ cmd = ['playsound', ...strs].filter(Boolean).join(' ');
1178
+ break;
1179
+ case 'clear':
1180
+ cmd = `clear ${strs[0]} ${strs[1] ?? ''}`.trim();
1181
+ break;
1182
+ case 'weather':
1183
+ cmd = `weather ${strs[0]}`;
1184
+ break;
1185
+ case 'time_set':
1186
+ cmd = `time set ${strs[0]}`;
1187
+ break;
1188
+ case 'time_add':
1189
+ cmd = `time add ${strs[0]}`;
1190
+ break;
1191
+ case 'gamerule':
1192
+ cmd = `gamerule ${strs[0]} ${strs[1]}`;
1193
+ break;
1194
+ case 'tag_add':
1195
+ cmd = `tag ${strs[0]} add ${strs[1]}`;
1196
+ break;
1197
+ case 'tag_remove':
1198
+ cmd = `tag ${strs[0]} remove ${strs[1]}`;
1199
+ break;
1200
+ case 'kick':
1201
+ cmd = `kick ${strs[0]} ${strs[1] ?? ''}`.trim();
1202
+ break;
1203
+ case 'clone':
1204
+ cmd = `clone ${strs.join(' ')}`;
1205
+ break;
1206
+ case 'difficulty':
1207
+ cmd = `difficulty ${strs[0]}`;
1208
+ break;
1209
+ case 'xp_add':
1210
+ cmd = `xp add ${strs[0]} ${strs[1]} ${strs[2] ?? 'points'}`;
1211
+ break;
1212
+ case 'xp_set':
1213
+ cmd = `xp set ${strs[0]} ${strs[1]} ${strs[2] ?? 'points'}`;
1214
+ break;
1215
+ default: cmd = `${fn} ${strs.join(' ')}`;
1216
+ }
1217
+ return hasMacro ? `${MACRO_SENTINEL}${cmd}` : cmd;
1218
+ }
1219
+ /** Convert an HIR expression to its MC command string representation */
1220
+ function exprToCommandArg(expr, macroParams) {
1221
+ switch (expr.kind) {
1222
+ case 'int_lit': return { str: String(expr.value), isMacro: false };
1223
+ case 'float_lit': return { str: String(expr.value), isMacro: false };
1224
+ case 'byte_lit': return { str: String(expr.value), isMacro: false };
1225
+ case 'short_lit': return { str: String(expr.value), isMacro: false };
1226
+ case 'long_lit': return { str: String(expr.value), isMacro: false };
1227
+ case 'double_lit': return { str: String(expr.value), isMacro: false };
1228
+ case 'bool_lit': return { str: expr.value ? 'true' : 'false', isMacro: false };
1229
+ case 'str_lit': return { str: expr.value, isMacro: false };
1230
+ case 'mc_name': return { str: expr.value, isMacro: false };
1231
+ case 'selector': return { str: expr.raw, isMacro: false };
1232
+ case 'ident':
1233
+ if (macroParams.has(expr.name))
1234
+ return { str: `$(${expr.name})`, isMacro: true };
1235
+ return { str: expr.name, isMacro: false };
1236
+ case 'local_coord': {
1237
+ const prefix = expr.value[0]; // ^
1238
+ const rest = expr.value.slice(1);
1239
+ if (rest && /^[a-zA-Z_]\w*$/.test(rest) && macroParams.has(rest)) {
1240
+ return { str: `${prefix}$(${rest})`, isMacro: true };
1241
+ }
1242
+ return { str: expr.value, isMacro: false };
1243
+ }
1244
+ case 'rel_coord': {
1245
+ const prefix = expr.value[0]; // ~
1246
+ const rest = expr.value.slice(1);
1247
+ if (rest && /^[a-zA-Z_]\w*$/.test(rest) && macroParams.has(rest)) {
1248
+ return { str: `${prefix}$(${rest})`, isMacro: true };
1249
+ }
1250
+ return { str: expr.value, isMacro: false };
1251
+ }
1252
+ case 'unary':
1253
+ if (expr.op === '-' && expr.operand.kind === 'float_lit') {
1254
+ return { str: String(-expr.operand.value), isMacro: false };
1255
+ }
1256
+ if (expr.op === '-' && expr.operand.kind === 'int_lit') {
1257
+ return { str: String(-expr.operand.value), isMacro: false };
1258
+ }
1259
+ return { str: '~', isMacro: false };
1260
+ default:
1261
+ return { str: '~', isMacro: false };
1262
+ }
1263
+ }
1264
+ //# sourceMappingURL=lower.js.map