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,299 @@
1
+ /**
2
+ * Tests for Phase 6a: Option<T> — null safety
3
+ *
4
+ * Covers:
5
+ * - Parsing Option<T> type annotation
6
+ * - Parsing Some(expr) and None expressions
7
+ * - Parsing if let Some(x) = opt { ... }
8
+ * - HIR lowering of Option nodes
9
+ * - MIR lowering: Option compiles to two slots (has + val)
10
+ * - if let Some(x) = opt → checks has slot, binds val slot
11
+ * - Function returning Option<int>
12
+ * - Correct scoreboard commands generated
13
+ */
14
+
15
+ import { Lexer } from '../lexer'
16
+ import { Parser } from '../parser'
17
+ import { compile } from '../emit/compile'
18
+ import { lowerToHIR } from '../hir/lower'
19
+ import type { Program } from '../ast/types'
20
+
21
+ function parse(source: string, namespace = 'test'): Program {
22
+ const tokens = new Lexer(source).tokenize()
23
+ return new Parser(tokens).parse(namespace)
24
+ }
25
+
26
+ function getFile(files: { path: string; content: string }[], pathSubstr: string): string | undefined {
27
+ // Prefer exact function file match: look for function/<name>.mcfunction
28
+ const exact = files.find(f => f.path.endsWith(`function/${pathSubstr}.mcfunction`))
29
+ if (exact) return exact.content
30
+ const f = files.find(f => f.path.includes(pathSubstr))
31
+ return f?.content
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Parser tests
36
+ // ---------------------------------------------------------------------------
37
+
38
+ describe('Option: Parser', () => {
39
+ it('parses Option<int> type annotation', () => {
40
+ const prog = parse('fn f(): Option<int> {}')
41
+ expect(prog.declarations[0].returnType).toEqual({ kind: 'option', inner: { kind: 'named', name: 'int' } })
42
+ })
43
+
44
+ it('parses Option<bool> parameter type', () => {
45
+ const prog = parse('fn f(x: Option<bool>): void {}')
46
+ expect(prog.declarations[0].params[0].type).toEqual({ kind: 'option', inner: { kind: 'named', name: 'bool' } })
47
+ })
48
+
49
+ it('parses Some(42) expression', () => {
50
+ const prog = parse('fn f(): void { let x: Option<int> = Some(42); }')
51
+ const letStmt = prog.declarations[0].body[0]
52
+ expect(letStmt.kind).toBe('let')
53
+ if (letStmt.kind === 'let') {
54
+ expect(letStmt.init.kind).toBe('some_lit')
55
+ if (letStmt.init.kind === 'some_lit') {
56
+ expect(letStmt.init.value).toEqual({ kind: 'int_lit', value: 42 })
57
+ }
58
+ }
59
+ })
60
+
61
+ it('parses None expression', () => {
62
+ const prog = parse('fn f(): void { let x: Option<int> = None; }')
63
+ const letStmt = prog.declarations[0].body[0]
64
+ expect(letStmt.kind).toBe('let')
65
+ if (letStmt.kind === 'let') {
66
+ expect(letStmt.init.kind).toBe('none_lit')
67
+ }
68
+ })
69
+
70
+ it('parses if let Some(x) = opt { ... }', () => {
71
+ const prog = parse('fn f(p: Option<int>): void { if let Some(x) = p { let y: int = x; } }')
72
+ const stmt = prog.declarations[0].body[0]
73
+ expect(stmt.kind).toBe('if_let_some')
74
+ if (stmt.kind === 'if_let_some') {
75
+ expect(stmt.binding).toBe('x')
76
+ expect(stmt.init).toEqual({ kind: 'ident', name: 'p' })
77
+ expect(stmt.then.length).toBe(1)
78
+ }
79
+ })
80
+
81
+ it('parses if let Some(x) = opt { } else { }', () => {
82
+ const prog = parse(`
83
+ fn f(p: Option<int>): void {
84
+ if let Some(x) = p {
85
+ let a: int = x;
86
+ } else {
87
+ let b: int = 0;
88
+ }
89
+ }
90
+ `)
91
+ const stmt = prog.declarations[0].body[0]
92
+ expect(stmt.kind).toBe('if_let_some')
93
+ if (stmt.kind === 'if_let_some') {
94
+ expect(stmt.else_).toBeDefined()
95
+ expect(stmt.else_!.length).toBe(1)
96
+ }
97
+ })
98
+
99
+ it('does not treat Some as identifier', () => {
100
+ const prog = parse('fn f(): void { let x: Option<int> = Some(1); }')
101
+ if (prog.declarations[0].body[0].kind === 'let') {
102
+ const init = prog.declarations[0].body[0].init
103
+ expect(init.kind).toBe('some_lit')
104
+ }
105
+ })
106
+
107
+ it('does not treat None as identifier', () => {
108
+ const prog = parse('fn f(): void { let x: Option<int> = None; }')
109
+ if (prog.declarations[0].body[0].kind === 'let') {
110
+ const init = prog.declarations[0].body[0].init
111
+ expect(init.kind).toBe('none_lit')
112
+ }
113
+ })
114
+ })
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // HIR lowering tests
118
+ // ---------------------------------------------------------------------------
119
+
120
+ describe('Option: HIR lowering', () => {
121
+ function hirOf(source: string) {
122
+ const tokens = new Lexer(source).tokenize()
123
+ const ast = new Parser(tokens).parse('test')
124
+ return lowerToHIR(ast)
125
+ }
126
+
127
+ it('lowers some_lit through HIR unchanged', () => {
128
+ const hir = hirOf('fn f(): void { let x: Option<int> = Some(42); }')
129
+ const fn0 = hir.functions[0]
130
+ const letStmt = fn0.body[0]
131
+ expect(letStmt.kind).toBe('let')
132
+ if (letStmt.kind === 'let') {
133
+ expect(letStmt.init.kind).toBe('some_lit')
134
+ }
135
+ })
136
+
137
+ it('lowers none_lit through HIR unchanged', () => {
138
+ const hir = hirOf('fn f(): void { let x: Option<int> = None; }')
139
+ const fn0 = hir.functions[0]
140
+ const letStmt = fn0.body[0]
141
+ expect(letStmt.kind).toBe('let')
142
+ if (letStmt.kind === 'let') {
143
+ expect(letStmt.init.kind).toBe('none_lit')
144
+ }
145
+ })
146
+
147
+ it('lowers if_let_some through HIR unchanged', () => {
148
+ const hir = hirOf('fn f(p: Option<int>): void { if let Some(x) = p {} }')
149
+ const fn0 = hir.functions[0]
150
+ const stmt = fn0.body[0]
151
+ expect(stmt.kind).toBe('if_let_some')
152
+ if (stmt.kind === 'if_let_some') {
153
+ expect(stmt.binding).toBe('x')
154
+ }
155
+ })
156
+ })
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // Compilation (E2E) tests
160
+ // ---------------------------------------------------------------------------
161
+
162
+ describe('Option: E2E compilation', () => {
163
+ it('compiles Some(42) assignment — sets has=1, val=42', () => {
164
+ const source = `
165
+ fn test(): void {
166
+ let p: Option<int> = Some(42);
167
+ }
168
+ `
169
+ const result = compile(source, { namespace: 'test' })
170
+ const fn = getFile(result.files, 'test')
171
+ expect(fn).toBeDefined()
172
+ expect(fn).toContain('scoreboard players set')
173
+ // has slot should be set to 1, val slot should be set to 42
174
+ expect(fn).toContain('1')
175
+ expect(fn).toContain('42')
176
+ })
177
+
178
+ it('compiles None assignment — sets has=0', () => {
179
+ const source = `
180
+ fn test(): void {
181
+ let p: Option<int> = None;
182
+ }
183
+ `
184
+ const result = compile(source, { namespace: 'test' })
185
+ const fn = getFile(result.files, 'test')
186
+ expect(fn).toBeDefined()
187
+ expect(fn).toContain('scoreboard players set')
188
+ expect(fn).toContain('0')
189
+ })
190
+
191
+ it('compiles if let Some(x) = p — conditional on has slot', () => {
192
+ const source = `
193
+ fn test(p: Option<int>): void {
194
+ if let Some(x) = p {
195
+ let y: int = x;
196
+ }
197
+ }
198
+ `
199
+ const result = compile(source, { namespace: 'test' })
200
+ // Should generate a conditional call checking has slot
201
+ expect(result.files.length).toBeGreaterThan(0)
202
+ })
203
+
204
+ it('compiles function returning Option<int> Some value', () => {
205
+ const source = `
206
+ fn make_some(): Option<int> {
207
+ return Some(99);
208
+ }
209
+ fn test(): void {
210
+ let p: Option<int> = make_some();
211
+ }
212
+ `
213
+ const result = compile(source, { namespace: 'test' })
214
+ const fn = getFile(result.files, 'make_some')
215
+ expect(fn).toBeDefined()
216
+ // Should set ret_has=1 and ret_val=99
217
+ expect(fn).toContain('$ret_has')
218
+ expect(fn).toContain('99')
219
+ })
220
+
221
+ it('compiles function returning Option<int> None value', () => {
222
+ const source = `
223
+ fn make_none(): Option<int> {
224
+ return None;
225
+ }
226
+ `
227
+ const result = compile(source, { namespace: 'test' })
228
+ const fn = getFile(result.files, 'make_none')
229
+ expect(fn).toBeDefined()
230
+ expect(fn).toContain('$ret_has')
231
+ // has=0
232
+ expect(fn).toContain('0')
233
+ })
234
+
235
+ it('compiles full if-let Some pattern with body using bound variable', () => {
236
+ // Use a function that returns Option<int> so the condition is not constant-folded
237
+ const source = `
238
+ fn maybe_val(): Option<int> {
239
+ return Some(10);
240
+ }
241
+ @tick
242
+ fn tick(): void {
243
+ let p: Option<int> = maybe_val();
244
+ if let Some(n) = p {
245
+ let doubled: int = n + n;
246
+ }
247
+ }
248
+ `
249
+ const result = compile(source, { namespace: 'test' })
250
+ expect(result.files.length).toBeGreaterThan(0)
251
+ // Verify a conditional function split was created
252
+ const hasConditional = result.files.some(f => f.content.includes('execute if score'))
253
+ expect(hasConditional).toBe(true)
254
+ })
255
+
256
+ it('compiles if-let with else branch', () => {
257
+ const source = `
258
+ @tick
259
+ fn tick(): void {
260
+ let q: Option<int> = None;
261
+ if let Some(v) = q {
262
+ let a: int = v;
263
+ } else {
264
+ let b: int = 0;
265
+ }
266
+ }
267
+ `
268
+ const result = compile(source, { namespace: 'test' })
269
+ expect(result.files.length).toBeGreaterThan(0)
270
+ })
271
+
272
+ it('compiles nested if-let inside if-let', () => {
273
+ const source = `
274
+ fn test(): void {
275
+ let a: Option<int> = Some(1);
276
+ let b: Option<int> = Some(2);
277
+ if let Some(x) = a {
278
+ if let Some(y) = b {
279
+ let sum: int = x + y;
280
+ }
281
+ }
282
+ }
283
+ `
284
+ const result = compile(source, { namespace: 'test' })
285
+ expect(result.files.length).toBeGreaterThan(0)
286
+ })
287
+
288
+ it('generated scoreboard slots are unique per function and variable', () => {
289
+ const source = `
290
+ fn test(): void {
291
+ let p: Option<int> = Some(5);
292
+ let q: Option<int> = None;
293
+ }
294
+ `
295
+ const result = compile(source, { namespace: 'test' })
296
+ const fn = getFile(result.files, 'test')
297
+ expect(fn).toBeDefined()
298
+ })
299
+ })
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Tests for @schedule decorator (Phase 5c)
3
+ *
4
+ * @schedule(ticks=N) generates a _schedule_xxx.mcfunction wrapper that
5
+ * emits `schedule function ns:xxx Nt`.
6
+ */
7
+
8
+ import { compile } from '../emit/compile'
9
+
10
+ function getFile(files: { path: string; content: string }[], pathSubstr: string): string | undefined {
11
+ const f = files.find(f => f.path.includes(pathSubstr))
12
+ return f?.content
13
+ }
14
+
15
+ describe('@schedule decorator', () => {
16
+ test('@schedule(ticks=20) generates _schedule wrapper with 20t', () => {
17
+ const source = `
18
+ @schedule(ticks=20)
19
+ fn after_one_second(): void {
20
+ say("One second passed!");
21
+ }
22
+ `
23
+ const result = compile(source, { namespace: 'test' })
24
+ const wrapper = getFile(result.files, '_schedule_after_one_second.mcfunction')
25
+ expect(wrapper).toBeDefined()
26
+ expect(wrapper).toBe('schedule function test:after_one_second 20t\n')
27
+ })
28
+
29
+ test('@schedule(ticks=1) generates _schedule wrapper with 1t', () => {
30
+ const source = `
31
+ @schedule(ticks=1)
32
+ fn next_tick(): void {
33
+ say("next tick!");
34
+ }
35
+ `
36
+ const result = compile(source, { namespace: 'ns' })
37
+ const wrapper = getFile(result.files, '_schedule_next_tick.mcfunction')
38
+ expect(wrapper).toBeDefined()
39
+ expect(wrapper).toBe('schedule function ns:next_tick 1t\n')
40
+ })
41
+
42
+ test('@schedule does not affect tick.json', () => {
43
+ const source = `
44
+ @schedule(ticks=20)
45
+ fn deferred(): void {
46
+ say("deferred");
47
+ }
48
+ `
49
+ const result = compile(source, { namespace: 'test' })
50
+ const tickJson = getFile(result.files, 'tick.json')
51
+ expect(tickJson).toBeUndefined()
52
+ })
53
+
54
+ test('@schedule coexists with @tick and @load', () => {
55
+ const source = `
56
+ @tick
57
+ fn game_tick(): void {
58
+ let x: int = 1;
59
+ }
60
+
61
+ @load
62
+ fn init(): void {
63
+ let y: int = 0;
64
+ }
65
+
66
+ @schedule(ticks=40)
67
+ fn two_seconds(): void {
68
+ say("two seconds!");
69
+ }
70
+ `
71
+ const result = compile(source, { namespace: 'combo' })
72
+
73
+ // @tick still works
74
+ const tickJson = getFile(result.files, 'tick.json')
75
+ expect(tickJson).toBeDefined()
76
+ expect(JSON.parse(tickJson!).values).toContain('combo:game_tick')
77
+
78
+ // @load still works
79
+ const loadJson = getFile(result.files, 'load.json')
80
+ expect(loadJson).toBeDefined()
81
+ expect(JSON.parse(loadJson!).values).toContain('combo:init')
82
+
83
+ // @schedule generates wrapper
84
+ const wrapper = getFile(result.files, '_schedule_two_seconds.mcfunction')
85
+ expect(wrapper).toBeDefined()
86
+ expect(wrapper).toBe('schedule function combo:two_seconds 40t\n')
87
+ })
88
+
89
+ test('calling _schedule_xxx() invokes the schedule wrapper', () => {
90
+ const source = `
91
+ @schedule(ticks=20)
92
+ fn after_one_second(): void {
93
+ say("delayed");
94
+ }
95
+
96
+ fn start(): void {
97
+ _schedule_after_one_second();
98
+ }
99
+ `
100
+ const result = compile(source, { namespace: 'test' })
101
+ const startFn = getFile(result.files, 'start.mcfunction')
102
+ expect(startFn).toBeDefined()
103
+ expect(startFn).toContain('function test:_schedule_after_one_second')
104
+ })
105
+ })
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Source Map Tests — Phase 4a
3
+ *
4
+ * Verifies that generated .sourcemap.json files correctly map output lines
5
+ * back to source .mcrs locations.
6
+ */
7
+
8
+ import { compile } from '../index'
9
+ import type { SourceMap } from '../emit/sourcemap'
10
+
11
+ function getSourceMap(
12
+ files: ReturnType<typeof compile>['files'],
13
+ fnSuffix: string,
14
+ ): SourceMap {
15
+ const smPath = `data/test/function/${fnSuffix}.sourcemap.json`
16
+ const file = files.find(f => f.path === smPath)
17
+ if (!file) {
18
+ const paths = files.map(f => f.path).join(', ')
19
+ throw new Error(`Missing sourcemap: ${smPath}\nAvailable: ${paths}`)
20
+ }
21
+ return JSON.parse(file.content) as SourceMap
22
+ }
23
+
24
+ function getMcFunction(
25
+ files: ReturnType<typeof compile>['files'],
26
+ fnSuffix: string,
27
+ ): string {
28
+ const mcPath = `data/test/function/${fnSuffix}.mcfunction`
29
+ const file = files.find(f => f.path === mcPath)
30
+ if (!file) throw new Error(`Missing mcfunction: ${mcPath}`)
31
+ return file.content
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Basic structure
36
+ // ---------------------------------------------------------------------------
37
+
38
+ describe('source map — basic structure', () => {
39
+ it('generates sourcemap.json only when generateSourceMap=true', () => {
40
+ const source = `fn add(a: int, b: int): int { return a + b; }`
41
+ const without = compile(source, { namespace: 'test', filePath: 'src/add.mcrs' })
42
+ expect(without.files.some(f => f.path.endsWith('.sourcemap.json'))).toBe(false)
43
+
44
+ const with_ = compile(source, { namespace: 'test', generateSourceMap: true, filePath: 'src/add.mcrs' })
45
+ expect(with_.files.some(f => f.path.endsWith('.sourcemap.json'))).toBe(true)
46
+ })
47
+
48
+ it('sourcemap has version=1', () => {
49
+ const source = `fn greet() { say("hello"); }`
50
+ const result = compile(source, {
51
+ namespace: 'test',
52
+ generateSourceMap: true,
53
+ filePath: 'src/greet.mcrs',
54
+ })
55
+ const sm = getSourceMap(result.files, 'greet')
56
+ expect(sm.version).toBe(1)
57
+ })
58
+
59
+ it('sourcemap generatedFile matches the mcfunction path', () => {
60
+ const source = `fn foo() { say("x"); }`
61
+ const result = compile(source, {
62
+ namespace: 'test',
63
+ generateSourceMap: true,
64
+ filePath: 'src/foo.mcrs',
65
+ })
66
+ const sm = getSourceMap(result.files, 'foo')
67
+ expect(sm.generatedFile).toBe('data/test/function/foo.mcfunction')
68
+ })
69
+
70
+ it('sources array contains the source file path', () => {
71
+ const source = `fn bar() { say("y"); }`
72
+ const result = compile(source, {
73
+ namespace: 'test',
74
+ generateSourceMap: true,
75
+ filePath: 'src/bar.mcrs',
76
+ })
77
+ const sm = getSourceMap(result.files, 'bar')
78
+ expect(sm.sources).toContain('src/bar.mcrs')
79
+ })
80
+ })
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Mapping correctness
84
+ // ---------------------------------------------------------------------------
85
+
86
+ describe('source map — mapping correctness', () => {
87
+ it('each mapping line references a valid output line', () => {
88
+ const source = `
89
+ fn simple(x: int): int {
90
+ let y = x + 1;
91
+ return y;
92
+ }
93
+ `
94
+ const result = compile(source, {
95
+ namespace: 'test',
96
+ generateSourceMap: true,
97
+ filePath: 'src/simple.mcrs',
98
+ })
99
+ const sm = getSourceMap(result.files, 'simple')
100
+ const mcfn = getMcFunction(result.files, 'simple')
101
+ const outputLines = mcfn.split('\n').filter(l => l.length > 0)
102
+
103
+ for (const mapping of sm.mappings) {
104
+ expect(mapping.line).toBeGreaterThanOrEqual(1)
105
+ expect(mapping.line).toBeLessThanOrEqual(outputLines.length)
106
+ expect(mapping.sourceLine).toBeGreaterThanOrEqual(1)
107
+ expect(mapping.sourceCol).toBeGreaterThanOrEqual(1)
108
+ }
109
+ })
110
+
111
+ it('source index in mappings refers to valid sources entry', () => {
112
+ const source = `fn calc(a: int, b: int): int { return a * b; }`
113
+ const result = compile(source, {
114
+ namespace: 'test',
115
+ generateSourceMap: true,
116
+ filePath: 'src/calc.mcrs',
117
+ })
118
+ const sm = getSourceMap(result.files, 'calc')
119
+ for (const m of sm.mappings) {
120
+ expect(m.source).toBeGreaterThanOrEqual(0)
121
+ expect(m.source).toBeLessThan(sm.sources.length)
122
+ }
123
+ })
124
+
125
+ it('mappings cover the output lines from a simple function body', () => {
126
+ const source = `
127
+ fn add(a: int, b: int): int {
128
+ return a + b;
129
+ }
130
+ `
131
+ const result = compile(source, {
132
+ namespace: 'test',
133
+ generateSourceMap: true,
134
+ filePath: 'src/add.mcrs',
135
+ })
136
+ const sm = getSourceMap(result.files, 'add')
137
+ // There should be at least one mapping
138
+ expect(sm.mappings.length).toBeGreaterThan(0)
139
+ // All mappings should point at non-zero source lines
140
+ for (const m of sm.mappings) {
141
+ expect(m.sourceLine).toBeGreaterThan(0)
142
+ }
143
+ })
144
+
145
+ it('sourceLine values are ordered and correspond to source line numbers', () => {
146
+ const source = `
147
+ fn multi() {
148
+ let a = 1;
149
+ let b = 2;
150
+ let c = a + b;
151
+ say("hello");
152
+ }
153
+ `
154
+ const result = compile(source, {
155
+ namespace: 'test',
156
+ generateSourceMap: true,
157
+ filePath: 'src/multi.mcrs',
158
+ })
159
+ const sm = getSourceMap(result.files, 'multi')
160
+ // All mapped source lines should be in the range of the function body
161
+ for (const m of sm.mappings) {
162
+ expect(m.sourceLine).toBeGreaterThanOrEqual(2) // fn starts at line 2
163
+ expect(m.sourceLine).toBeLessThanOrEqual(8) // fn ends at line 8
164
+ }
165
+ })
166
+ })
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // No sourcemap when no filePath
170
+ // ---------------------------------------------------------------------------
171
+
172
+ describe('source map — no filePath', () => {
173
+ it('generates sourcemap with empty sources when no filePath is provided', () => {
174
+ const source = `fn noloc() { say("no file"); }`
175
+ const result = compile(source, {
176
+ namespace: 'test',
177
+ generateSourceMap: true,
178
+ // no filePath
179
+ })
180
+ // Source map should not be generated (no sourceLoc info to record)
181
+ const hasSm = result.files.some(f => f.path.endsWith('.sourcemap.json'))
182
+ // Either no sourcemap generated, or it has empty mappings
183
+ if (hasSm) {
184
+ const sm = getSourceMap(result.files, 'noloc')
185
+ expect(sm.mappings.length).toBe(0)
186
+ }
187
+ // This is acceptable either way — just verify it doesn't crash
188
+ })
189
+ })
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Nested function calls
193
+ // ---------------------------------------------------------------------------
194
+
195
+ describe('source map — nested function calls', () => {
196
+ it('each function gets its own sourcemap', () => {
197
+ const source = `
198
+ fn helper(x: int): int {
199
+ return x * 2;
200
+ }
201
+
202
+ fn caller() {
203
+ let r = helper(5);
204
+ say("done");
205
+ }
206
+ `
207
+ const result = compile(source, {
208
+ namespace: 'test',
209
+ generateSourceMap: true,
210
+ filePath: 'src/nested.mcrs',
211
+ })
212
+ // Both functions should have sourcemaps
213
+ const helperSm = getSourceMap(result.files, 'helper')
214
+ const callerSm = getSourceMap(result.files, 'caller')
215
+
216
+ expect(helperSm.mappings.length).toBeGreaterThan(0)
217
+ expect(callerSm.mappings.length).toBeGreaterThan(0)
218
+
219
+ // helper's mappings should reference lines 2-4
220
+ for (const m of helperSm.mappings) {
221
+ expect(m.sourceLine).toBeGreaterThanOrEqual(2)
222
+ expect(m.sourceLine).toBeLessThanOrEqual(4)
223
+ }
224
+
225
+ // caller's mappings should reference lines 7-9
226
+ for (const m of callerSm.mappings) {
227
+ expect(m.sourceLine).toBeGreaterThanOrEqual(7)
228
+ expect(m.sourceLine).toBeLessThanOrEqual(9)
229
+ }
230
+ })
231
+ })
232
+
233
+ // ---------------------------------------------------------------------------
234
+ // sourcemap.json sidecar path
235
+ // ---------------------------------------------------------------------------
236
+
237
+ describe('source map — file path convention', () => {
238
+ it('sourcemap path replaces .mcfunction with .sourcemap.json', () => {
239
+ const source = `fn test_fn() { say("test"); }`
240
+ const result = compile(source, {
241
+ namespace: 'test',
242
+ generateSourceMap: true,
243
+ filePath: 'src/test.mcrs',
244
+ })
245
+ const smFiles = result.files.filter(f => f.path.endsWith('.sourcemap.json'))
246
+ expect(smFiles.length).toBeGreaterThan(0)
247
+ for (const sf of smFiles) {
248
+ expect(sf.path).toMatch(/\.sourcemap\.json$/)
249
+ // Corresponding .mcfunction should also exist
250
+ const mcPath = sf.path.replace('.sourcemap.json', '.mcfunction')
251
+ expect(result.files.some(f => f.path === mcPath)).toBe(true)
252
+ }
253
+ })
254
+ })