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/src/parser/index.ts
CHANGED
|
@@ -10,7 +10,8 @@ import type {
|
|
|
10
10
|
Block, ConstDecl, Decorator, EntitySelector, Expr, FnDecl, GlobalDecl, LiteralExpr, Param,
|
|
11
11
|
Program, RangeExpr, SelectorFilter, SelectorKind, Span, Stmt, TypeNode, AssignOp,
|
|
12
12
|
StructDecl, StructField, ExecuteSubcommand, EnumDecl, EnumVariant, BlockPosExpr, ImplBlock,
|
|
13
|
-
CoordComponent, LambdaParam, EntityTypeName, ImportDecl, MatchPattern
|
|
13
|
+
CoordComponent, LambdaParam, EntityTypeName, ImportDecl, MatchPattern,
|
|
14
|
+
InterfaceDecl, InterfaceMethod
|
|
14
15
|
} from '../ast/types'
|
|
15
16
|
import type { BinOp, CmpOp } from '../ast/types'
|
|
16
17
|
import { DiagnosticError } from '../diagnostics'
|
|
@@ -83,6 +84,8 @@ export class Parser {
|
|
|
83
84
|
private inLibraryMode: boolean = false
|
|
84
85
|
/** Warnings accumulated during parsing (e.g. deprecated keyword usage). */
|
|
85
86
|
readonly warnings: string[] = []
|
|
87
|
+
/** Parse errors collected during error-recovery mode. */
|
|
88
|
+
readonly parseErrors: DiagnosticError[] = []
|
|
86
89
|
|
|
87
90
|
constructor(tokens: Token[], source?: string, filePath?: string) {
|
|
88
91
|
this.tokens = tokens
|
|
@@ -164,6 +167,54 @@ export class Parser {
|
|
|
164
167
|
return { kind: 'eof', value: '', line: span.line, col: span.col }
|
|
165
168
|
}
|
|
166
169
|
|
|
170
|
+
// -------------------------------------------------------------------------
|
|
171
|
+
// Error Recovery
|
|
172
|
+
// -------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Synchronize to the next top-level declaration boundary after a parse error.
|
|
176
|
+
* Skips tokens until we find a keyword that starts a top-level declaration,
|
|
177
|
+
* or a `}` (end of a block), or EOF.
|
|
178
|
+
*/
|
|
179
|
+
private syncToNextDecl(): void {
|
|
180
|
+
const TOP_LEVEL_KEYWORDS = new Set([
|
|
181
|
+
'fn', 'struct', 'impl', 'enum', 'const', 'let', 'export', 'declare', 'import', 'namespace', 'module'
|
|
182
|
+
])
|
|
183
|
+
while (!this.check('eof')) {
|
|
184
|
+
const kind = this.peek().kind
|
|
185
|
+
if (kind === '}') {
|
|
186
|
+
this.advance() // consume the stray `}`
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
if (TOP_LEVEL_KEYWORDS.has(kind)) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
// Also recover on a plain ident that could be 'import' keyword used as ident
|
|
193
|
+
if (kind === 'ident' && this.peek().value === 'import') {
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
this.advance()
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Synchronize to the next statement boundary inside a block after a parse error.
|
|
202
|
+
* Skips tokens until we reach `;`, `}`, or EOF.
|
|
203
|
+
*/
|
|
204
|
+
private syncToNextStmt(): void {
|
|
205
|
+
while (!this.check('eof')) {
|
|
206
|
+
const kind = this.peek().kind
|
|
207
|
+
if (kind === ';') {
|
|
208
|
+
this.advance() // consume the `;`
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
if (kind === '}') {
|
|
212
|
+
return // leave `}` for parseBlock to consume
|
|
213
|
+
}
|
|
214
|
+
this.advance()
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
167
218
|
// -------------------------------------------------------------------------
|
|
168
219
|
// Program
|
|
169
220
|
// -------------------------------------------------------------------------
|
|
@@ -177,6 +228,7 @@ export class Parser {
|
|
|
177
228
|
const enums: EnumDecl[] = []
|
|
178
229
|
const consts: ConstDecl[] = []
|
|
179
230
|
const imports: ImportDecl[] = []
|
|
231
|
+
const interfaces: InterfaceDecl[] = []
|
|
180
232
|
let isLibrary = false
|
|
181
233
|
let moduleName: string | undefined
|
|
182
234
|
|
|
@@ -207,43 +259,81 @@ export class Parser {
|
|
|
207
259
|
|
|
208
260
|
// Parse struct, function, and import declarations
|
|
209
261
|
while (!this.check('eof')) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
this.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (this.check('
|
|
234
|
-
this.
|
|
235
|
-
|
|
262
|
+
try {
|
|
263
|
+
if (this.check('decorator') && this.peek().value.startsWith('@config')) {
|
|
264
|
+
// @config decorator on a global let
|
|
265
|
+
const decorToken = this.advance()
|
|
266
|
+
const decorator = this.parseDecoratorValue(decorToken.value)
|
|
267
|
+
if (!this.check('let')) {
|
|
268
|
+
this.error('@config decorator must be followed by a let declaration')
|
|
269
|
+
}
|
|
270
|
+
const g = this.parseGlobalDecl(true)
|
|
271
|
+
g.configKey = decorator.args?.configKey
|
|
272
|
+
g.configDefault = decorator.args?.configDefault
|
|
273
|
+
globals.push(g)
|
|
274
|
+
} else if (this.check('let')) {
|
|
275
|
+
globals.push(this.parseGlobalDecl(true))
|
|
276
|
+
} else if (this.check('decorator') && this.peek().value === '@singleton') {
|
|
277
|
+
// @singleton decorator on a struct
|
|
278
|
+
this.advance() // consume '@singleton'
|
|
279
|
+
if (!this.check('struct')) {
|
|
280
|
+
this.error('@singleton decorator must be followed by a struct declaration')
|
|
281
|
+
}
|
|
282
|
+
const s = this.parseStructDecl()
|
|
283
|
+
s.isSingleton = true
|
|
284
|
+
structs.push(s)
|
|
285
|
+
} else if (this.check('struct')) {
|
|
286
|
+
structs.push(this.parseStructDecl())
|
|
287
|
+
} else if (this.check('impl')) {
|
|
288
|
+
implBlocks.push(this.parseImplBlock())
|
|
289
|
+
} else if (this.check('interface')) {
|
|
290
|
+
interfaces.push(this.parseInterfaceDecl())
|
|
291
|
+
} else if (this.check('enum')) {
|
|
292
|
+
enums.push(this.parseEnumDecl())
|
|
293
|
+
} else if (this.check('const')) {
|
|
294
|
+
consts.push(this.parseConstDecl())
|
|
295
|
+
} else if (this.check('declare')) {
|
|
296
|
+
// Declaration-only stub (e.g. from builtins.d.mcrs) — parse and discard
|
|
297
|
+
this.advance() // consume 'declare'
|
|
298
|
+
this.parseDeclareStub()
|
|
299
|
+
} else if (this.check('export')) {
|
|
300
|
+
declarations.push(this.parseExportedFnDecl())
|
|
301
|
+
} else if (this.check('import') || (this.check('ident') && this.peek().value === 'import')) {
|
|
302
|
+
// `import math::sin;` or `import math::*;` or `import player_utils;` (whole-module file import)
|
|
303
|
+
this.advance() // consume 'import' (keyword or ident)
|
|
304
|
+
const importToken = this.peek()
|
|
305
|
+
const modName = this.expect('ident').value
|
|
306
|
+
// Check for `::` — if present, this is a symbol import; otherwise, whole-module import
|
|
307
|
+
if (this.check('::')) {
|
|
308
|
+
this.advance() // consume '::'
|
|
309
|
+
let symbol: string
|
|
310
|
+
if (this.check('*')) {
|
|
311
|
+
this.advance()
|
|
312
|
+
symbol = '*'
|
|
313
|
+
} else {
|
|
314
|
+
symbol = this.expect('ident').value
|
|
315
|
+
}
|
|
316
|
+
this.match(';')
|
|
317
|
+
imports.push(this.withLoc({ moduleName: modName, symbol }, importToken))
|
|
318
|
+
} else {
|
|
319
|
+
// Whole-module import: `import player_utils;`
|
|
320
|
+
this.match(';')
|
|
321
|
+
imports.push(this.withLoc({ moduleName: modName, symbol: undefined }, importToken))
|
|
322
|
+
}
|
|
236
323
|
} else {
|
|
237
|
-
|
|
324
|
+
declarations.push(this.parseFnDecl())
|
|
325
|
+
}
|
|
326
|
+
} catch (err) {
|
|
327
|
+
if (err instanceof DiagnosticError) {
|
|
328
|
+
this.parseErrors.push(err)
|
|
329
|
+
this.syncToNextDecl()
|
|
330
|
+
} else {
|
|
331
|
+
throw err
|
|
238
332
|
}
|
|
239
|
-
this.match(';')
|
|
240
|
-
imports.push(this.withLoc({ moduleName: modName, symbol }, importToken))
|
|
241
|
-
} else {
|
|
242
|
-
declarations.push(this.parseFnDecl())
|
|
243
333
|
}
|
|
244
334
|
}
|
|
245
335
|
|
|
246
|
-
return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, isLibrary }
|
|
336
|
+
return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, interfaces, isLibrary }
|
|
247
337
|
}
|
|
248
338
|
|
|
249
339
|
// -------------------------------------------------------------------------
|
|
@@ -253,6 +343,7 @@ export class Parser {
|
|
|
253
343
|
private parseStructDecl(): StructDecl {
|
|
254
344
|
const structToken = this.expect('struct')
|
|
255
345
|
const name = this.expect('ident').value
|
|
346
|
+
const extendsName = this.match('extends') ? this.expect('ident').value : undefined
|
|
256
347
|
this.expect('{')
|
|
257
348
|
|
|
258
349
|
const fields: StructField[] = []
|
|
@@ -267,7 +358,7 @@ export class Parser {
|
|
|
267
358
|
}
|
|
268
359
|
|
|
269
360
|
this.expect('}')
|
|
270
|
-
return this.withLoc({ name, fields }, structToken)
|
|
361
|
+
return this.withLoc({ name, extends: extendsName, fields }, structToken)
|
|
271
362
|
}
|
|
272
363
|
|
|
273
364
|
private parseEnumDecl(): EnumDecl {
|
|
@@ -282,6 +373,21 @@ export class Parser {
|
|
|
282
373
|
const variantToken = this.expect('ident')
|
|
283
374
|
const variant: EnumVariant = { name: variantToken.value }
|
|
284
375
|
|
|
376
|
+
// Payload fields: Variant(field: Type, ...)
|
|
377
|
+
if (this.check('(')) {
|
|
378
|
+
this.advance() // consume '('
|
|
379
|
+
const fields: { name: string; type: TypeNode }[] = []
|
|
380
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
381
|
+
const fieldName = this.expect('ident').value
|
|
382
|
+
this.expect(':')
|
|
383
|
+
const fieldType = this.parseType()
|
|
384
|
+
fields.push({ name: fieldName, type: fieldType })
|
|
385
|
+
if (!this.match(',')) break
|
|
386
|
+
}
|
|
387
|
+
this.expect(')')
|
|
388
|
+
variant.fields = fields
|
|
389
|
+
}
|
|
390
|
+
|
|
285
391
|
if (this.match('=')) {
|
|
286
392
|
const valueToken = this.expect('int_lit')
|
|
287
393
|
variant.value = parseInt(valueToken.value, 10)
|
|
@@ -303,7 +409,15 @@ export class Parser {
|
|
|
303
409
|
|
|
304
410
|
private parseImplBlock(): ImplBlock {
|
|
305
411
|
const implToken = this.expect('impl')
|
|
306
|
-
|
|
412
|
+
let traitName: string | undefined
|
|
413
|
+
let typeName: string
|
|
414
|
+
const firstName = this.expect('ident').value
|
|
415
|
+
if (this.match('for')) {
|
|
416
|
+
traitName = firstName
|
|
417
|
+
typeName = this.expect('ident').value
|
|
418
|
+
} else {
|
|
419
|
+
typeName = firstName
|
|
420
|
+
}
|
|
307
421
|
this.expect('{')
|
|
308
422
|
|
|
309
423
|
const methods: FnDecl[] = []
|
|
@@ -312,7 +426,63 @@ export class Parser {
|
|
|
312
426
|
}
|
|
313
427
|
|
|
314
428
|
this.expect('}')
|
|
315
|
-
return this.withLoc({ kind: 'impl_block', typeName, methods }, implToken)
|
|
429
|
+
return this.withLoc({ kind: 'impl_block', traitName, typeName, methods }, implToken)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Parse an interface declaration:
|
|
434
|
+
* interface <Name> {
|
|
435
|
+
* fn <method>(<params>): <retType>
|
|
436
|
+
* ...
|
|
437
|
+
* }
|
|
438
|
+
* Method signatures have no body — they are prototype-only.
|
|
439
|
+
*/
|
|
440
|
+
private parseInterfaceDecl(): InterfaceDecl {
|
|
441
|
+
const ifaceToken = this.expect('interface')
|
|
442
|
+
const name = this.expect('ident').value
|
|
443
|
+
this.expect('{')
|
|
444
|
+
|
|
445
|
+
const methods: InterfaceMethod[] = []
|
|
446
|
+
while (!this.check('}') && !this.check('eof')) {
|
|
447
|
+
const fnToken = this.expect('fn')
|
|
448
|
+
const methodName = this.expect('ident').value
|
|
449
|
+
this.expect('(')
|
|
450
|
+
const params = this.parseInterfaceParams()
|
|
451
|
+
this.expect(')')
|
|
452
|
+
let returnType: TypeNode | undefined
|
|
453
|
+
if (this.match(':')) {
|
|
454
|
+
returnType = this.parseType()
|
|
455
|
+
}
|
|
456
|
+
// No body — interface methods are signature-only
|
|
457
|
+
methods.push(this.withLoc({ name: methodName, params, returnType }, fnToken) as InterfaceMethod)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
this.expect('}')
|
|
461
|
+
return this.withLoc({ name, methods }, ifaceToken) as InterfaceDecl
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Parse interface method params — like parseParams but allows bare `self`
|
|
466
|
+
* (no `:` required for the first param named 'self').
|
|
467
|
+
*/
|
|
468
|
+
private parseInterfaceParams(): Param[] {
|
|
469
|
+
const params: Param[] = []
|
|
470
|
+
if (!this.check(')')) {
|
|
471
|
+
do {
|
|
472
|
+
const paramToken = this.expect('ident')
|
|
473
|
+
const paramName = paramToken.value
|
|
474
|
+
let type: TypeNode
|
|
475
|
+
if (params.length === 0 && paramName === 'self' && !this.check(':')) {
|
|
476
|
+
// self without type annotation — use a sentinel struct type
|
|
477
|
+
type = { kind: 'named', name: 'void' }
|
|
478
|
+
} else {
|
|
479
|
+
this.expect(':')
|
|
480
|
+
type = this.parseType()
|
|
481
|
+
}
|
|
482
|
+
params.push(this.withLoc({ name: paramName, type }, paramToken))
|
|
483
|
+
} while (this.match(','))
|
|
484
|
+
}
|
|
485
|
+
return params
|
|
316
486
|
}
|
|
317
487
|
|
|
318
488
|
private parseConstDecl(): ConstDecl {
|
|
@@ -340,8 +510,14 @@ export class Parser {
|
|
|
340
510
|
const name = this.expect('ident').value
|
|
341
511
|
this.expect(':')
|
|
342
512
|
const type = this.parseType()
|
|
343
|
-
|
|
344
|
-
|
|
513
|
+
let init: Expr
|
|
514
|
+
if (this.match('=')) {
|
|
515
|
+
init = this.parseExpr()
|
|
516
|
+
} else {
|
|
517
|
+
// No init — valid only for @config-decorated globals (resolved later)
|
|
518
|
+
// Use a placeholder zero literal; will be replaced in compile step
|
|
519
|
+
init = { kind: 'int_lit', value: 0 }
|
|
520
|
+
}
|
|
345
521
|
this.match(';')
|
|
346
522
|
return this.withLoc({ kind: 'global', name, type, init, mutable }, token)
|
|
347
523
|
}
|
|
@@ -360,6 +536,7 @@ export class Parser {
|
|
|
360
536
|
|
|
361
537
|
private parseFnDecl(implTypeName?: string): FnDecl {
|
|
362
538
|
const decorators = this.parseDecorators()
|
|
539
|
+
const watchObjective = decorators.find(decorator => decorator.name === 'watch')?.args?.objective
|
|
363
540
|
|
|
364
541
|
// Map @keep decorator to isExported flag (backward compat)
|
|
365
542
|
let isExported: boolean | undefined
|
|
@@ -400,7 +577,7 @@ export class Parser {
|
|
|
400
577
|
|
|
401
578
|
const fn: import('../ast/types').FnDecl = this.withLoc(
|
|
402
579
|
{ name, typeParams, params, returnType, decorators: filteredDecorators, body,
|
|
403
|
-
isLibraryFn: this.inLibraryMode || undefined, isExported },
|
|
580
|
+
isLibraryFn: this.inLibraryMode || undefined, isExported, watchObjective },
|
|
404
581
|
fnToken,
|
|
405
582
|
)
|
|
406
583
|
if (fn.span && closingBraceLine) fn.span.endLine = closingBraceLine
|
|
@@ -439,8 +616,9 @@ export class Parser {
|
|
|
439
616
|
}
|
|
440
617
|
|
|
441
618
|
private parseDecoratorValue(value: string): Decorator {
|
|
442
|
-
// Parse @tick, @on(PlayerDeath),
|
|
443
|
-
|
|
619
|
+
// Parse @tick, @on(PlayerDeath), @on_trigger("name"), or @deprecated("msg with ) parens")
|
|
620
|
+
// Use a greedy match for args that allows any content inside the outermost parens.
|
|
621
|
+
const match = value.match(/^@([A-Za-z_][A-Za-z0-9_-]*)(?:\((.*)\))?$/s)
|
|
444
622
|
if (!match) {
|
|
445
623
|
this.error(`Invalid decorator: ${value}`)
|
|
446
624
|
}
|
|
@@ -452,6 +630,10 @@ export class Parser {
|
|
|
452
630
|
return { name }
|
|
453
631
|
}
|
|
454
632
|
|
|
633
|
+
if (name === 'profile' || name === 'memoize') {
|
|
634
|
+
this.error(`@${name} decorator does not accept arguments`)
|
|
635
|
+
}
|
|
636
|
+
|
|
455
637
|
const args: Decorator['args'] = {}
|
|
456
638
|
|
|
457
639
|
if (name === 'on') {
|
|
@@ -462,11 +644,13 @@ export class Parser {
|
|
|
462
644
|
}
|
|
463
645
|
}
|
|
464
646
|
|
|
465
|
-
// Handle @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
|
|
466
|
-
if (name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
|
|
647
|
+
// Handle @watch("objective"), @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
|
|
648
|
+
if (name === 'watch' || name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
|
|
467
649
|
const strMatch = argsStr.match(/^"([^"]*)"$/)
|
|
468
650
|
if (strMatch) {
|
|
469
|
-
if (name === '
|
|
651
|
+
if (name === 'watch') {
|
|
652
|
+
args.objective = strMatch[1]
|
|
653
|
+
} else if (name === 'on_trigger') {
|
|
470
654
|
args.trigger = strMatch[1]
|
|
471
655
|
} else if (name === 'on_advancement') {
|
|
472
656
|
args.advancement = strMatch[1]
|
|
@@ -479,6 +663,41 @@ export class Parser {
|
|
|
479
663
|
}
|
|
480
664
|
}
|
|
481
665
|
|
|
666
|
+
// Handle @config("key", default: value)
|
|
667
|
+
if (name === 'config') {
|
|
668
|
+
// Format: @config("key_name", default: 42)
|
|
669
|
+
const configMatch = argsStr.match(/^"([^"]+)"\s*,\s*default\s*:\s*(-?\d+(?:\.\d+)?)$/)
|
|
670
|
+
if (configMatch) {
|
|
671
|
+
return { name, args: { configKey: configMatch[1], configDefault: parseFloat(configMatch[2]) } }
|
|
672
|
+
}
|
|
673
|
+
// Format: @config("key_name") — no default
|
|
674
|
+
const keyOnlyMatch = argsStr.match(/^"([^"]+)"$/)
|
|
675
|
+
if (keyOnlyMatch) {
|
|
676
|
+
return { name, args: { configKey: keyOnlyMatch[1] } }
|
|
677
|
+
}
|
|
678
|
+
this.error(`Invalid @config syntax. Expected: @config("key", default: value) or @config("key")`)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Handle @deprecated("message")
|
|
682
|
+
if (name === 'deprecated') {
|
|
683
|
+
const strMatch = argsStr.match(/^"([^"]*)"$/)
|
|
684
|
+
if (strMatch) {
|
|
685
|
+
return { name, args: { message: strMatch[1] } }
|
|
686
|
+
}
|
|
687
|
+
// @deprecated with no message string
|
|
688
|
+
return { name, args: {} }
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// @test("label") — marks a test function with a human-readable label
|
|
692
|
+
if (name === 'test') {
|
|
693
|
+
const strMatch = argsStr.match(/^"([^"]*)"$/)
|
|
694
|
+
if (strMatch) {
|
|
695
|
+
return { name, args: { testLabel: strMatch[1] } }
|
|
696
|
+
}
|
|
697
|
+
// @test with no label — use empty string
|
|
698
|
+
return { name, args: { testLabel: '' } }
|
|
699
|
+
}
|
|
700
|
+
|
|
482
701
|
// @require_on_load(fn_name) — when this fn is used, fn_name is called from __load.
|
|
483
702
|
// Accepts bare identifiers (with optional leading _) or quoted strings.
|
|
484
703
|
if (name === 'require_on_load') {
|
|
@@ -519,6 +738,8 @@ export class Parser {
|
|
|
519
738
|
args.item = val
|
|
520
739
|
} else if (key === 'team') {
|
|
521
740
|
args.team = val
|
|
741
|
+
} else if (key === 'max') {
|
|
742
|
+
args.max = parseInt(val, 10)
|
|
522
743
|
}
|
|
523
744
|
}
|
|
524
745
|
|
|
@@ -645,7 +866,16 @@ export class Parser {
|
|
|
645
866
|
const stmts: Stmt[] = []
|
|
646
867
|
|
|
647
868
|
while (!this.check('}') && !this.check('eof')) {
|
|
648
|
-
|
|
869
|
+
try {
|
|
870
|
+
stmts.push(this.parseStmt())
|
|
871
|
+
} catch (err) {
|
|
872
|
+
if (err instanceof DiagnosticError) {
|
|
873
|
+
this.parseErrors.push(err)
|
|
874
|
+
this.syncToNextStmt()
|
|
875
|
+
} else {
|
|
876
|
+
throw err
|
|
877
|
+
}
|
|
878
|
+
}
|
|
649
879
|
}
|
|
650
880
|
|
|
651
881
|
this.expect('}')
|
|
@@ -658,21 +888,38 @@ export class Parser {
|
|
|
658
888
|
return this.parseLetStmt()
|
|
659
889
|
}
|
|
660
890
|
|
|
891
|
+
// Const declaration (local)
|
|
892
|
+
if (this.check('const')) {
|
|
893
|
+
return this.parseLocalConstDecl()
|
|
894
|
+
}
|
|
895
|
+
|
|
661
896
|
// Return statement
|
|
662
897
|
if (this.check('return')) {
|
|
663
898
|
return this.parseReturnStmt()
|
|
664
899
|
}
|
|
665
900
|
|
|
666
|
-
// Break statement
|
|
901
|
+
// Break statement (with optional label: break outer)
|
|
667
902
|
if (this.check('break')) {
|
|
668
903
|
const token = this.advance()
|
|
904
|
+
// Check if next token is an identifier (label name)
|
|
905
|
+
if (this.check('ident')) {
|
|
906
|
+
const labelToken = this.advance()
|
|
907
|
+
this.match(';')
|
|
908
|
+
return this.withLoc({ kind: 'break_label', label: labelToken.value }, token)
|
|
909
|
+
}
|
|
669
910
|
this.match(';')
|
|
670
911
|
return this.withLoc({ kind: 'break' }, token)
|
|
671
912
|
}
|
|
672
913
|
|
|
673
|
-
// Continue statement
|
|
914
|
+
// Continue statement (with optional label: continue outer)
|
|
674
915
|
if (this.check('continue')) {
|
|
675
916
|
const token = this.advance()
|
|
917
|
+
// Check if next token is an identifier (label name)
|
|
918
|
+
if (this.check('ident')) {
|
|
919
|
+
const labelToken = this.advance()
|
|
920
|
+
this.match(';')
|
|
921
|
+
return this.withLoc({ kind: 'continue_label', label: labelToken.value }, token)
|
|
922
|
+
}
|
|
676
923
|
this.match(';')
|
|
677
924
|
return this.withLoc({ kind: 'continue' }, token)
|
|
678
925
|
}
|
|
@@ -682,11 +929,45 @@ export class Parser {
|
|
|
682
929
|
return this.parseIfStmt()
|
|
683
930
|
}
|
|
684
931
|
|
|
932
|
+
// Labeled loop: ident ':' (while|for|foreach|repeat)
|
|
933
|
+
if (this.check('ident') && this.peek(1).kind === ':') {
|
|
934
|
+
const labelToken = this.advance() // consume ident
|
|
935
|
+
const colonToken = this.advance() // consume ':'
|
|
936
|
+
// Now parse the loop body
|
|
937
|
+
let loopStmt: Stmt
|
|
938
|
+
if (this.check('while')) {
|
|
939
|
+
loopStmt = this.parseWhileStmt()
|
|
940
|
+
} else if (this.check('for')) {
|
|
941
|
+
loopStmt = this.parseForStmt()
|
|
942
|
+
} else if (this.check('foreach')) {
|
|
943
|
+
loopStmt = this.parseForeachStmt()
|
|
944
|
+
} else if (this.check('repeat')) {
|
|
945
|
+
loopStmt = this.parseRepeatStmt()
|
|
946
|
+
} else {
|
|
947
|
+
throw new DiagnosticError(
|
|
948
|
+
'ParseError',
|
|
949
|
+
`Expected loop statement after label '${labelToken.value}:', found '${this.peek().kind}'`,
|
|
950
|
+
{ line: labelToken.line, col: labelToken.col },
|
|
951
|
+
)
|
|
952
|
+
}
|
|
953
|
+
return this.withLoc({ kind: 'labeled_loop', label: labelToken.value, body: loopStmt }, labelToken)
|
|
954
|
+
}
|
|
955
|
+
|
|
685
956
|
// While statement
|
|
686
957
|
if (this.check('while')) {
|
|
687
958
|
return this.parseWhileStmt()
|
|
688
959
|
}
|
|
689
960
|
|
|
961
|
+
// Do-while statement
|
|
962
|
+
if (this.check('do')) {
|
|
963
|
+
return this.parseDoWhileStmt()
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Repeat N statement
|
|
967
|
+
if (this.check('repeat')) {
|
|
968
|
+
return this.parseRepeatStmt()
|
|
969
|
+
}
|
|
970
|
+
|
|
690
971
|
// For statement
|
|
691
972
|
if (this.check('for')) {
|
|
692
973
|
return this.parseForStmt()
|
|
@@ -763,6 +1044,17 @@ export class Parser {
|
|
|
763
1044
|
return this.withLoc({ kind: 'let', name, type, init }, letToken)
|
|
764
1045
|
}
|
|
765
1046
|
|
|
1047
|
+
private parseLocalConstDecl(): Stmt {
|
|
1048
|
+
const constToken = this.expect('const')
|
|
1049
|
+
const name = this.expect('ident').value
|
|
1050
|
+
this.expect(':')
|
|
1051
|
+
const type = this.parseType()
|
|
1052
|
+
this.expect('=')
|
|
1053
|
+
const value = this.parseExpr()
|
|
1054
|
+
this.match(';')
|
|
1055
|
+
return this.withLoc({ kind: 'const_decl', name, type, value }, constToken)
|
|
1056
|
+
}
|
|
1057
|
+
|
|
766
1058
|
private parseReturnStmt(): Stmt {
|
|
767
1059
|
const returnToken = this.expect('return')
|
|
768
1060
|
|
|
@@ -801,9 +1093,7 @@ export class Parser {
|
|
|
801
1093
|
return this.withLoc({ kind: 'if_let_some', binding, init, then, else_ }, ifToken)
|
|
802
1094
|
}
|
|
803
1095
|
|
|
804
|
-
this.
|
|
805
|
-
const cond = this.parseExpr()
|
|
806
|
-
this.expect(')')
|
|
1096
|
+
const cond = this.parseParenOptionalCond()
|
|
807
1097
|
const then = this.parseBlock()
|
|
808
1098
|
|
|
809
1099
|
let else_: Block | undefined
|
|
@@ -821,14 +1111,52 @@ export class Parser {
|
|
|
821
1111
|
|
|
822
1112
|
private parseWhileStmt(): Stmt {
|
|
823
1113
|
const whileToken = this.expect('while')
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
this.
|
|
1114
|
+
|
|
1115
|
+
// while let Some(x) = expr { ... }
|
|
1116
|
+
if (this.check('let') && this.peek(1).kind === 'ident' && this.peek(1).value === 'Some') {
|
|
1117
|
+
this.advance() // consume 'let'
|
|
1118
|
+
this.advance() // consume 'Some'
|
|
1119
|
+
this.expect('(')
|
|
1120
|
+
const binding = this.expect('ident').value
|
|
1121
|
+
this.expect(')')
|
|
1122
|
+
this.expect('=')
|
|
1123
|
+
const init = this.parseExpr()
|
|
1124
|
+
const body = this.parseBlock()
|
|
1125
|
+
return this.withLoc({ kind: 'while_let_some', binding, init, body }, whileToken)
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
const cond = this.parseParenOptionalCond()
|
|
827
1129
|
const body = this.parseBlock()
|
|
828
1130
|
|
|
829
1131
|
return this.withLoc({ kind: 'while', cond, body }, whileToken)
|
|
830
1132
|
}
|
|
831
1133
|
|
|
1134
|
+
private parseDoWhileStmt(): Stmt {
|
|
1135
|
+
const doToken = this.expect('do')
|
|
1136
|
+
const body = this.parseBlock()
|
|
1137
|
+
this.expect('while')
|
|
1138
|
+
const cond = this.parseParenOptionalCond()
|
|
1139
|
+
this.match(';')
|
|
1140
|
+
return this.withLoc({ kind: 'do_while', cond, body }, doToken)
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
private parseRepeatStmt(): Stmt {
|
|
1144
|
+
const repeatToken = this.expect('repeat')
|
|
1145
|
+
const countToken = this.expect('int_lit')
|
|
1146
|
+
const count = parseInt(countToken.value, 10)
|
|
1147
|
+
const body = this.parseBlock()
|
|
1148
|
+
return this.withLoc({ kind: 'repeat', count, body }, repeatToken)
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
private parseParenOptionalCond(): Expr {
|
|
1152
|
+
if (this.match('(')) {
|
|
1153
|
+
const cond = this.parseExpr()
|
|
1154
|
+
this.expect(')')
|
|
1155
|
+
return cond
|
|
1156
|
+
}
|
|
1157
|
+
return this.parseExpr()
|
|
1158
|
+
}
|
|
1159
|
+
|
|
832
1160
|
private parseForStmt(): Stmt {
|
|
833
1161
|
const forToken = this.expect('for')
|
|
834
1162
|
|
|
@@ -986,6 +1314,22 @@ export class Parser {
|
|
|
986
1314
|
this.expect(')')
|
|
987
1315
|
return { kind: 'PatSome', binding }
|
|
988
1316
|
}
|
|
1317
|
+
// Enum pattern: EnumName::Variant or EnumName::Variant(b1, b2, ...)
|
|
1318
|
+
if (this.check('ident') && this.peek(1).kind === '::') {
|
|
1319
|
+
const enumName = this.advance().value
|
|
1320
|
+
this.expect('::')
|
|
1321
|
+
const variant = this.expect('ident').value
|
|
1322
|
+
const bindings: string[] = []
|
|
1323
|
+
if (this.check('(')) {
|
|
1324
|
+
this.advance() // consume '('
|
|
1325
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
1326
|
+
bindings.push(this.expect('ident').value)
|
|
1327
|
+
if (!this.match(',')) break
|
|
1328
|
+
}
|
|
1329
|
+
this.expect(')')
|
|
1330
|
+
}
|
|
1331
|
+
return { kind: 'PatEnum', enumName, variant, bindings }
|
|
1332
|
+
}
|
|
989
1333
|
// Integer literal
|
|
990
1334
|
if (this.check('int_lit')) {
|
|
991
1335
|
const tok = this.advance()
|
|
@@ -1390,6 +1734,17 @@ export class Parser {
|
|
|
1390
1734
|
// Member call: entity.tag("name") → __entity_tag(entity, "name")
|
|
1391
1735
|
// Also handle arr.push(val) and arr.length
|
|
1392
1736
|
if (expr.kind === 'member') {
|
|
1737
|
+
// Option.unwrap_or(default) → unwrap_or AST node
|
|
1738
|
+
if (expr.field === 'unwrap_or') {
|
|
1739
|
+
const defaultExpr = this.parseExpr()
|
|
1740
|
+
this.expect(')')
|
|
1741
|
+
expr = this.withLoc(
|
|
1742
|
+
{ kind: 'unwrap_or', opt: expr.obj, default_: defaultExpr },
|
|
1743
|
+
this.getLocToken(expr) ?? openParenToken
|
|
1744
|
+
)
|
|
1745
|
+
continue
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1393
1748
|
const methodMap: Record<string, string> = {
|
|
1394
1749
|
'tag': '__entity_tag',
|
|
1395
1750
|
'untag': '__entity_untag',
|
|
@@ -1502,6 +1857,24 @@ export class Parser {
|
|
|
1502
1857
|
this.expect('::')
|
|
1503
1858
|
const memberToken = this.expect('ident')
|
|
1504
1859
|
if (this.check('(')) {
|
|
1860
|
+
// Peek inside: if first non-'(' token is `ident :` it's enum construction with named args.
|
|
1861
|
+
// We only treat it as enum_construct when there are actual named args (not empty parens),
|
|
1862
|
+
// because empty `()` is ambiguous and most commonly means a static method call.
|
|
1863
|
+
const isNamedArgs = this.peek(1).kind === 'ident' && this.peek(2).kind === ':'
|
|
1864
|
+
if (isNamedArgs) {
|
|
1865
|
+
// Enum variant construction: EnumName::Variant(field: expr, ...)
|
|
1866
|
+
this.advance() // consume '('
|
|
1867
|
+
const args: { name: string; value: Expr }[] = []
|
|
1868
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
1869
|
+
const fieldName = this.expect('ident').value
|
|
1870
|
+
this.expect(':')
|
|
1871
|
+
const value = this.parseExpr()
|
|
1872
|
+
args.push({ name: fieldName, value })
|
|
1873
|
+
if (!this.match(',')) break
|
|
1874
|
+
}
|
|
1875
|
+
this.expect(')')
|
|
1876
|
+
return this.withLoc({ kind: 'enum_construct', enumName: typeToken.value, variant: memberToken.value, args }, typeToken)
|
|
1877
|
+
}
|
|
1505
1878
|
// Static method call: Type::method(args)
|
|
1506
1879
|
this.advance() // consume '('
|
|
1507
1880
|
const args = this.parseArgs()
|