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.
- package/.github/workflows/ci.yml +11 -0
- package/CHANGELOG.md +18 -9
- package/README-benchmarks.md +48 -0
- package/README-vscode-test.md +251 -0
- package/RELEASE_NOTES.md +74 -0
- package/ROADMAP.md +131 -167
- package/benchmarks/_shared.ts +468 -0
- package/benchmarks/baseline.json +2816 -0
- package/benchmarks/baseline.md +13 -0
- package/benchmarks/compiler-perf.report.json +207 -0
- package/benchmarks/compiler-perf.ts +76 -0
- package/benchmarks/results.md +13 -0
- package/benchmarks/stdlib-complexity.report.json +2606 -0
- package/benchmarks/stdlib-complexity.ts +54 -0
- package/benchmarks/stdlib-size.md +57 -0
- package/benchmarks/stdlib-size.ts +91 -0
- package/coverage-report.md +177 -0
- package/dist/src/__tests__/budget.test.js +4 -0
- package/dist/src/__tests__/cache/cache-behavior.test.d.ts +10 -0
- package/dist/src/__tests__/cache/cache-behavior.test.js +425 -0
- package/dist/src/__tests__/cache-extra.test.d.ts +5 -0
- package/dist/src/__tests__/cache-extra.test.js +211 -0
- package/dist/src/__tests__/cli-init.test.d.ts +1 -0
- package/dist/src/__tests__/cli-init.test.js +97 -0
- package/dist/src/__tests__/cli-publish.test.d.ts +9 -0
- package/dist/src/__tests__/cli-publish.test.js +189 -0
- package/dist/src/__tests__/cli.test.js +76 -0
- package/dist/src/__tests__/compile-preprocess.test.d.ts +11 -0
- package/dist/src/__tests__/compile-preprocess.test.js +328 -0
- package/dist/src/__tests__/compiler/break-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/break-stmt.test.js +58 -0
- package/dist/src/__tests__/compiler/const-decl.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/const-decl.test.js +123 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.js +67 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.d.ts +17 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.js +565 -0
- package/dist/src/__tests__/compiler/deprecated.test.d.ts +4 -0
- package/dist/src/__tests__/compiler/deprecated.test.js +285 -0
- package/dist/src/__tests__/compiler/do-while.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/do-while.test.js +120 -0
- package/dist/src/__tests__/compiler/enum-payload.test.d.ts +9 -0
- package/dist/src/__tests__/compiler/enum-payload.test.js +272 -0
- package/dist/src/__tests__/compiler/interface.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/interface.test.js +258 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.js +263 -0
- package/dist/src/__tests__/compiler/match-string.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/match-string.test.js +43 -0
- package/dist/src/__tests__/compiler/memoize.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/memoize.test.js +113 -0
- package/dist/src/__tests__/compiler/method-chain.test.d.ts +5 -0
- package/dist/src/__tests__/compiler/method-chain.test.js +115 -0
- package/dist/src/__tests__/compiler/module-import.test.d.ts +12 -0
- package/dist/src/__tests__/compiler/module-import.test.js +261 -0
- package/dist/src/__tests__/compiler/option-extensions.test.d.ts +6 -0
- package/dist/src/__tests__/compiler/option-extensions.test.js +191 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.js +69 -0
- package/dist/src/__tests__/compiler/string-advanced.test.d.ts +7 -0
- package/dist/src/__tests__/compiler/string-advanced.test.js +281 -0
- package/dist/src/__tests__/compiler/struct-extends.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/struct-extends.test.js +95 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.js +166 -0
- package/dist/src/__tests__/compiler/tuple-type.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/tuple-type.test.js +229 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.js +65 -0
- package/dist/src/__tests__/config/project-config.test.d.ts +1 -0
- package/dist/src/__tests__/config/project-config.test.js +199 -0
- package/dist/src/__tests__/config-decorator.test.d.ts +8 -0
- package/dist/src/__tests__/config-decorator.test.js +142 -0
- package/dist/src/__tests__/diagnostics-extra.test.d.ts +6 -0
- package/dist/src/__tests__/diagnostics-extra.test.js +132 -0
- package/dist/src/__tests__/emit/compile-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/compile-branches.test.js +123 -0
- package/dist/src/__tests__/emit/compile-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/emit/compile-coverage.test.js +617 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.d.ts +12 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.js +225 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.d.ts +0 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.js +238 -0
- package/dist/src/__tests__/emit/execute-chain.test.d.ts +10 -0
- package/dist/src/__tests__/emit/execute-chain.test.js +94 -0
- package/dist/src/__tests__/emit/index.test.js +2 -1
- package/dist/src/__tests__/emit/modules-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/modules-branches.test.js +88 -0
- package/dist/src/__tests__/emit/modules-coverage.test.d.ts +15 -0
- package/dist/src/__tests__/emit/modules-coverage.test.js +221 -0
- package/dist/src/__tests__/emit/modules-errors.test.d.ts +12 -0
- package/dist/src/__tests__/emit/modules-errors.test.js +169 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.d.ts +17 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.js +204 -0
- package/dist/src/__tests__/emit/source-map.test.d.ts +1 -0
- package/dist/src/__tests__/emit/source-map.test.js +167 -0
- package/dist/src/__tests__/enum.test.js +9 -4
- package/dist/src/__tests__/error-recovery.test.d.ts +7 -0
- package/dist/src/__tests__/error-recovery.test.js +217 -0
- package/dist/src/__tests__/events-types-extra.test.d.ts +10 -0
- package/dist/src/__tests__/events-types-extra.test.js +91 -0
- package/dist/src/__tests__/events-types.test.d.ts +4 -0
- package/dist/src/__tests__/events-types.test.js +56 -0
- package/dist/src/__tests__/formatter.test.js +13 -5
- package/dist/src/__tests__/hir/lower-extra.test.d.ts +9 -0
- package/dist/src/__tests__/hir/lower-extra.test.js +140 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.d.ts +15 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.js +200 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.d.ts +16 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.js +316 -0
- package/dist/src/__tests__/incremental.test.js +10 -2
- package/dist/src/__tests__/index-extra.test.d.ts +10 -0
- package/dist/src/__tests__/index-extra.test.js +71 -0
- package/dist/src/__tests__/lexer.test.js +2 -2
- package/dist/src/__tests__/lint/rules.test.d.ts +5 -0
- package/dist/src/__tests__/lint/rules.test.js +208 -0
- package/dist/src/__tests__/lir/lower.test.js +29 -0
- package/dist/src/__tests__/lir/verify.test.js +30 -0
- package/dist/src/__tests__/lsp/completion.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/completion.test.js +583 -0
- package/dist/src/__tests__/lsp/definition.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/definition.test.js +454 -0
- package/dist/src/__tests__/lsp/diagnostics.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/diagnostics.test.js +98 -0
- package/dist/src/__tests__/lsp/hover-docs.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/hover-docs.test.js +210 -0
- package/dist/src/__tests__/lsp.test.js +4 -1
- package/dist/src/__tests__/mc-integration/item-entity-events.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1227 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1509 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.d.ts +14 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1374 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.d.ts +10 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +759 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +855 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-integration/syntax-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-validator-coverage.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-coverage.test.js +296 -0
- package/dist/src/__tests__/mc-validator-extra.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-extra.test.js +245 -0
- package/dist/src/__tests__/mir/lower-extra.test.d.ts +20 -0
- package/dist/src/__tests__/mir/lower-extra.test.js +361 -0
- package/dist/src/__tests__/mir/lower-extra2.test.d.ts +17 -0
- package/dist/src/__tests__/mir/lower-extra2.test.js +317 -0
- package/dist/src/__tests__/mir/lower-extra3.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra3.test.js +249 -0
- package/dist/src/__tests__/mir/lower-extra4.test.d.ts +23 -0
- package/dist/src/__tests__/mir/lower-extra4.test.js +606 -0
- package/dist/src/__tests__/mir/lower-extra5.test.d.ts +25 -0
- package/dist/src/__tests__/mir/lower-extra5.test.js +543 -0
- package/dist/src/__tests__/mir/lower-extra6.test.d.ts +16 -0
- package/dist/src/__tests__/mir/lower-extra6.test.js +471 -0
- package/dist/src/__tests__/mir/lower-extra7.test.d.ts +35 -0
- package/dist/src/__tests__/mir/lower-extra7.test.js +921 -0
- package/dist/src/__tests__/mir/lower-extra8.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra8.test.js +626 -0
- package/dist/src/__tests__/mir/lower-extra9.test.d.ts +14 -0
- package/dist/src/__tests__/mir/lower-extra9.test.js +717 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.js +176 -0
- package/dist/src/__tests__/optimizer/cse.test.d.ts +4 -0
- package/dist/src/__tests__/optimizer/cse.test.js +178 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.js +221 -0
- package/dist/src/__tests__/optimizer/licm.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/licm.test.js +244 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.d.ts +12 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.js +993 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.js +86 -0
- package/dist/src/__tests__/optimizer/tco.test.d.ts +14 -0
- package/dist/src/__tests__/optimizer/tco.test.js +203 -0
- package/dist/src/__tests__/parser-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/parser-coverage.test.js +491 -0
- package/dist/src/__tests__/parser-extra.test.d.ts +6 -0
- package/dist/src/__tests__/parser-extra.test.js +451 -0
- package/dist/src/__tests__/parser.test.js +12 -0
- package/dist/src/__tests__/repl-extra.test.d.ts +13 -0
- package/dist/src/__tests__/repl-extra.test.js +174 -0
- package/dist/src/__tests__/repl-server-extra.test.d.ts +10 -0
- package/dist/src/__tests__/repl-server-extra.test.js +161 -0
- package/dist/src/__tests__/repl-server.test.d.ts +6 -0
- package/dist/src/__tests__/repl-server.test.js +146 -0
- package/dist/src/__tests__/runtime-extra.test.d.ts +15 -0
- package/dist/src/__tests__/runtime-extra.test.js +732 -0
- package/dist/src/__tests__/singleton-decorator.test.d.ts +11 -0
- package/dist/src/__tests__/singleton-decorator.test.js +260 -0
- package/dist/src/__tests__/sourcemap.test.js +1 -1
- package/dist/src/__tests__/stdlib/advanced.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/advanced.test.js +301 -0
- package/dist/src/__tests__/stdlib/bigint.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bigint.test.js +83 -0
- package/dist/src/__tests__/stdlib/bits.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bits.test.js +96 -0
- package/dist/src/__tests__/stdlib/bossbar.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bossbar.test.js +72 -0
- package/dist/src/__tests__/stdlib/color.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/color.test.js +84 -0
- package/dist/src/__tests__/stdlib/combat.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/combat.test.js +64 -0
- package/dist/src/__tests__/stdlib/cooldown.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/cooldown.test.js +64 -0
- package/dist/src/__tests__/stdlib/dialog.test.js +15 -7
- package/dist/src/__tests__/stdlib/ecs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ecs.test.js +81 -0
- package/dist/src/__tests__/stdlib/effects.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/effects.test.js +72 -0
- package/dist/src/__tests__/stdlib/events.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/events.test.js +55 -0
- package/dist/src/__tests__/stdlib/expr.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/expr.test.js +77 -0
- package/dist/src/__tests__/stdlib/fft.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/fft.test.js +82 -0
- package/dist/src/__tests__/stdlib/graph.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/graph.test.js +102 -0
- package/dist/src/__tests__/stdlib/interactions.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/interactions.test.js +60 -0
- package/dist/src/__tests__/stdlib/inventory.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/inventory.test.js +68 -0
- package/dist/src/__tests__/stdlib/linalg.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/linalg.test.js +78 -0
- package/dist/src/__tests__/stdlib/map.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/map.test.js +84 -0
- package/dist/src/__tests__/stdlib/math.test.js +19 -6
- package/dist/src/__tests__/stdlib/math_hp.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/math_hp.test.js +80 -0
- package/dist/src/__tests__/stdlib/mobs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/mobs.test.js +61 -0
- package/dist/src/__tests__/stdlib/noise.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/noise.test.js +73 -0
- package/dist/src/__tests__/stdlib/ode.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ode.test.js +68 -0
- package/dist/src/__tests__/stdlib/parabola.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/parabola.test.js +77 -0
- package/dist/src/__tests__/stdlib/particles.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/particles.test.js +68 -0
- package/dist/src/__tests__/stdlib/physics.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/physics.test.js +76 -0
- package/dist/src/__tests__/stdlib/player.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/player.test.js +64 -0
- package/dist/src/__tests__/stdlib/quaternion.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/quaternion.test.js +73 -0
- package/dist/src/__tests__/stdlib/queue.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/queue.test.js +97 -0
- package/dist/src/__tests__/stdlib/random.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/random.test.js +76 -0
- package/dist/src/__tests__/stdlib/result.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/result.test.js +329 -0
- package/dist/src/__tests__/stdlib/scheduler.test.js +19 -8
- package/dist/src/__tests__/stdlib/set_int.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/set_int.test.js +88 -0
- package/dist/src/__tests__/stdlib/sets.test.d.ts +6 -0
- package/dist/src/__tests__/stdlib/sets.test.js +60 -0
- package/dist/src/__tests__/stdlib/signal.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/signal.test.js +84 -0
- package/dist/src/__tests__/stdlib/spawn.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/spawn.test.js +68 -0
- package/dist/src/__tests__/stdlib/string.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/string.test.js +231 -0
- package/dist/src/__tests__/stdlib/strings.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/strings.test.js +83 -0
- package/dist/src/__tests__/stdlib/tags.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/tags.test.js +57 -0
- package/dist/src/__tests__/stdlib/teams.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/teams.test.js +72 -0
- package/dist/src/__tests__/stdlib/timer.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/timer.test.js +79 -0
- package/dist/src/__tests__/stdlib/vec.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/vec.test.js +94 -0
- package/dist/src/__tests__/stdlib/world.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/world.test.js +72 -0
- package/dist/src/__tests__/struct-display.test.d.ts +1 -0
- package/dist/src/__tests__/struct-display.test.js +64 -0
- package/dist/src/__tests__/test-framework/runner.test.d.ts +10 -0
- package/dist/src/__tests__/test-framework/runner.test.js +193 -0
- package/dist/src/__tests__/tuner/adapters.test.d.ts +14 -0
- package/dist/src/__tests__/tuner/adapters.test.js +194 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.d.ts +4 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.js +193 -0
- package/dist/src/__tests__/typechecker-coverage.test.d.ts +30 -0
- package/dist/src/__tests__/typechecker-coverage.test.js +627 -0
- package/dist/src/__tests__/typechecker.test.js +3 -3
- package/dist/src/__tests__/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/watch-decorator.test.js +54 -0
- package/dist/src/ast/types.d.ts +102 -3
- package/dist/src/cache/incremental.d.ts +13 -14
- package/dist/src/cache/incremental.js +106 -89
- package/dist/src/cache/index.d.ts +8 -2
- package/dist/src/cache/index.js +18 -6
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +466 -17
- package/dist/src/config/project-config.d.ts +29 -0
- package/dist/src/config/project-config.js +180 -0
- package/dist/src/diagnostics/index.d.ts +9 -0
- package/dist/src/diagnostics/index.js +18 -1
- package/dist/src/emit/compile.d.ts +10 -0
- package/dist/src/emit/compile.js +395 -50
- package/dist/src/emit/index.d.ts +40 -0
- package/dist/src/emit/index.js +307 -14
- package/dist/src/emit/modules.js +21 -3
- package/dist/src/emit/sourcemap.d.ts +23 -27
- package/dist/src/emit/sourcemap.js +52 -30
- package/dist/src/formatter/index.js +33 -8
- package/dist/src/hir/deprecated.d.ts +13 -0
- package/dist/src/hir/deprecated.js +218 -0
- package/dist/src/hir/lower.js +114 -8
- package/dist/src/hir/monomorphize.js +22 -2
- package/dist/src/hir/types.d.ts +65 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +18 -3
- package/dist/src/lexer/index.d.ts +2 -1
- package/dist/src/lexer/index.js +39 -3
- package/dist/src/lint/index.d.ts +45 -0
- package/dist/src/lint/index.js +930 -0
- package/dist/src/lir/lower.js +29 -2
- package/dist/src/lir/types.d.ts +2 -0
- package/dist/src/lsp/server.js +92 -5
- package/dist/src/mir/lower.js +775 -34
- package/dist/src/mir/macro.js +36 -2
- package/dist/src/mir/types.d.ts +12 -0
- package/dist/src/mir/verify.js +9 -0
- package/dist/src/optimizer/auto-inline.d.ts +2 -0
- package/dist/src/optimizer/auto-inline.js +67 -0
- package/dist/src/optimizer/cse.d.ts +20 -0
- package/dist/src/optimizer/cse.js +234 -0
- package/dist/src/optimizer/inline.d.ts +26 -0
- package/dist/src/optimizer/inline.js +286 -0
- package/dist/src/optimizer/interprocedural.js +4 -0
- package/dist/src/optimizer/licm.d.ts +32 -0
- package/dist/src/optimizer/licm.js +371 -0
- package/dist/src/optimizer/pipeline.js +12 -2
- package/dist/src/optimizer/strength_reduction.d.ts +15 -0
- package/dist/src/optimizer/strength_reduction.js +90 -0
- package/dist/src/optimizer/tco.d.ts +53 -0
- package/dist/src/optimizer/tco.js +238 -0
- package/dist/src/parser/index.d.ts +32 -0
- package/dist/src/parser/index.js +421 -59
- package/dist/src/repl-server.d.ts +13 -0
- package/dist/src/repl-server.js +127 -0
- package/dist/src/structs/expand.d.ts +15 -0
- package/dist/src/structs/expand.js +46 -0
- package/dist/src/testing/runner.d.ts +40 -0
- package/dist/src/testing/runner.js +237 -0
- package/dist/src/typechecker/index.d.ts +3 -0
- package/dist/src/typechecker/index.js +254 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/doc-drafts/redscript-docs/docs/en/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/quaternion.md +135 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/quaternion.md +135 -0
- package/docs/stdlib/result.md +156 -0
- package/docs/stdlib/result.zh.md +156 -0
- package/editors/vscode/fixtures/test.mcrs +7 -0
- package/editors/vscode/out/extension.js +2095 -225
- package/editors/vscode/out/lsp-server.js +519 -51
- package/editors/vscode/package-lock.json +9 -4
- package/editors/vscode/package.json +1 -1
- package/examples/display-demo.mcrs +64 -0
- package/examples/game/racing.mcrs +301 -0
- package/examples/game/tower_defense.mcrs +311 -0
- package/examples/math/physics_sim.mcrs +322 -0
- package/examples/rpg/boss_fight.mcrs +313 -0
- package/examples/rpg/health_system.mcrs +237 -0
- package/examples/rpg/inventory.mcrs +265 -0
- package/examples/util/debug_hud.mcrs +279 -0
- package/jest.config.js +10 -0
- package/package.json +12 -3
- package/playground/index.html +823 -0
- package/scripts/gen-docs.ts +533 -0
- package/scripts/update-redscript-docs-stdlib.sh +770 -0
- package/src/__tests__/budget.test.ts +5 -0
- package/src/__tests__/cache/cache-behavior.test.ts +480 -0
- package/src/__tests__/cache-extra.test.ts +199 -0
- package/src/__tests__/cli-docs.test.ts +77 -0
- package/src/__tests__/cli-init.test.ts +91 -0
- package/src/__tests__/cli-publish.test.ts +190 -0
- package/src/__tests__/cli.test.ts +117 -1
- package/src/__tests__/compile-preprocess.test.ts +366 -0
- package/src/__tests__/compiler/break-stmt.test.ts +66 -0
- package/src/__tests__/compiler/const-decl.test.ts +141 -0
- package/src/__tests__/compiler/continue-stmt.test.ts +81 -0
- package/src/__tests__/compiler/coroutine-extended.test.ts +723 -0
- package/src/__tests__/compiler/deprecated.test.ts +305 -0
- package/src/__tests__/compiler/do-while.test.ts +130 -0
- package/src/__tests__/compiler/enum-payload.test.ts +299 -0
- package/src/__tests__/compiler/interface.test.ts +287 -0
- package/src/__tests__/compiler/labeled-loops.test.ts +279 -0
- package/src/__tests__/compiler/match-string.test.ts +45 -0
- package/src/__tests__/compiler/memoize.test.ts +126 -0
- package/src/__tests__/compiler/method-chain.test.ts +121 -0
- package/src/__tests__/compiler/module-import.test.ts +240 -0
- package/src/__tests__/compiler/option-extensions.test.ts +207 -0
- package/src/__tests__/compiler/profile-decorator.test.ts +79 -0
- package/src/__tests__/compiler/string-advanced.test.ts +310 -0
- package/src/__tests__/compiler/struct-extends.test.ts +109 -0
- package/src/__tests__/compiler/throttle-retry.test.ts +191 -0
- package/src/__tests__/compiler/tuple-type.test.ts +263 -0
- package/src/__tests__/compiler/watch-decorator.test.ts +72 -0
- package/src/__tests__/config/project-config.test.ts +181 -0
- package/src/__tests__/config-decorator.test.ts +157 -0
- package/src/__tests__/diagnostics-extra.test.ts +155 -0
- package/src/__tests__/emit/compile-branches.test.ts +135 -0
- package/src/__tests__/emit/compile-coverage.test.ts +696 -0
- package/src/__tests__/emit/compile-extra-branches.test.ts +228 -0
- package/src/__tests__/emit/compile-mocked-branches.test.ts +249 -0
- package/src/__tests__/emit/compile.test.ts +6 -1
- package/src/__tests__/emit/execute-chain.test.ts +114 -0
- package/src/__tests__/emit/index.test.ts +2 -1
- package/src/__tests__/emit/modules-branches.test.ts +90 -0
- package/src/__tests__/emit/modules-coverage.test.ts +241 -0
- package/src/__tests__/emit/modules-errors.test.ts +192 -0
- package/src/__tests__/emit/modules-rewrite.test.ts +232 -0
- package/src/__tests__/emit/source-map.test.ts +152 -0
- package/src/__tests__/enum.test.ts +9 -4
- package/src/__tests__/error-recovery.test.ts +226 -0
- package/src/__tests__/events-types-extra.test.ts +110 -0
- package/src/__tests__/events-types.test.ts +66 -0
- package/src/__tests__/formatter.test.ts +15 -5
- package/src/__tests__/generics.test.ts +16 -9
- package/src/__tests__/hir/lower-extra.test.ts +151 -0
- package/src/__tests__/hir/monomorphize-coverage.test.ts +432 -0
- package/src/__tests__/hir/monomorphize-extra.test.ts +220 -0
- package/src/__tests__/hir/monomorphize-extra2.test.ts +350 -0
- package/src/__tests__/impl.test.ts +12 -8
- package/src/__tests__/incremental.test.ts +10 -2
- package/src/__tests__/index-extra.test.ts +79 -0
- package/src/__tests__/lexer.test.ts +2 -2
- package/src/__tests__/lint/hir-coverage.test.ts +1716 -0
- package/src/__tests__/lint/rules-coverage.test.ts +598 -0
- package/src/__tests__/lint/rules.test.ts +230 -0
- package/src/__tests__/lir/lower.test.ts +33 -0
- package/src/__tests__/lir/verify.test.ts +33 -0
- package/src/__tests__/lsp/completion.test.ts +687 -0
- package/src/__tests__/lsp/definition.test.ts +499 -0
- package/src/__tests__/lsp/diagnostics.test.ts +108 -0
- package/src/__tests__/lsp/hover-docs.test.ts +222 -0
- package/src/__tests__/lsp.test.ts +4 -1
- package/src/__tests__/mc-integration/item-entity-events.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1105 -0
- package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1366 -0
- package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1245 -0
- package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +755 -0
- package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +771 -0
- package/src/__tests__/mc-integration/stdlib-coverage.test.ts +5 -0
- package/src/__tests__/mc-integration/syntax-coverage.test.ts +5 -0
- package/src/__tests__/mc-validator-coverage.test.ts +325 -0
- package/src/__tests__/mc-validator-extra.test.ts +252 -0
- package/src/__tests__/mir/lower-extra.test.ts +402 -0
- package/src/__tests__/mir/lower-extra2.test.ts +348 -0
- package/src/__tests__/mir/lower-extra3.test.ts +277 -0
- package/src/__tests__/mir/lower-extra4.test.ts +636 -0
- package/src/__tests__/mir/lower-extra5.test.ts +612 -0
- package/src/__tests__/mir/lower-extra6.test.ts +520 -0
- package/src/__tests__/mir/lower-extra7.test.ts +1045 -0
- package/src/__tests__/mir/lower-extra8.test.ts +704 -0
- package/src/__tests__/mir/lower-extra9.test.ts +821 -0
- package/src/__tests__/optimizer/auto-inline.test.ts +206 -0
- package/src/__tests__/optimizer/cse.test.ts +195 -0
- package/src/__tests__/optimizer/inline_fn.test.ts +263 -0
- package/src/__tests__/optimizer/licm.test.ts +358 -0
- package/src/__tests__/optimizer/nbt-coalesce.test.ts +147 -0
- package/src/__tests__/optimizer/optimizer-extended.test.ts +1081 -0
- package/src/__tests__/optimizer/scoreboard-batch.test.ts +141 -0
- package/src/__tests__/optimizer/strength-reduction.test.ts +111 -0
- package/src/__tests__/optimizer/tco-coverage.test.ts +309 -0
- package/src/__tests__/optimizer/tco.test.ts +238 -0
- package/src/__tests__/option.test.ts +14 -7
- package/src/__tests__/parser-coverage.test.ts +576 -0
- package/src/__tests__/parser-extra.test.ts +531 -0
- package/src/__tests__/parser.test.ts +14 -0
- package/src/__tests__/repl-extra.test.ts +195 -0
- package/src/__tests__/repl-server-extra.test.ts +150 -0
- package/src/__tests__/repl-server.test.ts +122 -0
- package/src/__tests__/runtime-extra.test.ts +862 -0
- package/src/__tests__/singleton-decorator.test.ts +285 -0
- package/src/__tests__/sourcemap.test.ts +1 -1
- package/src/__tests__/stdlib/advanced.test.ts +312 -0
- package/src/__tests__/stdlib/bigint.test.ts +57 -0
- package/src/__tests__/stdlib/bits.test.ts +75 -0
- package/src/__tests__/stdlib/bossbar.test.ts +45 -0
- package/src/__tests__/stdlib/color.test.ts +60 -0
- package/src/__tests__/stdlib/combat.test.ts +35 -0
- package/src/__tests__/stdlib/cooldown.test.ts +35 -0
- package/src/__tests__/stdlib/dialog.test.ts +14 -6
- package/src/__tests__/stdlib/ecs.test.ts +54 -0
- package/src/__tests__/stdlib/effects.test.ts +45 -0
- package/src/__tests__/stdlib/events.test.ts +23 -0
- package/src/__tests__/stdlib/expr.test.ts +48 -0
- package/src/__tests__/stdlib/fft.test.ts +54 -0
- package/src/__tests__/stdlib/graph.test.ts +77 -0
- package/src/__tests__/stdlib/interactions.test.ts +30 -0
- package/src/__tests__/stdlib/inventory.test.ts +40 -0
- package/src/__tests__/stdlib/linalg.test.ts +52 -0
- package/src/__tests__/stdlib/map.test.ts +55 -0
- package/src/__tests__/stdlib/math.test.ts +19 -5
- package/src/__tests__/stdlib/math_hp.test.ts +55 -0
- package/src/__tests__/stdlib/mobs.test.ts +40 -0
- package/src/__tests__/stdlib/noise.test.ts +46 -0
- package/src/__tests__/stdlib/ode.test.ts +40 -0
- package/src/__tests__/stdlib/parabola.test.ts +51 -0
- package/src/__tests__/stdlib/particles.test.ts +40 -0
- package/src/__tests__/stdlib/physics.test.ts +50 -0
- package/src/__tests__/stdlib/player.test.ts +35 -0
- package/src/__tests__/stdlib/quaternion.test.ts +46 -0
- package/src/__tests__/stdlib/queue.test.ts +73 -0
- package/src/__tests__/stdlib/random.test.ts +50 -0
- package/src/__tests__/stdlib/result.test.ts +326 -0
- package/src/__tests__/stdlib/scheduler.test.ts +18 -7
- package/src/__tests__/stdlib/set_int.test.ts +62 -0
- package/src/__tests__/stdlib/sets.test.ts +28 -0
- package/src/__tests__/stdlib/signal.test.ts +60 -0
- package/src/__tests__/stdlib/spawn.test.ts +40 -0
- package/src/__tests__/stdlib/string.test.ts +224 -0
- package/src/__tests__/stdlib/strings.test.ts +55 -0
- package/src/__tests__/stdlib/tags.test.ts +32 -0
- package/src/__tests__/stdlib/teams.test.ts +45 -0
- package/src/__tests__/stdlib/timer.test.ts +53 -0
- package/src/__tests__/stdlib/vec.test.ts +72 -0
- package/src/__tests__/stdlib/world.test.ts +45 -0
- package/src/__tests__/struct-display.test.ts +69 -0
- package/src/__tests__/test-framework/runner.test.ts +208 -0
- package/src/__tests__/tuner/adapters.test.ts +232 -0
- package/src/__tests__/tuner/simulator-extra.test.ts +222 -0
- package/src/__tests__/tuple.test.ts +11 -4
- package/src/__tests__/typechecker-coverage.test.ts +671 -0
- package/src/__tests__/typechecker.test.ts +4 -3
- package/src/__tests__/watch-decorator.test.ts +59 -0
- package/src/ast/types.ts +65 -3
- package/src/cache/incremental.ts +128 -99
- package/src/cache/index.ts +35 -8
- package/src/cli.ts +538 -29
- package/src/config/project-config.ts +176 -0
- package/src/diagnostics/index.ts +22 -0
- package/src/docs.ts +98 -0
- package/src/emit/compile.ts +408 -51
- package/src/emit/index.ts +366 -18
- package/src/emit/modules.ts +19 -3
- package/src/emit/sourcemap.ts +64 -43
- package/src/formatter/index.ts +35 -8
- package/src/hir/deprecated.ts +212 -0
- package/src/hir/lower.ts +128 -8
- package/src/hir/monomorphize.ts +24 -2
- package/src/hir/types.ts +26 -1
- package/src/index.ts +23 -3
- package/src/lexer/index.ts +45 -6
- package/src/lint/index.ts +922 -0
- package/src/lir/lower.ts +30 -2
- package/src/lir/types.ts +4 -0
- package/src/lsp/server.ts +100 -1
- package/src/mir/lower.ts +785 -40
- package/src/mir/macro.ts +30 -2
- package/src/mir/types.ts +13 -0
- package/src/mir/verify.ts +10 -2
- package/src/optimizer/auto-inline.ts +86 -0
- package/src/optimizer/copy_prop.ts +2 -2
- package/src/optimizer/coroutine.ts +3 -3
- package/src/optimizer/cse.ts +205 -0
- package/src/optimizer/dce.ts +2 -2
- package/src/optimizer/inline.ts +335 -0
- package/src/optimizer/interprocedural.ts +5 -1
- package/src/optimizer/licm.ts +454 -0
- package/src/optimizer/nbt-coalesce.ts +109 -0
- package/src/optimizer/pipeline.ts +16 -2
- package/src/optimizer/scoreboard-batch.ts +52 -0
- package/src/optimizer/strength_reduction.ts +95 -0
- package/src/optimizer/tco.ts +267 -0
- package/src/optimizer/unroll.ts +2 -2
- package/src/parser/index.ts +426 -53
- package/src/repl-server.ts +102 -0
- package/src/stdlib/advanced.mcrs +271 -101
- package/src/stdlib/bigint.mcrs +97 -11
- package/src/stdlib/bits.mcrs +75 -12
- package/src/stdlib/bossbar.mcrs +37 -8
- package/src/stdlib/calculus.mcrs +82 -26
- package/src/stdlib/color.mcrs +98 -16
- package/src/stdlib/combat.mcrs +23 -5
- package/src/stdlib/cooldown.mcrs +19 -0
- package/src/stdlib/dialog.mcrs +45 -7
- package/src/stdlib/easing.mcrs +132 -12
- package/src/stdlib/ecs.mcrs +142 -25
- package/src/stdlib/effects.mcrs +88 -12
- package/src/stdlib/events.mcrs +21 -2
- package/src/stdlib/expr.mcrs +18 -3
- package/src/stdlib/fft.mcrs +66 -56
- package/src/stdlib/geometry.mcrs +137 -39
- package/src/stdlib/graph.mcrs +73 -0
- package/src/stdlib/heap.mcrs +49 -8
- package/src/stdlib/i18n/zh.yaml +2891 -0
- package/src/stdlib/interactions.mcrs +43 -20
- package/src/stdlib/inventory.mcrs +14 -3
- package/src/stdlib/linalg.mcrs +185 -30
- package/src/stdlib/list.mcrs +168 -18
- package/src/stdlib/map.mcrs +112 -0
- package/src/stdlib/math.mcrs +68 -18
- package/src/stdlib/math_hp.mcrs +124 -33
- package/src/stdlib/matrix.mcrs +133 -20
- package/src/stdlib/mobs.mcrs +87 -0
- package/src/stdlib/noise.mcrs +65 -21
- package/src/stdlib/ode.mcrs +96 -0
- package/src/stdlib/parabola.mcrs +104 -29
- package/src/stdlib/particles.mcrs +78 -21
- package/src/stdlib/pathfind.mcrs +89 -35
- package/src/stdlib/physics.mcrs +134 -26
- package/src/stdlib/player.mcrs +18 -0
- package/src/stdlib/quaternion.mcrs +213 -9
- package/src/stdlib/queue.mcrs +123 -0
- package/src/stdlib/random.mcrs +63 -18
- package/src/stdlib/result.mcrs +111 -0
- package/src/stdlib/scheduler.mcrs +59 -10
- package/src/stdlib/set_int.mcrs +240 -0
- package/src/stdlib/sets.mcrs +49 -19
- package/src/stdlib/signal.mcrs +151 -79
- package/src/stdlib/sort.mcrs +44 -24
- package/src/stdlib/spawn.mcrs +30 -7
- package/src/stdlib/state.mcrs +40 -5
- package/src/stdlib/strings.mcrs +131 -3
- package/src/stdlib/tags.mcrs +2 -2
- package/src/stdlib/teams.mcrs +22 -10
- package/src/stdlib/timer.mcrs +36 -6
- package/src/stdlib/vec.mcrs +44 -9
- package/src/stdlib/world.mcrs +57 -25
- package/src/structs/expand.ts +64 -0
- package/src/testing/runner.ts +271 -0
- package/src/typechecker/index.ts +273 -9
package/dist/src/mir/lower.js
CHANGED
|
@@ -8,34 +8,89 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.lowerToMIR = lowerToMIR;
|
|
10
10
|
const macro_1 = require("./macro");
|
|
11
|
+
function formatTypeNode(type) {
|
|
12
|
+
switch (type.kind) {
|
|
13
|
+
case 'named':
|
|
14
|
+
return type.name;
|
|
15
|
+
case 'array':
|
|
16
|
+
return `${formatTypeNode(type.elem)}[]`;
|
|
17
|
+
case 'struct':
|
|
18
|
+
case 'enum':
|
|
19
|
+
return type.name;
|
|
20
|
+
case 'function_type':
|
|
21
|
+
return `fn(${type.params.map(formatTypeNode).join(', ')}) -> ${formatTypeNode(type.return)}`;
|
|
22
|
+
case 'entity':
|
|
23
|
+
return type.entityType;
|
|
24
|
+
case 'selector':
|
|
25
|
+
return type.entityType ? `selector<${type.entityType}>` : 'selector';
|
|
26
|
+
case 'tuple':
|
|
27
|
+
return `(${type.elements.map(formatTypeNode).join(', ')})`;
|
|
28
|
+
case 'option':
|
|
29
|
+
return `Option<${formatTypeNode(type.inner)}>`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function formatFunctionSignature(fn) {
|
|
33
|
+
const params = fn.params
|
|
34
|
+
.map(param => `${param.name}: ${formatTypeNode(param.type)}`)
|
|
35
|
+
.join(', ');
|
|
36
|
+
return `fn ${fn.name}(${params}) -> ${formatTypeNode(fn.returnType)}`;
|
|
37
|
+
}
|
|
11
38
|
// ---------------------------------------------------------------------------
|
|
12
39
|
// Public API
|
|
13
40
|
// ---------------------------------------------------------------------------
|
|
14
41
|
function lowerToMIR(hir, sourceFile) {
|
|
15
42
|
// Build struct definitions: name → field names
|
|
16
43
|
const structDefs = new Map();
|
|
44
|
+
// Track @singleton struct names for special expansion of GameState::set(gs) calls
|
|
45
|
+
const singletonStructs = new Set();
|
|
17
46
|
for (const s of hir.structs) {
|
|
18
47
|
structDefs.set(s.name, s.fields.map(f => f.name));
|
|
48
|
+
if (s.isSingleton)
|
|
49
|
+
singletonStructs.add(s.name);
|
|
19
50
|
}
|
|
20
51
|
// Build enum definitions: enumName → variantName → integer value
|
|
21
52
|
const enumDefs = new Map();
|
|
53
|
+
// Build enum payload info: enumName → variantName → field list
|
|
54
|
+
const enumPayloads = new Map();
|
|
22
55
|
for (const e of hir.enums) {
|
|
23
56
|
const variants = new Map();
|
|
57
|
+
const payloads = new Map();
|
|
24
58
|
for (const v of e.variants) {
|
|
25
59
|
variants.set(v.name, v.value ?? 0);
|
|
60
|
+
if (v.fields && v.fields.length > 0) {
|
|
61
|
+
payloads.set(v.name, v.fields);
|
|
62
|
+
}
|
|
26
63
|
}
|
|
27
64
|
enumDefs.set(e.name, variants);
|
|
65
|
+
if (payloads.size > 0) {
|
|
66
|
+
enumPayloads.set(e.name, payloads);
|
|
67
|
+
}
|
|
28
68
|
}
|
|
29
|
-
// Build impl method info: typeName → methodName → { hasSelf }
|
|
69
|
+
// Build impl method info: typeName → methodName → { hasSelf, returnStructName? }
|
|
30
70
|
const implMethods = new Map();
|
|
31
71
|
for (const ib of hir.implBlocks) {
|
|
32
72
|
const methods = new Map();
|
|
33
73
|
for (const m of ib.methods) {
|
|
34
74
|
const hasSelf = m.params.length > 0 && m.params[0].name === 'self';
|
|
35
|
-
|
|
75
|
+
const returnStructName = m.returnType.kind === 'struct' ? m.returnType.name : undefined;
|
|
76
|
+
methods.set(m.name, { hasSelf, returnStructName });
|
|
36
77
|
}
|
|
37
78
|
implMethods.set(ib.typeName, methods);
|
|
38
79
|
}
|
|
80
|
+
// Build Display impl registry: typeName → f-string parts from to_string body
|
|
81
|
+
// Used to inline Display::to_string() calls at call sites instead of generating a function.
|
|
82
|
+
const displayImpls = new Map();
|
|
83
|
+
for (const ib of hir.implBlocks) {
|
|
84
|
+
if (ib.traitName === 'Display') {
|
|
85
|
+
const toStringMethod = ib.methods.find(m => m.name === 'to_string');
|
|
86
|
+
if (toStringMethod && toStringMethod.body.length > 0) {
|
|
87
|
+
const firstStmt = toStringMethod.body[0];
|
|
88
|
+
if (firstStmt.kind === 'return' && firstStmt.value && firstStmt.value.kind === 'f_string') {
|
|
89
|
+
displayImpls.set(ib.typeName, firstStmt.value.parts);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
39
94
|
// Pre-scan for macro functions
|
|
40
95
|
const macroInfo = (0, macro_1.detectMacroFunctions)(hir);
|
|
41
96
|
// Build function param info for call_macro generation at call sites
|
|
@@ -56,15 +111,27 @@ function lowerToMIR(hir, sourceFile) {
|
|
|
56
111
|
}
|
|
57
112
|
// Shared registry: specializedName → [mirFn, ...helpers]
|
|
58
113
|
const specializedFnsRegistry = new Map();
|
|
114
|
+
// Build module-level const map: name → integer value (for inlining at use sites)
|
|
115
|
+
const constValues = new Map();
|
|
116
|
+
for (const c of hir.consts) {
|
|
117
|
+
if (c.value.kind === 'int_lit')
|
|
118
|
+
constValues.set(c.name, c.value.value);
|
|
119
|
+
else if (c.value.kind === 'bool_lit')
|
|
120
|
+
constValues.set(c.name, c.value.value ? 1 : 0);
|
|
121
|
+
else if (c.value.kind === 'float_lit')
|
|
122
|
+
constValues.set(c.name, Math.round(c.value.value * 10000));
|
|
123
|
+
}
|
|
59
124
|
const allFunctions = [];
|
|
60
125
|
for (const f of hir.functions) {
|
|
61
|
-
const { fn, helpers } = lowerFunction(f, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile, timerCounter, undefined, hirFnMap, specializedFnsRegistry);
|
|
126
|
+
const { fn, helpers } = lowerFunction(f, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile, timerCounter, undefined, hirFnMap, specializedFnsRegistry, undefined, enumPayloads, constValues, singletonStructs, displayImpls);
|
|
62
127
|
allFunctions.push(fn, ...helpers);
|
|
63
128
|
}
|
|
64
|
-
// Lower impl block methods
|
|
129
|
+
// Lower impl block methods (skip Display::to_string — inlined at call sites instead)
|
|
65
130
|
for (const ib of hir.implBlocks) {
|
|
131
|
+
if (ib.traitName === 'Display')
|
|
132
|
+
continue; // Display impls are inlined, not emitted as functions
|
|
66
133
|
for (const m of ib.methods) {
|
|
67
|
-
const { fn, helpers } = lowerImplMethod(m, ib.typeName, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile, timerCounter);
|
|
134
|
+
const { fn, helpers } = lowerImplMethod(m, ib.typeName, hir.namespace, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, sourceFile, timerCounter, enumPayloads, constValues);
|
|
68
135
|
allFunctions.push(fn, ...helpers);
|
|
69
136
|
}
|
|
70
137
|
}
|
|
@@ -82,12 +149,14 @@ function lowerToMIR(hir, sourceFile) {
|
|
|
82
149
|
// Function lowering context
|
|
83
150
|
// ---------------------------------------------------------------------------
|
|
84
151
|
class FnContext {
|
|
85
|
-
constructor(namespace, fnName, structDefs = new Map(), implMethods = new Map(), macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), timerCounter = { count: 0, timerId: 0 }) {
|
|
152
|
+
constructor(namespace, fnName, structDefs = new Map(), implMethods = new Map(), macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), timerCounter = { count: 0, timerId: 0 }, enumPayloads = new Map()) {
|
|
86
153
|
this.tempCounter = 0;
|
|
87
154
|
this.blockCounter = 0;
|
|
88
155
|
this.blocks = [];
|
|
89
|
-
/** Stack of (loopHeader, loopExit, continueTo) for break/continue */
|
|
156
|
+
/** Stack of (loopHeader, loopExit, continueTo, label?) for break/continue */
|
|
90
157
|
this.loopStack = [];
|
|
158
|
+
/** Pending label to attach to the next pushLoop call (set by labeled_loop lowering) */
|
|
159
|
+
this.pendingLoopLabel = undefined;
|
|
91
160
|
/** Extracted helper functions for execute blocks */
|
|
92
161
|
this.helperFunctions = [];
|
|
93
162
|
/** Struct variable tracking: varName → { typeName, fields: fieldName → temp } */
|
|
@@ -96,6 +165,8 @@ class FnContext {
|
|
|
96
165
|
this.tupleVars = new Map();
|
|
97
166
|
/** Array variable tracking: varName → { ns, pathPrefix } for NBT-backed int[] */
|
|
98
167
|
this.arrayVars = new Map();
|
|
168
|
+
/** String variable tracking: varName → storage path within rs:strings */
|
|
169
|
+
this.stringVars = new Map();
|
|
99
170
|
/** Current source location (set during statement lowering) */
|
|
100
171
|
this.currentSourceLoc = undefined;
|
|
101
172
|
/** Source file path for the module being compiled */
|
|
@@ -107,10 +178,17 @@ class FnContext {
|
|
|
107
178
|
/** Tracks double variables: varName → NBT storage path (without "rs:d " prefix) */
|
|
108
179
|
this.doubleVars = new Map();
|
|
109
180
|
this.doubleVarCount = 0;
|
|
181
|
+
this.stringVarCount = 0;
|
|
110
182
|
/** HIR function definitions for array-arg monomorphization */
|
|
111
183
|
this.hirFunctions = new Map();
|
|
112
184
|
/** Shared registry of already-generated specialized (monomorphized) MIR functions */
|
|
113
185
|
this.specializedFnsRegistry = new Map();
|
|
186
|
+
/** Module-level const values: name → integer value (inlined at use sites) */
|
|
187
|
+
this.constValues = new Map();
|
|
188
|
+
/** @singleton struct names — static_call GameState::set(gs) expands struct fields */
|
|
189
|
+
this.singletonStructs = new Set();
|
|
190
|
+
/** Display trait impls: typeName → f-string parts from to_string body (inlined at call sites) */
|
|
191
|
+
this.displayImpls = new Map();
|
|
114
192
|
this.namespace = namespace;
|
|
115
193
|
this.fnName = fnName;
|
|
116
194
|
this.structDefs = structDefs;
|
|
@@ -119,6 +197,7 @@ class FnContext {
|
|
|
119
197
|
this.fnParamInfo = fnParamInfo;
|
|
120
198
|
this.currentMacroParams = macroInfo.get(fnName)?.macroParams ?? new Set();
|
|
121
199
|
this.enumDefs = enumDefs;
|
|
200
|
+
this.enumPayloads = enumPayloads;
|
|
122
201
|
this.timerCounter = timerCounter;
|
|
123
202
|
const entry = this.makeBlock('entry');
|
|
124
203
|
this.currentBlock = entry;
|
|
@@ -157,8 +236,13 @@ class FnContext {
|
|
|
157
236
|
current() {
|
|
158
237
|
return this.currentBlock;
|
|
159
238
|
}
|
|
160
|
-
|
|
161
|
-
this.
|
|
239
|
+
setPendingLoopLabel(label) {
|
|
240
|
+
this.pendingLoopLabel = label;
|
|
241
|
+
}
|
|
242
|
+
pushLoop(header, exit, continueTo, label) {
|
|
243
|
+
const effectiveLabel = label ?? this.pendingLoopLabel;
|
|
244
|
+
this.pendingLoopLabel = undefined;
|
|
245
|
+
this.loopStack.push({ header, exit, continueTo: continueTo ?? header, label: effectiveLabel });
|
|
162
246
|
}
|
|
163
247
|
popLoop() {
|
|
164
248
|
this.loopStack.pop();
|
|
@@ -166,6 +250,14 @@ class FnContext {
|
|
|
166
250
|
currentLoop() {
|
|
167
251
|
return this.loopStack[this.loopStack.length - 1];
|
|
168
252
|
}
|
|
253
|
+
/** Find loop by label — searches from innermost to outermost */
|
|
254
|
+
findLoopByLabel(label) {
|
|
255
|
+
for (let i = this.loopStack.length - 1; i >= 0; i--) {
|
|
256
|
+
if (this.loopStack[i].label === label)
|
|
257
|
+
return this.loopStack[i];
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
169
261
|
getNamespace() {
|
|
170
262
|
return this.namespace;
|
|
171
263
|
}
|
|
@@ -178,6 +270,10 @@ class FnContext {
|
|
|
178
270
|
this.doubleVars.set(varName, path);
|
|
179
271
|
return path;
|
|
180
272
|
}
|
|
273
|
+
/** Allocate a unique NBT storage path for a string value */
|
|
274
|
+
freshStringVar(varName) {
|
|
275
|
+
return `${this.namespace}_${this.fnName}_${varName}_${this.stringVarCount++}`;
|
|
276
|
+
}
|
|
181
277
|
}
|
|
182
278
|
// ---------------------------------------------------------------------------
|
|
183
279
|
// Function lowering
|
|
@@ -190,10 +286,13 @@ hirFnMap,
|
|
|
190
286
|
/** Shared registry of already-generated specialized MIR functions */
|
|
191
287
|
specializedFnsRegistry,
|
|
192
288
|
/** Override the MIR function name (used when generating specialized versions) */
|
|
193
|
-
overrideName) {
|
|
289
|
+
overrideName, enumPayloads = new Map(), constValues = new Map(), singletonStructs = new Set(), displayImpls = new Map()) {
|
|
194
290
|
const mirFnName = overrideName ?? fn.name;
|
|
195
|
-
const ctx = new FnContext(namespace, mirFnName, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, timerCounter);
|
|
196
|
-
ctx.sourceFile = sourceFile;
|
|
291
|
+
const ctx = new FnContext(namespace, mirFnName, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, timerCounter, enumPayloads);
|
|
292
|
+
ctx.sourceFile = fn.sourceFile ?? sourceFile;
|
|
293
|
+
ctx.constValues = constValues;
|
|
294
|
+
ctx.singletonStructs = singletonStructs;
|
|
295
|
+
ctx.displayImpls = displayImpls;
|
|
197
296
|
if (hirFnMap)
|
|
198
297
|
ctx.hirFunctions = hirFnMap;
|
|
199
298
|
if (specializedFnsRegistry)
|
|
@@ -210,6 +309,7 @@ overrideName) {
|
|
|
210
309
|
const params = [];
|
|
211
310
|
const scope = new Map();
|
|
212
311
|
let doubleParamSlot = 0;
|
|
312
|
+
let stringParamSlot = 0;
|
|
213
313
|
fn.params.forEach((p) => {
|
|
214
314
|
if (p.type.kind === 'array' && arrayArgBindings?.has(p.name)) {
|
|
215
315
|
// Array param already bound via arrayVars; no scoreboard slot needed
|
|
@@ -222,6 +322,10 @@ overrideName) {
|
|
|
222
322
|
// No scoreboard param slot; callee reads from rs:d __dp<i> via doubleVars
|
|
223
323
|
return;
|
|
224
324
|
}
|
|
325
|
+
if (p.type.kind === 'named' && (p.type.name === 'string' || p.type.name === 'format_string')) {
|
|
326
|
+
ctx.stringVars.set(p.name, `__sp${stringParamSlot++}`);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
225
329
|
const t = ctx.freshTemp();
|
|
226
330
|
params.push({ name: t, isMacroParam: fnMacroInfo?.macroParams.has(p.name) ?? false });
|
|
227
331
|
scope.set(p.name, t);
|
|
@@ -243,13 +347,16 @@ overrideName) {
|
|
|
243
347
|
blocks: liveBlocks,
|
|
244
348
|
entry: 'entry',
|
|
245
349
|
isMacro: fnMacroInfo != null,
|
|
350
|
+
sourceLoc: fn.span && (fn.sourceFile ?? sourceFile) ? { file: fn.sourceFile ?? sourceFile, line: fn.span.line, col: fn.span.col } : undefined,
|
|
351
|
+
sourceSnippet: formatFunctionSignature(fn),
|
|
246
352
|
};
|
|
247
353
|
return { fn: result, helpers: ctx.helperFunctions };
|
|
248
354
|
}
|
|
249
|
-
function lowerImplMethod(method, typeName, namespace, structDefs, implMethods, macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), sourceFile, timerCounter = { count: 0, timerId: 0 }) {
|
|
355
|
+
function lowerImplMethod(method, typeName, namespace, structDefs, implMethods, macroInfo = new Map(), fnParamInfo = new Map(), enumDefs = new Map(), sourceFile, timerCounter = { count: 0, timerId: 0 }, enumPayloads = new Map(), constValues = new Map()) {
|
|
250
356
|
const fnName = `${typeName}::${method.name}`;
|
|
251
|
-
const ctx = new FnContext(namespace, fnName, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, timerCounter);
|
|
252
|
-
ctx.sourceFile = sourceFile;
|
|
357
|
+
const ctx = new FnContext(namespace, fnName, structDefs, implMethods, macroInfo, fnParamInfo, enumDefs, timerCounter, enumPayloads);
|
|
358
|
+
ctx.sourceFile = method.sourceFile ?? sourceFile;
|
|
359
|
+
ctx.constValues = constValues;
|
|
253
360
|
const fields = structDefs.get(typeName) ?? [];
|
|
254
361
|
const hasSelf = method.params.length > 0 && method.params[0].name === 'self';
|
|
255
362
|
const params = [];
|
|
@@ -322,6 +429,8 @@ function lowerImplMethod(method, typeName, namespace, structDefs, implMethods, m
|
|
|
322
429
|
blocks: liveBlocks,
|
|
323
430
|
entry: 'entry',
|
|
324
431
|
isMacro: macroInfo.has(fnName),
|
|
432
|
+
sourceLoc: method.span && (method.sourceFile ?? sourceFile) ? { file: method.sourceFile ?? sourceFile, line: method.span.line, col: method.span.col } : undefined,
|
|
433
|
+
sourceSnippet: formatFunctionSignature(method),
|
|
325
434
|
};
|
|
326
435
|
return { fn: result, helpers: ctx.helperFunctions };
|
|
327
436
|
}
|
|
@@ -384,7 +493,14 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
384
493
|
}
|
|
385
494
|
switch (stmt.kind) {
|
|
386
495
|
case 'let': {
|
|
387
|
-
if (stmt.
|
|
496
|
+
if (stmt.type?.kind === 'named' && (stmt.type.name === 'string' || stmt.type.name === 'format_string')) {
|
|
497
|
+
const path = lowerStringExprToPath(stmt.init, ctx, scope, stmt.name) ?? ctx.freshStringVar(stmt.name);
|
|
498
|
+
ctx.stringVars.set(stmt.name, path);
|
|
499
|
+
const t = ctx.freshTemp();
|
|
500
|
+
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
501
|
+
scope.set(stmt.name, t);
|
|
502
|
+
}
|
|
503
|
+
else if (stmt.init.kind === 'some_lit') {
|
|
388
504
|
// Some(expr) — create option struct vars: has=1, val=expr
|
|
389
505
|
// Use __opt_ prefix so DCE treats these as side-effectful scoreboard writes
|
|
390
506
|
const hasTemp = `__opt_${stmt.name}_has`;
|
|
@@ -446,9 +562,17 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
446
562
|
const fieldTemps = new Map([['has', hasTemp], ['val', valTemp]]);
|
|
447
563
|
ctx.structVars.set(stmt.name, { typeName: '__option', fields: fieldTemps });
|
|
448
564
|
}
|
|
449
|
-
else if (
|
|
565
|
+
else if (
|
|
566
|
+
// Struct-typed let: explicit annotation OR inferred from @singleton::get() return
|
|
567
|
+
stmt.type?.kind === 'struct' ||
|
|
568
|
+
(stmt.init.kind === 'static_call' &&
|
|
569
|
+
ctx.singletonStructs.has(stmt.init.type) &&
|
|
570
|
+
stmt.init.method === 'get')) {
|
|
450
571
|
// Struct-typed let with non-literal init (e.g., call returning struct)
|
|
451
|
-
const
|
|
572
|
+
const inferredStructName = stmt.type?.kind === 'struct'
|
|
573
|
+
? stmt.type.name
|
|
574
|
+
: stmt.init.type;
|
|
575
|
+
const fields = ctx.structDefs.get(inferredStructName);
|
|
452
576
|
if (fields) {
|
|
453
577
|
lowerExpr(stmt.init, ctx, scope);
|
|
454
578
|
// Copy from return field slots into struct variable temps
|
|
@@ -464,7 +588,7 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
464
588
|
ctx.constTemps.set(t, constVal);
|
|
465
589
|
}
|
|
466
590
|
}
|
|
467
|
-
ctx.structVars.set(stmt.name, { typeName:
|
|
591
|
+
ctx.structVars.set(stmt.name, { typeName: inferredStructName, fields: fieldTemps });
|
|
468
592
|
}
|
|
469
593
|
else {
|
|
470
594
|
const valOp = lowerExpr(stmt.init, ctx, scope);
|
|
@@ -606,6 +730,13 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
606
730
|
}
|
|
607
731
|
break;
|
|
608
732
|
}
|
|
733
|
+
case 'const_decl': {
|
|
734
|
+
// Evaluate the literal at compile time and store in constValues for inlining at use sites
|
|
735
|
+
const op = lowerExpr(stmt.value, ctx, scope);
|
|
736
|
+
const numericValue = op.kind === 'const' ? op.value : 0;
|
|
737
|
+
ctx.constValues.set(stmt.name, numericValue);
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
609
740
|
case 'expr': {
|
|
610
741
|
lowerExpr(stmt.expr, ctx, scope);
|
|
611
742
|
break;
|
|
@@ -682,6 +813,32 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
682
813
|
ctx.switchTo(dead);
|
|
683
814
|
break;
|
|
684
815
|
}
|
|
816
|
+
case 'break_label': {
|
|
817
|
+
const loop = ctx.findLoopByLabel(stmt.label);
|
|
818
|
+
if (!loop)
|
|
819
|
+
throw new Error(`break: label '${stmt.label}' not found`);
|
|
820
|
+
ctx.terminate({ kind: 'jump', target: loop.exit });
|
|
821
|
+
const dead = ctx.newBlock('post_break_label');
|
|
822
|
+
ctx.switchTo(dead);
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
case 'continue_label': {
|
|
826
|
+
const loop = ctx.findLoopByLabel(stmt.label);
|
|
827
|
+
if (!loop)
|
|
828
|
+
throw new Error(`continue: label '${stmt.label}' not found`);
|
|
829
|
+
ctx.terminate({ kind: 'jump', target: loop.continueTo });
|
|
830
|
+
const dead = ctx.newBlock('post_continue_label');
|
|
831
|
+
ctx.switchTo(dead);
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
case 'labeled_loop': {
|
|
835
|
+
// The body is a while/foreach stmt; we need to push the label into the loop stack.
|
|
836
|
+
// We do this by injecting the label into the next pushLoop call by temporarily
|
|
837
|
+
// storing the pending label in ctx, then letting the inner loop case handle it.
|
|
838
|
+
ctx.setPendingLoopLabel(stmt.label);
|
|
839
|
+
lowerStmt(stmt.body, ctx, scope);
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
685
842
|
case 'if': {
|
|
686
843
|
const condOp = lowerExpr(stmt.cond, ctx, scope);
|
|
687
844
|
const thenBlock = ctx.newBlock('then');
|
|
@@ -770,6 +927,8 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
770
927
|
blocks: helperBlocks,
|
|
771
928
|
entry: 'entry',
|
|
772
929
|
isMacro: false,
|
|
930
|
+
sourceLoc: stmt.span && ctx.sourceFile ? { file: ctx.sourceFile, line: stmt.span.line, col: stmt.span.col } : undefined,
|
|
931
|
+
sourceSnippet: 'foreach helper',
|
|
773
932
|
});
|
|
774
933
|
ctx.emit({ kind: 'call_context', fn: helperName, subcommands });
|
|
775
934
|
break;
|
|
@@ -793,11 +952,52 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
793
952
|
blocks: execBlocks,
|
|
794
953
|
entry: 'entry',
|
|
795
954
|
isMacro: false,
|
|
955
|
+
sourceLoc: stmt.span && ctx.sourceFile ? { file: ctx.sourceFile, line: stmt.span.line, col: stmt.span.col } : undefined,
|
|
956
|
+
sourceSnippet: 'execute helper',
|
|
796
957
|
});
|
|
797
958
|
ctx.emit({ kind: 'call_context', fn: helperName, subcommands });
|
|
798
959
|
break;
|
|
799
960
|
}
|
|
800
961
|
case 'match': {
|
|
962
|
+
const hasStringPats = stmt.arms.some(a => a.pattern.kind === 'PatExpr' && a.pattern.expr.kind === 'str_lit');
|
|
963
|
+
if (hasStringPats) {
|
|
964
|
+
const matchPath = lowerStringExprToPath(stmt.expr, ctx, scope, 'match');
|
|
965
|
+
if (!matchPath) {
|
|
966
|
+
throw new Error('String match requires a string literal or tracked string variable');
|
|
967
|
+
}
|
|
968
|
+
const mergeBlock = ctx.newBlock('match_merge');
|
|
969
|
+
for (let i = 0; i < stmt.arms.length; i++) {
|
|
970
|
+
const arm = stmt.arms[i];
|
|
971
|
+
const pat = arm.pattern;
|
|
972
|
+
if (pat.kind === 'PatWild') {
|
|
973
|
+
lowerBlock(arm.body, ctx, new Map(scope));
|
|
974
|
+
if (isPlaceholderTerm(ctx.current().term)) {
|
|
975
|
+
ctx.terminate({ kind: 'jump', target: mergeBlock.id });
|
|
976
|
+
}
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
if (pat.kind === 'PatExpr' && pat.expr.kind === 'str_lit') {
|
|
980
|
+
const cmpTemp = ctx.freshTemp();
|
|
981
|
+
ctx.emit({ kind: 'string_match', dst: cmpTemp, ns: 'rs:strings', path: matchPath, value: pat.expr.value });
|
|
982
|
+
const armBody = ctx.newBlock('match_arm');
|
|
983
|
+
const nextArm = ctx.newBlock('match_next');
|
|
984
|
+
ctx.terminate({ kind: 'branch', cond: { kind: 'temp', name: cmpTemp }, then: armBody.id, else: nextArm.id });
|
|
985
|
+
ctx.switchTo(armBody);
|
|
986
|
+
lowerBlock(arm.body, ctx, new Map(scope));
|
|
987
|
+
if (isPlaceholderTerm(ctx.current().term)) {
|
|
988
|
+
ctx.terminate({ kind: 'jump', target: mergeBlock.id });
|
|
989
|
+
}
|
|
990
|
+
ctx.switchTo(nextArm);
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
throw new Error(`Unsupported string match pattern: ${pat.kind}`);
|
|
994
|
+
}
|
|
995
|
+
if (isPlaceholderTerm(ctx.current().term)) {
|
|
996
|
+
ctx.terminate({ kind: 'jump', target: mergeBlock.id });
|
|
997
|
+
}
|
|
998
|
+
ctx.switchTo(mergeBlock);
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
801
1001
|
// Lower match as chained if/else
|
|
802
1002
|
const mergeBlock = ctx.newBlock('match_merge');
|
|
803
1003
|
// Determine if any arm uses Option patterns (PatSome / PatNone).
|
|
@@ -893,6 +1093,38 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
893
1093
|
}
|
|
894
1094
|
ctx.switchTo(nextArm);
|
|
895
1095
|
}
|
|
1096
|
+
else if (pat.kind === 'PatEnum') {
|
|
1097
|
+
// Enum pattern: check tag value matches, then bind payload fields via NBT reads
|
|
1098
|
+
const tagValue = ctx.enumDefs.get(pat.enumName)?.get(pat.variant) ?? 0;
|
|
1099
|
+
const cmpTemp = ctx.freshTemp();
|
|
1100
|
+
ctx.emit({ kind: 'cmp', dst: cmpTemp, op: 'eq', a: matchVal, b: { kind: 'const', value: tagValue } });
|
|
1101
|
+
const armBody = ctx.newBlock('match_arm');
|
|
1102
|
+
const nextArm = ctx.newBlock('match_next');
|
|
1103
|
+
ctx.terminate({ kind: 'branch', cond: { kind: 'temp', name: cmpTemp }, then: armBody.id, else: nextArm.id });
|
|
1104
|
+
ctx.switchTo(armBody);
|
|
1105
|
+
const armScope = new Map(scope);
|
|
1106
|
+
// Bind each pattern variable by reading the corresponding NBT payload field
|
|
1107
|
+
const payloadFields = ctx.enumPayloads.get(pat.enumName)?.get(pat.variant) ?? [];
|
|
1108
|
+
for (let bi = 0; bi < pat.bindings.length; bi++) {
|
|
1109
|
+
const binding = pat.bindings[bi];
|
|
1110
|
+
const fieldDef = payloadFields[bi];
|
|
1111
|
+
const fieldName = fieldDef ? fieldDef.name : binding;
|
|
1112
|
+
const bindTemp = ctx.freshTemp();
|
|
1113
|
+
ctx.emit({
|
|
1114
|
+
kind: 'nbt_read',
|
|
1115
|
+
dst: bindTemp,
|
|
1116
|
+
ns: 'rs:enums',
|
|
1117
|
+
path: `${pat.enumName}_${fieldName}`,
|
|
1118
|
+
scale: 1,
|
|
1119
|
+
});
|
|
1120
|
+
armScope.set(binding, bindTemp);
|
|
1121
|
+
}
|
|
1122
|
+
lowerBlock(arm.body, ctx, armScope);
|
|
1123
|
+
if (isPlaceholderTerm(ctx.current().term)) {
|
|
1124
|
+
ctx.terminate({ kind: 'jump', target: mergeBlock.id });
|
|
1125
|
+
}
|
|
1126
|
+
ctx.switchTo(nextArm);
|
|
1127
|
+
}
|
|
896
1128
|
else if (pat.kind === 'PatExpr') {
|
|
897
1129
|
// Legacy: range_lit or other expression
|
|
898
1130
|
const expr = pat.expr;
|
|
@@ -1010,6 +1242,52 @@ function lowerStmt(stmt, ctx, scope) {
|
|
|
1010
1242
|
ctx.switchTo(mergeBlock);
|
|
1011
1243
|
break;
|
|
1012
1244
|
}
|
|
1245
|
+
case 'while_let_some': {
|
|
1246
|
+
// while let Some(x) = init { body }
|
|
1247
|
+
// Compiles to: loop { check opt.has; if 0 break; bind x = opt.val; body }
|
|
1248
|
+
const headerBlock = ctx.newBlock('whl_header');
|
|
1249
|
+
const bodyBlock = ctx.newBlock('whl_body');
|
|
1250
|
+
const exitBlock = ctx.newBlock('whl_exit');
|
|
1251
|
+
ctx.terminate({ kind: 'jump', target: headerBlock.id });
|
|
1252
|
+
// Header: re-evaluate init and check has
|
|
1253
|
+
ctx.switchTo(headerBlock);
|
|
1254
|
+
let hasOp;
|
|
1255
|
+
let valTemp;
|
|
1256
|
+
const sv = (() => {
|
|
1257
|
+
if (stmt.init.kind === 'ident')
|
|
1258
|
+
return ctx.structVars.get(stmt.init.name);
|
|
1259
|
+
return undefined;
|
|
1260
|
+
})();
|
|
1261
|
+
if (sv && sv.typeName === '__option') {
|
|
1262
|
+
const hasT = sv.fields.get('has');
|
|
1263
|
+
const valT = sv.fields.get('val');
|
|
1264
|
+
hasOp = { kind: 'temp', name: hasT };
|
|
1265
|
+
valTemp = valT;
|
|
1266
|
+
}
|
|
1267
|
+
else {
|
|
1268
|
+
lowerExpr(stmt.init, ctx, scope);
|
|
1269
|
+
const hasT = ctx.freshTemp();
|
|
1270
|
+
const valT = ctx.freshTemp();
|
|
1271
|
+
ctx.emit({ kind: 'copy', dst: hasT, src: { kind: 'temp', name: '__rf_has' } });
|
|
1272
|
+
ctx.emit({ kind: 'copy', dst: valT, src: { kind: 'temp', name: '__rf_val' } });
|
|
1273
|
+
hasOp = { kind: 'temp', name: hasT };
|
|
1274
|
+
valTemp = valT;
|
|
1275
|
+
}
|
|
1276
|
+
ctx.terminate({ kind: 'branch', cond: hasOp, then: bodyBlock.id, else: exitBlock.id });
|
|
1277
|
+
// Body: bind x = val, run body
|
|
1278
|
+
ctx.switchTo(bodyBlock);
|
|
1279
|
+
const bodyScope = new Map(scope);
|
|
1280
|
+
if (valTemp)
|
|
1281
|
+
bodyScope.set(stmt.binding, valTemp);
|
|
1282
|
+
ctx.pushLoop(headerBlock.id, exitBlock.id, headerBlock.id);
|
|
1283
|
+
lowerBlock(stmt.body, ctx, bodyScope);
|
|
1284
|
+
ctx.popLoop();
|
|
1285
|
+
if (isPlaceholderTerm(ctx.current().term)) {
|
|
1286
|
+
ctx.terminate({ kind: 'jump', target: headerBlock.id });
|
|
1287
|
+
}
|
|
1288
|
+
ctx.switchTo(exitBlock);
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1013
1291
|
default: {
|
|
1014
1292
|
const _exhaustive = stmt;
|
|
1015
1293
|
throw new Error(`Unknown HIR statement kind: ${_exhaustive.kind}`);
|
|
@@ -1085,6 +1363,10 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1085
1363
|
const temp = scope.get(expr.name);
|
|
1086
1364
|
if (temp)
|
|
1087
1365
|
return { kind: 'temp', name: temp };
|
|
1366
|
+
// Module-level const: inline the literal value directly (no scoreboard slot)
|
|
1367
|
+
if (ctx.constValues.has(expr.name)) {
|
|
1368
|
+
return { kind: 'const', value: ctx.constValues.get(expr.name) };
|
|
1369
|
+
}
|
|
1088
1370
|
// Unresolved ident — could be a global or external reference
|
|
1089
1371
|
const t = ctx.freshTemp();
|
|
1090
1372
|
ctx.emit({ kind: 'copy', dst: t, src: { kind: 'const', value: 0 } });
|
|
@@ -1213,6 +1495,35 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1213
1495
|
const value = variants?.get(expr.variant) ?? 0;
|
|
1214
1496
|
return { kind: 'const', value };
|
|
1215
1497
|
}
|
|
1498
|
+
case 'enum_construct': {
|
|
1499
|
+
// Enum variant construction with payload:
|
|
1500
|
+
// Color::RGB(r: 10, g: 20, b: 30)
|
|
1501
|
+
// → scoreboard set tag = variant int value
|
|
1502
|
+
// → nbt_write rs:enums Color_r = 10, Color_g = 20, Color_b = 30
|
|
1503
|
+
const variants = ctx.enumDefs.get(expr.enumName);
|
|
1504
|
+
const tagValue = variants?.get(expr.variant) ?? 0;
|
|
1505
|
+
// Write tag to a temp (the result of the expression is the integer tag)
|
|
1506
|
+
const tagTemp = ctx.freshTemp();
|
|
1507
|
+
ctx.emit({ kind: 'const', dst: tagTemp, value: tagValue });
|
|
1508
|
+
// Write payload fields to NBT storage rs:enums
|
|
1509
|
+
const payloadFields = ctx.enumPayloads.get(expr.enumName)?.get(expr.variant) ?? [];
|
|
1510
|
+
for (const arg of expr.args) {
|
|
1511
|
+
const fieldDef = payloadFields.find(f => f.name === arg.name);
|
|
1512
|
+
const argOp = lowerExpr(arg.value, ctx, scope);
|
|
1513
|
+
// Determine NBT type from field definition
|
|
1514
|
+
const nbtType = fieldDef && (fieldDef.type.kind === 'named') &&
|
|
1515
|
+
(fieldDef.type.name === 'float' || fieldDef.type.name === 'fixed') ? 'float' : 'int';
|
|
1516
|
+
ctx.emit({
|
|
1517
|
+
kind: 'nbt_write',
|
|
1518
|
+
ns: 'rs:enums',
|
|
1519
|
+
path: `${expr.enumName}_${arg.name}`,
|
|
1520
|
+
type: nbtType,
|
|
1521
|
+
scale: 1,
|
|
1522
|
+
src: argOp,
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
return { kind: 'temp', name: tagTemp };
|
|
1526
|
+
}
|
|
1216
1527
|
case 'member': {
|
|
1217
1528
|
// Enum variant access via dot syntax: Phase.Idle → integer constant
|
|
1218
1529
|
if (expr.obj.kind === 'ident') {
|
|
@@ -1535,18 +1846,78 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1535
1846
|
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1536
1847
|
return { kind: 'temp', name: t };
|
|
1537
1848
|
}
|
|
1849
|
+
// Handle int_to_str / bool_to_str — identity functions for scoreboard int/bool → string
|
|
1850
|
+
// In f-string context these are handled by precomputeFStringParts; outside that, just
|
|
1851
|
+
// evaluate the argument and return it (integer stays as integer for scoreboard purposes).
|
|
1852
|
+
if (expr.fn === 'int_to_str' || expr.fn === 'bool_to_str') {
|
|
1853
|
+
if (expr.args.length === 1) {
|
|
1854
|
+
return lowerExpr(expr.args[0], ctx, scope);
|
|
1855
|
+
}
|
|
1856
|
+
const t = ctx.freshTemp();
|
|
1857
|
+
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1858
|
+
return { kind: 'temp', name: t };
|
|
1859
|
+
}
|
|
1860
|
+
// Handle assert(cond[, message]) — test framework builtin
|
|
1861
|
+
if (expr.fn === 'assert') {
|
|
1862
|
+
const condArg = expr.args[0];
|
|
1863
|
+
const msgArg = expr.args[1];
|
|
1864
|
+
const condOp = condArg ? lowerExpr(condArg, ctx, scope) : { kind: 'const', value: 0 };
|
|
1865
|
+
// Evaluate condition to a temp
|
|
1866
|
+
let condTemp;
|
|
1867
|
+
if (condOp.kind === 'temp') {
|
|
1868
|
+
condTemp = condOp.name;
|
|
1869
|
+
}
|
|
1870
|
+
else {
|
|
1871
|
+
condTemp = ctx.freshTemp();
|
|
1872
|
+
ctx.emit({ kind: 'const', dst: condTemp, value: condOp.value });
|
|
1873
|
+
}
|
|
1874
|
+
// Get message string
|
|
1875
|
+
let msgStr = 'assert failed';
|
|
1876
|
+
if (msgArg && msgArg.kind === 'str_lit') {
|
|
1877
|
+
msgStr = msgArg.value;
|
|
1878
|
+
}
|
|
1879
|
+
const obj = `__${ctx.getNamespace()}`;
|
|
1880
|
+
// emit: execute unless score $condTemp <obj> matches 1 run tellraw @a "FAIL: <msg>"
|
|
1881
|
+
const failMsg = JSON.stringify({ text: `FAIL: ${msgStr}`, color: 'red' });
|
|
1882
|
+
ctx.emit({ kind: 'call', dst: null, fn: `__raw:execute unless score $${ctx.getFnName()}_${condTemp} ${obj} matches 1 run tellraw @a ${failMsg}`, args: [] });
|
|
1883
|
+
ctx.emit({ kind: 'call', dst: null, fn: `__raw:execute unless score $${ctx.getFnName()}_${condTemp} ${obj} matches 1 run scoreboard players add rs.test_failed rs.meta 1`, args: [] });
|
|
1884
|
+
const t = ctx.freshTemp();
|
|
1885
|
+
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1886
|
+
return { kind: 'temp', name: t };
|
|
1887
|
+
}
|
|
1538
1888
|
// Handle builtin calls → raw MC commands
|
|
1539
1889
|
if (macro_1.BUILTIN_SET.has(expr.fn)) {
|
|
1540
|
-
|
|
1890
|
+
// For text builtins with f-string args, precompute complex expressions to temp vars
|
|
1891
|
+
const TEXT_BUILTINS_SET = new Set(['tell', 'tellraw', 'title', 'subtitle', 'actionbar', 'announce']);
|
|
1892
|
+
let resolvedArgs = expr.args;
|
|
1893
|
+
if (TEXT_BUILTINS_SET.has(expr.fn)) {
|
|
1894
|
+
resolvedArgs = expr.args.map(arg => arg.kind === 'f_string' ? precomputeFStringParts(arg, ctx, scope) : arg);
|
|
1895
|
+
}
|
|
1896
|
+
const cmd = formatBuiltinCall(expr.fn, resolvedArgs, ctx.currentMacroParams, ctx.getNamespace());
|
|
1541
1897
|
ctx.emit({ kind: 'call', dst: null, fn: `__raw:${cmd}`, args: [] });
|
|
1542
1898
|
const t = ctx.freshTemp();
|
|
1543
1899
|
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1544
1900
|
return { kind: 'temp', name: t };
|
|
1545
1901
|
}
|
|
1546
1902
|
// Check for struct instance method call: parser desugars v.method() → call('method', [v, ...])
|
|
1903
|
+
// Some method names are remapped by the parser (e.g. add→set_add for set builtins).
|
|
1904
|
+
// We reverse-map them here to support impl methods with those names.
|
|
1905
|
+
const PARSER_METHOD_REMAP = {
|
|
1906
|
+
'set_add': 'add', 'set_contains': 'contains', 'set_remove': 'remove', 'set_clear': 'clear',
|
|
1907
|
+
'__array_push': 'push', '__array_pop': 'pop',
|
|
1908
|
+
'__entity_tag': 'tag', '__entity_untag': 'untag', '__entity_has_tag': 'has_tag',
|
|
1909
|
+
};
|
|
1547
1910
|
if (expr.args.length > 0 && expr.args[0].kind === 'ident') {
|
|
1548
1911
|
const sv = ctx.structVars.get(expr.args[0].name);
|
|
1549
1912
|
if (sv) {
|
|
1913
|
+
// Intercept Display::to_string() calls — inlined at f-string call sites; return 0 otherwise
|
|
1914
|
+
if (expr.fn === 'to_string' && ctx.displayImpls.has(sv.typeName)) {
|
|
1915
|
+
// Display::to_string() is expanded inline in f-string context (precomputeFStringParts).
|
|
1916
|
+
// Outside of that context, return a dummy 0 (the call is not valid standalone).
|
|
1917
|
+
const t = ctx.freshTemp();
|
|
1918
|
+
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1919
|
+
return { kind: 'temp', name: t };
|
|
1920
|
+
}
|
|
1550
1921
|
// Intercept Timer method calls when _id is a known compile-time constant
|
|
1551
1922
|
if (sv.typeName === 'Timer') {
|
|
1552
1923
|
const idTemp = sv.fields.get('_id');
|
|
@@ -1555,7 +1926,10 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1555
1926
|
return lowerTimerMethod(expr.fn, timerId, sv, ctx, scope, expr.args.slice(1));
|
|
1556
1927
|
}
|
|
1557
1928
|
}
|
|
1558
|
-
|
|
1929
|
+
// Try direct name, then try reverse-mapped name (for parser-remapped builtins)
|
|
1930
|
+
const originalMethodName = PARSER_METHOD_REMAP[expr.fn] ?? expr.fn;
|
|
1931
|
+
const methodInfo = ctx.implMethods.get(sv.typeName)?.get(expr.fn)
|
|
1932
|
+
?? ctx.implMethods.get(sv.typeName)?.get(originalMethodName);
|
|
1559
1933
|
if (methodInfo?.hasSelf) {
|
|
1560
1934
|
// Build args: self fields first, then remaining explicit args
|
|
1561
1935
|
const fields = ctx.structDefs.get(sv.typeName) ?? [];
|
|
@@ -1584,7 +1958,7 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1584
1958
|
}
|
|
1585
1959
|
const allArgs = [...selfArgs, ...explicitArgs];
|
|
1586
1960
|
const t = ctx.freshTemp();
|
|
1587
|
-
ctx.emit({ kind: 'call', dst: t, fn: `${sv.typeName}::${
|
|
1961
|
+
ctx.emit({ kind: 'call', dst: t, fn: `${sv.typeName}::${originalMethodName}`, args: allArgs });
|
|
1588
1962
|
return { kind: 'temp', name: t };
|
|
1589
1963
|
}
|
|
1590
1964
|
}
|
|
@@ -1592,21 +1966,47 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1592
1966
|
// Check if calling a macro function → emit call_macro
|
|
1593
1967
|
const targetMacro = ctx.macroInfo.get(expr.fn);
|
|
1594
1968
|
if (targetMacro) {
|
|
1595
|
-
const args = expr.args.map(a => lowerExpr(a, ctx, scope));
|
|
1596
1969
|
const targetParams = ctx.fnParamInfo.get(expr.fn) ?? [];
|
|
1597
1970
|
const macroArgs = [];
|
|
1598
|
-
for (let i = 0; i < targetParams.length && i < args.length; i++) {
|
|
1971
|
+
for (let i = 0; i < targetParams.length && i < expr.args.length; i++) {
|
|
1599
1972
|
const paramName = targetParams[i].name;
|
|
1600
1973
|
if (targetMacro.macroParams.has(paramName)) {
|
|
1601
1974
|
const paramTypeName = targetMacro.paramTypes.get(paramName) ?? 'int';
|
|
1602
|
-
const
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1975
|
+
const isString = paramTypeName === 'string' || paramTypeName === 'format_string';
|
|
1976
|
+
const isSelector = paramTypeName === 'selector';
|
|
1977
|
+
if (isString) {
|
|
1978
|
+
// String macro params: store directly to rs:macro_args as NBT string
|
|
1979
|
+
const srcPath = lowerStringExprToPath(expr.args[i], ctx, scope, paramName);
|
|
1980
|
+
if (srcPath) {
|
|
1981
|
+
ctx.emit({
|
|
1982
|
+
kind: 'call',
|
|
1983
|
+
dst: null,
|
|
1984
|
+
fn: `__raw:data modify storage rs:macro_args ${paramName} set from storage rs:strings ${srcPath}`,
|
|
1985
|
+
args: [],
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
else if (isSelector) {
|
|
1990
|
+
// Selector macro params: store the selector string as an NBT string in rs:macro_args
|
|
1991
|
+
const arg = expr.args[i];
|
|
1992
|
+
const selStr = arg.kind === 'selector' ? arg.raw : '@s';
|
|
1993
|
+
ctx.emit({
|
|
1994
|
+
kind: 'call',
|
|
1995
|
+
dst: null,
|
|
1996
|
+
fn: `__raw:data modify storage rs:macro_args ${paramName} set value ${JSON.stringify(selStr)}`,
|
|
1997
|
+
args: [],
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
else {
|
|
2001
|
+
const isFloat = paramTypeName === 'float';
|
|
2002
|
+
const isFixed = paramTypeName === 'fixed';
|
|
2003
|
+
macroArgs.push({
|
|
2004
|
+
name: paramName,
|
|
2005
|
+
value: lowerExpr(expr.args[i], ctx, scope),
|
|
2006
|
+
type: (isFloat || isFixed) ? 'double' : 'int',
|
|
2007
|
+
scale: isFloat ? 0.01 : isFixed ? 0.0001 : 1,
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
1610
2010
|
}
|
|
1611
2011
|
}
|
|
1612
2012
|
const t = ctx.freshTemp();
|
|
@@ -1640,7 +2040,7 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1640
2040
|
if (!ctx.specializedFnsRegistry.has(specializedName)) {
|
|
1641
2041
|
// Placeholder to prevent re-entry
|
|
1642
2042
|
ctx.specializedFnsRegistry.set(specializedName, []);
|
|
1643
|
-
const { fn: specFn, helpers: specHelpers } = lowerFunction(targetHirFn, ctx.getNamespace(), ctx.structDefs, ctx.implMethods, ctx.macroInfo, ctx.fnParamInfo, ctx.enumDefs, ctx.sourceFile, ctx.timerCounter, arrayArgBindings, ctx.hirFunctions, ctx.specializedFnsRegistry, specializedName);
|
|
2043
|
+
const { fn: specFn, helpers: specHelpers } = lowerFunction(targetHirFn, ctx.getNamespace(), ctx.structDefs, ctx.implMethods, ctx.macroInfo, ctx.fnParamInfo, ctx.enumDefs, ctx.sourceFile, ctx.timerCounter, arrayArgBindings, ctx.hirFunctions, ctx.specializedFnsRegistry, specializedName, ctx.enumPayloads, ctx.constValues, ctx.singletonStructs, ctx.displayImpls);
|
|
1644
2044
|
ctx.specializedFnsRegistry.set(specializedName, [specFn, ...specHelpers]);
|
|
1645
2045
|
}
|
|
1646
2046
|
// Emit call to the specialized function, passing only non-array args
|
|
@@ -1662,6 +2062,35 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1662
2062
|
{
|
|
1663
2063
|
const targetParams = ctx.fnParamInfo.get(expr.fn);
|
|
1664
2064
|
if (targetParams) {
|
|
2065
|
+
const hasStringParam = targetParams.some(p => p.type.kind === 'named' && (p.type.name === 'string' || p.type.name === 'format_string'));
|
|
2066
|
+
if (hasStringParam) {
|
|
2067
|
+
const nonStringArgs = [];
|
|
2068
|
+
let stringSlot = 0;
|
|
2069
|
+
for (let i = 0; i < targetParams.length && i < expr.args.length; i++) {
|
|
2070
|
+
const p = targetParams[i];
|
|
2071
|
+
if (p.type.kind === 'named' && (p.type.name === 'string' || p.type.name === 'format_string')) {
|
|
2072
|
+
const srcPath = lowerStringExprToPath(expr.args[i], ctx, scope, `arg${stringSlot}`);
|
|
2073
|
+
if (srcPath) {
|
|
2074
|
+
ctx.emit({
|
|
2075
|
+
kind: 'call',
|
|
2076
|
+
dst: null,
|
|
2077
|
+
fn: `__raw:data modify storage rs:strings __sp${stringSlot} set from storage rs:strings ${srcPath}`,
|
|
2078
|
+
args: [],
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
stringSlot++;
|
|
2082
|
+
}
|
|
2083
|
+
else {
|
|
2084
|
+
nonStringArgs.push(lowerExpr(expr.args[i], ctx, scope));
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
for (let i = targetParams.length; i < expr.args.length; i++) {
|
|
2088
|
+
nonStringArgs.push(lowerExpr(expr.args[i], ctx, scope));
|
|
2089
|
+
}
|
|
2090
|
+
const t = ctx.freshTemp();
|
|
2091
|
+
ctx.emit({ kind: 'call', dst: t, fn: expr.fn, args: nonStringArgs });
|
|
2092
|
+
return { kind: 'temp', name: t };
|
|
2093
|
+
}
|
|
1665
2094
|
const hasDoubleParam = targetParams.some(p => p.type.kind === 'named' && p.type.name === 'double');
|
|
1666
2095
|
if (hasDoubleParam) {
|
|
1667
2096
|
const ns = ctx.getNamespace();
|
|
@@ -1732,6 +2161,12 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1732
2161
|
if (expr.callee.kind === 'member' && expr.callee.obj.kind === 'ident') {
|
|
1733
2162
|
const sv = ctx.structVars.get(expr.callee.obj.name);
|
|
1734
2163
|
if (sv) {
|
|
2164
|
+
// Intercept Display::to_string() — inlined in f-string context; return 0 otherwise
|
|
2165
|
+
if (expr.callee.field === 'to_string' && ctx.displayImpls.has(sv.typeName)) {
|
|
2166
|
+
const t = ctx.freshTemp();
|
|
2167
|
+
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
2168
|
+
return { kind: 'temp', name: t };
|
|
2169
|
+
}
|
|
1735
2170
|
// Intercept Timer method calls when _id is a known compile-time constant
|
|
1736
2171
|
if (sv.typeName === 'Timer') {
|
|
1737
2172
|
const idTemp = sv.fields.get('_id');
|
|
@@ -1756,6 +2191,35 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1756
2191
|
}
|
|
1757
2192
|
}
|
|
1758
2193
|
}
|
|
2194
|
+
// Method chaining: callee obj is not a simple ident (e.g. v.scale(2).add(...))
|
|
2195
|
+
// Determine if the callee obj expression returns a struct via __rf_ slots
|
|
2196
|
+
if (expr.callee.kind === 'member' && expr.callee.obj.kind !== 'ident') {
|
|
2197
|
+
const returnedStructType = inferInvokeReturnStructType(expr.callee.obj, ctx);
|
|
2198
|
+
if (returnedStructType) {
|
|
2199
|
+
// Lower the inner call — result goes into __rf_ slots
|
|
2200
|
+
lowerExpr(expr.callee.obj, ctx, scope);
|
|
2201
|
+
// Read __rf_ slots into temps for this chained call
|
|
2202
|
+
const chainFields = ctx.structDefs.get(returnedStructType) ?? [];
|
|
2203
|
+
const chainFieldTemps = new Map();
|
|
2204
|
+
for (const fieldName of chainFields) {
|
|
2205
|
+
const ft = ctx.freshTemp();
|
|
2206
|
+
ctx.emit({ kind: 'copy', dst: ft, src: { kind: 'temp', name: `__rf_${fieldName}` } });
|
|
2207
|
+
chainFieldTemps.set(fieldName, ft);
|
|
2208
|
+
}
|
|
2209
|
+
const methodInfo = ctx.implMethods.get(returnedStructType)?.get(expr.callee.field);
|
|
2210
|
+
if (methodInfo?.hasSelf) {
|
|
2211
|
+
const selfArgs = chainFields.map(f => {
|
|
2212
|
+
const temp = chainFieldTemps.get(f);
|
|
2213
|
+
return temp ? { kind: 'temp', name: temp } : { kind: 'const', value: 0 };
|
|
2214
|
+
});
|
|
2215
|
+
const explicitArgs = expr.args.map(a => lowerExpr(a, ctx, scope));
|
|
2216
|
+
const allArgs = [...selfArgs, ...explicitArgs];
|
|
2217
|
+
const ct = ctx.freshTemp();
|
|
2218
|
+
ctx.emit({ kind: 'call', dst: ct, fn: `${returnedStructType}::${expr.callee.field}`, args: allArgs });
|
|
2219
|
+
return { kind: 'temp', name: ct };
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
1759
2223
|
// Fallback: generic invoke
|
|
1760
2224
|
const calleeOp = lowerExpr(expr.callee, ctx, scope);
|
|
1761
2225
|
const args = expr.args.map(a => lowerExpr(a, ctx, scope));
|
|
@@ -1782,6 +2246,29 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1782
2246
|
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1783
2247
|
return { kind: 'temp', name: t };
|
|
1784
2248
|
}
|
|
2249
|
+
// @singleton struct static calls: expand struct arg field-by-field for ::set
|
|
2250
|
+
if (ctx.singletonStructs.has(expr.type)) {
|
|
2251
|
+
if (expr.method === 'get') {
|
|
2252
|
+
// GameState::get() — no struct args, our synthetic LIR fn writes to $__rf_<field> slots
|
|
2253
|
+
const t = ctx.freshTemp();
|
|
2254
|
+
ctx.emit({ kind: 'call', dst: t, fn: `${expr.type}::${expr.method}`, args: [] });
|
|
2255
|
+
return { kind: 'temp', name: t };
|
|
2256
|
+
}
|
|
2257
|
+
else if (expr.method === 'set' && expr.args.length === 1 && expr.args[0].kind === 'ident') {
|
|
2258
|
+
// GameState::set(gs) — flatten struct arg into individual field args ($p0, $p1, ...)
|
|
2259
|
+
const sv = ctx.structVars.get(expr.args[0].name);
|
|
2260
|
+
if (sv) {
|
|
2261
|
+
const fields = ctx.structDefs.get(sv.typeName) ?? [];
|
|
2262
|
+
const fieldArgs = fields.map(f => {
|
|
2263
|
+
const temp = sv.fields.get(f);
|
|
2264
|
+
return temp ? { kind: 'temp', name: temp } : { kind: 'const', value: 0 };
|
|
2265
|
+
});
|
|
2266
|
+
const t = ctx.freshTemp();
|
|
2267
|
+
ctx.emit({ kind: 'call', dst: t, fn: `${expr.type}::${expr.method}`, args: fieldArgs });
|
|
2268
|
+
return { kind: 'temp', name: t };
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
1785
2272
|
const args = expr.args.map(a => lowerExpr(a, ctx, scope));
|
|
1786
2273
|
const t = ctx.freshTemp();
|
|
1787
2274
|
ctx.emit({ kind: 'call', dst: t, fn: `${expr.type}::${expr.method}`, args });
|
|
@@ -1815,6 +2302,43 @@ function lowerExpr(expr, ctx, scope) {
|
|
|
1815
2302
|
ctx.emit({ kind: 'const', dst: t, value: 0 });
|
|
1816
2303
|
return { kind: 'temp', name: t };
|
|
1817
2304
|
}
|
|
2305
|
+
case 'unwrap_or': {
|
|
2306
|
+
// opt.unwrap_or(default) → evaluate opt, if has=1 return val else return default
|
|
2307
|
+
const resultTemp = ctx.freshTemp();
|
|
2308
|
+
const defaultOp = lowerExpr(expr.default_, ctx, scope);
|
|
2309
|
+
ctx.emit({ kind: 'copy', dst: resultTemp, src: defaultOp });
|
|
2310
|
+
const sv = (() => {
|
|
2311
|
+
if (expr.opt.kind === 'ident')
|
|
2312
|
+
return ctx.structVars.get(expr.opt.name);
|
|
2313
|
+
return undefined;
|
|
2314
|
+
})();
|
|
2315
|
+
let hasOp;
|
|
2316
|
+
let valTemp;
|
|
2317
|
+
if (sv && sv.typeName === '__option') {
|
|
2318
|
+
const hasT = sv.fields.get('has');
|
|
2319
|
+
const valT = sv.fields.get('val');
|
|
2320
|
+
hasOp = { kind: 'temp', name: hasT };
|
|
2321
|
+
valTemp = valT;
|
|
2322
|
+
}
|
|
2323
|
+
else {
|
|
2324
|
+
lowerExpr(expr.opt, ctx, scope);
|
|
2325
|
+
const hasT = ctx.freshTemp();
|
|
2326
|
+
const valT = ctx.freshTemp();
|
|
2327
|
+
ctx.emit({ kind: 'copy', dst: hasT, src: { kind: 'temp', name: '__rf_has' } });
|
|
2328
|
+
ctx.emit({ kind: 'copy', dst: valT, src: { kind: 'temp', name: '__rf_val' } });
|
|
2329
|
+
hasOp = { kind: 'temp', name: hasT };
|
|
2330
|
+
valTemp = valT;
|
|
2331
|
+
}
|
|
2332
|
+
const someBlock = ctx.newBlock('unwrap_some');
|
|
2333
|
+
const mergeBlock = ctx.newBlock('unwrap_merge');
|
|
2334
|
+
ctx.terminate({ kind: 'branch', cond: hasOp, then: someBlock.id, else: mergeBlock.id });
|
|
2335
|
+
ctx.switchTo(someBlock);
|
|
2336
|
+
if (valTemp)
|
|
2337
|
+
ctx.emit({ kind: 'copy', dst: resultTemp, src: { kind: 'temp', name: valTemp } });
|
|
2338
|
+
ctx.terminate({ kind: 'jump', target: mergeBlock.id });
|
|
2339
|
+
ctx.switchTo(mergeBlock);
|
|
2340
|
+
return { kind: 'temp', name: resultTemp };
|
|
2341
|
+
}
|
|
1818
2342
|
case 'type_cast': {
|
|
1819
2343
|
const ns = ctx.getNamespace();
|
|
1820
2344
|
const targetName = expr.targetType.kind === 'named' ? expr.targetType.name : null;
|
|
@@ -1942,6 +2466,31 @@ function lowerShortCircuitOr(expr, ctx, scope) {
|
|
|
1942
2466
|
// ---------------------------------------------------------------------------
|
|
1943
2467
|
// Timer method inlining
|
|
1944
2468
|
// ---------------------------------------------------------------------------
|
|
2469
|
+
/**
|
|
2470
|
+
* Infer the struct type name returned by a chained invoke/call expression.
|
|
2471
|
+
* Used to support method chaining: v.scale(2).add(...) where scale() returns Vec2.
|
|
2472
|
+
* Returns the struct type name if determinable, otherwise undefined.
|
|
2473
|
+
*/
|
|
2474
|
+
function inferInvokeReturnStructType(expr, ctx) {
|
|
2475
|
+
if (expr.kind === 'invoke' && expr.callee.kind === 'member') {
|
|
2476
|
+
// Find the receiver type via structVars
|
|
2477
|
+
let receiverTypeName;
|
|
2478
|
+
if (expr.callee.obj.kind === 'ident') {
|
|
2479
|
+
receiverTypeName = ctx.structVars.get(expr.callee.obj.name)?.typeName;
|
|
2480
|
+
}
|
|
2481
|
+
else {
|
|
2482
|
+
// Recursively infer the type for deeper chains
|
|
2483
|
+
receiverTypeName = inferInvokeReturnStructType(expr.callee.obj, ctx);
|
|
2484
|
+
}
|
|
2485
|
+
if (receiverTypeName) {
|
|
2486
|
+
const methodInfo = ctx.implMethods.get(receiverTypeName)?.get(expr.callee.field);
|
|
2487
|
+
if (methodInfo?.returnStructName) {
|
|
2488
|
+
return methodInfo.returnStructName;
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return undefined;
|
|
2493
|
+
}
|
|
1945
2494
|
/**
|
|
1946
2495
|
* Inline a Timer instance method call using the statically-assigned timer ID.
|
|
1947
2496
|
* Emits scoreboard operations directly, bypassing the Timer::* function calls.
|
|
@@ -2080,6 +2629,39 @@ function lowerExecuteSubcmd(sub) {
|
|
|
2080
2629
|
}
|
|
2081
2630
|
}
|
|
2082
2631
|
}
|
|
2632
|
+
function lowerStringExprToPath(expr, ctx, scope, hint = 'str') {
|
|
2633
|
+
switch (expr.kind) {
|
|
2634
|
+
case 'str_lit': {
|
|
2635
|
+
const path = ctx.freshStringVar(hint);
|
|
2636
|
+
ctx.emit({
|
|
2637
|
+
kind: 'call',
|
|
2638
|
+
dst: null,
|
|
2639
|
+
fn: `__raw:data modify storage rs:strings ${path} set value ${JSON.stringify(expr.value)}`,
|
|
2640
|
+
args: [],
|
|
2641
|
+
});
|
|
2642
|
+
return path;
|
|
2643
|
+
}
|
|
2644
|
+
case 'ident':
|
|
2645
|
+
return ctx.stringVars.get(expr.name) ?? null;
|
|
2646
|
+
case 'assign': {
|
|
2647
|
+
if (!ctx.stringVars.has(expr.target))
|
|
2648
|
+
return null;
|
|
2649
|
+
const dstPath = ctx.stringVars.get(expr.target);
|
|
2650
|
+
const srcPath = lowerStringExprToPath(expr.value, ctx, scope, expr.target);
|
|
2651
|
+
if (!srcPath || srcPath === dstPath)
|
|
2652
|
+
return dstPath;
|
|
2653
|
+
ctx.emit({
|
|
2654
|
+
kind: 'call',
|
|
2655
|
+
dst: null,
|
|
2656
|
+
fn: `__raw:data modify storage rs:strings ${dstPath} set from storage rs:strings ${srcPath}`,
|
|
2657
|
+
args: [],
|
|
2658
|
+
});
|
|
2659
|
+
return dstPath;
|
|
2660
|
+
}
|
|
2661
|
+
default:
|
|
2662
|
+
return null;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2083
2665
|
function selectorToString(sel) {
|
|
2084
2666
|
// EntitySelector has kind like '@a', '@e', '@s', etc.
|
|
2085
2667
|
// Filters are key=value pairs that become [key=value,key=value]
|
|
@@ -2120,6 +2702,102 @@ const MACRO_SENTINEL = '\x01';
|
|
|
2120
2702
|
* Convert an f_string HIRExpr to a Minecraft JSON text component string.
|
|
2121
2703
|
* Each interpolated variable becomes a {"score":{"name":"$var","objective":"__ns"}} component.
|
|
2122
2704
|
*/
|
|
2705
|
+
/**
|
|
2706
|
+
* Pre-evaluate complex f-string expression parts to MIR temp vars,
|
|
2707
|
+
* returning a rewritten HIRExpr where each complex part is replaced by a simple ident.
|
|
2708
|
+
*/
|
|
2709
|
+
function precomputeFStringParts(expr, ctx, scope) {
|
|
2710
|
+
if (expr.kind !== 'f_string')
|
|
2711
|
+
return expr;
|
|
2712
|
+
const newParts = [];
|
|
2713
|
+
for (const part of expr.parts) {
|
|
2714
|
+
if (part.kind === 'text') {
|
|
2715
|
+
newParts.push(part);
|
|
2716
|
+
continue;
|
|
2717
|
+
}
|
|
2718
|
+
const inner = part.expr;
|
|
2719
|
+
// Simple cases that fStringToJsonText already handles
|
|
2720
|
+
if (inner.kind === 'ident' || inner.kind === 'int_lit' || inner.kind === 'bool_lit') {
|
|
2721
|
+
newParts.push({ kind: 'expr', expr: inner });
|
|
2722
|
+
continue;
|
|
2723
|
+
}
|
|
2724
|
+
// Display::to_string() inline expansion in f-string context:
|
|
2725
|
+
// v.to_string() (desugared as call{fn:'to_string', args:[v]}) → inline the Display impl's f-string
|
|
2726
|
+
if (inner.kind === 'call' && inner.fn === 'to_string' && inner.args.length === 1 && inner.args[0].kind === 'ident') {
|
|
2727
|
+
const argName = inner.args[0].name;
|
|
2728
|
+
const sv = ctx.structVars.get(argName);
|
|
2729
|
+
if (sv && ctx.displayImpls.has(sv.typeName)) {
|
|
2730
|
+
const displayParts = ctx.displayImpls.get(sv.typeName);
|
|
2731
|
+
// Expand Display impl parts, substituting self.<field> with the actual struct field temps
|
|
2732
|
+
for (const dp of displayParts) {
|
|
2733
|
+
if (dp.kind === 'text') {
|
|
2734
|
+
newParts.push(dp);
|
|
2735
|
+
}
|
|
2736
|
+
else {
|
|
2737
|
+
const dpExpr = dp.expr;
|
|
2738
|
+
// member(ident('self'), field) → lookup struct field temp
|
|
2739
|
+
if (dpExpr.kind === 'member' && dpExpr.obj.kind === 'ident' && dpExpr.obj.name === 'self') {
|
|
2740
|
+
const fieldTemp = sv.fields.get(dpExpr.field);
|
|
2741
|
+
if (fieldTemp) {
|
|
2742
|
+
newParts.push({ kind: 'expr', expr: { kind: 'ident', name: fieldTemp } });
|
|
2743
|
+
}
|
|
2744
|
+
else {
|
|
2745
|
+
newParts.push({ kind: 'expr', expr: { kind: 'int_lit', value: 0 } });
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
else {
|
|
2749
|
+
// Other expressions: lower them with self fields in scope
|
|
2750
|
+
const selfScope = new Map(scope);
|
|
2751
|
+
for (const [fieldName, fieldTemp] of sv.fields) {
|
|
2752
|
+
selfScope.set(`self.${fieldName}`, fieldTemp);
|
|
2753
|
+
}
|
|
2754
|
+
const tempOp = lowerExpr(dpExpr, ctx, selfScope);
|
|
2755
|
+
if (tempOp.kind === 'temp') {
|
|
2756
|
+
newParts.push({ kind: 'expr', expr: { kind: 'ident', name: tempOp.name } });
|
|
2757
|
+
}
|
|
2758
|
+
else if (tempOp.kind === 'const') {
|
|
2759
|
+
newParts.push({ kind: 'expr', expr: { kind: 'int_lit', value: tempOp.value } });
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
continue;
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
// int_to_str(x) / bool_to_str(x) in f-string: pass through the inner arg as a scoreboard score ref
|
|
2768
|
+
if (inner.kind === 'call' && (inner.fn === 'int_to_str' || inner.fn === 'bool_to_str') && inner.args.length === 1) {
|
|
2769
|
+
const arg = inner.args[0];
|
|
2770
|
+
if (arg.kind === 'ident') {
|
|
2771
|
+
newParts.push({ kind: 'expr', expr: arg });
|
|
2772
|
+
continue;
|
|
2773
|
+
}
|
|
2774
|
+
// If arg is complex, lower it first
|
|
2775
|
+
const argOp = lowerExpr(arg, ctx, scope);
|
|
2776
|
+
if (argOp.kind === 'temp') {
|
|
2777
|
+
newParts.push({ kind: 'expr', expr: { kind: 'ident', name: argOp.name } });
|
|
2778
|
+
}
|
|
2779
|
+
else if (argOp.kind === 'const') {
|
|
2780
|
+
newParts.push({ kind: 'expr', expr: { kind: 'int_lit', value: argOp.value } });
|
|
2781
|
+
}
|
|
2782
|
+
else {
|
|
2783
|
+
newParts.push(part);
|
|
2784
|
+
}
|
|
2785
|
+
continue;
|
|
2786
|
+
}
|
|
2787
|
+
// Complex expression: lower to a temp var, then reference it as ident
|
|
2788
|
+
const tempOp = lowerExpr(inner, ctx, scope);
|
|
2789
|
+
if (tempOp.kind === 'temp') {
|
|
2790
|
+
newParts.push({ kind: 'expr', expr: { kind: 'ident', name: tempOp.name } });
|
|
2791
|
+
}
|
|
2792
|
+
else if (tempOp.kind === 'const') {
|
|
2793
|
+
newParts.push({ kind: 'expr', expr: { kind: 'int_lit', value: tempOp.value } });
|
|
2794
|
+
}
|
|
2795
|
+
else {
|
|
2796
|
+
newParts.push(part);
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
return { kind: 'f_string', parts: newParts };
|
|
2800
|
+
}
|
|
2123
2801
|
function fStringToJsonText(expr, namespace) {
|
|
2124
2802
|
if (expr.kind !== 'f_string')
|
|
2125
2803
|
return JSON.stringify(expr.kind === 'str_lit' ? { text: expr.value } : { text: '~' });
|
|
@@ -2131,7 +2809,7 @@ function fStringToJsonText(expr, namespace) {
|
|
|
2131
2809
|
extra.push({ text: part.value });
|
|
2132
2810
|
}
|
|
2133
2811
|
else {
|
|
2134
|
-
// expr part — must be a scoreboard variable (ident)
|
|
2812
|
+
// expr part — must be a scoreboard variable (ident) or literal
|
|
2135
2813
|
const inner = part.expr;
|
|
2136
2814
|
if (inner.kind === 'ident') {
|
|
2137
2815
|
extra.push({ score: { name: `$${inner.name}`, objective } });
|
|
@@ -2139,6 +2817,9 @@ function fStringToJsonText(expr, namespace) {
|
|
|
2139
2817
|
else if (inner.kind === 'int_lit') {
|
|
2140
2818
|
extra.push({ text: String(inner.value) });
|
|
2141
2819
|
}
|
|
2820
|
+
else if (inner.kind === 'bool_lit') {
|
|
2821
|
+
extra.push({ text: inner.value ? 'true' : 'false' });
|
|
2822
|
+
}
|
|
2142
2823
|
else {
|
|
2143
2824
|
extra.push({ text: '?' });
|
|
2144
2825
|
}
|
|
@@ -2303,6 +2984,66 @@ function formatBuiltinCall(fn, args, macroParams, namespace = '') {
|
|
|
2303
2984
|
case 'xp_set':
|
|
2304
2985
|
cmd = `xp set ${strs[0]} ${strs[1]} ${strs[2] ?? 'points'}`;
|
|
2305
2986
|
break;
|
|
2987
|
+
case 'scoreboard_add_objective':
|
|
2988
|
+
cmd = strs[2] ? `scoreboard objectives add ${strs[0]} ${strs[1]} ${strs[2]}` : `scoreboard objectives add ${strs[0]} ${strs[1]}`;
|
|
2989
|
+
break;
|
|
2990
|
+
case 'scoreboard_remove_objective':
|
|
2991
|
+
cmd = `scoreboard objectives remove ${strs[0]}`;
|
|
2992
|
+
break;
|
|
2993
|
+
case 'scoreboard_display':
|
|
2994
|
+
cmd = `scoreboard objectives setdisplay ${strs[0]} ${strs[1] ?? ''}`;
|
|
2995
|
+
break;
|
|
2996
|
+
case 'scoreboard_hide':
|
|
2997
|
+
cmd = `scoreboard objectives setdisplay ${strs[0]}`;
|
|
2998
|
+
break;
|
|
2999
|
+
case 'team_add':
|
|
3000
|
+
cmd = strs[1] ? `team add ${strs[0]} ${strs[1]}` : `team add ${strs[0]}`;
|
|
3001
|
+
break;
|
|
3002
|
+
case 'team_remove':
|
|
3003
|
+
cmd = `team remove ${strs[0]}`;
|
|
3004
|
+
break;
|
|
3005
|
+
case 'team_join':
|
|
3006
|
+
cmd = `team join ${strs[0]} ${strs[1]}`;
|
|
3007
|
+
break;
|
|
3008
|
+
case 'team_leave':
|
|
3009
|
+
cmd = `team leave ${strs[0]}`;
|
|
3010
|
+
break;
|
|
3011
|
+
case 'team_option':
|
|
3012
|
+
cmd = `team modify ${strs[0]} ${strs[1]} ${strs[2]}`;
|
|
3013
|
+
break;
|
|
3014
|
+
case 'bossbar_add':
|
|
3015
|
+
cmd = `bossbar add ${strs[0]} ${strs[1] ? JSON.stringify({ text: strs[1] }) : '""'}`;
|
|
3016
|
+
break;
|
|
3017
|
+
case 'bossbar_remove':
|
|
3018
|
+
cmd = `bossbar remove ${strs[0]}`;
|
|
3019
|
+
break;
|
|
3020
|
+
case 'bossbar_set_value':
|
|
3021
|
+
cmd = `bossbar set ${strs[0]} value ${strs[1]}`;
|
|
3022
|
+
break;
|
|
3023
|
+
case 'bossbar_get_value':
|
|
3024
|
+
cmd = `bossbar get ${strs[0]} value`;
|
|
3025
|
+
break;
|
|
3026
|
+
case 'bossbar_set_max':
|
|
3027
|
+
cmd = `bossbar set ${strs[0]} max ${strs[1]}`;
|
|
3028
|
+
break;
|
|
3029
|
+
case 'bossbar_set_color':
|
|
3030
|
+
cmd = `bossbar set ${strs[0]} color ${strs[1]}`;
|
|
3031
|
+
break;
|
|
3032
|
+
case 'bossbar_set_style':
|
|
3033
|
+
cmd = `bossbar set ${strs[0]} style ${strs[1]}`;
|
|
3034
|
+
break;
|
|
3035
|
+
case 'bossbar_set_visible':
|
|
3036
|
+
cmd = `bossbar set ${strs[0]} visible ${strs[1]}`;
|
|
3037
|
+
break;
|
|
3038
|
+
case 'bossbar_set_players':
|
|
3039
|
+
cmd = `bossbar set ${strs[0]} players ${strs[1]}`;
|
|
3040
|
+
break;
|
|
3041
|
+
case 'data_get':
|
|
3042
|
+
cmd = `data get ${strs[0]} ${strs[1]} ${strs[2] ?? ''}`.trimEnd();
|
|
3043
|
+
break;
|
|
3044
|
+
case 'data_merge':
|
|
3045
|
+
cmd = `data merge ${strs[0]} ${strs[1]} ${strs[2]}`;
|
|
3046
|
+
break;
|
|
2306
3047
|
default: cmd = `${fn} ${strs.join(' ')}`;
|
|
2307
3048
|
}
|
|
2308
3049
|
return hasMacro ? `${MACRO_SENTINEL}${cmd}` : cmd;
|