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/parser/index.js
CHANGED
|
@@ -71,6 +71,8 @@ class Parser {
|
|
|
71
71
|
this.inLibraryMode = false;
|
|
72
72
|
/** Warnings accumulated during parsing (e.g. deprecated keyword usage). */
|
|
73
73
|
this.warnings = [];
|
|
74
|
+
/** Parse errors collected during error-recovery mode. */
|
|
75
|
+
this.parseErrors = [];
|
|
74
76
|
this.tokens = tokens;
|
|
75
77
|
this.sourceLines = source?.split('\n') ?? [];
|
|
76
78
|
this.filePath = filePath;
|
|
@@ -132,6 +134,51 @@ class Parser {
|
|
|
132
134
|
return { kind: 'eof', value: '', line: span.line, col: span.col };
|
|
133
135
|
}
|
|
134
136
|
// -------------------------------------------------------------------------
|
|
137
|
+
// Error Recovery
|
|
138
|
+
// -------------------------------------------------------------------------
|
|
139
|
+
/**
|
|
140
|
+
* Synchronize to the next top-level declaration boundary after a parse error.
|
|
141
|
+
* Skips tokens until we find a keyword that starts a top-level declaration,
|
|
142
|
+
* or a `}` (end of a block), or EOF.
|
|
143
|
+
*/
|
|
144
|
+
syncToNextDecl() {
|
|
145
|
+
const TOP_LEVEL_KEYWORDS = new Set([
|
|
146
|
+
'fn', 'struct', 'impl', 'enum', 'const', 'let', 'export', 'declare', 'import', 'namespace', 'module'
|
|
147
|
+
]);
|
|
148
|
+
while (!this.check('eof')) {
|
|
149
|
+
const kind = this.peek().kind;
|
|
150
|
+
if (kind === '}') {
|
|
151
|
+
this.advance(); // consume the stray `}`
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (TOP_LEVEL_KEYWORDS.has(kind)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Also recover on a plain ident that could be 'import' keyword used as ident
|
|
158
|
+
if (kind === 'ident' && this.peek().value === 'import') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.advance();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Synchronize to the next statement boundary inside a block after a parse error.
|
|
166
|
+
* Skips tokens until we reach `;`, `}`, or EOF.
|
|
167
|
+
*/
|
|
168
|
+
syncToNextStmt() {
|
|
169
|
+
while (!this.check('eof')) {
|
|
170
|
+
const kind = this.peek().kind;
|
|
171
|
+
if (kind === ';') {
|
|
172
|
+
this.advance(); // consume the `;`
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (kind === '}') {
|
|
176
|
+
return; // leave `}` for parseBlock to consume
|
|
177
|
+
}
|
|
178
|
+
this.advance();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// -------------------------------------------------------------------------
|
|
135
182
|
// Program
|
|
136
183
|
// -------------------------------------------------------------------------
|
|
137
184
|
parse(defaultNamespace = 'redscript') {
|
|
@@ -143,6 +190,7 @@ class Parser {
|
|
|
143
190
|
const enums = [];
|
|
144
191
|
const consts = [];
|
|
145
192
|
const imports = [];
|
|
193
|
+
const interfaces = [];
|
|
146
194
|
let isLibrary = false;
|
|
147
195
|
let moduleName;
|
|
148
196
|
// Check for namespace declaration
|
|
@@ -171,51 +219,95 @@ class Parser {
|
|
|
171
219
|
}
|
|
172
220
|
// Parse struct, function, and import declarations
|
|
173
221
|
while (!this.check('eof')) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
222
|
+
try {
|
|
223
|
+
if (this.check('decorator') && this.peek().value.startsWith('@config')) {
|
|
224
|
+
// @config decorator on a global let
|
|
225
|
+
const decorToken = this.advance();
|
|
226
|
+
const decorator = this.parseDecoratorValue(decorToken.value);
|
|
227
|
+
if (!this.check('let')) {
|
|
228
|
+
this.error('@config decorator must be followed by a let declaration');
|
|
229
|
+
}
|
|
230
|
+
const g = this.parseGlobalDecl(true);
|
|
231
|
+
g.configKey = decorator.args?.configKey;
|
|
232
|
+
g.configDefault = decorator.args?.configDefault;
|
|
233
|
+
globals.push(g);
|
|
234
|
+
}
|
|
235
|
+
else if (this.check('let')) {
|
|
236
|
+
globals.push(this.parseGlobalDecl(true));
|
|
237
|
+
}
|
|
238
|
+
else if (this.check('decorator') && this.peek().value === '@singleton') {
|
|
239
|
+
// @singleton decorator on a struct
|
|
240
|
+
this.advance(); // consume '@singleton'
|
|
241
|
+
if (!this.check('struct')) {
|
|
242
|
+
this.error('@singleton decorator must be followed by a struct declaration');
|
|
243
|
+
}
|
|
244
|
+
const s = this.parseStructDecl();
|
|
245
|
+
s.isSingleton = true;
|
|
246
|
+
structs.push(s);
|
|
247
|
+
}
|
|
248
|
+
else if (this.check('struct')) {
|
|
249
|
+
structs.push(this.parseStructDecl());
|
|
250
|
+
}
|
|
251
|
+
else if (this.check('impl')) {
|
|
252
|
+
implBlocks.push(this.parseImplBlock());
|
|
253
|
+
}
|
|
254
|
+
else if (this.check('interface')) {
|
|
255
|
+
interfaces.push(this.parseInterfaceDecl());
|
|
256
|
+
}
|
|
257
|
+
else if (this.check('enum')) {
|
|
258
|
+
enums.push(this.parseEnumDecl());
|
|
259
|
+
}
|
|
260
|
+
else if (this.check('const')) {
|
|
261
|
+
consts.push(this.parseConstDecl());
|
|
262
|
+
}
|
|
263
|
+
else if (this.check('declare')) {
|
|
264
|
+
// Declaration-only stub (e.g. from builtins.d.mcrs) — parse and discard
|
|
265
|
+
this.advance(); // consume 'declare'
|
|
266
|
+
this.parseDeclareStub();
|
|
267
|
+
}
|
|
268
|
+
else if (this.check('export')) {
|
|
269
|
+
declarations.push(this.parseExportedFnDecl());
|
|
270
|
+
}
|
|
271
|
+
else if (this.check('import') || (this.check('ident') && this.peek().value === 'import')) {
|
|
272
|
+
// `import math::sin;` or `import math::*;` or `import player_utils;` (whole-module file import)
|
|
273
|
+
this.advance(); // consume 'import' (keyword or ident)
|
|
274
|
+
const importToken = this.peek();
|
|
275
|
+
const modName = this.expect('ident').value;
|
|
276
|
+
// Check for `::` — if present, this is a symbol import; otherwise, whole-module import
|
|
277
|
+
if (this.check('::')) {
|
|
278
|
+
this.advance(); // consume '::'
|
|
279
|
+
let symbol;
|
|
280
|
+
if (this.check('*')) {
|
|
281
|
+
this.advance();
|
|
282
|
+
symbol = '*';
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
symbol = this.expect('ident').value;
|
|
286
|
+
}
|
|
287
|
+
this.match(';');
|
|
288
|
+
imports.push(this.withLoc({ moduleName: modName, symbol }, importToken));
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// Whole-module import: `import player_utils;`
|
|
292
|
+
this.match(';');
|
|
293
|
+
imports.push(this.withLoc({ moduleName: modName, symbol: undefined }, importToken));
|
|
294
|
+
}
|
|
207
295
|
}
|
|
208
296
|
else {
|
|
209
|
-
|
|
297
|
+
declarations.push(this.parseFnDecl());
|
|
210
298
|
}
|
|
211
|
-
this.match(';');
|
|
212
|
-
imports.push(this.withLoc({ moduleName: modName, symbol }, importToken));
|
|
213
299
|
}
|
|
214
|
-
|
|
215
|
-
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (err instanceof diagnostics_1.DiagnosticError) {
|
|
302
|
+
this.parseErrors.push(err);
|
|
303
|
+
this.syncToNextDecl();
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
throw err;
|
|
307
|
+
}
|
|
216
308
|
}
|
|
217
309
|
}
|
|
218
|
-
return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, isLibrary };
|
|
310
|
+
return { namespace, moduleName, globals, declarations, structs, implBlocks, enums, consts, imports, interfaces, isLibrary };
|
|
219
311
|
}
|
|
220
312
|
// -------------------------------------------------------------------------
|
|
221
313
|
// Struct Declaration
|
|
@@ -223,6 +315,7 @@ class Parser {
|
|
|
223
315
|
parseStructDecl() {
|
|
224
316
|
const structToken = this.expect('struct');
|
|
225
317
|
const name = this.expect('ident').value;
|
|
318
|
+
const extendsName = this.match('extends') ? this.expect('ident').value : undefined;
|
|
226
319
|
this.expect('{');
|
|
227
320
|
const fields = [];
|
|
228
321
|
while (!this.check('}') && !this.check('eof')) {
|
|
@@ -234,7 +327,7 @@ class Parser {
|
|
|
234
327
|
this.match(',');
|
|
235
328
|
}
|
|
236
329
|
this.expect('}');
|
|
237
|
-
return this.withLoc({ name, fields }, structToken);
|
|
330
|
+
return this.withLoc({ name, extends: extendsName, fields }, structToken);
|
|
238
331
|
}
|
|
239
332
|
parseEnumDecl() {
|
|
240
333
|
const enumToken = this.expect('enum');
|
|
@@ -245,6 +338,21 @@ class Parser {
|
|
|
245
338
|
while (!this.check('}') && !this.check('eof')) {
|
|
246
339
|
const variantToken = this.expect('ident');
|
|
247
340
|
const variant = { name: variantToken.value };
|
|
341
|
+
// Payload fields: Variant(field: Type, ...)
|
|
342
|
+
if (this.check('(')) {
|
|
343
|
+
this.advance(); // consume '('
|
|
344
|
+
const fields = [];
|
|
345
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
346
|
+
const fieldName = this.expect('ident').value;
|
|
347
|
+
this.expect(':');
|
|
348
|
+
const fieldType = this.parseType();
|
|
349
|
+
fields.push({ name: fieldName, type: fieldType });
|
|
350
|
+
if (!this.match(','))
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
this.expect(')');
|
|
354
|
+
variant.fields = fields;
|
|
355
|
+
}
|
|
248
356
|
if (this.match('=')) {
|
|
249
357
|
const valueToken = this.expect('int_lit');
|
|
250
358
|
variant.value = parseInt(valueToken.value, 10);
|
|
@@ -263,14 +371,76 @@ class Parser {
|
|
|
263
371
|
}
|
|
264
372
|
parseImplBlock() {
|
|
265
373
|
const implToken = this.expect('impl');
|
|
266
|
-
|
|
374
|
+
let traitName;
|
|
375
|
+
let typeName;
|
|
376
|
+
const firstName = this.expect('ident').value;
|
|
377
|
+
if (this.match('for')) {
|
|
378
|
+
traitName = firstName;
|
|
379
|
+
typeName = this.expect('ident').value;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
typeName = firstName;
|
|
383
|
+
}
|
|
267
384
|
this.expect('{');
|
|
268
385
|
const methods = [];
|
|
269
386
|
while (!this.check('}') && !this.check('eof')) {
|
|
270
387
|
methods.push(this.parseFnDecl(typeName));
|
|
271
388
|
}
|
|
272
389
|
this.expect('}');
|
|
273
|
-
return this.withLoc({ kind: 'impl_block', typeName, methods }, implToken);
|
|
390
|
+
return this.withLoc({ kind: 'impl_block', traitName, typeName, methods }, implToken);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Parse an interface declaration:
|
|
394
|
+
* interface <Name> {
|
|
395
|
+
* fn <method>(<params>): <retType>
|
|
396
|
+
* ...
|
|
397
|
+
* }
|
|
398
|
+
* Method signatures have no body — they are prototype-only.
|
|
399
|
+
*/
|
|
400
|
+
parseInterfaceDecl() {
|
|
401
|
+
const ifaceToken = this.expect('interface');
|
|
402
|
+
const name = this.expect('ident').value;
|
|
403
|
+
this.expect('{');
|
|
404
|
+
const methods = [];
|
|
405
|
+
while (!this.check('}') && !this.check('eof')) {
|
|
406
|
+
const fnToken = this.expect('fn');
|
|
407
|
+
const methodName = this.expect('ident').value;
|
|
408
|
+
this.expect('(');
|
|
409
|
+
const params = this.parseInterfaceParams();
|
|
410
|
+
this.expect(')');
|
|
411
|
+
let returnType;
|
|
412
|
+
if (this.match(':')) {
|
|
413
|
+
returnType = this.parseType();
|
|
414
|
+
}
|
|
415
|
+
// No body — interface methods are signature-only
|
|
416
|
+
methods.push(this.withLoc({ name: methodName, params, returnType }, fnToken));
|
|
417
|
+
}
|
|
418
|
+
this.expect('}');
|
|
419
|
+
return this.withLoc({ name, methods }, ifaceToken);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Parse interface method params — like parseParams but allows bare `self`
|
|
423
|
+
* (no `:` required for the first param named 'self').
|
|
424
|
+
*/
|
|
425
|
+
parseInterfaceParams() {
|
|
426
|
+
const params = [];
|
|
427
|
+
if (!this.check(')')) {
|
|
428
|
+
do {
|
|
429
|
+
const paramToken = this.expect('ident');
|
|
430
|
+
const paramName = paramToken.value;
|
|
431
|
+
let type;
|
|
432
|
+
if (params.length === 0 && paramName === 'self' && !this.check(':')) {
|
|
433
|
+
// self without type annotation — use a sentinel struct type
|
|
434
|
+
type = { kind: 'named', name: 'void' };
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
this.expect(':');
|
|
438
|
+
type = this.parseType();
|
|
439
|
+
}
|
|
440
|
+
params.push(this.withLoc({ name: paramName, type }, paramToken));
|
|
441
|
+
} while (this.match(','));
|
|
442
|
+
}
|
|
443
|
+
return params;
|
|
274
444
|
}
|
|
275
445
|
parseConstDecl() {
|
|
276
446
|
const constToken = this.expect('const');
|
|
@@ -294,8 +464,15 @@ class Parser {
|
|
|
294
464
|
const name = this.expect('ident').value;
|
|
295
465
|
this.expect(':');
|
|
296
466
|
const type = this.parseType();
|
|
297
|
-
|
|
298
|
-
|
|
467
|
+
let init;
|
|
468
|
+
if (this.match('=')) {
|
|
469
|
+
init = this.parseExpr();
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
// No init — valid only for @config-decorated globals (resolved later)
|
|
473
|
+
// Use a placeholder zero literal; will be replaced in compile step
|
|
474
|
+
init = { kind: 'int_lit', value: 0 };
|
|
475
|
+
}
|
|
299
476
|
this.match(';');
|
|
300
477
|
return this.withLoc({ kind: 'global', name, type, init, mutable }, token);
|
|
301
478
|
}
|
|
@@ -311,6 +488,7 @@ class Parser {
|
|
|
311
488
|
}
|
|
312
489
|
parseFnDecl(implTypeName) {
|
|
313
490
|
const decorators = this.parseDecorators();
|
|
491
|
+
const watchObjective = decorators.find(decorator => decorator.name === 'watch')?.args?.objective;
|
|
314
492
|
// Map @keep decorator to isExported flag (backward compat)
|
|
315
493
|
let isExported;
|
|
316
494
|
const filteredDecorators = decorators.filter(d => {
|
|
@@ -343,7 +521,7 @@ class Parser {
|
|
|
343
521
|
// Record the closing '}' line as endLine for accurate LSP scope detection
|
|
344
522
|
const closingBraceLine = this.tokens[this.pos - 1]?.line;
|
|
345
523
|
const fn = this.withLoc({ name, typeParams, params, returnType, decorators: filteredDecorators, body,
|
|
346
|
-
isLibraryFn: this.inLibraryMode || undefined, isExported }, fnToken);
|
|
524
|
+
isLibraryFn: this.inLibraryMode || undefined, isExported, watchObjective }, fnToken);
|
|
347
525
|
if (fn.span && closingBraceLine)
|
|
348
526
|
fn.span.endLine = closingBraceLine;
|
|
349
527
|
return fn;
|
|
@@ -378,8 +556,9 @@ class Parser {
|
|
|
378
556
|
return decorators;
|
|
379
557
|
}
|
|
380
558
|
parseDecoratorValue(value) {
|
|
381
|
-
// Parse @tick, @on(PlayerDeath),
|
|
382
|
-
|
|
559
|
+
// Parse @tick, @on(PlayerDeath), @on_trigger("name"), or @deprecated("msg with ) parens")
|
|
560
|
+
// Use a greedy match for args that allows any content inside the outermost parens.
|
|
561
|
+
const match = value.match(/^@([A-Za-z_][A-Za-z0-9_-]*)(?:\((.*)\))?$/s);
|
|
383
562
|
if (!match) {
|
|
384
563
|
this.error(`Invalid decorator: ${value}`);
|
|
385
564
|
}
|
|
@@ -388,6 +567,9 @@ class Parser {
|
|
|
388
567
|
if (!argsStr) {
|
|
389
568
|
return { name };
|
|
390
569
|
}
|
|
570
|
+
if (name === 'profile' || name === 'memoize') {
|
|
571
|
+
this.error(`@${name} decorator does not accept arguments`);
|
|
572
|
+
}
|
|
391
573
|
const args = {};
|
|
392
574
|
if (name === 'on') {
|
|
393
575
|
const eventTypeMatch = argsStr.match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
@@ -396,11 +578,14 @@ class Parser {
|
|
|
396
578
|
return { name, args };
|
|
397
579
|
}
|
|
398
580
|
}
|
|
399
|
-
// Handle @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
|
|
400
|
-
if (name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
|
|
581
|
+
// Handle @watch("objective"), @on_trigger("name"), @on_advancement("id"), @on_craft("item"), @on_join_team("team")
|
|
582
|
+
if (name === 'watch' || name === 'on_trigger' || name === 'on_advancement' || name === 'on_craft' || name === 'on_join_team') {
|
|
401
583
|
const strMatch = argsStr.match(/^"([^"]*)"$/);
|
|
402
584
|
if (strMatch) {
|
|
403
|
-
if (name === '
|
|
585
|
+
if (name === 'watch') {
|
|
586
|
+
args.objective = strMatch[1];
|
|
587
|
+
}
|
|
588
|
+
else if (name === 'on_trigger') {
|
|
404
589
|
args.trigger = strMatch[1];
|
|
405
590
|
}
|
|
406
591
|
else if (name === 'on_advancement') {
|
|
@@ -415,6 +600,38 @@ class Parser {
|
|
|
415
600
|
return { name, args };
|
|
416
601
|
}
|
|
417
602
|
}
|
|
603
|
+
// Handle @config("key", default: value)
|
|
604
|
+
if (name === 'config') {
|
|
605
|
+
// Format: @config("key_name", default: 42)
|
|
606
|
+
const configMatch = argsStr.match(/^"([^"]+)"\s*,\s*default\s*:\s*(-?\d+(?:\.\d+)?)$/);
|
|
607
|
+
if (configMatch) {
|
|
608
|
+
return { name, args: { configKey: configMatch[1], configDefault: parseFloat(configMatch[2]) } };
|
|
609
|
+
}
|
|
610
|
+
// Format: @config("key_name") — no default
|
|
611
|
+
const keyOnlyMatch = argsStr.match(/^"([^"]+)"$/);
|
|
612
|
+
if (keyOnlyMatch) {
|
|
613
|
+
return { name, args: { configKey: keyOnlyMatch[1] } };
|
|
614
|
+
}
|
|
615
|
+
this.error(`Invalid @config syntax. Expected: @config("key", default: value) or @config("key")`);
|
|
616
|
+
}
|
|
617
|
+
// Handle @deprecated("message")
|
|
618
|
+
if (name === 'deprecated') {
|
|
619
|
+
const strMatch = argsStr.match(/^"([^"]*)"$/);
|
|
620
|
+
if (strMatch) {
|
|
621
|
+
return { name, args: { message: strMatch[1] } };
|
|
622
|
+
}
|
|
623
|
+
// @deprecated with no message string
|
|
624
|
+
return { name, args: {} };
|
|
625
|
+
}
|
|
626
|
+
// @test("label") — marks a test function with a human-readable label
|
|
627
|
+
if (name === 'test') {
|
|
628
|
+
const strMatch = argsStr.match(/^"([^"]*)"$/);
|
|
629
|
+
if (strMatch) {
|
|
630
|
+
return { name, args: { testLabel: strMatch[1] } };
|
|
631
|
+
}
|
|
632
|
+
// @test with no label — use empty string
|
|
633
|
+
return { name, args: { testLabel: '' } };
|
|
634
|
+
}
|
|
418
635
|
// @require_on_load(fn_name) — when this fn is used, fn_name is called from __load.
|
|
419
636
|
// Accepts bare identifiers (with optional leading _) or quoted strings.
|
|
420
637
|
if (name === 'require_on_load') {
|
|
@@ -463,6 +680,9 @@ class Parser {
|
|
|
463
680
|
else if (key === 'team') {
|
|
464
681
|
args.team = val;
|
|
465
682
|
}
|
|
683
|
+
else if (key === 'max') {
|
|
684
|
+
args.max = parseInt(val, 10);
|
|
685
|
+
}
|
|
466
686
|
}
|
|
467
687
|
return { name, args };
|
|
468
688
|
}
|
|
@@ -579,7 +799,18 @@ class Parser {
|
|
|
579
799
|
this.expect('{');
|
|
580
800
|
const stmts = [];
|
|
581
801
|
while (!this.check('}') && !this.check('eof')) {
|
|
582
|
-
|
|
802
|
+
try {
|
|
803
|
+
stmts.push(this.parseStmt());
|
|
804
|
+
}
|
|
805
|
+
catch (err) {
|
|
806
|
+
if (err instanceof diagnostics_1.DiagnosticError) {
|
|
807
|
+
this.parseErrors.push(err);
|
|
808
|
+
this.syncToNextStmt();
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
throw err;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
583
814
|
}
|
|
584
815
|
this.expect('}');
|
|
585
816
|
return stmts;
|
|
@@ -589,19 +820,35 @@ class Parser {
|
|
|
589
820
|
if (this.check('let')) {
|
|
590
821
|
return this.parseLetStmt();
|
|
591
822
|
}
|
|
823
|
+
// Const declaration (local)
|
|
824
|
+
if (this.check('const')) {
|
|
825
|
+
return this.parseLocalConstDecl();
|
|
826
|
+
}
|
|
592
827
|
// Return statement
|
|
593
828
|
if (this.check('return')) {
|
|
594
829
|
return this.parseReturnStmt();
|
|
595
830
|
}
|
|
596
|
-
// Break statement
|
|
831
|
+
// Break statement (with optional label: break outer)
|
|
597
832
|
if (this.check('break')) {
|
|
598
833
|
const token = this.advance();
|
|
834
|
+
// Check if next token is an identifier (label name)
|
|
835
|
+
if (this.check('ident')) {
|
|
836
|
+
const labelToken = this.advance();
|
|
837
|
+
this.match(';');
|
|
838
|
+
return this.withLoc({ kind: 'break_label', label: labelToken.value }, token);
|
|
839
|
+
}
|
|
599
840
|
this.match(';');
|
|
600
841
|
return this.withLoc({ kind: 'break' }, token);
|
|
601
842
|
}
|
|
602
|
-
// Continue statement
|
|
843
|
+
// Continue statement (with optional label: continue outer)
|
|
603
844
|
if (this.check('continue')) {
|
|
604
845
|
const token = this.advance();
|
|
846
|
+
// Check if next token is an identifier (label name)
|
|
847
|
+
if (this.check('ident')) {
|
|
848
|
+
const labelToken = this.advance();
|
|
849
|
+
this.match(';');
|
|
850
|
+
return this.withLoc({ kind: 'continue_label', label: labelToken.value }, token);
|
|
851
|
+
}
|
|
605
852
|
this.match(';');
|
|
606
853
|
return this.withLoc({ kind: 'continue' }, token);
|
|
607
854
|
}
|
|
@@ -609,10 +856,41 @@ class Parser {
|
|
|
609
856
|
if (this.check('if')) {
|
|
610
857
|
return this.parseIfStmt();
|
|
611
858
|
}
|
|
859
|
+
// Labeled loop: ident ':' (while|for|foreach|repeat)
|
|
860
|
+
if (this.check('ident') && this.peek(1).kind === ':') {
|
|
861
|
+
const labelToken = this.advance(); // consume ident
|
|
862
|
+
const colonToken = this.advance(); // consume ':'
|
|
863
|
+
// Now parse the loop body
|
|
864
|
+
let loopStmt;
|
|
865
|
+
if (this.check('while')) {
|
|
866
|
+
loopStmt = this.parseWhileStmt();
|
|
867
|
+
}
|
|
868
|
+
else if (this.check('for')) {
|
|
869
|
+
loopStmt = this.parseForStmt();
|
|
870
|
+
}
|
|
871
|
+
else if (this.check('foreach')) {
|
|
872
|
+
loopStmt = this.parseForeachStmt();
|
|
873
|
+
}
|
|
874
|
+
else if (this.check('repeat')) {
|
|
875
|
+
loopStmt = this.parseRepeatStmt();
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
throw new diagnostics_1.DiagnosticError('ParseError', `Expected loop statement after label '${labelToken.value}:', found '${this.peek().kind}'`, { line: labelToken.line, col: labelToken.col });
|
|
879
|
+
}
|
|
880
|
+
return this.withLoc({ kind: 'labeled_loop', label: labelToken.value, body: loopStmt }, labelToken);
|
|
881
|
+
}
|
|
612
882
|
// While statement
|
|
613
883
|
if (this.check('while')) {
|
|
614
884
|
return this.parseWhileStmt();
|
|
615
885
|
}
|
|
886
|
+
// Do-while statement
|
|
887
|
+
if (this.check('do')) {
|
|
888
|
+
return this.parseDoWhileStmt();
|
|
889
|
+
}
|
|
890
|
+
// Repeat N statement
|
|
891
|
+
if (this.check('repeat')) {
|
|
892
|
+
return this.parseRepeatStmt();
|
|
893
|
+
}
|
|
616
894
|
// For statement
|
|
617
895
|
if (this.check('for')) {
|
|
618
896
|
return this.parseForStmt();
|
|
@@ -675,6 +953,16 @@ class Parser {
|
|
|
675
953
|
this.match(';');
|
|
676
954
|
return this.withLoc({ kind: 'let', name, type, init }, letToken);
|
|
677
955
|
}
|
|
956
|
+
parseLocalConstDecl() {
|
|
957
|
+
const constToken = this.expect('const');
|
|
958
|
+
const name = this.expect('ident').value;
|
|
959
|
+
this.expect(':');
|
|
960
|
+
const type = this.parseType();
|
|
961
|
+
this.expect('=');
|
|
962
|
+
const value = this.parseExpr();
|
|
963
|
+
this.match(';');
|
|
964
|
+
return this.withLoc({ kind: 'const_decl', name, type, value }, constToken);
|
|
965
|
+
}
|
|
678
966
|
parseReturnStmt() {
|
|
679
967
|
const returnToken = this.expect('return');
|
|
680
968
|
let value;
|
|
@@ -707,9 +995,7 @@ class Parser {
|
|
|
707
995
|
}
|
|
708
996
|
return this.withLoc({ kind: 'if_let_some', binding, init, then, else_ }, ifToken);
|
|
709
997
|
}
|
|
710
|
-
this.
|
|
711
|
-
const cond = this.parseExpr();
|
|
712
|
-
this.expect(')');
|
|
998
|
+
const cond = this.parseParenOptionalCond();
|
|
713
999
|
const then = this.parseBlock();
|
|
714
1000
|
let else_;
|
|
715
1001
|
if (this.match('else')) {
|
|
@@ -725,12 +1011,45 @@ class Parser {
|
|
|
725
1011
|
}
|
|
726
1012
|
parseWhileStmt() {
|
|
727
1013
|
const whileToken = this.expect('while');
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
1014
|
+
// while let Some(x) = expr { ... }
|
|
1015
|
+
if (this.check('let') && this.peek(1).kind === 'ident' && this.peek(1).value === 'Some') {
|
|
1016
|
+
this.advance(); // consume 'let'
|
|
1017
|
+
this.advance(); // consume 'Some'
|
|
1018
|
+
this.expect('(');
|
|
1019
|
+
const binding = this.expect('ident').value;
|
|
1020
|
+
this.expect(')');
|
|
1021
|
+
this.expect('=');
|
|
1022
|
+
const init = this.parseExpr();
|
|
1023
|
+
const body = this.parseBlock();
|
|
1024
|
+
return this.withLoc({ kind: 'while_let_some', binding, init, body }, whileToken);
|
|
1025
|
+
}
|
|
1026
|
+
const cond = this.parseParenOptionalCond();
|
|
731
1027
|
const body = this.parseBlock();
|
|
732
1028
|
return this.withLoc({ kind: 'while', cond, body }, whileToken);
|
|
733
1029
|
}
|
|
1030
|
+
parseDoWhileStmt() {
|
|
1031
|
+
const doToken = this.expect('do');
|
|
1032
|
+
const body = this.parseBlock();
|
|
1033
|
+
this.expect('while');
|
|
1034
|
+
const cond = this.parseParenOptionalCond();
|
|
1035
|
+
this.match(';');
|
|
1036
|
+
return this.withLoc({ kind: 'do_while', cond, body }, doToken);
|
|
1037
|
+
}
|
|
1038
|
+
parseRepeatStmt() {
|
|
1039
|
+
const repeatToken = this.expect('repeat');
|
|
1040
|
+
const countToken = this.expect('int_lit');
|
|
1041
|
+
const count = parseInt(countToken.value, 10);
|
|
1042
|
+
const body = this.parseBlock();
|
|
1043
|
+
return this.withLoc({ kind: 'repeat', count, body }, repeatToken);
|
|
1044
|
+
}
|
|
1045
|
+
parseParenOptionalCond() {
|
|
1046
|
+
if (this.match('(')) {
|
|
1047
|
+
const cond = this.parseExpr();
|
|
1048
|
+
this.expect(')');
|
|
1049
|
+
return cond;
|
|
1050
|
+
}
|
|
1051
|
+
return this.parseExpr();
|
|
1052
|
+
}
|
|
734
1053
|
parseForStmt() {
|
|
735
1054
|
const forToken = this.expect('for');
|
|
736
1055
|
// Check for for-range syntax: for <ident> in <range_lit> { ... }
|
|
@@ -873,6 +1192,23 @@ class Parser {
|
|
|
873
1192
|
this.expect(')');
|
|
874
1193
|
return { kind: 'PatSome', binding };
|
|
875
1194
|
}
|
|
1195
|
+
// Enum pattern: EnumName::Variant or EnumName::Variant(b1, b2, ...)
|
|
1196
|
+
if (this.check('ident') && this.peek(1).kind === '::') {
|
|
1197
|
+
const enumName = this.advance().value;
|
|
1198
|
+
this.expect('::');
|
|
1199
|
+
const variant = this.expect('ident').value;
|
|
1200
|
+
const bindings = [];
|
|
1201
|
+
if (this.check('(')) {
|
|
1202
|
+
this.advance(); // consume '('
|
|
1203
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
1204
|
+
bindings.push(this.expect('ident').value);
|
|
1205
|
+
if (!this.match(','))
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
this.expect(')');
|
|
1209
|
+
}
|
|
1210
|
+
return { kind: 'PatEnum', enumName, variant, bindings };
|
|
1211
|
+
}
|
|
876
1212
|
// Integer literal
|
|
877
1213
|
if (this.check('int_lit')) {
|
|
878
1214
|
const tok = this.advance();
|
|
@@ -1250,6 +1586,13 @@ class Parser {
|
|
|
1250
1586
|
// Member call: entity.tag("name") → __entity_tag(entity, "name")
|
|
1251
1587
|
// Also handle arr.push(val) and arr.length
|
|
1252
1588
|
if (expr.kind === 'member') {
|
|
1589
|
+
// Option.unwrap_or(default) → unwrap_or AST node
|
|
1590
|
+
if (expr.field === 'unwrap_or') {
|
|
1591
|
+
const defaultExpr = this.parseExpr();
|
|
1592
|
+
this.expect(')');
|
|
1593
|
+
expr = this.withLoc({ kind: 'unwrap_or', opt: expr.obj, default_: defaultExpr }, this.getLocToken(expr) ?? openParenToken);
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1253
1596
|
const methodMap = {
|
|
1254
1597
|
'tag': '__entity_tag',
|
|
1255
1598
|
'untag': '__entity_untag',
|
|
@@ -1334,6 +1677,25 @@ class Parser {
|
|
|
1334
1677
|
this.expect('::');
|
|
1335
1678
|
const memberToken = this.expect('ident');
|
|
1336
1679
|
if (this.check('(')) {
|
|
1680
|
+
// Peek inside: if first non-'(' token is `ident :` it's enum construction with named args.
|
|
1681
|
+
// We only treat it as enum_construct when there are actual named args (not empty parens),
|
|
1682
|
+
// because empty `()` is ambiguous and most commonly means a static method call.
|
|
1683
|
+
const isNamedArgs = this.peek(1).kind === 'ident' && this.peek(2).kind === ':';
|
|
1684
|
+
if (isNamedArgs) {
|
|
1685
|
+
// Enum variant construction: EnumName::Variant(field: expr, ...)
|
|
1686
|
+
this.advance(); // consume '('
|
|
1687
|
+
const args = [];
|
|
1688
|
+
while (!this.check(')') && !this.check('eof')) {
|
|
1689
|
+
const fieldName = this.expect('ident').value;
|
|
1690
|
+
this.expect(':');
|
|
1691
|
+
const value = this.parseExpr();
|
|
1692
|
+
args.push({ name: fieldName, value });
|
|
1693
|
+
if (!this.match(','))
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
this.expect(')');
|
|
1697
|
+
return this.withLoc({ kind: 'enum_construct', enumName: typeToken.value, variant: memberToken.value, args }, typeToken);
|
|
1698
|
+
}
|
|
1337
1699
|
// Static method call: Type::method(args)
|
|
1338
1700
|
this.advance(); // consume '('
|
|
1339
1701
|
const args = this.parseArgs();
|