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.
- package/.claudeignore +21 -0
- package/.github/workflows/ci.yml +1 -0
- package/README.md +12 -16
- package/README.zh.md +2 -2
- package/demo.gif +0 -0
- package/dist/cli.js +2 -554
- package/dist/compile.js +2 -266
- package/dist/index.js +2 -159
- package/dist/src/__tests__/budget.test.js +261 -0
- package/dist/src/__tests__/cli.test.js +104 -0
- package/dist/{__tests__ → src/__tests__}/dce.test.js +11 -47
- package/dist/{__tests__ → src/__tests__}/diagnostics.test.js +67 -40
- package/dist/src/__tests__/e2e/basic.test.d.ts +8 -0
- package/dist/src/__tests__/e2e/basic.test.js +140 -0
- package/dist/src/__tests__/e2e/coroutine.test.d.ts +7 -0
- package/dist/src/__tests__/e2e/coroutine.test.js +132 -0
- package/dist/src/__tests__/e2e/macros.test.d.ts +9 -0
- package/dist/src/__tests__/e2e/macros.test.js +182 -0
- package/dist/src/__tests__/e2e/migrate.test.d.ts +13 -0
- package/dist/src/__tests__/e2e/migrate.test.js +2739 -0
- package/dist/src/__tests__/e2e/stdlib-e2e.test.d.ts +10 -0
- package/dist/src/__tests__/e2e/stdlib-e2e.test.js +324 -0
- package/dist/src/__tests__/enum.test.d.ts +10 -0
- package/dist/src/__tests__/enum.test.js +389 -0
- package/dist/src/__tests__/generics.test.d.ts +14 -0
- package/dist/src/__tests__/generics.test.js +367 -0
- package/dist/src/__tests__/hir/desugar.test.js +234 -0
- package/dist/src/__tests__/incremental.test.d.ts +5 -0
- package/dist/src/__tests__/incremental.test.js +308 -0
- package/dist/src/__tests__/lir/lower.test.js +559 -0
- package/dist/src/__tests__/lir/types.test.js +185 -0
- package/dist/src/__tests__/lir/verify.test.js +221 -0
- package/dist/src/__tests__/lsp.test.d.ts +7 -0
- package/dist/src/__tests__/lsp.test.js +245 -0
- package/dist/{__tests__ → src/__tests__}/mc-integration.test.js +1 -3
- package/dist/src/__tests__/mc-version.test.d.ts +10 -0
- package/dist/src/__tests__/mc-version.test.js +154 -0
- package/dist/src/__tests__/mir/arithmetic.test.js +130 -0
- package/dist/src/__tests__/mir/control-flow.test.js +205 -0
- package/dist/src/__tests__/mir/verify.test.js +223 -0
- package/dist/src/__tests__/modules.test.d.ts +7 -0
- package/dist/src/__tests__/modules.test.js +333 -0
- package/dist/src/__tests__/optimizer/block_merge.test.js +78 -0
- package/dist/src/__tests__/optimizer/branch_simplify.test.js +58 -0
- package/dist/src/__tests__/optimizer/constant_fold.test.js +131 -0
- package/dist/src/__tests__/optimizer/copy_prop.test.js +91 -0
- package/dist/src/__tests__/optimizer/coroutine.test.d.ts +12 -0
- package/dist/src/__tests__/optimizer/coroutine.test.js +251 -0
- package/dist/src/__tests__/optimizer/dce.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/dce.test.js +76 -0
- package/dist/src/__tests__/optimizer/interprocedural.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/interprocedural.test.js +145 -0
- package/dist/src/__tests__/optimizer/lir/const_imm.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/lir/const_imm.test.js +138 -0
- package/dist/src/__tests__/optimizer/lir/dead_slot.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/lir/dead_slot.test.js +141 -0
- package/dist/src/__tests__/optimizer/lir/peephole.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/lir/peephole.test.js +126 -0
- package/dist/src/__tests__/optimizer/lir/pipeline.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/lir/pipeline.test.js +84 -0
- package/dist/src/__tests__/optimizer/nbt-batch.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/nbt-batch.test.js +110 -0
- package/dist/src/__tests__/optimizer/pipeline.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/pipeline.test.js +102 -0
- package/dist/src/__tests__/optimizer/selector-cache.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/selector-cache.test.js +103 -0
- package/dist/src/__tests__/optimizer/unroll.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/unroll.test.js +206 -0
- package/dist/src/__tests__/option.test.d.ts +14 -0
- package/dist/src/__tests__/option.test.js +275 -0
- package/dist/src/__tests__/parser.test.d.ts +1 -0
- package/dist/src/__tests__/repl.test.d.ts +1 -0
- package/dist/src/__tests__/schedule.test.d.ts +7 -0
- package/dist/src/__tests__/schedule.test.js +98 -0
- package/dist/src/__tests__/sourcemap.test.d.ts +7 -0
- package/dist/src/__tests__/sourcemap.test.js +227 -0
- package/dist/src/__tests__/tuple.test.d.ts +11 -0
- package/dist/src/__tests__/tuple.test.js +202 -0
- package/dist/src/__tests__/typechecker-strict.test.d.ts +10 -0
- package/dist/src/__tests__/typechecker-strict.test.js +197 -0
- package/dist/src/__tests__/typechecker.test.d.ts +1 -0
- package/dist/{ast → src/ast}/types.d.ts +58 -3
- package/dist/src/cache/deps.d.ts +41 -0
- package/dist/src/cache/deps.js +158 -0
- package/dist/src/cache/incremental.d.ts +35 -0
- package/dist/src/cache/incremental.js +165 -0
- package/dist/src/cache/index.d.ts +37 -0
- package/dist/src/cache/index.js +152 -0
- package/dist/{cli.d.ts → src/cli.d.ts} +1 -1
- package/dist/src/cli.js +474 -0
- package/dist/src/compile.d.ts +37 -0
- package/dist/src/compile.js +165 -0
- package/dist/{diagnostics → src/diagnostics}/index.d.ts +1 -1
- package/dist/{diagnostics → src/diagnostics}/index.js +8 -11
- package/dist/src/emit/compile.d.ts +29 -0
- package/dist/src/emit/compile.js +143 -0
- package/dist/src/emit/index.d.ts +26 -0
- package/dist/src/emit/index.js +223 -0
- package/dist/src/emit/modules.d.ts +29 -0
- package/dist/src/emit/modules.js +492 -0
- package/dist/src/emit/sourcemap.d.ts +53 -0
- package/dist/src/emit/sourcemap.js +73 -0
- package/dist/src/hir/lower.d.ts +15 -0
- package/dist/src/hir/lower.js +399 -0
- package/dist/src/hir/monomorphize.d.ts +22 -0
- package/dist/src/hir/monomorphize.js +379 -0
- package/dist/src/hir/types.d.ts +406 -0
- package/dist/src/hir/types.js +16 -0
- package/dist/src/index.d.ts +39 -0
- package/dist/src/index.js +67 -0
- package/dist/{lexer → src/lexer}/index.d.ts +1 -1
- package/dist/{lexer → src/lexer}/index.js +1 -0
- package/dist/src/lir/budget.d.ts +37 -0
- package/dist/src/lir/budget.js +280 -0
- package/dist/src/lir/lower.d.ts +15 -0
- package/dist/src/lir/lower.js +472 -0
- package/dist/src/lir/types.d.ts +139 -0
- package/dist/src/lir/types.js +11 -0
- package/dist/src/lir/verify.d.ts +14 -0
- package/dist/src/lir/verify.js +113 -0
- package/dist/src/lsp/main.d.ts +8 -0
- package/dist/src/lsp/main.js +11 -0
- package/dist/src/lsp/server.d.ts +11 -0
- package/dist/src/lsp/server.js +352 -0
- package/dist/{mc-test → src/mc-test}/runner.js +4 -3
- package/dist/src/mir/lower.d.ts +9 -0
- package/dist/src/mir/lower.js +1264 -0
- package/dist/src/mir/macro.d.ts +22 -0
- package/dist/src/mir/macro.js +168 -0
- package/dist/src/mir/types.d.ts +191 -0
- package/dist/src/mir/types.js +11 -0
- package/dist/src/mir/verify.d.ts +16 -0
- package/dist/src/mir/verify.js +216 -0
- package/dist/src/optimizer/block_merge.d.ts +12 -0
- package/dist/src/optimizer/block_merge.js +84 -0
- package/dist/src/optimizer/branch_simplify.d.ts +9 -0
- package/dist/src/optimizer/branch_simplify.js +28 -0
- package/dist/src/optimizer/constant_fold.d.ts +10 -0
- package/dist/src/optimizer/constant_fold.js +85 -0
- package/dist/src/optimizer/copy_prop.d.ts +9 -0
- package/dist/src/optimizer/copy_prop.js +113 -0
- package/dist/src/optimizer/coroutine.d.ts +34 -0
- package/dist/src/optimizer/coroutine.js +789 -0
- package/dist/src/optimizer/dce.d.ts +8 -0
- package/dist/src/optimizer/dce.js +156 -0
- package/dist/src/optimizer/interprocedural.d.ts +14 -0
- package/dist/src/optimizer/interprocedural.js +186 -0
- package/dist/src/optimizer/lir/const_imm.d.ts +12 -0
- package/dist/src/optimizer/lir/const_imm.js +139 -0
- package/dist/src/optimizer/lir/dead_slot.d.ts +14 -0
- package/dist/src/optimizer/lir/dead_slot.js +130 -0
- package/dist/src/optimizer/lir/peephole.d.ts +21 -0
- package/dist/src/optimizer/lir/peephole.js +52 -0
- package/dist/src/optimizer/lir/pipeline.d.ts +10 -0
- package/dist/src/optimizer/lir/pipeline.js +34 -0
- package/dist/src/optimizer/nbt-batch.d.ts +11 -0
- package/dist/src/optimizer/nbt-batch.js +51 -0
- package/dist/src/optimizer/pipeline.d.ts +14 -0
- package/dist/src/optimizer/pipeline.js +58 -0
- package/dist/src/optimizer/selector-cache.d.ts +22 -0
- package/dist/src/optimizer/selector-cache.js +100 -0
- package/dist/src/optimizer/unroll.d.ts +32 -0
- package/dist/src/optimizer/unroll.js +348 -0
- package/dist/{parser → src/parser}/index.d.ts +8 -0
- package/dist/{parser → src/parser}/index.js +204 -14
- package/dist/{repl.d.ts → src/repl.d.ts} +1 -1
- package/dist/{runtime → src/runtime}/index.js +1 -1
- package/dist/{typechecker → src/typechecker}/index.d.ts +4 -0
- package/dist/{typechecker → src/typechecker}/index.js +198 -13
- package/dist/src/types/mc-version.d.ts +24 -0
- package/dist/src/types/mc-version.js +49 -0
- package/docs/ROADMAP.md +395 -0
- package/docs/compiler-pipeline-redesign.md +2260 -0
- package/docs/optimization-ideas.md +1076 -0
- package/editors/vscode/out/extension.js +25176 -8000
- package/editors/vscode/package-lock.json +90 -6
- package/editors/vscode/package.json +3 -2
- package/editors/vscode/src/extension.ts +97 -67
- package/examples/showcase.mcrs +3 -3
- package/package.json +13 -6
- package/scripts/postbuild.js +15 -0
- package/src/__tests__/budget.test.ts +297 -0
- package/src/__tests__/cli.test.ts +8 -220
- package/src/__tests__/dce.test.ts +11 -56
- package/src/__tests__/diagnostics.test.ts +61 -41
- package/src/__tests__/e2e/basic.test.ts +154 -0
- package/src/__tests__/e2e/coroutine.test.ts +142 -0
- package/src/__tests__/e2e/macros.test.ts +199 -0
- package/src/__tests__/e2e/migrate.test.ts +3008 -0
- package/src/__tests__/e2e/stdlib-e2e.test.ts +348 -0
- package/src/__tests__/enum.test.ts +425 -0
- package/src/__tests__/generics.test.ts +390 -0
- package/src/__tests__/hir/desugar.test.ts +263 -0
- package/src/__tests__/incremental.test.ts +337 -0
- package/src/__tests__/lir/lower.test.ts +619 -0
- package/src/__tests__/lir/types.test.ts +207 -0
- package/src/__tests__/lir/verify.test.ts +249 -0
- package/src/__tests__/lsp.test.ts +270 -0
- package/src/__tests__/mc-integration.test.ts +1 -2
- package/src/__tests__/mc-version.test.ts +178 -0
- package/src/__tests__/mir/arithmetic.test.ts +156 -0
- package/src/__tests__/mir/control-flow.test.ts +242 -0
- package/src/__tests__/mir/verify.test.ts +254 -0
- package/src/__tests__/modules.test.ts +365 -0
- package/src/__tests__/optimizer/block_merge.test.ts +84 -0
- package/src/__tests__/optimizer/branch_simplify.test.ts +64 -0
- package/src/__tests__/optimizer/constant_fold.test.ts +145 -0
- package/src/__tests__/optimizer/copy_prop.test.ts +99 -0
- package/src/__tests__/optimizer/coroutine.test.ts +312 -0
- package/src/__tests__/optimizer/dce.test.ts +83 -0
- package/src/__tests__/optimizer/interprocedural.test.ts +174 -0
- package/src/__tests__/optimizer/lir/const_imm.test.ts +151 -0
- package/src/__tests__/optimizer/lir/dead_slot.test.ts +156 -0
- package/src/__tests__/optimizer/lir/peephole.test.ts +136 -0
- package/src/__tests__/optimizer/lir/pipeline.test.ts +113 -0
- package/src/__tests__/optimizer/nbt-batch.test.ts +119 -0
- package/src/__tests__/optimizer/pipeline.test.ts +116 -0
- package/src/__tests__/optimizer/selector-cache.test.ts +112 -0
- package/src/__tests__/optimizer/unroll.test.ts +231 -0
- package/src/__tests__/option.test.ts +299 -0
- package/src/__tests__/schedule.test.ts +105 -0
- package/src/__tests__/sourcemap.test.ts +254 -0
- package/src/__tests__/tuple.test.ts +220 -0
- package/src/__tests__/typechecker-strict.test.ts +216 -0
- package/src/ast/types.ts +39 -3
- package/src/cache/deps.ts +132 -0
- package/src/cache/incremental.ts +173 -0
- package/src/cache/index.ts +135 -0
- package/src/cli.ts +111 -195
- package/src/compile.ts +6 -162
- package/src/diagnostics/index.ts +8 -11
- package/src/emit/compile.ts +177 -0
- package/src/emit/index.ts +286 -0
- package/src/emit/modules.ts +581 -0
- package/src/emit/sourcemap.ts +101 -0
- package/src/hir/lower.ts +455 -0
- package/src/hir/monomorphize.ts +416 -0
- package/src/hir/types.ts +228 -0
- package/src/index.ts +37 -182
- package/src/lexer/index.ts +2 -1
- package/src/lir/budget.ts +321 -0
- package/src/lir/lower.ts +587 -0
- package/src/lir/types.ts +113 -0
- package/src/lir/verify.ts +129 -0
- package/src/lsp/main.ts +9 -0
- package/src/lsp/server.ts +414 -0
- package/src/mc-test/runner.ts +4 -3
- package/src/mir/lower.ts +1403 -0
- package/src/mir/macro.ts +167 -0
- package/src/mir/types.ts +117 -0
- package/src/mir/verify.ts +218 -0
- package/src/optimizer/block_merge.ts +93 -0
- package/src/optimizer/branch_simplify.ts +27 -0
- package/src/optimizer/constant_fold.ts +88 -0
- package/src/optimizer/copy_prop.ts +106 -0
- package/src/optimizer/coroutine.ts +996 -0
- package/src/optimizer/dce.ts +108 -653
- package/src/optimizer/interprocedural.ts +177 -0
- package/src/optimizer/lir/const_imm.ts +143 -0
- package/src/optimizer/lir/dead_slot.ts +123 -0
- package/src/optimizer/lir/peephole.ts +57 -0
- package/src/optimizer/lir/pipeline.ts +37 -0
- package/src/optimizer/nbt-batch.ts +50 -0
- package/src/optimizer/pipeline.ts +59 -0
- package/src/optimizer/selector-cache.ts +103 -0
- package/src/optimizer/unroll.ts +386 -0
- package/src/parser/index.ts +213 -16
- package/src/repl.ts +1 -1
- package/src/runtime/index.ts +1 -1
- package/src/stdlib/math.mcrs +4 -4
- package/src/templates/quest.mcrs +4 -4
- package/src/typechecker/index.ts +215 -15
- package/src/types/mc-version.ts +46 -0
- package/tsconfig.json +1 -1
- package/dist/__tests__/cli.test.js +0 -278
- package/dist/__tests__/codegen.test.js +0 -152
- package/dist/__tests__/e2e.test.d.ts +0 -6
- package/dist/__tests__/e2e.test.js +0 -1847
- package/dist/__tests__/entity-types.test.js +0 -203
- package/dist/__tests__/lowering.test.js +0 -1015
- package/dist/__tests__/macro.test.d.ts +0 -8
- package/dist/__tests__/macro.test.js +0 -305
- package/dist/__tests__/nbt.test.js +0 -82
- package/dist/__tests__/optimizer-advanced.test.js +0 -124
- package/dist/__tests__/optimizer.test.js +0 -149
- package/dist/__tests__/runtime.test.js +0 -289
- package/dist/__tests__/stdlib-advanced.test.d.ts +0 -4
- package/dist/__tests__/stdlib-advanced.test.js +0 -378
- package/dist/__tests__/stdlib-bigint.test.d.ts +0 -7
- package/dist/__tests__/stdlib-bigint.test.js +0 -428
- package/dist/__tests__/stdlib-math.test.d.ts +0 -7
- package/dist/__tests__/stdlib-math.test.js +0 -352
- package/dist/__tests__/stdlib-vec.test.d.ts +0 -4
- package/dist/__tests__/stdlib-vec.test.js +0 -264
- package/dist/__tests__/structure-optimizer.test.js +0 -33
- package/dist/__tests__/var-allocator.test.js +0 -69
- package/dist/codegen/cmdblock/index.d.ts +0 -26
- package/dist/codegen/cmdblock/index.js +0 -45
- package/dist/codegen/mcfunction/index.d.ts +0 -40
- package/dist/codegen/mcfunction/index.js +0 -606
- package/dist/codegen/structure/index.d.ts +0 -24
- package/dist/codegen/structure/index.js +0 -279
- package/dist/codegen/var-allocator.d.ts +0 -45
- package/dist/codegen/var-allocator.js +0 -104
- package/dist/compile.d.ts +0 -68
- package/dist/data/arena/function/__load.mcfunction +0 -6
- package/dist/data/arena/function/__tick.mcfunction +0 -2
- package/dist/data/arena/function/announce_leaders/else_1.mcfunction +0 -3
- package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +0 -1
- package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +0 -3
- package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +0 -7
- package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +0 -1
- package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +0 -4
- package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +0 -6
- package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +0 -1
- package/dist/data/arena/function/announce_leaders/then_0.mcfunction +0 -4
- package/dist/data/arena/function/announce_leaders.mcfunction +0 -6
- package/dist/data/arena/function/arena_tick/merge_2.mcfunction +0 -1
- package/dist/data/arena/function/arena_tick/then_0.mcfunction +0 -4
- package/dist/data/arena/function/arena_tick.mcfunction +0 -11
- package/dist/data/counter/function/__load.mcfunction +0 -5
- package/dist/data/counter/function/__tick.mcfunction +0 -2
- package/dist/data/counter/function/counter_tick/merge_2.mcfunction +0 -1
- package/dist/data/counter/function/counter_tick/then_0.mcfunction +0 -3
- package/dist/data/counter/function/counter_tick.mcfunction +0 -11
- package/dist/data/gcd2/function/__load.mcfunction +0 -3
- package/dist/data/gcd2/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/gcd2/function/abs/then_0.mcfunction +0 -5
- package/dist/data/gcd2/function/abs.mcfunction +0 -7
- package/dist/data/gcd2/function/gcd/loop_body_1.mcfunction +0 -7
- package/dist/data/gcd2/function/gcd/loop_check_0.mcfunction +0 -5
- package/dist/data/gcd2/function/gcd/loop_exit_2.mcfunction +0 -3
- package/dist/data/gcd2/function/gcd.mcfunction +0 -14
- package/dist/data/gcd3/function/__load.mcfunction +0 -3
- package/dist/data/gcd3/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/gcd3/function/abs/then_0.mcfunction +0 -5
- package/dist/data/gcd3/function/abs.mcfunction +0 -7
- package/dist/data/gcd3/function/gcd/loop_body_1.mcfunction +0 -7
- package/dist/data/gcd3/function/gcd/loop_check_0.mcfunction +0 -5
- package/dist/data/gcd3/function/gcd/loop_exit_2.mcfunction +0 -3
- package/dist/data/gcd3/function/gcd.mcfunction +0 -14
- package/dist/data/gcd3/function/test.mcfunction +0 -7
- package/dist/data/gcd3nm/function/__load.mcfunction +0 -3
- package/dist/data/gcd3nm/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/gcd3nm/function/abs/then_0.mcfunction +0 -5
- package/dist/data/gcd3nm/function/abs.mcfunction +0 -7
- package/dist/data/gcd3nm/function/gcd/loop_body_1.mcfunction +0 -7
- package/dist/data/gcd3nm/function/gcd/loop_check_0.mcfunction +0 -5
- package/dist/data/gcd3nm/function/gcd/loop_exit_2.mcfunction +0 -3
- package/dist/data/gcd3nm/function/gcd.mcfunction +0 -14
- package/dist/data/gcd3nm/function/test.mcfunction +0 -7
- package/dist/data/gcd_test/function/__load.mcfunction +0 -3
- package/dist/data/gcd_test/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/gcd_test/function/abs/then_0.mcfunction +0 -5
- package/dist/data/gcd_test/function/abs.mcfunction +0 -7
- package/dist/data/gcd_test/function/gcd/loop_body_1.mcfunction +0 -7
- package/dist/data/gcd_test/function/gcd/loop_check_0.mcfunction +0 -5
- package/dist/data/gcd_test/function/gcd/loop_exit_2.mcfunction +0 -3
- package/dist/data/gcd_test/function/gcd.mcfunction +0 -14
- package/dist/data/isqrttest/function/__load.mcfunction +0 -6
- package/dist/data/isqrttest/function/isqrt/loop_body_4.mcfunction +0 -12
- package/dist/data/isqrttest/function/isqrt/loop_check_3.mcfunction +0 -5
- package/dist/data/isqrttest/function/isqrt/loop_exit_5.mcfunction +0 -3
- package/dist/data/isqrttest/function/isqrt/merge_2.mcfunction +0 -4
- package/dist/data/isqrttest/function/isqrt/merge_8.mcfunction +0 -6
- package/dist/data/isqrttest/function/isqrt/then_0.mcfunction +0 -3
- package/dist/data/isqrttest/function/isqrt/then_6.mcfunction +0 -3
- package/dist/data/isqrttest/function/isqrt.mcfunction +0 -7
- package/dist/data/isqrttest/function/test.mcfunction +0 -6
- package/dist/data/mathtest/function/__load.mcfunction +0 -3
- package/dist/data/mathtest/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/mathtest/function/abs/then_0.mcfunction +0 -5
- package/dist/data/mathtest/function/abs.mcfunction +0 -6
- package/dist/data/mathtest/function/test.mcfunction +0 -5
- package/dist/data/minecraft/tags/function/load.json +0 -5
- package/dist/data/minecraft/tags/function/tick.json +0 -5
- package/dist/data/mypack/function/__load.mcfunction +0 -13
- package/dist/data/mypack/function/_atan_init.mcfunction +0 -2
- package/dist/data/mypack/function/abs/merge_2.mcfunction +0 -3
- package/dist/data/mypack/function/abs/then_0.mcfunction +0 -5
- package/dist/data/mypack/function/abs.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/__sgi_1.mcfunction +0 -2
- package/dist/data/mypack/function/atan2_fixed/else_34.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/loop_body_31.mcfunction +0 -19
- package/dist/data/mypack/function/atan2_fixed/loop_check_30.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/loop_exit_32.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/merge_11.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/merge_14.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/merge_17.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/merge_2.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_20.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_23.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_26.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/merge_29.mcfunction +0 -4
- package/dist/data/mypack/function/atan2_fixed/merge_38.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_41.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_44.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_47.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_5.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/merge_8.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_0.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_12.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_15.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_18.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_21.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_24.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_27.mcfunction +0 -6
- package/dist/data/mypack/function/atan2_fixed/then_3.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_33.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_36.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_39.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_42.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_45.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed/then_6.mcfunction +0 -3
- package/dist/data/mypack/function/atan2_fixed/then_9.mcfunction +0 -5
- package/dist/data/mypack/function/atan2_fixed.mcfunction +0 -7
- package/dist/data/mypack/function/my_game.mcfunction +0 -10
- package/dist/data/quiz/function/__load.mcfunction +0 -16
- package/dist/data/quiz/function/__tick.mcfunction +0 -6
- package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +0 -4
- package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +0 -4
- package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +0 -4
- package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +0 -4
- package/dist/data/quiz/function/answer_a.mcfunction +0 -4
- package/dist/data/quiz/function/answer_b.mcfunction +0 -4
- package/dist/data/quiz/function/answer_c.mcfunction +0 -4
- package/dist/data/quiz/function/ask_question/else_1.mcfunction +0 -5
- package/dist/data/quiz/function/ask_question/else_4.mcfunction +0 -5
- package/dist/data/quiz/function/ask_question/else_7.mcfunction +0 -4
- package/dist/data/quiz/function/ask_question/merge_2.mcfunction +0 -1
- package/dist/data/quiz/function/ask_question/merge_5.mcfunction +0 -2
- package/dist/data/quiz/function/ask_question/merge_8.mcfunction +0 -2
- package/dist/data/quiz/function/ask_question/then_0.mcfunction +0 -4
- package/dist/data/quiz/function/ask_question/then_3.mcfunction +0 -4
- package/dist/data/quiz/function/ask_question/then_6.mcfunction +0 -4
- package/dist/data/quiz/function/ask_question.mcfunction +0 -7
- package/dist/data/quiz/function/finish_quiz.mcfunction +0 -6
- package/dist/data/quiz/function/handle_answer/else_1.mcfunction +0 -5
- package/dist/data/quiz/function/handle_answer/else_10.mcfunction +0 -3
- package/dist/data/quiz/function/handle_answer/else_16.mcfunction +0 -3
- package/dist/data/quiz/function/handle_answer/else_4.mcfunction +0 -3
- package/dist/data/quiz/function/handle_answer/else_7.mcfunction +0 -5
- package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +0 -2
- package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +0 -2
- package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +0 -2
- package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +0 -8
- package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +0 -2
- package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +0 -2
- package/dist/data/quiz/function/handle_answer/then_0.mcfunction +0 -5
- package/dist/data/quiz/function/handle_answer/then_12.mcfunction +0 -5
- package/dist/data/quiz/function/handle_answer/then_15.mcfunction +0 -6
- package/dist/data/quiz/function/handle_answer/then_3.mcfunction +0 -6
- package/dist/data/quiz/function/handle_answer/then_6.mcfunction +0 -5
- package/dist/data/quiz/function/handle_answer/then_9.mcfunction +0 -6
- package/dist/data/quiz/function/handle_answer.mcfunction +0 -11
- package/dist/data/quiz/function/start_quiz.mcfunction +0 -5
- package/dist/data/reqtest/function/__load.mcfunction +0 -4
- package/dist/data/reqtest/function/_table_init.mcfunction +0 -2
- package/dist/data/reqtest/function/no_trig.mcfunction +0 -3
- package/dist/data/reqtest/function/use_table.mcfunction +0 -4
- package/dist/data/reqtest2/function/__load.mcfunction +0 -3
- package/dist/data/reqtest2/function/no_trig.mcfunction +0 -3
- package/dist/data/runtime/function/__load.mcfunction +0 -5
- package/dist/data/runtime/function/__tick.mcfunction +0 -2
- package/dist/data/runtime/function/counter_tick/then_0.mcfunction +0 -3
- package/dist/data/runtime/function/counter_tick.mcfunction +0 -13
- package/dist/data/shop/function/__load.mcfunction +0 -7
- package/dist/data/shop/function/__tick.mcfunction +0 -3
- package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +0 -4
- package/dist/data/shop/function/complete_purchase/else_1.mcfunction +0 -5
- package/dist/data/shop/function/complete_purchase/else_4.mcfunction +0 -5
- package/dist/data/shop/function/complete_purchase/else_7.mcfunction +0 -3
- package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +0 -2
- package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +0 -2
- package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +0 -2
- package/dist/data/shop/function/complete_purchase/then_0.mcfunction +0 -4
- package/dist/data/shop/function/complete_purchase/then_3.mcfunction +0 -4
- package/dist/data/shop/function/complete_purchase/then_6.mcfunction +0 -4
- package/dist/data/shop/function/complete_purchase.mcfunction +0 -7
- package/dist/data/shop/function/handle_shop_trigger.mcfunction +0 -3
- package/dist/data/swap_test/function/__load.mcfunction +0 -3
- package/dist/data/swap_test/function/gcd_old/loop_body_1.mcfunction +0 -7
- package/dist/data/swap_test/function/gcd_old/loop_check_0.mcfunction +0 -5
- package/dist/data/swap_test/function/gcd_old/loop_exit_2.mcfunction +0 -3
- package/dist/data/swap_test/function/gcd_old.mcfunction +0 -8
- package/dist/data/turret/function/__load.mcfunction +0 -5
- package/dist/data/turret/function/__tick.mcfunction +0 -4
- package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +0 -4
- package/dist/data/turret/function/deploy_turret.mcfunction +0 -8
- package/dist/data/turret/function/turret_tick/at_1.mcfunction +0 -2
- package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +0 -2
- package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +0 -2
- package/dist/data/turret/function/turret_tick/tick_body.mcfunction +0 -3
- package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +0 -1
- package/dist/data/turret/function/turret_tick.mcfunction +0 -5
- package/dist/gcd2.map.json +0 -15
- package/dist/gcd3.map.json +0 -17
- package/dist/gcd_test.map.json +0 -15
- package/dist/index.d.ts +0 -62
- package/dist/ir/builder.d.ts +0 -33
- package/dist/ir/builder.js +0 -99
- package/dist/ir/types.d.ts +0 -132
- package/dist/ir/types.js +0 -15
- package/dist/isqrttest.map.json +0 -15
- package/dist/lowering/index.d.ts +0 -188
- package/dist/lowering/index.js +0 -3403
- package/dist/mathtest.map.json +0 -6
- package/dist/mypack.map.json +0 -27
- package/dist/optimizer/commands.d.ts +0 -38
- package/dist/optimizer/commands.js +0 -451
- package/dist/optimizer/dce.d.ts +0 -34
- package/dist/optimizer/dce.js +0 -639
- package/dist/optimizer/passes.d.ts +0 -34
- package/dist/optimizer/passes.js +0 -243
- package/dist/optimizer/structure.d.ts +0 -9
- package/dist/optimizer/structure.js +0 -356
- package/dist/pack.mcmeta +0 -6
- package/dist/reqtest.map.json +0 -4
- package/dist/reqtest2.map.json +0 -4
- package/dist/runtime.map.json +0 -7
- package/dist/swap_test.map.json +0 -14
- package/src/__tests__/codegen.test.ts +0 -161
- package/src/__tests__/e2e.test.ts +0 -2039
- package/src/__tests__/entity-types.test.ts +0 -236
- package/src/__tests__/lowering.test.ts +0 -1185
- package/src/__tests__/macro.test.ts +0 -343
- package/src/__tests__/nbt.test.ts +0 -58
- package/src/__tests__/optimizer-advanced.test.ts +0 -144
- package/src/__tests__/optimizer.test.ts +0 -162
- package/src/__tests__/runtime.test.ts +0 -305
- package/src/__tests__/stdlib-advanced.test.ts +0 -379
- package/src/__tests__/stdlib-bigint.test.ts +0 -427
- package/src/__tests__/stdlib-math.test.ts +0 -374
- package/src/__tests__/stdlib-vec.test.ts +0 -259
- package/src/__tests__/structure-optimizer.test.ts +0 -38
- package/src/__tests__/var-allocator.test.ts +0 -75
- package/src/codegen/cmdblock/index.ts +0 -63
- package/src/codegen/mcfunction/index.ts +0 -662
- package/src/codegen/structure/index.ts +0 -346
- package/src/codegen/var-allocator.ts +0 -104
- package/src/ir/builder.ts +0 -116
- package/src/ir/types.ts +0 -134
- package/src/lowering/index.ts +0 -3876
- package/src/optimizer/commands.ts +0 -534
- package/src/optimizer/passes.ts +0 -250
- package/src/optimizer/structure.ts +0 -450
- /package/dist/{__tests__/cli.test.d.ts → src/__tests__/budget.test.d.ts} +0 -0
- /package/dist/{__tests__/codegen.test.d.ts → src/__tests__/cli.test.d.ts} +0 -0
- /package/dist/{__tests__ → src/__tests__}/compile-all.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/compile-all.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/dce.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/diagnostics.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/formatter.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/formatter.test.js +0 -0
- /package/dist/{__tests__/entity-types.test.d.ts → src/__tests__/hir/desugar.test.d.ts} +0 -0
- /package/dist/{__tests__ → src/__tests__}/lexer.test.d.ts +0 -0
- /package/dist/{__tests__ → src/__tests__}/lexer.test.js +0 -0
- /package/dist/{__tests__/lowering.test.d.ts → src/__tests__/lir/lower.test.d.ts} +0 -0
- /package/dist/{__tests__/mc-syntax.test.d.ts → src/__tests__/lir/types.test.d.ts} +0 -0
- /package/dist/{__tests__/nbt.test.d.ts → src/__tests__/lir/verify.test.d.ts} +0 -0
- /package/dist/{__tests__ → src/__tests__}/mc-integration.test.d.ts +0 -0
- /package/dist/{__tests__/optimizer-advanced.test.d.ts → src/__tests__/mc-syntax.test.d.ts} +0 -0
- /package/dist/{__tests__ → src/__tests__}/mc-syntax.test.js +0 -0
- /package/dist/{__tests__/optimizer.test.d.ts → src/__tests__/mir/arithmetic.test.d.ts} +0 -0
- /package/dist/{__tests__/parser.test.d.ts → src/__tests__/mir/control-flow.test.d.ts} +0 -0
- /package/dist/{__tests__/repl.test.d.ts → src/__tests__/mir/verify.test.d.ts} +0 -0
- /package/dist/{__tests__/runtime.test.d.ts → src/__tests__/optimizer/block_merge.test.d.ts} +0 -0
- /package/dist/{__tests__/structure-optimizer.test.d.ts → src/__tests__/optimizer/branch_simplify.test.d.ts} +0 -0
- /package/dist/{__tests__/typechecker.test.d.ts → src/__tests__/optimizer/constant_fold.test.d.ts} +0 -0
- /package/dist/{__tests__/var-allocator.test.d.ts → src/__tests__/optimizer/copy_prop.test.d.ts} +0 -0
- /package/dist/{__tests__ → src/__tests__}/parser.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/repl.test.js +0 -0
- /package/dist/{__tests__ → src/__tests__}/typechecker.test.js +0 -0
- /package/dist/{ast → src/ast}/types.js +0 -0
- /package/dist/{builtins → src/builtins}/metadata.d.ts +0 -0
- /package/dist/{builtins → src/builtins}/metadata.js +0 -0
- /package/dist/{events → src/events}/types.d.ts +0 -0
- /package/dist/{events → src/events}/types.js +0 -0
- /package/dist/{formatter → src/formatter}/index.d.ts +0 -0
- /package/dist/{formatter → src/formatter}/index.js +0 -0
- /package/dist/{mc-test → src/mc-test}/client.d.ts +0 -0
- /package/dist/{mc-test → src/mc-test}/client.js +0 -0
- /package/dist/{mc-test → src/mc-test}/runner.d.ts +0 -0
- /package/dist/{mc-test → src/mc-test}/setup.d.ts +0 -0
- /package/dist/{mc-test → src/mc-test}/setup.js +0 -0
- /package/dist/{mc-validator → src/mc-validator}/index.d.ts +0 -0
- /package/dist/{mc-validator → src/mc-validator}/index.js +0 -0
- /package/dist/{nbt → src/nbt}/index.d.ts +0 -0
- /package/dist/{nbt → src/nbt}/index.js +0 -0
- /package/dist/{repl.js → src/repl.js} +0 -0
- /package/dist/{runtime → src/runtime}/index.d.ts +0 -0
- /package/dist/{types → src/types}/entity-hierarchy.d.ts +0 -0
- /package/dist/{types → src/types}/entity-hierarchy.js +0 -0
package/src/index.ts
CHANGED
|
@@ -1,205 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RedScript Compiler
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Main entry point for programmatic usage.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
export const version = '1.2.11'
|
|
7
|
+
export const version = '2.0.0'
|
|
9
8
|
|
|
10
|
-
import {
|
|
11
|
-
import { Parser } from './parser'
|
|
12
|
-
import { TypeChecker } from './typechecker'
|
|
13
|
-
import { Lowering, setScoreboardObjective } from './lowering'
|
|
14
|
-
import type { Warning } from './lowering'
|
|
15
|
-
import {
|
|
16
|
-
constantFoldingWithStats,
|
|
17
|
-
copyPropagation,
|
|
18
|
-
deadCodeEliminationWithStats,
|
|
19
|
-
} from './optimizer/passes'
|
|
20
|
-
import { eliminateDeadCode } from './optimizer/dce'
|
|
21
|
-
import {
|
|
22
|
-
countMcfunctionCommands,
|
|
23
|
-
generateDatapackWithStats,
|
|
24
|
-
DatapackFile,
|
|
25
|
-
} from './codegen/mcfunction'
|
|
26
|
-
import { preprocessSource, preprocessSourceWithMetadata } from './compile'
|
|
27
|
-
import type { IRModule } from './ir/types'
|
|
28
|
-
import type { Program } from './ast/types'
|
|
29
|
-
import type { DiagnosticError } from './diagnostics'
|
|
30
|
-
import { createEmptyOptimizationStats, type OptimizationStats } from './optimizer/commands'
|
|
9
|
+
import { compile } from './emit/compile'
|
|
31
10
|
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
mangle?: boolean
|
|
39
|
-
/** Scoreboard objective used for all variable slots.
|
|
40
|
-
* Defaults to '__<namespace>' (e.g. '__mathshow') to avoid collisions when
|
|
41
|
-
* multiple RedScript datapacks are loaded simultaneously, without occupying
|
|
42
|
-
* the user's own namespace. Override only if you need a specific name. */
|
|
43
|
-
scoreboardObjective?: string
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface CompileResult {
|
|
47
|
-
files: DatapackFile[]
|
|
48
|
-
advancements: DatapackFile[]
|
|
49
|
-
ast: Program
|
|
50
|
-
ir: IRModule
|
|
51
|
-
typeErrors?: DiagnosticError[]
|
|
52
|
-
warnings?: Warning[]
|
|
53
|
-
stats?: OptimizationStats
|
|
54
|
-
sourceMap?: Record<string, string>
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Compile RedScript source code to a Minecraft datapack.
|
|
59
|
-
*
|
|
60
|
-
* @param source - The RedScript source code
|
|
61
|
-
* @param options - Compilation options
|
|
62
|
-
* @returns Compiled datapack files
|
|
63
|
-
*/
|
|
64
|
-
export function compile(source: string, options: CompileOptions = {}): CompileResult {
|
|
65
|
-
const namespace = options.namespace ?? 'redscript'
|
|
66
|
-
const shouldOptimize = options.optimize ?? true
|
|
67
|
-
const shouldTypeCheck = options.typeCheck ?? true
|
|
68
|
-
const shouldRunDce = options.dce ?? shouldOptimize
|
|
69
|
-
const mangle = options.mangle ?? false
|
|
70
|
-
const filePath = options.filePath
|
|
71
|
-
const preprocessed = preprocessSourceWithMetadata(source, { filePath })
|
|
72
|
-
const preprocessedSource = preprocessed.source
|
|
73
|
-
|
|
74
|
-
// Lexing
|
|
75
|
-
const tokens = new Lexer(preprocessedSource, filePath).tokenize()
|
|
76
|
-
|
|
77
|
-
// Parsing — user source
|
|
78
|
-
const parsedAst = new Parser(tokens, preprocessedSource, filePath).parse(namespace)
|
|
79
|
-
|
|
80
|
-
// Library imports: files that declared `module library;` are parsed independently
|
|
81
|
-
// (fresh Parser per file) so their functions are DCE-eligible but never bleed into user code.
|
|
82
|
-
const allLibrarySources: Array<{ src: string; fp?: string }> = []
|
|
83
|
-
for (const li of preprocessed.libraryImports ?? []) {
|
|
84
|
-
allLibrarySources.push({ src: li.source, fp: li.filePath })
|
|
85
|
-
}
|
|
86
|
-
for (const { src, fp } of allLibrarySources) {
|
|
87
|
-
const libPreprocessed = preprocessSourceWithMetadata(src, fp ? { filePath: fp } : {})
|
|
88
|
-
const libTokens = new Lexer(libPreprocessed.source, fp).tokenize()
|
|
89
|
-
const libAst = new Parser(libTokens, libPreprocessed.source, fp).parse(namespace)
|
|
90
|
-
for (const fn of libAst.declarations) fn.isLibraryFn = true
|
|
91
|
-
parsedAst.declarations.push(...libAst.declarations)
|
|
92
|
-
parsedAst.structs.push(...libAst.structs)
|
|
93
|
-
parsedAst.implBlocks.push(...libAst.implBlocks)
|
|
94
|
-
parsedAst.enums.push(...libAst.enums)
|
|
95
|
-
parsedAst.consts.push(...libAst.consts)
|
|
96
|
-
parsedAst.globals.push(...libAst.globals)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const dceResult = shouldRunDce ? eliminateDeadCode(parsedAst, preprocessed.ranges) : { program: parsedAst, warnings: [] }
|
|
100
|
-
const ast = dceResult.program
|
|
101
|
-
|
|
102
|
-
// Type checking (warn mode - collect errors but don't block)
|
|
103
|
-
let typeErrors: DiagnosticError[] | undefined
|
|
104
|
-
if (shouldTypeCheck) {
|
|
105
|
-
const checker = new TypeChecker(preprocessedSource, filePath)
|
|
106
|
-
typeErrors = checker.check(ast)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Configure scoreboard objective for this compilation.
|
|
110
|
-
// Default: use the datapack namespace so each datapack gets its own objective
|
|
111
|
-
// automatically, preventing variable collisions when multiple datapacks coexist.
|
|
112
|
-
const scoreboardObj = options.scoreboardObjective ?? `__${namespace}`
|
|
113
|
-
setScoreboardObjective(scoreboardObj)
|
|
114
|
-
|
|
115
|
-
// Lowering to IR
|
|
116
|
-
const lowering = new Lowering(namespace, preprocessed.ranges)
|
|
117
|
-
const ir = lowering.lower(ast)
|
|
118
|
-
|
|
119
|
-
let optimizedIR: IRModule = ir
|
|
120
|
-
let generated = generateDatapackWithStats(ir, { optimizeCommands: shouldOptimize, mangle, scoreboardObjective: scoreboardObj })
|
|
121
|
-
let optimizationStats: OptimizationStats | undefined
|
|
122
|
-
|
|
123
|
-
if (shouldOptimize) {
|
|
124
|
-
const stats = createEmptyOptimizationStats()
|
|
125
|
-
const copyPropagatedFunctions = []
|
|
126
|
-
const deadCodeEliminatedFunctions = []
|
|
127
|
-
|
|
128
|
-
for (const fn of ir.functions) {
|
|
129
|
-
const folded = constantFoldingWithStats(fn)
|
|
130
|
-
stats.constantFolds += folded.stats.constantFolds ?? 0
|
|
11
|
+
// Re-export v2 compile API
|
|
12
|
+
export { compile, CompileOptions, CompileResult } from './emit/compile'
|
|
13
|
+
export { compileModules } from './emit/modules'
|
|
14
|
+
export type { ModuleInput, CompileModulesOptions, CompileModulesResult } from './emit/modules'
|
|
15
|
+
export { McVersion, parseMcVersion, compareMcVersion, DEFAULT_MC_VERSION } from './types/mc-version'
|
|
16
|
+
export type { DatapackFile } from './emit/index'
|
|
131
17
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const copyPropagatedIR: IRModule = { ...ir, functions: copyPropagatedFunctions }
|
|
140
|
-
optimizedIR = { ...ir, functions: deadCodeEliminatedFunctions }
|
|
141
|
-
|
|
142
|
-
const baselineGenerated = generateDatapackWithStats(ir, { optimizeCommands: false, mangle, scoreboardObjective: scoreboardObj })
|
|
143
|
-
const beforeDceGenerated = generateDatapackWithStats(copyPropagatedIR, { optimizeCommands: false, mangle, scoreboardObjective: scoreboardObj })
|
|
144
|
-
const afterDceGenerated = generateDatapackWithStats(optimizedIR, { optimizeCommands: false, mangle, scoreboardObjective: scoreboardObj })
|
|
145
|
-
generated = generateDatapackWithStats(optimizedIR, { optimizeCommands: true, mangle, scoreboardObjective: scoreboardObj })
|
|
18
|
+
// Re-export utilities
|
|
19
|
+
export { Lexer } from './lexer'
|
|
20
|
+
export { Parser } from './parser'
|
|
21
|
+
export { preprocessSource, preprocessSourceWithMetadata } from './compile'
|
|
22
|
+
export { MCCommandValidator } from './mc-validator'
|
|
23
|
+
export type { Program, FnDecl, Expr, Stmt, Span } from './ast/types'
|
|
24
|
+
export type { DiagnosticError } from './diagnostics'
|
|
146
25
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
stats.cseArithmetic = generated.stats.cseArithmetic
|
|
153
|
-
stats.setblockMergedCommands = generated.stats.setblockMergedCommands
|
|
154
|
-
stats.setblockFillCommands = generated.stats.setblockFillCommands
|
|
155
|
-
stats.setblockSavedCommands = generated.stats.setblockSavedCommands
|
|
156
|
-
stats.totalCommandsBefore = countMcfunctionCommands(baselineGenerated.files)
|
|
157
|
-
stats.totalCommandsAfter = countMcfunctionCommands(generated.files)
|
|
158
|
-
optimizationStats = stats
|
|
159
|
-
} else {
|
|
160
|
-
optimizedIR = ir
|
|
161
|
-
generated = generateDatapackWithStats(ir, { optimizeCommands: false, mangle, scoreboardObjective: scoreboardObj })
|
|
162
|
-
}
|
|
26
|
+
// Incremental compilation
|
|
27
|
+
export { FileCache, hashFile } from './cache/index'
|
|
28
|
+
export { DependencyGraph, parseImports } from './cache/deps'
|
|
29
|
+
export { compileIncremental, resetCompileCache } from './cache/incremental'
|
|
30
|
+
export type { IncrementalOptions, IncrementalResult } from './cache/incremental'
|
|
163
31
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
ast,
|
|
168
|
-
ir: optimizedIR,
|
|
169
|
-
typeErrors,
|
|
170
|
-
warnings: [...dceResult.warnings, ...lowering.warnings],
|
|
171
|
-
stats: optimizationStats,
|
|
172
|
-
sourceMap: generated.sourceMap,
|
|
173
|
-
}
|
|
32
|
+
export interface CheckResult {
|
|
33
|
+
error: Error | null
|
|
34
|
+
warnings: string[]
|
|
174
35
|
}
|
|
175
36
|
|
|
176
37
|
/**
|
|
177
38
|
* Check RedScript source code for errors without generating output.
|
|
178
|
-
*
|
|
39
|
+
* Runs the full compile pipeline (lex → parse → HIR → MIR → LIR → emit)
|
|
40
|
+
* to catch type-level and lowering errors, not just parse errors.
|
|
41
|
+
*
|
|
179
42
|
* @param source - The RedScript source code
|
|
180
43
|
* @param namespace - Optional namespace
|
|
181
44
|
* @returns null if no errors, or an error object
|
|
182
45
|
*/
|
|
183
46
|
export function check(source: string, namespace = 'redscript', filePath?: string): Error | null {
|
|
47
|
+
return checkWithWarnings(source, namespace, filePath).error
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Like check(), but also returns warnings (e.g., tick budget analysis).
|
|
52
|
+
*/
|
|
53
|
+
export function checkWithWarnings(source: string, namespace = 'redscript', filePath?: string): CheckResult {
|
|
184
54
|
try {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
new Parser(tokens, preprocessedSource, filePath).parse(namespace)
|
|
188
|
-
return null
|
|
55
|
+
const result = compile(source, { namespace, filePath })
|
|
56
|
+
return { error: null, warnings: result.warnings }
|
|
189
57
|
} catch (err) {
|
|
190
|
-
return err as Error
|
|
58
|
+
return { error: err as Error, warnings: [] }
|
|
191
59
|
}
|
|
192
60
|
}
|
|
193
|
-
|
|
194
|
-
// Re-export types and classes for advanced usage
|
|
195
|
-
export { Lexer } from './lexer'
|
|
196
|
-
export { Parser } from './parser'
|
|
197
|
-
export { TypeChecker } from './typechecker'
|
|
198
|
-
export { Lowering } from './lowering'
|
|
199
|
-
export { optimize } from './optimizer/passes'
|
|
200
|
-
export { generateDatapack } from './codegen/mcfunction'
|
|
201
|
-
export { MCCommandValidator } from './mc-validator'
|
|
202
|
-
export type { DatapackFile } from './codegen/mcfunction'
|
|
203
|
-
export type { IRModule, IRFunction } from './ir/types'
|
|
204
|
-
export type { Program, FnDecl, Expr, Stmt, Span } from './ast/types'
|
|
205
|
-
export type { DiagnosticError } from './diagnostics'
|
package/src/lexer/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ export type TokenKind =
|
|
|
16
16
|
// Keywords
|
|
17
17
|
| 'fn' | 'let' | 'const' | 'if' | 'else' | 'while' | 'for' | 'foreach' | 'match'
|
|
18
18
|
| 'return' | 'break' | 'continue' | 'as' | 'at' | 'in' | 'is' | 'struct' | 'impl' | 'enum' | 'trigger' | 'namespace' | 'module'
|
|
19
|
-
| 'execute' | 'run' | 'unless' | 'declare'
|
|
19
|
+
| 'execute' | 'run' | 'unless' | 'declare' | 'export'
|
|
20
20
|
// Types
|
|
21
21
|
| 'int' | 'bool' | 'float' | 'string' | 'void'
|
|
22
22
|
| 'BlockPos'
|
|
@@ -91,6 +91,7 @@ const KEYWORDS: Record<string, TokenKind> = {
|
|
|
91
91
|
run: 'run',
|
|
92
92
|
unless: 'unless',
|
|
93
93
|
declare: 'declare',
|
|
94
|
+
export: 'export',
|
|
94
95
|
int: 'int',
|
|
95
96
|
bool: 'bool',
|
|
96
97
|
float: 'float',
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static Tick Budget Analysis — Phase 1a
|
|
3
|
+
*
|
|
4
|
+
* Estimates the number of MC commands a function will execute at runtime.
|
|
5
|
+
* Used to warn when loops may exceed Minecraft's maxCommandChainLength (65536).
|
|
6
|
+
*
|
|
7
|
+
* In LIR, loops are represented as mutually-recursive function calls
|
|
8
|
+
* (e.g., fn__header ↔ fn__body). This module detects call-graph cycles
|
|
9
|
+
* and multiplies the loop body cost by an estimated iteration count.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { LIRModule, LIRFunction, LIRInstr } from './types'
|
|
13
|
+
|
|
14
|
+
/** Default estimated iteration count when the upper bound is unknown */
|
|
15
|
+
const DEFAULT_LOOP_ITERATIONS = 100
|
|
16
|
+
|
|
17
|
+
/** Warning threshold: suggest @coroutine */
|
|
18
|
+
export const BUDGET_WARN_THRESHOLD = 32768
|
|
19
|
+
|
|
20
|
+
/** Error threshold: likely exceeds maxCommandChainLength */
|
|
21
|
+
export const BUDGET_ERROR_THRESHOLD = 65536
|
|
22
|
+
|
|
23
|
+
export interface BudgetDiagnostic {
|
|
24
|
+
level: 'warning' | 'error'
|
|
25
|
+
fnName: string
|
|
26
|
+
estimatedCommands: number
|
|
27
|
+
message: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Call graph utilities
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/** Extract all function names called by an instruction */
|
|
35
|
+
function getCalledFunctions(instr: LIRInstr): string[] {
|
|
36
|
+
switch (instr.kind) {
|
|
37
|
+
case 'call':
|
|
38
|
+
case 'call_macro':
|
|
39
|
+
return [instr.fn]
|
|
40
|
+
case 'call_if_matches':
|
|
41
|
+
case 'call_unless_matches':
|
|
42
|
+
case 'call_if_score':
|
|
43
|
+
case 'call_unless_score':
|
|
44
|
+
case 'call_context':
|
|
45
|
+
return [instr.fn]
|
|
46
|
+
case 'store_cmd_to_score':
|
|
47
|
+
// The nested cmd may also be a call
|
|
48
|
+
return getCalledFunctions(instr.cmd)
|
|
49
|
+
default:
|
|
50
|
+
return []
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Build adjacency list: fnName → set of called function names (module-local only) */
|
|
55
|
+
function buildCallGraph(mod: LIRModule): Map<string, Set<string>> {
|
|
56
|
+
const fnNames = new Set(mod.functions.map(f => f.name))
|
|
57
|
+
const graph = new Map<string, Set<string>>()
|
|
58
|
+
|
|
59
|
+
for (const fn of mod.functions) {
|
|
60
|
+
const callees = new Set<string>()
|
|
61
|
+
for (const instr of fn.instructions) {
|
|
62
|
+
for (const callee of getCalledFunctions(instr)) {
|
|
63
|
+
// Strip namespace prefix to match local function names
|
|
64
|
+
const local = stripNamespace(callee, mod.namespace)
|
|
65
|
+
if (fnNames.has(local)) {
|
|
66
|
+
callees.add(local)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
graph.set(fn.name, callees)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return graph
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Strip "namespace:" prefix from a qualified function name */
|
|
77
|
+
function stripNamespace(qualifiedName: string, namespace: string): string {
|
|
78
|
+
const prefix = `${namespace}:`
|
|
79
|
+
if (qualifiedName.startsWith(prefix)) {
|
|
80
|
+
return qualifiedName.slice(prefix.length)
|
|
81
|
+
}
|
|
82
|
+
return qualifiedName
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Find all strongly connected components (Tarjan's algorithm) */
|
|
86
|
+
function findSCCs(graph: Map<string, Set<string>>): string[][] {
|
|
87
|
+
let index = 0
|
|
88
|
+
const stack: string[] = []
|
|
89
|
+
const onStack = new Set<string>()
|
|
90
|
+
const indices = new Map<string, number>()
|
|
91
|
+
const lowlinks = new Map<string, number>()
|
|
92
|
+
const sccs: string[][] = []
|
|
93
|
+
|
|
94
|
+
function strongconnect(v: string): void {
|
|
95
|
+
indices.set(v, index)
|
|
96
|
+
lowlinks.set(v, index)
|
|
97
|
+
index++
|
|
98
|
+
stack.push(v)
|
|
99
|
+
onStack.add(v)
|
|
100
|
+
|
|
101
|
+
for (const w of graph.get(v) ?? []) {
|
|
102
|
+
if (!indices.has(w)) {
|
|
103
|
+
strongconnect(w)
|
|
104
|
+
lowlinks.set(v, Math.min(lowlinks.get(v)!, lowlinks.get(w)!))
|
|
105
|
+
} else if (onStack.has(w)) {
|
|
106
|
+
lowlinks.set(v, Math.min(lowlinks.get(v)!, indices.get(w)!))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (lowlinks.get(v) === indices.get(v)) {
|
|
111
|
+
const scc: string[] = []
|
|
112
|
+
let w: string
|
|
113
|
+
do {
|
|
114
|
+
w = stack.pop()!
|
|
115
|
+
onStack.delete(w)
|
|
116
|
+
scc.push(w)
|
|
117
|
+
} while (w !== v)
|
|
118
|
+
sccs.push(scc)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const v of graph.keys()) {
|
|
123
|
+
if (!indices.has(v)) {
|
|
124
|
+
strongconnect(v)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return sccs
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Command count estimation
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
/** Count the number of MC commands an instruction generates (non-recursive) */
|
|
136
|
+
function instrCommandCount(instr: LIRInstr): number {
|
|
137
|
+
switch (instr.kind) {
|
|
138
|
+
case 'store_cmd_to_score':
|
|
139
|
+
// The execute store wrapper + the inner command
|
|
140
|
+
return 1
|
|
141
|
+
default:
|
|
142
|
+
// Each LIR instruction maps to ~1 MC command
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Count raw (non-call) commands in a function */
|
|
148
|
+
function localCommandCount(fn: LIRFunction): number {
|
|
149
|
+
let count = 0
|
|
150
|
+
for (const instr of fn.instructions) {
|
|
151
|
+
count += instrCommandCount(instr)
|
|
152
|
+
}
|
|
153
|
+
return count
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Try to extract a constant loop bound from a loop's LIR functions.
|
|
158
|
+
*
|
|
159
|
+
* Looks for patterns like:
|
|
160
|
+
* score_set <limit_slot> <N>
|
|
161
|
+
* in the cycle's functions, where N is used as a comparison bound.
|
|
162
|
+
*
|
|
163
|
+
* Returns the bound if found, otherwise DEFAULT_LOOP_ITERATIONS.
|
|
164
|
+
*/
|
|
165
|
+
function estimateLoopIterations(cycleFns: LIRFunction[]): number {
|
|
166
|
+
// Look for score_set instructions that might be loop bounds
|
|
167
|
+
// Heuristic: find the largest constant set in the cycle's callers
|
|
168
|
+
// that looks like a loop limit (typically set before the loop)
|
|
169
|
+
for (const fn of cycleFns) {
|
|
170
|
+
for (const instr of fn.instructions) {
|
|
171
|
+
if (instr.kind === 'call_if_matches' || instr.kind === 'call_unless_matches') {
|
|
172
|
+
// Parse range like "..999" or "0..999" to extract upper bound
|
|
173
|
+
const range = instr.range
|
|
174
|
+
const match = range.match(/\.\.(\d+)/)
|
|
175
|
+
if (match) {
|
|
176
|
+
return parseInt(match[1], 10) + 1
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return DEFAULT_LOOP_ITERATIONS
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Estimate the total command count for a function, including callees.
|
|
187
|
+
*
|
|
188
|
+
* @param fnName - Name of the function to estimate
|
|
189
|
+
* @param mod - The LIR module
|
|
190
|
+
* @returns Estimated number of MC commands
|
|
191
|
+
*/
|
|
192
|
+
export function estimateCommandCount(fnName: string, mod: LIRModule): number {
|
|
193
|
+
const fnMap = new Map<string, LIRFunction>()
|
|
194
|
+
for (const fn of mod.functions) {
|
|
195
|
+
fnMap.set(fn.name, fn)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const callGraph = buildCallGraph(mod)
|
|
199
|
+
const sccs = findSCCs(callGraph)
|
|
200
|
+
|
|
201
|
+
// Map each function to its SCC
|
|
202
|
+
const fnToSCC = new Map<string, string[]>()
|
|
203
|
+
for (const scc of sccs) {
|
|
204
|
+
for (const name of scc) {
|
|
205
|
+
fnToSCC.set(name, scc)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Memoize estimated counts
|
|
210
|
+
const memo = new Map<string, number>()
|
|
211
|
+
|
|
212
|
+
function estimate(name: string, visiting: Set<string>): number {
|
|
213
|
+
if (memo.has(name)) return memo.get(name)!
|
|
214
|
+
|
|
215
|
+
const fn = fnMap.get(name)
|
|
216
|
+
if (!fn) return 0
|
|
217
|
+
|
|
218
|
+
// Detect cycle: if we're already visiting this function, return 0
|
|
219
|
+
// (cycle cost is handled at the SCC level)
|
|
220
|
+
if (visiting.has(name)) return 0
|
|
221
|
+
|
|
222
|
+
visiting.add(name)
|
|
223
|
+
|
|
224
|
+
const scc = fnToSCC.get(name)!
|
|
225
|
+
const isCyclic = scc.length > 1 || (scc.length === 1 && callGraph.get(name)?.has(name))
|
|
226
|
+
|
|
227
|
+
if (isCyclic) {
|
|
228
|
+
// Sum local commands across all functions in the cycle
|
|
229
|
+
let cycleLocalCost = 0
|
|
230
|
+
for (const member of scc) {
|
|
231
|
+
const memberFn = fnMap.get(member)
|
|
232
|
+
if (memberFn) cycleLocalCost += localCommandCount(memberFn)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Estimate iterations
|
|
236
|
+
const cycleFns = scc.map(n => fnMap.get(n)!).filter(Boolean)
|
|
237
|
+
const iterations = estimateLoopIterations(cycleFns)
|
|
238
|
+
|
|
239
|
+
// Also add cost of non-cycle callees
|
|
240
|
+
let externalCalleeCost = 0
|
|
241
|
+
for (const member of scc) {
|
|
242
|
+
for (const callee of callGraph.get(member) ?? []) {
|
|
243
|
+
if (!scc.includes(callee)) {
|
|
244
|
+
externalCalleeCost += estimate(callee, new Set(visiting))
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const total = (cycleLocalCost + externalCalleeCost) * iterations
|
|
250
|
+
// Memoize for all members of this SCC
|
|
251
|
+
for (const member of scc) {
|
|
252
|
+
memo.set(member, total)
|
|
253
|
+
}
|
|
254
|
+
visiting.delete(name)
|
|
255
|
+
return total
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Non-cyclic: local cost + callee costs
|
|
259
|
+
let total = localCommandCount(fn)
|
|
260
|
+
for (const callee of callGraph.get(name) ?? []) {
|
|
261
|
+
total += estimate(callee, visiting)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
memo.set(name, total)
|
|
265
|
+
visiting.delete(name)
|
|
266
|
+
return total
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return estimate(fnName, new Set())
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// Budget analysis for a full module
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Analyze all "top-level" functions in the module for tick budget violations.
|
|
278
|
+
*
|
|
279
|
+
* @param mod - The LIR module to analyze
|
|
280
|
+
* @param coroutineFunctions - Set of function names marked @coroutine (skip these)
|
|
281
|
+
* @returns Array of budget diagnostics (warnings and errors)
|
|
282
|
+
*/
|
|
283
|
+
export function analyzeBudget(
|
|
284
|
+
mod: LIRModule,
|
|
285
|
+
coroutineFunctions: Set<string> = new Set(),
|
|
286
|
+
): BudgetDiagnostic[] {
|
|
287
|
+
const diagnostics: BudgetDiagnostic[] = []
|
|
288
|
+
|
|
289
|
+
// Only analyze user-defined "root" functions, not compiler-generated helper blocks
|
|
290
|
+
// Helper blocks have names like "fnname__blockid"
|
|
291
|
+
for (const fn of mod.functions) {
|
|
292
|
+
// Skip coroutine-annotated functions
|
|
293
|
+
if (coroutineFunctions.has(fn.name)) continue
|
|
294
|
+
|
|
295
|
+
// Skip compiler-generated helper functions (contain __)
|
|
296
|
+
if (fn.name.includes('__')) continue
|
|
297
|
+
|
|
298
|
+
// Skip coroutine-generated functions
|
|
299
|
+
if (fn.name.startsWith('_coro_')) continue
|
|
300
|
+
|
|
301
|
+
const estimated = estimateCommandCount(fn.name, mod)
|
|
302
|
+
|
|
303
|
+
if (estimated > BUDGET_ERROR_THRESHOLD) {
|
|
304
|
+
diagnostics.push({
|
|
305
|
+
level: 'error',
|
|
306
|
+
fnName: fn.name,
|
|
307
|
+
estimatedCommands: estimated,
|
|
308
|
+
message: `function '${fn.name}' may exceed tick budget (~${estimated} commands), this will likely crash. Consider @coroutine or reducing loop iterations`,
|
|
309
|
+
})
|
|
310
|
+
} else if (estimated > BUDGET_WARN_THRESHOLD) {
|
|
311
|
+
diagnostics.push({
|
|
312
|
+
level: 'warning',
|
|
313
|
+
fnName: fn.name,
|
|
314
|
+
estimatedCommands: estimated,
|
|
315
|
+
message: `loop may exceed tick budget (~${estimated} commands), consider @coroutine`,
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return diagnostics
|
|
321
|
+
}
|