redscript-mc 2.6.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (636) hide show
  1. package/.github/workflows/ci.yml +11 -0
  2. package/CHANGELOG.md +18 -9
  3. package/README-benchmarks.md +48 -0
  4. package/README-vscode-test.md +251 -0
  5. package/RELEASE_NOTES.md +74 -0
  6. package/ROADMAP.md +131 -167
  7. package/benchmarks/_shared.ts +468 -0
  8. package/benchmarks/baseline.json +2816 -0
  9. package/benchmarks/baseline.md +13 -0
  10. package/benchmarks/compiler-perf.report.json +207 -0
  11. package/benchmarks/compiler-perf.ts +76 -0
  12. package/benchmarks/results.md +13 -0
  13. package/benchmarks/stdlib-complexity.report.json +2606 -0
  14. package/benchmarks/stdlib-complexity.ts +54 -0
  15. package/benchmarks/stdlib-size.md +57 -0
  16. package/benchmarks/stdlib-size.ts +91 -0
  17. package/coverage-report.md +177 -0
  18. package/dist/src/__tests__/budget.test.js +4 -0
  19. package/dist/src/__tests__/cache/cache-behavior.test.d.ts +10 -0
  20. package/dist/src/__tests__/cache/cache-behavior.test.js +425 -0
  21. package/dist/src/__tests__/cache-extra.test.d.ts +5 -0
  22. package/dist/src/__tests__/cache-extra.test.js +211 -0
  23. package/dist/src/__tests__/cli-init.test.d.ts +1 -0
  24. package/dist/src/__tests__/cli-init.test.js +97 -0
  25. package/dist/src/__tests__/cli-publish.test.d.ts +9 -0
  26. package/dist/src/__tests__/cli-publish.test.js +189 -0
  27. package/dist/src/__tests__/cli.test.js +76 -0
  28. package/dist/src/__tests__/compile-preprocess.test.d.ts +11 -0
  29. package/dist/src/__tests__/compile-preprocess.test.js +328 -0
  30. package/dist/src/__tests__/compiler/break-stmt.test.d.ts +1 -0
  31. package/dist/src/__tests__/compiler/break-stmt.test.js +58 -0
  32. package/dist/src/__tests__/compiler/const-decl.test.d.ts +1 -0
  33. package/dist/src/__tests__/compiler/const-decl.test.js +123 -0
  34. package/dist/src/__tests__/compiler/continue-stmt.test.d.ts +1 -0
  35. package/dist/src/__tests__/compiler/continue-stmt.test.js +67 -0
  36. package/dist/src/__tests__/compiler/coroutine-extended.test.d.ts +17 -0
  37. package/dist/src/__tests__/compiler/coroutine-extended.test.js +565 -0
  38. package/dist/src/__tests__/compiler/deprecated.test.d.ts +4 -0
  39. package/dist/src/__tests__/compiler/deprecated.test.js +285 -0
  40. package/dist/src/__tests__/compiler/do-while.test.d.ts +1 -0
  41. package/dist/src/__tests__/compiler/do-while.test.js +120 -0
  42. package/dist/src/__tests__/compiler/enum-payload.test.d.ts +9 -0
  43. package/dist/src/__tests__/compiler/enum-payload.test.js +272 -0
  44. package/dist/src/__tests__/compiler/interface.test.d.ts +10 -0
  45. package/dist/src/__tests__/compiler/interface.test.js +258 -0
  46. package/dist/src/__tests__/compiler/labeled-loops.test.d.ts +1 -0
  47. package/dist/src/__tests__/compiler/labeled-loops.test.js +263 -0
  48. package/dist/src/__tests__/compiler/match-string.test.d.ts +1 -0
  49. package/dist/src/__tests__/compiler/match-string.test.js +43 -0
  50. package/dist/src/__tests__/compiler/memoize.test.d.ts +1 -0
  51. package/dist/src/__tests__/compiler/memoize.test.js +113 -0
  52. package/dist/src/__tests__/compiler/method-chain.test.d.ts +5 -0
  53. package/dist/src/__tests__/compiler/method-chain.test.js +115 -0
  54. package/dist/src/__tests__/compiler/module-import.test.d.ts +12 -0
  55. package/dist/src/__tests__/compiler/module-import.test.js +261 -0
  56. package/dist/src/__tests__/compiler/option-extensions.test.d.ts +6 -0
  57. package/dist/src/__tests__/compiler/option-extensions.test.js +191 -0
  58. package/dist/src/__tests__/compiler/profile-decorator.test.d.ts +1 -0
  59. package/dist/src/__tests__/compiler/profile-decorator.test.js +69 -0
  60. package/dist/src/__tests__/compiler/string-advanced.test.d.ts +7 -0
  61. package/dist/src/__tests__/compiler/string-advanced.test.js +281 -0
  62. package/dist/src/__tests__/compiler/struct-extends.test.d.ts +1 -0
  63. package/dist/src/__tests__/compiler/struct-extends.test.js +95 -0
  64. package/dist/src/__tests__/compiler/throttle-retry.test.d.ts +1 -0
  65. package/dist/src/__tests__/compiler/throttle-retry.test.js +166 -0
  66. package/dist/src/__tests__/compiler/tuple-type.test.d.ts +10 -0
  67. package/dist/src/__tests__/compiler/tuple-type.test.js +229 -0
  68. package/dist/src/__tests__/compiler/watch-decorator.test.d.ts +1 -0
  69. package/dist/src/__tests__/compiler/watch-decorator.test.js +65 -0
  70. package/dist/src/__tests__/config/project-config.test.d.ts +1 -0
  71. package/dist/src/__tests__/config/project-config.test.js +199 -0
  72. package/dist/src/__tests__/config-decorator.test.d.ts +8 -0
  73. package/dist/src/__tests__/config-decorator.test.js +142 -0
  74. package/dist/src/__tests__/diagnostics-extra.test.d.ts +6 -0
  75. package/dist/src/__tests__/diagnostics-extra.test.js +132 -0
  76. package/dist/src/__tests__/emit/compile-branches.test.d.ts +1 -0
  77. package/dist/src/__tests__/emit/compile-branches.test.js +123 -0
  78. package/dist/src/__tests__/emit/compile-coverage.test.d.ts +25 -0
  79. package/dist/src/__tests__/emit/compile-coverage.test.js +617 -0
  80. package/dist/src/__tests__/emit/compile-extra-branches.test.d.ts +12 -0
  81. package/dist/src/__tests__/emit/compile-extra-branches.test.js +225 -0
  82. package/dist/src/__tests__/emit/compile-mocked-branches.test.d.ts +0 -0
  83. package/dist/src/__tests__/emit/compile-mocked-branches.test.js +238 -0
  84. package/dist/src/__tests__/emit/execute-chain.test.d.ts +10 -0
  85. package/dist/src/__tests__/emit/execute-chain.test.js +94 -0
  86. package/dist/src/__tests__/emit/index.test.js +2 -1
  87. package/dist/src/__tests__/emit/modules-branches.test.d.ts +1 -0
  88. package/dist/src/__tests__/emit/modules-branches.test.js +88 -0
  89. package/dist/src/__tests__/emit/modules-coverage.test.d.ts +15 -0
  90. package/dist/src/__tests__/emit/modules-coverage.test.js +221 -0
  91. package/dist/src/__tests__/emit/modules-errors.test.d.ts +12 -0
  92. package/dist/src/__tests__/emit/modules-errors.test.js +169 -0
  93. package/dist/src/__tests__/emit/modules-rewrite.test.d.ts +17 -0
  94. package/dist/src/__tests__/emit/modules-rewrite.test.js +204 -0
  95. package/dist/src/__tests__/emit/source-map.test.d.ts +1 -0
  96. package/dist/src/__tests__/emit/source-map.test.js +167 -0
  97. package/dist/src/__tests__/enum.test.js +9 -4
  98. package/dist/src/__tests__/error-recovery.test.d.ts +7 -0
  99. package/dist/src/__tests__/error-recovery.test.js +217 -0
  100. package/dist/src/__tests__/events-types-extra.test.d.ts +10 -0
  101. package/dist/src/__tests__/events-types-extra.test.js +91 -0
  102. package/dist/src/__tests__/events-types.test.d.ts +4 -0
  103. package/dist/src/__tests__/events-types.test.js +56 -0
  104. package/dist/src/__tests__/formatter.test.js +13 -5
  105. package/dist/src/__tests__/hir/lower-extra.test.d.ts +9 -0
  106. package/dist/src/__tests__/hir/lower-extra.test.js +140 -0
  107. package/dist/src/__tests__/hir/monomorphize-extra.test.d.ts +15 -0
  108. package/dist/src/__tests__/hir/monomorphize-extra.test.js +200 -0
  109. package/dist/src/__tests__/hir/monomorphize-extra2.test.d.ts +16 -0
  110. package/dist/src/__tests__/hir/monomorphize-extra2.test.js +316 -0
  111. package/dist/src/__tests__/incremental.test.js +10 -2
  112. package/dist/src/__tests__/index-extra.test.d.ts +10 -0
  113. package/dist/src/__tests__/index-extra.test.js +71 -0
  114. package/dist/src/__tests__/lexer.test.js +2 -2
  115. package/dist/src/__tests__/lint/rules.test.d.ts +5 -0
  116. package/dist/src/__tests__/lint/rules.test.js +208 -0
  117. package/dist/src/__tests__/lir/lower.test.js +29 -0
  118. package/dist/src/__tests__/lir/verify.test.js +30 -0
  119. package/dist/src/__tests__/lsp/completion.test.d.ts +7 -0
  120. package/dist/src/__tests__/lsp/completion.test.js +583 -0
  121. package/dist/src/__tests__/lsp/definition.test.d.ts +7 -0
  122. package/dist/src/__tests__/lsp/definition.test.js +454 -0
  123. package/dist/src/__tests__/lsp/diagnostics.test.d.ts +10 -0
  124. package/dist/src/__tests__/lsp/diagnostics.test.js +98 -0
  125. package/dist/src/__tests__/lsp/hover-docs.test.d.ts +10 -0
  126. package/dist/src/__tests__/lsp/hover-docs.test.js +210 -0
  127. package/dist/src/__tests__/lsp.test.js +4 -1
  128. package/dist/src/__tests__/mc-integration/item-entity-events.test.js +4 -0
  129. package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +4 -0
  130. package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.d.ts +13 -0
  131. package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1227 -0
  132. package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.d.ts +13 -0
  133. package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1509 -0
  134. package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.d.ts +14 -0
  135. package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1374 -0
  136. package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.d.ts +10 -0
  137. package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +759 -0
  138. package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.d.ts +13 -0
  139. package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +855 -0
  140. package/dist/src/__tests__/mc-integration/stdlib-coverage.test.js +4 -0
  141. package/dist/src/__tests__/mc-integration/syntax-coverage.test.js +4 -0
  142. package/dist/src/__tests__/mc-validator-coverage.test.d.ts +13 -0
  143. package/dist/src/__tests__/mc-validator-coverage.test.js +296 -0
  144. package/dist/src/__tests__/mc-validator-extra.test.d.ts +13 -0
  145. package/dist/src/__tests__/mc-validator-extra.test.js +245 -0
  146. package/dist/src/__tests__/mir/lower-extra.test.d.ts +20 -0
  147. package/dist/src/__tests__/mir/lower-extra.test.js +361 -0
  148. package/dist/src/__tests__/mir/lower-extra2.test.d.ts +17 -0
  149. package/dist/src/__tests__/mir/lower-extra2.test.js +317 -0
  150. package/dist/src/__tests__/mir/lower-extra3.test.d.ts +19 -0
  151. package/dist/src/__tests__/mir/lower-extra3.test.js +249 -0
  152. package/dist/src/__tests__/mir/lower-extra4.test.d.ts +23 -0
  153. package/dist/src/__tests__/mir/lower-extra4.test.js +606 -0
  154. package/dist/src/__tests__/mir/lower-extra5.test.d.ts +25 -0
  155. package/dist/src/__tests__/mir/lower-extra5.test.js +543 -0
  156. package/dist/src/__tests__/mir/lower-extra6.test.d.ts +16 -0
  157. package/dist/src/__tests__/mir/lower-extra6.test.js +471 -0
  158. package/dist/src/__tests__/mir/lower-extra7.test.d.ts +35 -0
  159. package/dist/src/__tests__/mir/lower-extra7.test.js +921 -0
  160. package/dist/src/__tests__/mir/lower-extra8.test.d.ts +19 -0
  161. package/dist/src/__tests__/mir/lower-extra8.test.js +626 -0
  162. package/dist/src/__tests__/mir/lower-extra9.test.d.ts +14 -0
  163. package/dist/src/__tests__/mir/lower-extra9.test.js +717 -0
  164. package/dist/src/__tests__/optimizer/auto-inline.test.d.ts +1 -0
  165. package/dist/src/__tests__/optimizer/auto-inline.test.js +176 -0
  166. package/dist/src/__tests__/optimizer/cse.test.d.ts +4 -0
  167. package/dist/src/__tests__/optimizer/cse.test.js +178 -0
  168. package/dist/src/__tests__/optimizer/inline_fn.test.d.ts +1 -0
  169. package/dist/src/__tests__/optimizer/inline_fn.test.js +221 -0
  170. package/dist/src/__tests__/optimizer/licm.test.d.ts +1 -0
  171. package/dist/src/__tests__/optimizer/licm.test.js +244 -0
  172. package/dist/src/__tests__/optimizer/optimizer-extended.test.d.ts +12 -0
  173. package/dist/src/__tests__/optimizer/optimizer-extended.test.js +993 -0
  174. package/dist/src/__tests__/optimizer/strength-reduction.test.d.ts +1 -0
  175. package/dist/src/__tests__/optimizer/strength-reduction.test.js +86 -0
  176. package/dist/src/__tests__/optimizer/tco.test.d.ts +14 -0
  177. package/dist/src/__tests__/optimizer/tco.test.js +203 -0
  178. package/dist/src/__tests__/parser-coverage.test.d.ts +25 -0
  179. package/dist/src/__tests__/parser-coverage.test.js +491 -0
  180. package/dist/src/__tests__/parser-extra.test.d.ts +6 -0
  181. package/dist/src/__tests__/parser-extra.test.js +451 -0
  182. package/dist/src/__tests__/parser.test.js +12 -0
  183. package/dist/src/__tests__/repl-extra.test.d.ts +13 -0
  184. package/dist/src/__tests__/repl-extra.test.js +174 -0
  185. package/dist/src/__tests__/repl-server-extra.test.d.ts +10 -0
  186. package/dist/src/__tests__/repl-server-extra.test.js +161 -0
  187. package/dist/src/__tests__/repl-server.test.d.ts +6 -0
  188. package/dist/src/__tests__/repl-server.test.js +146 -0
  189. package/dist/src/__tests__/runtime-extra.test.d.ts +15 -0
  190. package/dist/src/__tests__/runtime-extra.test.js +732 -0
  191. package/dist/src/__tests__/singleton-decorator.test.d.ts +11 -0
  192. package/dist/src/__tests__/singleton-decorator.test.js +260 -0
  193. package/dist/src/__tests__/sourcemap.test.js +1 -1
  194. package/dist/src/__tests__/stdlib/advanced.test.d.ts +5 -0
  195. package/dist/src/__tests__/stdlib/advanced.test.js +301 -0
  196. package/dist/src/__tests__/stdlib/bigint.test.d.ts +4 -0
  197. package/dist/src/__tests__/stdlib/bigint.test.js +83 -0
  198. package/dist/src/__tests__/stdlib/bits.test.d.ts +4 -0
  199. package/dist/src/__tests__/stdlib/bits.test.js +96 -0
  200. package/dist/src/__tests__/stdlib/bossbar.test.d.ts +4 -0
  201. package/dist/src/__tests__/stdlib/bossbar.test.js +72 -0
  202. package/dist/src/__tests__/stdlib/color.test.d.ts +4 -0
  203. package/dist/src/__tests__/stdlib/color.test.js +84 -0
  204. package/dist/src/__tests__/stdlib/combat.test.d.ts +4 -0
  205. package/dist/src/__tests__/stdlib/combat.test.js +64 -0
  206. package/dist/src/__tests__/stdlib/cooldown.test.d.ts +4 -0
  207. package/dist/src/__tests__/stdlib/cooldown.test.js +64 -0
  208. package/dist/src/__tests__/stdlib/dialog.test.js +15 -7
  209. package/dist/src/__tests__/stdlib/ecs.test.d.ts +4 -0
  210. package/dist/src/__tests__/stdlib/ecs.test.js +81 -0
  211. package/dist/src/__tests__/stdlib/effects.test.d.ts +4 -0
  212. package/dist/src/__tests__/stdlib/effects.test.js +72 -0
  213. package/dist/src/__tests__/stdlib/events.test.d.ts +4 -0
  214. package/dist/src/__tests__/stdlib/events.test.js +55 -0
  215. package/dist/src/__tests__/stdlib/expr.test.d.ts +4 -0
  216. package/dist/src/__tests__/stdlib/expr.test.js +77 -0
  217. package/dist/src/__tests__/stdlib/fft.test.d.ts +4 -0
  218. package/dist/src/__tests__/stdlib/fft.test.js +82 -0
  219. package/dist/src/__tests__/stdlib/graph.test.d.ts +4 -0
  220. package/dist/src/__tests__/stdlib/graph.test.js +102 -0
  221. package/dist/src/__tests__/stdlib/interactions.test.d.ts +4 -0
  222. package/dist/src/__tests__/stdlib/interactions.test.js +60 -0
  223. package/dist/src/__tests__/stdlib/inventory.test.d.ts +4 -0
  224. package/dist/src/__tests__/stdlib/inventory.test.js +68 -0
  225. package/dist/src/__tests__/stdlib/linalg.test.d.ts +5 -0
  226. package/dist/src/__tests__/stdlib/linalg.test.js +78 -0
  227. package/dist/src/__tests__/stdlib/map.test.d.ts +1 -0
  228. package/dist/src/__tests__/stdlib/map.test.js +84 -0
  229. package/dist/src/__tests__/stdlib/math.test.js +19 -6
  230. package/dist/src/__tests__/stdlib/math_hp.test.d.ts +4 -0
  231. package/dist/src/__tests__/stdlib/math_hp.test.js +80 -0
  232. package/dist/src/__tests__/stdlib/mobs.test.d.ts +4 -0
  233. package/dist/src/__tests__/stdlib/mobs.test.js +61 -0
  234. package/dist/src/__tests__/stdlib/noise.test.d.ts +4 -0
  235. package/dist/src/__tests__/stdlib/noise.test.js +73 -0
  236. package/dist/src/__tests__/stdlib/ode.test.d.ts +4 -0
  237. package/dist/src/__tests__/stdlib/ode.test.js +68 -0
  238. package/dist/src/__tests__/stdlib/parabola.test.d.ts +4 -0
  239. package/dist/src/__tests__/stdlib/parabola.test.js +77 -0
  240. package/dist/src/__tests__/stdlib/particles.test.d.ts +4 -0
  241. package/dist/src/__tests__/stdlib/particles.test.js +68 -0
  242. package/dist/src/__tests__/stdlib/physics.test.d.ts +4 -0
  243. package/dist/src/__tests__/stdlib/physics.test.js +76 -0
  244. package/dist/src/__tests__/stdlib/player.test.d.ts +4 -0
  245. package/dist/src/__tests__/stdlib/player.test.js +64 -0
  246. package/dist/src/__tests__/stdlib/quaternion.test.d.ts +4 -0
  247. package/dist/src/__tests__/stdlib/quaternion.test.js +73 -0
  248. package/dist/src/__tests__/stdlib/queue.test.d.ts +1 -0
  249. package/dist/src/__tests__/stdlib/queue.test.js +97 -0
  250. package/dist/src/__tests__/stdlib/random.test.d.ts +4 -0
  251. package/dist/src/__tests__/stdlib/random.test.js +76 -0
  252. package/dist/src/__tests__/stdlib/result.test.d.ts +12 -0
  253. package/dist/src/__tests__/stdlib/result.test.js +329 -0
  254. package/dist/src/__tests__/stdlib/scheduler.test.js +19 -8
  255. package/dist/src/__tests__/stdlib/set_int.test.d.ts +1 -0
  256. package/dist/src/__tests__/stdlib/set_int.test.js +88 -0
  257. package/dist/src/__tests__/stdlib/sets.test.d.ts +6 -0
  258. package/dist/src/__tests__/stdlib/sets.test.js +60 -0
  259. package/dist/src/__tests__/stdlib/signal.test.d.ts +4 -0
  260. package/dist/src/__tests__/stdlib/signal.test.js +84 -0
  261. package/dist/src/__tests__/stdlib/spawn.test.d.ts +4 -0
  262. package/dist/src/__tests__/stdlib/spawn.test.js +68 -0
  263. package/dist/src/__tests__/stdlib/string.test.d.ts +12 -0
  264. package/dist/src/__tests__/stdlib/string.test.js +231 -0
  265. package/dist/src/__tests__/stdlib/strings.test.d.ts +4 -0
  266. package/dist/src/__tests__/stdlib/strings.test.js +83 -0
  267. package/dist/src/__tests__/stdlib/tags.test.d.ts +4 -0
  268. package/dist/src/__tests__/stdlib/tags.test.js +57 -0
  269. package/dist/src/__tests__/stdlib/teams.test.d.ts +4 -0
  270. package/dist/src/__tests__/stdlib/teams.test.js +72 -0
  271. package/dist/src/__tests__/stdlib/timer.test.d.ts +4 -0
  272. package/dist/src/__tests__/stdlib/timer.test.js +79 -0
  273. package/dist/src/__tests__/stdlib/vec.test.d.ts +5 -0
  274. package/dist/src/__tests__/stdlib/vec.test.js +94 -0
  275. package/dist/src/__tests__/stdlib/world.test.d.ts +4 -0
  276. package/dist/src/__tests__/stdlib/world.test.js +72 -0
  277. package/dist/src/__tests__/struct-display.test.d.ts +1 -0
  278. package/dist/src/__tests__/struct-display.test.js +64 -0
  279. package/dist/src/__tests__/test-framework/runner.test.d.ts +10 -0
  280. package/dist/src/__tests__/test-framework/runner.test.js +193 -0
  281. package/dist/src/__tests__/tuner/adapters.test.d.ts +14 -0
  282. package/dist/src/__tests__/tuner/adapters.test.js +194 -0
  283. package/dist/src/__tests__/tuner/simulator-extra.test.d.ts +4 -0
  284. package/dist/src/__tests__/tuner/simulator-extra.test.js +193 -0
  285. package/dist/src/__tests__/typechecker-coverage.test.d.ts +30 -0
  286. package/dist/src/__tests__/typechecker-coverage.test.js +627 -0
  287. package/dist/src/__tests__/typechecker.test.js +3 -3
  288. package/dist/src/__tests__/watch-decorator.test.d.ts +1 -0
  289. package/dist/src/__tests__/watch-decorator.test.js +54 -0
  290. package/dist/src/ast/types.d.ts +102 -3
  291. package/dist/src/cache/incremental.d.ts +13 -14
  292. package/dist/src/cache/incremental.js +106 -89
  293. package/dist/src/cache/index.d.ts +8 -2
  294. package/dist/src/cache/index.js +18 -6
  295. package/dist/src/cli.d.ts +1 -0
  296. package/dist/src/cli.js +466 -17
  297. package/dist/src/config/project-config.d.ts +29 -0
  298. package/dist/src/config/project-config.js +180 -0
  299. package/dist/src/diagnostics/index.d.ts +9 -0
  300. package/dist/src/diagnostics/index.js +18 -1
  301. package/dist/src/emit/compile.d.ts +10 -0
  302. package/dist/src/emit/compile.js +395 -50
  303. package/dist/src/emit/index.d.ts +40 -0
  304. package/dist/src/emit/index.js +307 -14
  305. package/dist/src/emit/modules.js +21 -3
  306. package/dist/src/emit/sourcemap.d.ts +23 -27
  307. package/dist/src/emit/sourcemap.js +52 -30
  308. package/dist/src/formatter/index.js +33 -8
  309. package/dist/src/hir/deprecated.d.ts +13 -0
  310. package/dist/src/hir/deprecated.js +218 -0
  311. package/dist/src/hir/lower.js +114 -8
  312. package/dist/src/hir/monomorphize.js +22 -2
  313. package/dist/src/hir/types.d.ts +65 -1
  314. package/dist/src/index.d.ts +6 -0
  315. package/dist/src/index.js +18 -3
  316. package/dist/src/lexer/index.d.ts +2 -1
  317. package/dist/src/lexer/index.js +39 -3
  318. package/dist/src/lint/index.d.ts +45 -0
  319. package/dist/src/lint/index.js +930 -0
  320. package/dist/src/lir/lower.js +29 -2
  321. package/dist/src/lir/types.d.ts +2 -0
  322. package/dist/src/lsp/server.js +92 -5
  323. package/dist/src/mir/lower.js +775 -34
  324. package/dist/src/mir/macro.js +36 -2
  325. package/dist/src/mir/types.d.ts +12 -0
  326. package/dist/src/mir/verify.js +9 -0
  327. package/dist/src/optimizer/auto-inline.d.ts +2 -0
  328. package/dist/src/optimizer/auto-inline.js +67 -0
  329. package/dist/src/optimizer/cse.d.ts +20 -0
  330. package/dist/src/optimizer/cse.js +234 -0
  331. package/dist/src/optimizer/inline.d.ts +26 -0
  332. package/dist/src/optimizer/inline.js +286 -0
  333. package/dist/src/optimizer/interprocedural.js +4 -0
  334. package/dist/src/optimizer/licm.d.ts +32 -0
  335. package/dist/src/optimizer/licm.js +371 -0
  336. package/dist/src/optimizer/pipeline.js +12 -2
  337. package/dist/src/optimizer/strength_reduction.d.ts +15 -0
  338. package/dist/src/optimizer/strength_reduction.js +90 -0
  339. package/dist/src/optimizer/tco.d.ts +53 -0
  340. package/dist/src/optimizer/tco.js +238 -0
  341. package/dist/src/parser/index.d.ts +32 -0
  342. package/dist/src/parser/index.js +421 -59
  343. package/dist/src/repl-server.d.ts +13 -0
  344. package/dist/src/repl-server.js +127 -0
  345. package/dist/src/structs/expand.d.ts +15 -0
  346. package/dist/src/structs/expand.js +46 -0
  347. package/dist/src/testing/runner.d.ts +40 -0
  348. package/dist/src/testing/runner.js +237 -0
  349. package/dist/src/typechecker/index.d.ts +3 -0
  350. package/dist/src/typechecker/index.js +254 -9
  351. package/dist/tsconfig.tsbuildinfo +1 -1
  352. package/doc-drafts/redscript-docs/docs/en/stdlib/graph.md +104 -0
  353. package/doc-drafts/redscript-docs/docs/en/stdlib/parabola.md +113 -0
  354. package/doc-drafts/redscript-docs/docs/en/stdlib/pathfind.md +104 -0
  355. package/doc-drafts/redscript-docs/docs/en/stdlib/physics.md +134 -0
  356. package/doc-drafts/redscript-docs/docs/en/stdlib/quaternion.md +135 -0
  357. package/doc-drafts/redscript-docs/docs/zh/stdlib/graph.md +104 -0
  358. package/doc-drafts/redscript-docs/docs/zh/stdlib/parabola.md +113 -0
  359. package/doc-drafts/redscript-docs/docs/zh/stdlib/pathfind.md +104 -0
  360. package/doc-drafts/redscript-docs/docs/zh/stdlib/physics.md +134 -0
  361. package/doc-drafts/redscript-docs/docs/zh/stdlib/quaternion.md +135 -0
  362. package/docs/stdlib/result.md +156 -0
  363. package/docs/stdlib/result.zh.md +156 -0
  364. package/editors/vscode/fixtures/test.mcrs +7 -0
  365. package/editors/vscode/out/extension.js +2095 -225
  366. package/editors/vscode/out/lsp-server.js +519 -51
  367. package/editors/vscode/package-lock.json +9 -4
  368. package/editors/vscode/package.json +1 -1
  369. package/examples/display-demo.mcrs +64 -0
  370. package/examples/game/racing.mcrs +301 -0
  371. package/examples/game/tower_defense.mcrs +311 -0
  372. package/examples/math/physics_sim.mcrs +322 -0
  373. package/examples/rpg/boss_fight.mcrs +313 -0
  374. package/examples/rpg/health_system.mcrs +237 -0
  375. package/examples/rpg/inventory.mcrs +265 -0
  376. package/examples/util/debug_hud.mcrs +279 -0
  377. package/jest.config.js +10 -0
  378. package/package.json +12 -3
  379. package/playground/index.html +823 -0
  380. package/scripts/gen-docs.ts +533 -0
  381. package/scripts/update-redscript-docs-stdlib.sh +770 -0
  382. package/src/__tests__/budget.test.ts +5 -0
  383. package/src/__tests__/cache/cache-behavior.test.ts +480 -0
  384. package/src/__tests__/cache-extra.test.ts +199 -0
  385. package/src/__tests__/cli-docs.test.ts +77 -0
  386. package/src/__tests__/cli-init.test.ts +91 -0
  387. package/src/__tests__/cli-publish.test.ts +190 -0
  388. package/src/__tests__/cli.test.ts +117 -1
  389. package/src/__tests__/compile-preprocess.test.ts +366 -0
  390. package/src/__tests__/compiler/break-stmt.test.ts +66 -0
  391. package/src/__tests__/compiler/const-decl.test.ts +141 -0
  392. package/src/__tests__/compiler/continue-stmt.test.ts +81 -0
  393. package/src/__tests__/compiler/coroutine-extended.test.ts +723 -0
  394. package/src/__tests__/compiler/deprecated.test.ts +305 -0
  395. package/src/__tests__/compiler/do-while.test.ts +130 -0
  396. package/src/__tests__/compiler/enum-payload.test.ts +299 -0
  397. package/src/__tests__/compiler/interface.test.ts +287 -0
  398. package/src/__tests__/compiler/labeled-loops.test.ts +279 -0
  399. package/src/__tests__/compiler/match-string.test.ts +45 -0
  400. package/src/__tests__/compiler/memoize.test.ts +126 -0
  401. package/src/__tests__/compiler/method-chain.test.ts +121 -0
  402. package/src/__tests__/compiler/module-import.test.ts +240 -0
  403. package/src/__tests__/compiler/option-extensions.test.ts +207 -0
  404. package/src/__tests__/compiler/profile-decorator.test.ts +79 -0
  405. package/src/__tests__/compiler/string-advanced.test.ts +310 -0
  406. package/src/__tests__/compiler/struct-extends.test.ts +109 -0
  407. package/src/__tests__/compiler/throttle-retry.test.ts +191 -0
  408. package/src/__tests__/compiler/tuple-type.test.ts +263 -0
  409. package/src/__tests__/compiler/watch-decorator.test.ts +72 -0
  410. package/src/__tests__/config/project-config.test.ts +181 -0
  411. package/src/__tests__/config-decorator.test.ts +157 -0
  412. package/src/__tests__/diagnostics-extra.test.ts +155 -0
  413. package/src/__tests__/emit/compile-branches.test.ts +135 -0
  414. package/src/__tests__/emit/compile-coverage.test.ts +696 -0
  415. package/src/__tests__/emit/compile-extra-branches.test.ts +228 -0
  416. package/src/__tests__/emit/compile-mocked-branches.test.ts +249 -0
  417. package/src/__tests__/emit/compile.test.ts +6 -1
  418. package/src/__tests__/emit/execute-chain.test.ts +114 -0
  419. package/src/__tests__/emit/index.test.ts +2 -1
  420. package/src/__tests__/emit/modules-branches.test.ts +90 -0
  421. package/src/__tests__/emit/modules-coverage.test.ts +241 -0
  422. package/src/__tests__/emit/modules-errors.test.ts +192 -0
  423. package/src/__tests__/emit/modules-rewrite.test.ts +232 -0
  424. package/src/__tests__/emit/source-map.test.ts +152 -0
  425. package/src/__tests__/enum.test.ts +9 -4
  426. package/src/__tests__/error-recovery.test.ts +226 -0
  427. package/src/__tests__/events-types-extra.test.ts +110 -0
  428. package/src/__tests__/events-types.test.ts +66 -0
  429. package/src/__tests__/formatter.test.ts +15 -5
  430. package/src/__tests__/generics.test.ts +16 -9
  431. package/src/__tests__/hir/lower-extra.test.ts +151 -0
  432. package/src/__tests__/hir/monomorphize-coverage.test.ts +432 -0
  433. package/src/__tests__/hir/monomorphize-extra.test.ts +220 -0
  434. package/src/__tests__/hir/monomorphize-extra2.test.ts +350 -0
  435. package/src/__tests__/impl.test.ts +12 -8
  436. package/src/__tests__/incremental.test.ts +10 -2
  437. package/src/__tests__/index-extra.test.ts +79 -0
  438. package/src/__tests__/lexer.test.ts +2 -2
  439. package/src/__tests__/lint/hir-coverage.test.ts +1716 -0
  440. package/src/__tests__/lint/rules-coverage.test.ts +598 -0
  441. package/src/__tests__/lint/rules.test.ts +230 -0
  442. package/src/__tests__/lir/lower.test.ts +33 -0
  443. package/src/__tests__/lir/verify.test.ts +33 -0
  444. package/src/__tests__/lsp/completion.test.ts +687 -0
  445. package/src/__tests__/lsp/definition.test.ts +499 -0
  446. package/src/__tests__/lsp/diagnostics.test.ts +108 -0
  447. package/src/__tests__/lsp/hover-docs.test.ts +222 -0
  448. package/src/__tests__/lsp.test.ts +4 -1
  449. package/src/__tests__/mc-integration/item-entity-events.test.ts +5 -0
  450. package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +5 -0
  451. package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1105 -0
  452. package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1366 -0
  453. package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1245 -0
  454. package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +755 -0
  455. package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +771 -0
  456. package/src/__tests__/mc-integration/stdlib-coverage.test.ts +5 -0
  457. package/src/__tests__/mc-integration/syntax-coverage.test.ts +5 -0
  458. package/src/__tests__/mc-validator-coverage.test.ts +325 -0
  459. package/src/__tests__/mc-validator-extra.test.ts +252 -0
  460. package/src/__tests__/mir/lower-extra.test.ts +402 -0
  461. package/src/__tests__/mir/lower-extra2.test.ts +348 -0
  462. package/src/__tests__/mir/lower-extra3.test.ts +277 -0
  463. package/src/__tests__/mir/lower-extra4.test.ts +636 -0
  464. package/src/__tests__/mir/lower-extra5.test.ts +612 -0
  465. package/src/__tests__/mir/lower-extra6.test.ts +520 -0
  466. package/src/__tests__/mir/lower-extra7.test.ts +1045 -0
  467. package/src/__tests__/mir/lower-extra8.test.ts +704 -0
  468. package/src/__tests__/mir/lower-extra9.test.ts +821 -0
  469. package/src/__tests__/optimizer/auto-inline.test.ts +206 -0
  470. package/src/__tests__/optimizer/cse.test.ts +195 -0
  471. package/src/__tests__/optimizer/inline_fn.test.ts +263 -0
  472. package/src/__tests__/optimizer/licm.test.ts +358 -0
  473. package/src/__tests__/optimizer/nbt-coalesce.test.ts +147 -0
  474. package/src/__tests__/optimizer/optimizer-extended.test.ts +1081 -0
  475. package/src/__tests__/optimizer/scoreboard-batch.test.ts +141 -0
  476. package/src/__tests__/optimizer/strength-reduction.test.ts +111 -0
  477. package/src/__tests__/optimizer/tco-coverage.test.ts +309 -0
  478. package/src/__tests__/optimizer/tco.test.ts +238 -0
  479. package/src/__tests__/option.test.ts +14 -7
  480. package/src/__tests__/parser-coverage.test.ts +576 -0
  481. package/src/__tests__/parser-extra.test.ts +531 -0
  482. package/src/__tests__/parser.test.ts +14 -0
  483. package/src/__tests__/repl-extra.test.ts +195 -0
  484. package/src/__tests__/repl-server-extra.test.ts +150 -0
  485. package/src/__tests__/repl-server.test.ts +122 -0
  486. package/src/__tests__/runtime-extra.test.ts +862 -0
  487. package/src/__tests__/singleton-decorator.test.ts +285 -0
  488. package/src/__tests__/sourcemap.test.ts +1 -1
  489. package/src/__tests__/stdlib/advanced.test.ts +312 -0
  490. package/src/__tests__/stdlib/bigint.test.ts +57 -0
  491. package/src/__tests__/stdlib/bits.test.ts +75 -0
  492. package/src/__tests__/stdlib/bossbar.test.ts +45 -0
  493. package/src/__tests__/stdlib/color.test.ts +60 -0
  494. package/src/__tests__/stdlib/combat.test.ts +35 -0
  495. package/src/__tests__/stdlib/cooldown.test.ts +35 -0
  496. package/src/__tests__/stdlib/dialog.test.ts +14 -6
  497. package/src/__tests__/stdlib/ecs.test.ts +54 -0
  498. package/src/__tests__/stdlib/effects.test.ts +45 -0
  499. package/src/__tests__/stdlib/events.test.ts +23 -0
  500. package/src/__tests__/stdlib/expr.test.ts +48 -0
  501. package/src/__tests__/stdlib/fft.test.ts +54 -0
  502. package/src/__tests__/stdlib/graph.test.ts +77 -0
  503. package/src/__tests__/stdlib/interactions.test.ts +30 -0
  504. package/src/__tests__/stdlib/inventory.test.ts +40 -0
  505. package/src/__tests__/stdlib/linalg.test.ts +52 -0
  506. package/src/__tests__/stdlib/map.test.ts +55 -0
  507. package/src/__tests__/stdlib/math.test.ts +19 -5
  508. package/src/__tests__/stdlib/math_hp.test.ts +55 -0
  509. package/src/__tests__/stdlib/mobs.test.ts +40 -0
  510. package/src/__tests__/stdlib/noise.test.ts +46 -0
  511. package/src/__tests__/stdlib/ode.test.ts +40 -0
  512. package/src/__tests__/stdlib/parabola.test.ts +51 -0
  513. package/src/__tests__/stdlib/particles.test.ts +40 -0
  514. package/src/__tests__/stdlib/physics.test.ts +50 -0
  515. package/src/__tests__/stdlib/player.test.ts +35 -0
  516. package/src/__tests__/stdlib/quaternion.test.ts +46 -0
  517. package/src/__tests__/stdlib/queue.test.ts +73 -0
  518. package/src/__tests__/stdlib/random.test.ts +50 -0
  519. package/src/__tests__/stdlib/result.test.ts +326 -0
  520. package/src/__tests__/stdlib/scheduler.test.ts +18 -7
  521. package/src/__tests__/stdlib/set_int.test.ts +62 -0
  522. package/src/__tests__/stdlib/sets.test.ts +28 -0
  523. package/src/__tests__/stdlib/signal.test.ts +60 -0
  524. package/src/__tests__/stdlib/spawn.test.ts +40 -0
  525. package/src/__tests__/stdlib/string.test.ts +224 -0
  526. package/src/__tests__/stdlib/strings.test.ts +55 -0
  527. package/src/__tests__/stdlib/tags.test.ts +32 -0
  528. package/src/__tests__/stdlib/teams.test.ts +45 -0
  529. package/src/__tests__/stdlib/timer.test.ts +53 -0
  530. package/src/__tests__/stdlib/vec.test.ts +72 -0
  531. package/src/__tests__/stdlib/world.test.ts +45 -0
  532. package/src/__tests__/struct-display.test.ts +69 -0
  533. package/src/__tests__/test-framework/runner.test.ts +208 -0
  534. package/src/__tests__/tuner/adapters.test.ts +232 -0
  535. package/src/__tests__/tuner/simulator-extra.test.ts +222 -0
  536. package/src/__tests__/tuple.test.ts +11 -4
  537. package/src/__tests__/typechecker-coverage.test.ts +671 -0
  538. package/src/__tests__/typechecker.test.ts +4 -3
  539. package/src/__tests__/watch-decorator.test.ts +59 -0
  540. package/src/ast/types.ts +65 -3
  541. package/src/cache/incremental.ts +128 -99
  542. package/src/cache/index.ts +35 -8
  543. package/src/cli.ts +538 -29
  544. package/src/config/project-config.ts +176 -0
  545. package/src/diagnostics/index.ts +22 -0
  546. package/src/docs.ts +98 -0
  547. package/src/emit/compile.ts +408 -51
  548. package/src/emit/index.ts +366 -18
  549. package/src/emit/modules.ts +19 -3
  550. package/src/emit/sourcemap.ts +64 -43
  551. package/src/formatter/index.ts +35 -8
  552. package/src/hir/deprecated.ts +212 -0
  553. package/src/hir/lower.ts +128 -8
  554. package/src/hir/monomorphize.ts +24 -2
  555. package/src/hir/types.ts +26 -1
  556. package/src/index.ts +23 -3
  557. package/src/lexer/index.ts +45 -6
  558. package/src/lint/index.ts +922 -0
  559. package/src/lir/lower.ts +30 -2
  560. package/src/lir/types.ts +4 -0
  561. package/src/lsp/server.ts +100 -1
  562. package/src/mir/lower.ts +785 -40
  563. package/src/mir/macro.ts +30 -2
  564. package/src/mir/types.ts +13 -0
  565. package/src/mir/verify.ts +10 -2
  566. package/src/optimizer/auto-inline.ts +86 -0
  567. package/src/optimizer/copy_prop.ts +2 -2
  568. package/src/optimizer/coroutine.ts +3 -3
  569. package/src/optimizer/cse.ts +205 -0
  570. package/src/optimizer/dce.ts +2 -2
  571. package/src/optimizer/inline.ts +335 -0
  572. package/src/optimizer/interprocedural.ts +5 -1
  573. package/src/optimizer/licm.ts +454 -0
  574. package/src/optimizer/nbt-coalesce.ts +109 -0
  575. package/src/optimizer/pipeline.ts +16 -2
  576. package/src/optimizer/scoreboard-batch.ts +52 -0
  577. package/src/optimizer/strength_reduction.ts +95 -0
  578. package/src/optimizer/tco.ts +267 -0
  579. package/src/optimizer/unroll.ts +2 -2
  580. package/src/parser/index.ts +426 -53
  581. package/src/repl-server.ts +102 -0
  582. package/src/stdlib/advanced.mcrs +271 -101
  583. package/src/stdlib/bigint.mcrs +97 -11
  584. package/src/stdlib/bits.mcrs +75 -12
  585. package/src/stdlib/bossbar.mcrs +37 -8
  586. package/src/stdlib/calculus.mcrs +82 -26
  587. package/src/stdlib/color.mcrs +98 -16
  588. package/src/stdlib/combat.mcrs +23 -5
  589. package/src/stdlib/cooldown.mcrs +19 -0
  590. package/src/stdlib/dialog.mcrs +45 -7
  591. package/src/stdlib/easing.mcrs +132 -12
  592. package/src/stdlib/ecs.mcrs +142 -25
  593. package/src/stdlib/effects.mcrs +88 -12
  594. package/src/stdlib/events.mcrs +21 -2
  595. package/src/stdlib/expr.mcrs +18 -3
  596. package/src/stdlib/fft.mcrs +66 -56
  597. package/src/stdlib/geometry.mcrs +137 -39
  598. package/src/stdlib/graph.mcrs +73 -0
  599. package/src/stdlib/heap.mcrs +49 -8
  600. package/src/stdlib/i18n/zh.yaml +2891 -0
  601. package/src/stdlib/interactions.mcrs +43 -20
  602. package/src/stdlib/inventory.mcrs +14 -3
  603. package/src/stdlib/linalg.mcrs +185 -30
  604. package/src/stdlib/list.mcrs +168 -18
  605. package/src/stdlib/map.mcrs +112 -0
  606. package/src/stdlib/math.mcrs +68 -18
  607. package/src/stdlib/math_hp.mcrs +124 -33
  608. package/src/stdlib/matrix.mcrs +133 -20
  609. package/src/stdlib/mobs.mcrs +87 -0
  610. package/src/stdlib/noise.mcrs +65 -21
  611. package/src/stdlib/ode.mcrs +96 -0
  612. package/src/stdlib/parabola.mcrs +104 -29
  613. package/src/stdlib/particles.mcrs +78 -21
  614. package/src/stdlib/pathfind.mcrs +89 -35
  615. package/src/stdlib/physics.mcrs +134 -26
  616. package/src/stdlib/player.mcrs +18 -0
  617. package/src/stdlib/quaternion.mcrs +213 -9
  618. package/src/stdlib/queue.mcrs +123 -0
  619. package/src/stdlib/random.mcrs +63 -18
  620. package/src/stdlib/result.mcrs +111 -0
  621. package/src/stdlib/scheduler.mcrs +59 -10
  622. package/src/stdlib/set_int.mcrs +240 -0
  623. package/src/stdlib/sets.mcrs +49 -19
  624. package/src/stdlib/signal.mcrs +151 -79
  625. package/src/stdlib/sort.mcrs +44 -24
  626. package/src/stdlib/spawn.mcrs +30 -7
  627. package/src/stdlib/state.mcrs +40 -5
  628. package/src/stdlib/strings.mcrs +131 -3
  629. package/src/stdlib/tags.mcrs +2 -2
  630. package/src/stdlib/teams.mcrs +22 -10
  631. package/src/stdlib/timer.mcrs +36 -6
  632. package/src/stdlib/vec.mcrs +44 -9
  633. package/src/stdlib/world.mcrs +57 -25
  634. package/src/structs/expand.ts +64 -0
  635. package/src/testing/runner.ts +271 -0
  636. package/src/typechecker/index.ts +273 -9
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Loop-Invariant Code Motion (LICM) — MIR optimization pass.
3
+ *
4
+ * For each natural loop (detected by the loop_header / loop_body / loop_latch
5
+ * naming convention used by the RedScript HIR→MIR lowering), instructions
6
+ * whose operands are not modified inside the loop and that have no side
7
+ * effects are hoisted to a newly-inserted preheader block that jumps to the
8
+ * loop header.
9
+ *
10
+ * Algorithm:
11
+ * 1. Identify all loops via the loop_header block naming convention.
12
+ * 2. Collect all temps defined anywhere in the loop (variant set).
13
+ * 3. Walk each loop block's instructions; an instruction is loop-invariant
14
+ * when:
15
+ * a. It has no side effects (no call, nbt_write, score_write, etc.).
16
+ * b. Every operand is either a constant OR a temp not in the variant set.
17
+ * 4. Insert a fresh preheader block before the loop header, redirect the
18
+ * predecessor(s) of the header (excluding the back-edge latch) to the
19
+ * preheader, and move the hoisted instructions there.
20
+ * 5. Remove hoisted instructions from their original blocks.
21
+ * 6. Recompute predecessor lists.
22
+ *
23
+ * Limitations:
24
+ * - Only handles the canonical loop shape produced by the RedScript compiler
25
+ * (loop_header / loop_body / loop_latch block id prefixes).
26
+ * - Requires that the loop have exactly one non-back-edge predecessor of
27
+ * the header (i.e. one entry edge).
28
+ * - Does not hoist instructions that could trap (div/mod with a variable
29
+ * denominator) — we conservatively keep those in place.
30
+ */
31
+
32
+ import type { MIRFunction, MIRBlock, MIRInstr, Operand, Temp, BlockId } from '../mir/types'
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Public API
36
+ // ---------------------------------------------------------------------------
37
+
38
+ export function licm(fn: MIRFunction): MIRFunction {
39
+ let current = fn
40
+ let changed = true
41
+ // Iterate to fixpoint — multiple loops, or newly-exposed invariants
42
+ while (changed) {
43
+ changed = false
44
+ const result = tryHoistOne(current)
45
+ if (result !== current) {
46
+ current = result
47
+ changed = true
48
+ }
49
+ }
50
+ return current
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Core: try to hoist invariant instructions from one loop
55
+ // ---------------------------------------------------------------------------
56
+
57
+ interface LoopInfo {
58
+ headerId: BlockId
59
+ /** All block ids that belong to the loop body (header + body blocks + latch) */
60
+ loopBlockIds: Set<BlockId>
61
+ /** The single non-back-edge predecessor of the header */
62
+ preHeaderPredId: BlockId
63
+ /** The latch block id (back-edge source) */
64
+ latchId: BlockId
65
+ }
66
+
67
+ function tryHoistOne(fn: MIRFunction): MIRFunction {
68
+ const blockMap = new Map(fn.blocks.map(b => [b.id, b]))
69
+
70
+ for (const block of fn.blocks) {
71
+ if (!block.id.startsWith('loop_header')) continue
72
+ const info = analyzeLoop(fn, blockMap, block)
73
+ if (!info) continue
74
+
75
+ const hoisted = collectInvariant(info, blockMap, fn)
76
+ if (hoisted.length === 0) continue
77
+
78
+ return applyHoist(fn, blockMap, info, hoisted)
79
+ }
80
+
81
+ return fn
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Loop detection
86
+ // ---------------------------------------------------------------------------
87
+
88
+ function analyzeLoop(
89
+ fn: MIRFunction,
90
+ blockMap: Map<BlockId, MIRBlock>,
91
+ header: MIRBlock,
92
+ ): LoopInfo | null {
93
+ // Header must branch (loop condition check)
94
+ if (header.term.kind !== 'branch') return null
95
+
96
+ // Find the latch: the block that jumps back to the header
97
+ const latchId = findLatch(fn, header.id)
98
+ if (!latchId) return null
99
+
100
+ // Find the non-back-edge predecessor (the block that first enters the loop)
101
+ const preHeaderPredId = findPreHeaderPred(fn, header.id, latchId)
102
+ if (!preHeaderPredId) return null
103
+
104
+ // Collect all loop block ids: header + any block reachable from header
105
+ // that can reach the latch (simple: everything up to and including latch)
106
+ const loopBlockIds = collectLoopBlocks(fn, blockMap, header.id, latchId)
107
+
108
+ return { headerId: header.id, loopBlockIds, preHeaderPredId, latchId }
109
+ }
110
+
111
+ /** Find the latch: a predecessor of header that is dominated by header.
112
+ * In the canonical shape, it's the block with id prefix loop_latch that
113
+ * jumps back to the header. Fall back to any predecessor != preheader. */
114
+ function findLatch(fn: MIRFunction, headerId: BlockId): BlockId | null {
115
+ for (const block of fn.blocks) {
116
+ if (block.id.startsWith('loop_latch')) {
117
+ const targets = getTermTargets(block.term)
118
+ if (targets.includes(headerId)) return block.id
119
+ }
120
+ }
121
+ // Fallback: any predecessor that comes after the header in block order
122
+ // (a back-edge in the CFG)
123
+ const headerIdx = fn.blocks.findIndex(b => b.id === headerId)
124
+ for (let i = headerIdx + 1; i < fn.blocks.length; i++) {
125
+ const block = fn.blocks[i]
126
+ const targets = getTermTargets(block.term)
127
+ if (targets.includes(headerId)) return block.id
128
+ }
129
+ return null
130
+ }
131
+
132
+ /** Find the single non-latch predecessor of the header. */
133
+ function findPreHeaderPred(fn: MIRFunction, headerId: BlockId, latchId: BlockId): BlockId | null {
134
+ const preds: BlockId[] = []
135
+ for (const block of fn.blocks) {
136
+ if (block.id === latchId) continue
137
+ const targets = getTermTargets(block.term)
138
+ if (targets.includes(headerId)) preds.push(block.id)
139
+ }
140
+ return preds.length === 1 ? preds[0] : null
141
+ }
142
+
143
+ /**
144
+ * Collect all block ids that belong to the loop using backward reachability.
145
+ *
146
+ * Algorithm: start from the latch and follow predecessors backward until we
147
+ * reach the header. Every visited block (including header and latch) is part
148
+ * of the loop. This is correct regardless of block naming conventions, so it
149
+ * handles branches, merges, and nested conditionals inside the loop body.
150
+ */
151
+ function collectLoopBlocks(
152
+ fn: MIRFunction,
153
+ blockMap: Map<BlockId, MIRBlock>,
154
+ headerId: BlockId,
155
+ latchId: BlockId,
156
+ ): Set<BlockId> {
157
+ // Build predecessor map
158
+ const predsMap = new Map<BlockId, BlockId[]>()
159
+ for (const b of fn.blocks) predsMap.set(b.id, [])
160
+ for (const b of fn.blocks) {
161
+ for (const tgt of getTermTargets(b.term)) {
162
+ const list = predsMap.get(tgt)
163
+ if (list) list.push(b.id)
164
+ }
165
+ }
166
+
167
+ // Backward BFS from latch to header
168
+ const result = new Set<BlockId>()
169
+ const queue: BlockId[] = [latchId]
170
+ while (queue.length > 0) {
171
+ const id = queue.shift()!
172
+ if (result.has(id)) continue
173
+ result.add(id)
174
+ if (id === headerId) continue // don't go past the header
175
+ for (const pred of predsMap.get(id) ?? []) {
176
+ if (!result.has(pred)) queue.push(pred)
177
+ }
178
+ }
179
+
180
+ return result
181
+ }
182
+
183
+ // ---------------------------------------------------------------------------
184
+ // Invariant detection
185
+ // ---------------------------------------------------------------------------
186
+
187
+ interface HoistedInstr {
188
+ fromBlockId: BlockId
189
+ instrIndex: number
190
+ instr: MIRInstr
191
+ }
192
+
193
+ function collectInvariant(
194
+ info: LoopInfo,
195
+ blockMap: Map<BlockId, MIRBlock>,
196
+ fn: MIRFunction,
197
+ ): HoistedInstr[] {
198
+ // Step 1: collect the set of all temps defined (written) anywhere in the loop
199
+ const variantTemps = new Set<Temp>()
200
+ for (const id of info.loopBlockIds) {
201
+ const block = blockMap.get(id)
202
+ if (!block) continue
203
+ for (const instr of block.instrs) {
204
+ const dst = getInstrDst(instr)
205
+ if (dst !== null) variantTemps.add(dst)
206
+ }
207
+ // Terminator dsts (there are none in practice, but be safe)
208
+ const termDst = getInstrDst(block.term)
209
+ if (termDst !== null) variantTemps.add(termDst)
210
+ }
211
+
212
+ // Step 2: iteratively find invariant instructions
213
+ // (an instr whose operands are all non-variant can itself be treated as
214
+ // non-variant after it is removed, exposing further candidates)
215
+ const hoisted: HoistedInstr[] = []
216
+ let changed = true
217
+ const removedKeys = new Set<string>() // "blockId:index"
218
+
219
+ // Compute the set of temps defined OUTSIDE the loop (in preheader or earlier).
220
+ // An instruction can only be safely hoisted from the loop body if its dst is
221
+ // NOT already defined outside the loop — otherwise hoisting would shadow the
222
+ // prior value when the loop iterates zero times (e.g. while(false)).
223
+ const definedOutsideLoop = new Set<Temp>()
224
+ for (const block of fn.blocks) {
225
+ if (info.loopBlockIds.has(block.id)) continue // skip loop blocks
226
+ for (const instr of block.instrs) {
227
+ const d = getInstrDst(instr)
228
+ if (d !== null) definedOutsideLoop.add(d)
229
+ }
230
+ }
231
+
232
+ while (changed) {
233
+ changed = false
234
+ for (const id of info.loopBlockIds) {
235
+ const block = blockMap.get(id)
236
+ if (!block) continue
237
+
238
+ for (let i = 0; i < block.instrs.length; i++) {
239
+ const key = `${id}:${i}`
240
+ if (removedKeys.has(key)) continue
241
+
242
+ const instr = block.instrs[i]
243
+ const dst = getInstrDst(instr)
244
+
245
+ // Must have a dst (otherwise it's a side-effectful no-dst instr)
246
+ if (dst === null) continue
247
+
248
+ // Must not have side effects
249
+ if (hasSideEffects(instr)) continue
250
+
251
+ // Skip div/mod with variable denominator (potential trap)
252
+ if ((instr.kind === 'div' || instr.kind === 'mod') && instr.b.kind === 'temp') continue
253
+
254
+ // All source operands must be invariant (not in variantTemps)
255
+ if (!allOperandsInvariant(instr, variantTemps)) continue
256
+
257
+ // Don't hoist if there are OTHER writers of dst in the loop (excluding
258
+ // this instruction itself). If another non-hoisted instruction also writes
259
+ // dst, hoisting this one would leave stale values on subsequent iterations.
260
+ const currentKeyForCheck = key // this instruction's key (not yet in removedKeys)
261
+ if (hasOtherWriters(dst, info.loopBlockIds, blockMap, removedKeys, currentKeyForCheck)) continue
262
+
263
+ // Don't hoist if dst is also defined outside the loop. Hoisting would
264
+ // shadow the prior value when the loop executes zero times.
265
+ if (definedOutsideLoop.has(dst)) continue
266
+
267
+ // This instruction is loop-invariant — hoist it
268
+ hoisted.push({ fromBlockId: id, instrIndex: i, instr })
269
+ removedKeys.add(key)
270
+ // After hoisting, the dst is no longer variant inside the loop
271
+ // (we already checked above that no other writer remains).
272
+ variantTemps.delete(dst)
273
+ changed = true
274
+ }
275
+ }
276
+ }
277
+
278
+ return hoisted
279
+ }
280
+
281
+ /** Returns true if there exists another non-hoisted instruction in the loop
282
+ * (other than `excludeKey`) that also writes to `dst`. */
283
+ function hasOtherWriters(
284
+ dst: Temp,
285
+ loopBlockIds: Set<BlockId>,
286
+ blockMap: Map<BlockId, MIRBlock>,
287
+ removedKeys: Set<string>,
288
+ excludeKey: string,
289
+ ): boolean {
290
+ for (const id of loopBlockIds) {
291
+ const block = blockMap.get(id)
292
+ if (!block) continue
293
+ for (let i = 0; i < block.instrs.length; i++) {
294
+ const k = `${id}:${i}`
295
+ if (k === excludeKey) continue // skip the current candidate
296
+ if (removedKeys.has(k)) continue // skip already-hoisted
297
+ const d = getInstrDst(block.instrs[i])
298
+ if (d === dst) return true
299
+ }
300
+ }
301
+ return false
302
+ }
303
+
304
+ function allOperandsInvariant(instr: MIRInstr, variantTemps: Set<Temp>): boolean {
305
+ for (const op of getSourceOperands(instr)) {
306
+ if (op.kind === 'temp' && variantTemps.has(op.name)) return false
307
+ }
308
+ return true
309
+ }
310
+
311
+ // ---------------------------------------------------------------------------
312
+ // Applying the hoist
313
+ // ---------------------------------------------------------------------------
314
+
315
+ function applyHoist(
316
+ fn: MIRFunction,
317
+ blockMap: Map<BlockId, MIRBlock>,
318
+ info: LoopInfo,
319
+ hoisted: HoistedInstr[],
320
+ ): MIRFunction {
321
+ const { headerId, preHeaderPredId, latchId } = info
322
+
323
+ // Build a key set for quick lookup: "blockId:instrIndex"
324
+ const hoistedKeys = new Set(hoisted.map(h => `${h.fromBlockId}:${h.instrIndex}`))
325
+ // Collect hoisted instrs in order (they were collected left-to-right)
326
+ const hoistedInstrs = hoisted.map(h => h.instr)
327
+
328
+ // Insert a fresh preheader block
329
+ const preHeaderId = headerId.replace('loop_header', 'loop_preheader')
330
+
331
+ const preHeaderBlock: MIRBlock = {
332
+ id: preHeaderId,
333
+ instrs: hoistedInstrs,
334
+ term: { kind: 'jump', target: headerId },
335
+ preds: [], // will be recomputed
336
+ }
337
+
338
+ // Rewrite the predecessor's jump from header → preHeader
339
+ const newBlocks: MIRBlock[] = []
340
+ for (const block of fn.blocks) {
341
+ if (block.id === preHeaderPredId) {
342
+ // Redirect its outgoing edge(s) from headerId to preHeaderId
343
+ newBlocks.push({
344
+ ...block,
345
+ term: redirectTerm(block.term, headerId, preHeaderId),
346
+ })
347
+ // Insert the new preheader right after this block
348
+ newBlocks.push(preHeaderBlock)
349
+ } else {
350
+ // Remove hoisted instructions from their source blocks
351
+ if (info.loopBlockIds.has(block.id)) {
352
+ const newInstrs = block.instrs.filter((_, i) => !hoistedKeys.has(`${block.id}:${i}`))
353
+ newBlocks.push({ ...block, instrs: newInstrs })
354
+ } else {
355
+ newBlocks.push(block)
356
+ }
357
+ }
358
+ }
359
+
360
+ return { ...fn, blocks: recomputePreds(newBlocks) }
361
+ }
362
+
363
+ function redirectTerm(term: MIRInstr, from: BlockId, to: BlockId): MIRInstr {
364
+ switch (term.kind) {
365
+ case 'jump':
366
+ return term.target === from ? { ...term, target: to } : term
367
+ case 'branch':
368
+ return {
369
+ ...term,
370
+ then: term.then === from ? to : term.then,
371
+ else: term.else === from ? to : term.else,
372
+ }
373
+ default:
374
+ return term
375
+ }
376
+ }
377
+
378
+ // ---------------------------------------------------------------------------
379
+ // Helpers
380
+ // ---------------------------------------------------------------------------
381
+
382
+ function hasSideEffects(instr: MIRInstr): boolean {
383
+ return (
384
+ instr.kind === 'call' ||
385
+ instr.kind === 'call_macro' ||
386
+ instr.kind === 'call_context' ||
387
+ instr.kind === 'nbt_write' ||
388
+ instr.kind === 'nbt_write_dynamic' ||
389
+ instr.kind === 'score_write'
390
+ )
391
+ }
392
+
393
+ function getInstrDst(instr: MIRInstr): Temp | null {
394
+ switch (instr.kind) {
395
+ case 'const': case 'copy':
396
+ case 'add': case 'sub': case 'mul': case 'div': case 'mod': case 'pow':
397
+ case 'neg': case 'cmp': case 'and': case 'or': case 'not':
398
+ case 'nbt_read': case 'nbt_read_dynamic': case 'nbt_list_len':
399
+ case 'string_match': case 'score_read':
400
+ return instr.dst
401
+ case 'call': case 'call_macro':
402
+ return instr.dst
403
+ default:
404
+ return null
405
+ }
406
+ }
407
+
408
+ function getSourceOperands(instr: MIRInstr): Operand[] {
409
+ switch (instr.kind) {
410
+ case 'copy': case 'neg': case 'not':
411
+ return [instr.src]
412
+ case 'add': case 'sub': case 'mul': case 'div': case 'mod': case 'pow':
413
+ case 'cmp': case 'and': case 'or':
414
+ return [instr.a, instr.b]
415
+ case 'nbt_write':
416
+ return [instr.src]
417
+ case 'nbt_write_dynamic':
418
+ return [instr.indexSrc, instr.valueSrc]
419
+ case 'nbt_read_dynamic':
420
+ return [instr.indexSrc]
421
+ case 'call':
422
+ return [...instr.args]
423
+ case 'call_macro':
424
+ return instr.args.map(a => a.value)
425
+ case 'branch':
426
+ return [instr.cond]
427
+ case 'return':
428
+ return instr.value ? [instr.value] : []
429
+ case 'score_write':
430
+ return [instr.src]
431
+ default:
432
+ return []
433
+ }
434
+ }
435
+
436
+ function getTermTargets(term: MIRInstr): BlockId[] {
437
+ switch (term.kind) {
438
+ case 'jump': return [term.target]
439
+ case 'branch': return [term.then, term.else]
440
+ default: return []
441
+ }
442
+ }
443
+
444
+ function recomputePreds(blocks: MIRBlock[]): MIRBlock[] {
445
+ const predMap = new Map<BlockId, BlockId[]>()
446
+ for (const b of blocks) predMap.set(b.id, [])
447
+ for (const block of blocks) {
448
+ for (const target of getTermTargets(block.term)) {
449
+ const preds = predMap.get(target)
450
+ if (preds) preds.push(block.id)
451
+ }
452
+ }
453
+ return blocks.map(b => ({ ...b, preds: predMap.get(b.id) ?? [] }))
454
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * NBT Write Coalescing — MIR backward analysis pass.
3
+ *
4
+ * Removes redundant consecutive writes to the same NBT storage path.
5
+ * If a path is written multiple times with no intervening read, only the
6
+ * last write (in program order) has any observable effect.
7
+ *
8
+ * Algorithm (backward scan per basic block):
9
+ * 1. Scan instructions from last to first.
10
+ * 2. Maintain `writtenPaths: Set<string>` — paths that are definitely
11
+ * overwritten later in the block.
12
+ * 3. nbt_write(path, ...):
13
+ * - If path is in writtenPaths → redundant, drop it.
14
+ * - Otherwise → keep it, add path to writtenPaths.
15
+ * 4. nbt_read(path) / nbt_read_dynamic / nbt_list_len → remove path
16
+ * from writtenPaths (the value is observed, cannot be dropped).
17
+ * 5. call / call_macro / call_context → conservatively clear writtenPaths
18
+ * (callee may read any NBT path).
19
+ *
20
+ * This is a single-block analysis; cross-block dataflow is left to
21
+ * future work (inter-block backward analysis).
22
+ */
23
+
24
+ import type { MIRBlock, MIRFunction, MIRInstr } from '../mir/types'
25
+
26
+ export function nbtCoalesce(fn: MIRFunction): MIRFunction {
27
+ return {
28
+ ...fn,
29
+ blocks: fn.blocks.map(coalesceBlock),
30
+ }
31
+ }
32
+
33
+ function coalesceBlock(block: MIRBlock): MIRBlock {
34
+ const writtenPaths = new Set<string>()
35
+ // Scan backwards and mark which instructions to keep
36
+ const keep: boolean[] = new Array(block.instrs.length).fill(true)
37
+
38
+ for (let i = block.instrs.length - 1; i >= 0; i--) {
39
+ const instr = block.instrs[i]
40
+ processInstr(instr, writtenPaths, keep, i)
41
+ }
42
+
43
+ return {
44
+ ...block,
45
+ instrs: block.instrs.filter((_, i) => keep[i]),
46
+ }
47
+ }
48
+
49
+ function nbtKey(ns: string, path: string): string {
50
+ return `${ns}\0${path}`
51
+ }
52
+
53
+ function processInstr(
54
+ instr: MIRInstr,
55
+ writtenPaths: Set<string>,
56
+ keep: boolean[],
57
+ idx: number,
58
+ ): void {
59
+ switch (instr.kind) {
60
+ case 'nbt_write': {
61
+ const key = nbtKey(instr.ns, instr.path)
62
+ if (writtenPaths.has(key)) {
63
+ // This write will be overwritten before being read — drop it.
64
+ keep[idx] = false
65
+ } else {
66
+ writtenPaths.add(key)
67
+ }
68
+ break
69
+ }
70
+
71
+ case 'nbt_read': {
72
+ // Value is consumed here; the write that produces it is no longer redundant.
73
+ writtenPaths.delete(nbtKey(instr.ns, instr.path))
74
+ break
75
+ }
76
+
77
+ case 'nbt_read_dynamic': {
78
+ // Dynamic read — conservatively invalidate all paths with the same ns+prefix.
79
+ // Simpler: clear everything (safe, just less precise).
80
+ writtenPaths.clear()
81
+ break
82
+ }
83
+
84
+ case 'nbt_list_len': {
85
+ writtenPaths.delete(nbtKey(instr.ns, instr.path))
86
+ break
87
+ }
88
+
89
+ case 'nbt_write_dynamic': {
90
+ // Dynamic write — we cannot determine the exact path statically.
91
+ // Conservatively do NOT add anything to writtenPaths, and do NOT remove
92
+ // anything (a dynamic write could alias any path).
93
+ writtenPaths.clear()
94
+ break
95
+ }
96
+
97
+ case 'call':
98
+ case 'call_macro':
99
+ case 'call_context': {
100
+ // Callee may read any NBT path — conservatively flush.
101
+ writtenPaths.clear()
102
+ break
103
+ }
104
+
105
+ default:
106
+ // Arithmetic, comparisons, copies, score ops, etc. — no NBT effect.
107
+ break
108
+ }
109
+ }
@@ -10,13 +10,20 @@
10
10
 
11
11
  import type { MIRFunction, MIRModule } from '../mir/types'
12
12
  import { constantFold } from './constant_fold'
13
+ import { strengthReduction } from './strength_reduction'
13
14
  import { copyProp } from './copy_prop'
14
15
  import { dce } from './dce'
15
16
  import { blockMerge } from './block_merge'
16
17
  import { branchSimplify } from './branch_simplify'
17
18
  import { loopUnroll } from './unroll'
19
+ import { licm } from './licm'
18
20
  import { nbtBatchRead } from './nbt-batch'
21
+ import { scoreboardBatchRead } from './scoreboard-batch'
19
22
  import { interproceduralConstProp } from './interprocedural'
23
+ import { autoInlineSmallFunctions } from './auto-inline'
24
+ import { inlinePass } from './inline'
25
+ import { cse } from './cse'
26
+ import { nbtCoalesce } from './nbt-coalesce'
20
27
 
21
28
  // selectorCache is intentionally excluded from the default pipeline:
22
29
  // it emits synthetic __sel_cleanup_* / __sel_tag_* call_context instructions
@@ -27,8 +34,13 @@ export type Pass = (fn: MIRFunction) => MIRFunction
27
34
 
28
35
  const defaultPasses: Pass[] = [
29
36
  loopUnroll,
37
+ licm,
30
38
  nbtBatchRead,
39
+ nbtCoalesce,
40
+ scoreboardBatchRead,
31
41
  constantFold,
42
+ strengthReduction,
43
+ cse,
32
44
  copyProp,
33
45
  branchSimplify,
34
46
  dce,
@@ -50,9 +62,11 @@ export function optimizeFunction(fn: MIRFunction, passes: Pass[] = defaultPasses
50
62
  }
51
63
 
52
64
  export function optimizeModule(mod: MIRModule, passes?: Pass[]): MIRModule {
65
+ // Module-level pass: inline @inline-marked functions before per-function opts
66
+ const inlined = autoInlineSmallFunctions(inlinePass(mod))
53
67
  const perFnOptimized = {
54
- ...mod,
55
- functions: mod.functions.map(fn => optimizeFunction(fn, passes)),
68
+ ...inlined,
69
+ functions: inlined.functions.map(fn => optimizeFunction(fn, passes)),
56
70
  }
57
71
  // Module-level pass: interprocedural constant propagation
58
72
  return interproceduralConstProp(perFnOptimized)
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Scoreboard Read Batching — MIR optimization pass.
3
+ *
4
+ * Eliminates redundant score_read instructions within a basic block:
5
+ * if the same (player, obj) is read twice with no intervening score_write
6
+ * to that player+obj, the second read is replaced with a copy from the
7
+ * first read's dst.
8
+ *
9
+ * This reduces expensive `scoreboard players get` commands in generated
10
+ * .mcfunction files.
11
+ */
12
+
13
+ import type { MIRFunction, MIRBlock, MIRInstr, Temp } from '../mir/types'
14
+
15
+ export function scoreboardBatchRead(fn: MIRFunction): MIRFunction {
16
+ return {
17
+ ...fn,
18
+ blocks: fn.blocks.map(deduplicateBlock),
19
+ }
20
+ }
21
+
22
+ function deduplicateBlock(block: MIRBlock): MIRBlock {
23
+ // Map from "player\0obj" → dst temp of the first read
24
+ const cache = new Map<string, Temp>()
25
+
26
+ const instrs: MIRInstr[] = []
27
+ for (const instr of block.instrs) {
28
+ if (instr.kind === 'score_read') {
29
+ const key = `${instr.player}\0${instr.obj}`
30
+ const cached = cache.get(key)
31
+ if (cached !== undefined) {
32
+ // Replace with copy from cached temp
33
+ instrs.push({ kind: 'copy', dst: instr.dst, src: { kind: 'temp', name: cached } })
34
+ } else {
35
+ cache.set(key, instr.dst)
36
+ instrs.push(instr)
37
+ }
38
+ } else if (instr.kind === 'score_write') {
39
+ // Invalidate cache for this player+obj
40
+ cache.delete(`${instr.player}\0${instr.obj}`)
41
+ instrs.push(instr)
42
+ } else if (instr.kind === 'call' || instr.kind === 'call_macro') {
43
+ // Conservative: calls may have side effects that modify scoreboards
44
+ cache.clear()
45
+ instrs.push(instr)
46
+ } else {
47
+ instrs.push(instr)
48
+ }
49
+ }
50
+
51
+ return { ...block, instrs }
52
+ }