@scriptc/compiler 0.0.34 → 0.0.36
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/ambient/scriptc-node-fallback.d.ts +7 -6
- package/dist/backend/build-cache.d.ts +44 -0
- package/dist/backend/build-cache.js +241 -0
- package/dist/backend/build-cache.js.map +1 -0
- package/dist/backend/{emission/emit-async.d.ts → c/async.d.ts} +21 -30
- package/dist/backend/{emission/emit-async.js → c/async.js} +270 -286
- package/dist/backend/c/async.js.map +1 -0
- package/dist/backend/{emission/emitter.d.ts → c/c-emitter.d.ts} +6 -23
- package/dist/backend/{emission/emitter.js → c/c-emitter.js} +53 -107
- package/dist/backend/c/c-emitter.js.map +1 -0
- package/dist/backend/c/exprs.d.ts +8 -0
- package/dist/backend/c/exprs.js +7913 -0
- package/dist/backend/c/exprs.js.map +1 -0
- package/dist/backend/{emission/emit-island.d.ts → c/island.d.ts} +5 -5
- package/dist/backend/{emission/emit-island.js → c/island.js} +24 -22
- package/dist/backend/c/island.js.map +1 -0
- package/dist/backend/{emission → c}/may-throw.d.ts +1 -1
- package/dist/backend/{emission → c}/may-throw.js +1 -1
- package/dist/backend/c/may-throw.js.map +1 -0
- package/dist/backend/{emission/emit-shapes.d.ts → c/shapes.d.ts} +19 -19
- package/dist/backend/{emission/emit-shapes.js → c/shapes.js} +78 -87
- package/dist/backend/c/shapes.js.map +1 -0
- package/dist/backend/{emission/emit-stmts.d.ts → c/stmts.d.ts} +12 -12
- package/dist/backend/{emission/emit-stmts.js → c/stmts.js} +377 -343
- package/dist/backend/c/stmts.js.map +1 -0
- package/dist/backend/{emission/emit-types.d.ts → c/types.d.ts} +1 -1
- package/dist/backend/{emission/emit-types.js → c/types.js} +42 -286
- package/dist/backend/c/types.js.map +1 -0
- package/dist/backend/c/types.test.js +25 -0
- package/dist/backend/c/types.test.js.map +1 -0
- package/dist/backend/{emission/emit-walkers.d.ts → c/walkers.d.ts} +19 -41
- package/dist/backend/{emission/emit-walkers.js → c/walkers.js} +238 -298
- package/dist/backend/c/walkers.js.map +1 -0
- package/dist/backend/ffi-callbacks.d.ts +1 -1
- package/dist/backend/ffi-callbacks.js +4 -3
- package/dist/backend/ffi-callbacks.js.map +1 -1
- package/dist/backend/{library-identity.d.ts → library-identity-markers.d.ts} +0 -4
- package/dist/backend/{library-identity.js → library-identity-markers.js} +10 -9
- package/dist/backend/library-identity-markers.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +4 -0
- package/dist/backend/llvm/blocks.js +29 -0
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +2 -19
- package/dist/backend/llvm/classes.js +20 -52
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +4 -0
- package/dist/backend/llvm/common.js +27 -0
- package/dist/backend/llvm/common.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +3 -8
- package/dist/backend/llvm/dyn.js +152 -224
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +4 -1
- package/dist/backend/llvm/emitter.js +514 -9981
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.d.ts +4 -0
- package/dist/backend/llvm/expr-async.js +726 -0
- package/dist/backend/llvm/expr-async.js.map +1 -0
- package/dist/backend/llvm/expr-bytes.d.ts +13 -0
- package/dist/backend/llvm/expr-bytes.js +456 -0
- package/dist/backend/llvm/expr-bytes.js.map +1 -0
- package/dist/backend/llvm/expr-callbacks.d.ts +22 -0
- package/dist/backend/llvm/expr-callbacks.js +520 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -0
- package/dist/backend/llvm/expr-calls.d.ts +2 -0
- package/dist/backend/llvm/expr-calls.js +618 -0
- package/dist/backend/llvm/expr-calls.js.map +1 -0
- package/dist/backend/llvm/expr-containers.d.ts +25 -0
- package/dist/backend/llvm/expr-containers.js +623 -0
- package/dist/backend/llvm/expr-containers.js.map +1 -0
- package/dist/backend/llvm/expr-context.d.ts +255 -0
- package/dist/backend/llvm/expr-context.js +2 -0
- package/dist/backend/llvm/expr-context.js.map +1 -0
- package/dist/backend/llvm/expr-control.d.ts +2 -0
- package/dist/backend/llvm/expr-control.js +473 -0
- package/dist/backend/llvm/expr-control.js.map +1 -0
- package/dist/backend/llvm/expr-dispatch.d.ts +4 -0
- package/dist/backend/llvm/expr-dispatch.js +151 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -0
- package/dist/backend/llvm/expr-dynamic.d.ts +2 -0
- package/dist/backend/llvm/expr-dynamic.js +810 -0
- package/dist/backend/llvm/expr-dynamic.js.map +1 -0
- package/dist/backend/llvm/expr-island.d.ts +15 -0
- package/dist/backend/llvm/expr-island.js +690 -0
- package/dist/backend/llvm/expr-island.js.map +1 -0
- package/dist/backend/llvm/expr-primitives.d.ts +6 -0
- package/dist/backend/llvm/expr-primitives.js +622 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -0
- package/dist/backend/llvm/expr-records.d.ts +9 -0
- package/dist/backend/llvm/expr-records.js +299 -0
- package/dist/backend/llvm/expr-records.js.map +1 -0
- package/dist/backend/llvm/expr-stream-bridges.d.ts +13 -0
- package/dist/backend/llvm/expr-stream-bridges.js +396 -0
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -0
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +12 -0
- package/dist/backend/llvm/expr-stream-callbacks.js +360 -0
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -0
- package/dist/backend/llvm/lib-dispatch.d.ts +5 -0
- package/dist/backend/llvm/lib-dispatch.js +267 -0
- package/dist/backend/llvm/lib-dispatch.js.map +1 -0
- package/dist/backend/llvm/lib-filesystem.d.ts +6 -0
- package/dist/backend/llvm/lib-filesystem.js +594 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -0
- package/dist/backend/llvm/lib-network.d.ts +2 -0
- package/dist/backend/llvm/lib-network.js +429 -0
- package/dist/backend/llvm/lib-network.js.map +1 -0
- package/dist/backend/llvm/lib-process.d.ts +5 -0
- package/dist/backend/llvm/lib-process.js +585 -0
- package/dist/backend/llvm/lib-process.js.map +1 -0
- package/dist/backend/llvm/lib-shared.d.ts +6 -0
- package/dist/backend/llvm/lib-shared.js +687 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -0
- package/dist/backend/llvm/lib-stream.d.ts +2 -0
- package/dist/backend/llvm/lib-stream.js +470 -0
- package/dist/backend/llvm/lib-stream.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +12 -2
- package/dist/backend/llvm/shapes.js +66 -307
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +52 -0
- package/dist/backend/llvm/shapes.test.js.map +1 -0
- package/dist/backend/llvm/split.d.ts +43 -0
- package/dist/backend/llvm/split.js +227 -0
- package/dist/backend/llvm/split.js.map +1 -0
- package/dist/backend/llvm/split.test.d.ts +1 -0
- package/dist/backend/llvm/split.test.js +102 -0
- package/dist/backend/llvm/split.test.js.map +1 -0
- package/dist/backend/llvm/unsupported.d.ts +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -3
- package/dist/backend/llvm/walkers.js +164 -218
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +38 -0
- package/dist/backend/native-codegen.js +261 -0
- package/dist/backend/native-codegen.js.map +1 -0
- package/dist/backend/native-codegen.test.d.ts +1 -0
- package/dist/backend/native-codegen.test.js +188 -0
- package/dist/backend/native-codegen.test.js.map +1 -0
- package/dist/backend/native-link-info.d.ts +96 -0
- package/dist/backend/native-link-info.js +219 -0
- package/dist/backend/native-link-info.js.map +1 -0
- package/dist/backend/native-link-info.test.d.ts +1 -0
- package/dist/backend/native-link-info.test.js +134 -0
- package/dist/backend/native-link-info.test.js.map +1 -0
- package/dist/backend/{cc.d.ts → native-toolchain.d.ts} +139 -47
- package/dist/backend/{cc.js → native-toolchain.js} +1008 -910
- package/dist/backend/native-toolchain.js.map +1 -0
- package/dist/backend/native-toolchain.test.d.ts +1 -0
- package/dist/backend/{cc-cache.test.js → native-toolchain.test.js} +1297 -127
- package/dist/backend/native-toolchain.test.js.map +1 -0
- package/dist/backend/object-localize.js +1 -1
- package/dist/backend/object-localize.test.js +20 -0
- package/dist/backend/object-localize.test.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +10 -0
- package/dist/backend/runtime-abi.js +11 -0
- package/dist/backend/runtime-abi.js.map +1 -0
- package/dist/backend/runtime-pack.d.ts +137 -0
- package/dist/backend/runtime-pack.js +400 -0
- package/dist/backend/runtime-pack.js.map +1 -0
- package/dist/backend/runtime-pack.test.d.ts +1 -0
- package/dist/backend/runtime-pack.test.js +438 -0
- package/dist/backend/runtime-pack.test.js.map +1 -0
- package/dist/backend/targets.d.ts +30 -0
- package/dist/backend/targets.js +46 -0
- package/dist/backend/targets.js.map +1 -0
- package/dist/backend/targets.test.d.ts +1 -0
- package/dist/backend/targets.test.js +19 -0
- package/dist/backend/targets.test.js.map +1 -0
- package/dist/backend/vendor-archives.d.ts +41 -0
- package/dist/backend/vendor-archives.js +462 -0
- package/dist/backend/vendor-archives.js.map +1 -0
- package/dist/compat/fetch-profile.d.ts +0 -1
- package/dist/compat/fetch-profile.js +0 -1
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/coverage/report.js +3 -3
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.js +25 -32
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +11 -12
- package/dist/diagnostics/diagnostic.js +19 -17
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.d.ts +1 -1
- package/dist/diagnostics/render.js +1 -1
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/executable/executable-cache.d.ts +86 -0
- package/dist/executable/executable-cache.js +398 -0
- package/dist/executable/executable-cache.js.map +1 -0
- package/dist/executable/executable-cache.test.d.ts +1 -0
- package/dist/executable/executable-cache.test.js +300 -0
- package/dist/executable/executable-cache.test.js.map +1 -0
- package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +7 -2
- package/dist/ffi/{profile.js → ffi-manifest.js} +2 -1
- package/dist/ffi/ffi-manifest.js.map +1 -0
- package/dist/frontend/builtin-modules.d.ts +21 -0
- package/dist/frontend/builtin-modules.js +82 -0
- package/dist/frontend/builtin-modules.js.map +1 -0
- package/dist/frontend/cjs-lexer.d.ts +7 -0
- package/dist/frontend/cjs-lexer.js +15 -17
- package/dist/frontend/cjs-lexer.js.map +1 -1
- package/dist/frontend/dts-paths.d.ts +26 -0
- package/dist/frontend/dts-paths.js +41 -0
- package/dist/frontend/dts-paths.js.map +1 -0
- package/dist/frontend/input-tracker.d.ts +0 -2
- package/dist/frontend/input-tracker.js +1 -4
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/lib-contract.d.ts +1 -5
- package/dist/frontend/lib-contract.js +1 -1
- package/dist/frontend/lib-contract.js.map +1 -1
- package/dist/frontend/lib-exports.d.ts +1 -1
- package/dist/frontend/lowering/call-position.d.ts +4 -0
- package/dist/frontend/lowering/call-position.js +7 -0
- package/dist/frontend/lowering/call-position.js.map +1 -0
- package/dist/frontend/lowering/callback-arg.d.ts +20 -0
- package/dist/frontend/lowering/callback-arg.js +44 -0
- package/dist/frontend/lowering/callback-arg.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.d.ts +1 -1
- package/dist/frontend/lowering/lib-boundary.js +34 -34
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.d.ts +3 -3
- package/dist/frontend/lowering/lower-assert.js +214 -241
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +74 -146
- package/dist/frontend/lowering/lower-builtins.js +1126 -1234
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +56 -188
- package/dist/frontend/lowering/lower-calls.js +1409 -1494
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +62 -125
- package/dist/frontend/lowering/lower-classes.js +832 -866
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.d.ts +5 -12
- package/dist/frontend/lowering/lower-comptime.js +32 -31
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +35 -135
- package/dist/frontend/lowering/lower-containers.js +1394 -1715
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.d.ts +3 -7
- package/dist/frontend/lowering/lower-dgram.js +97 -111
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-enums.d.ts +4 -4
- package/dist/frontend/lowering/lower-enums.js +30 -30
- package/dist/frontend/lowering/lower-enums.js.map +1 -1
- package/dist/frontend/lowering/{lower-emitter.d.ts → lower-event-emitter.d.ts} +7 -18
- package/dist/frontend/lowering/{lower-emitter.js → lower-event-emitter.js} +172 -174
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -0
- package/dist/frontend/lowering/lower-expando.d.ts +5 -5
- package/dist/frontend/lowering/lower-expando.js +40 -40
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +56 -264
- package/dist/frontend/lowering/lower-exprs.js +1644 -1704
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +6 -6
- package/dist/frontend/lowering/lower-generators.js +73 -72
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +5 -17
- package/dist/frontend/lowering/lower-inspect.js +236 -238
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +34 -45
- package/dist/frontend/lowering/lower-island.js +440 -511
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.d.ts +7 -10
- package/dist/frontend/lowering/lower-mixins.js +86 -86
- package/dist/frontend/lowering/lower-mixins.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +12 -18
- package/dist/frontend/lowering/lower-modules.js +284 -283
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +23 -49
- package/dist/frontend/lowering/lower-namespaces.js +123 -115
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +18 -25
- package/dist/frontend/lowering/lower-server.js +899 -899
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +30 -149
- package/dist/frontend/lowering/lower-stmts.js +1176 -1229
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +12 -12
- package/dist/frontend/lowering/lower-stream.js +300 -301
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.d.ts +5 -5
- package/dist/frontend/lowering/lower-test.js +82 -82
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +66 -20
- package/dist/frontend/lowering/lowerer.js +421 -198
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +11 -0
- package/dist/frontend/lowering/pairs-snapshot.js +85 -0
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -0
- package/dist/frontend/lowering/static-this.d.ts +6 -0
- package/dist/frontend/lowering/static-this.js +24 -0
- package/dist/frontend/lowering/static-this.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +14 -33
- package/dist/frontend/lowering/surfaces.js +64 -64
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-rewrite.js +6 -28
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static.d.ts +0 -10
- package/dist/frontend/npm-static.js +4 -7
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +0 -24
- package/dist/frontend/npm.js +11 -85
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.d.ts +3 -1
- package/dist/frontend/program.js +51 -17
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/provenance-registry.d.ts +0 -2
- package/dist/frontend/provenance-registry.js +0 -10
- package/dist/frontend/provenance-registry.js.map +1 -1
- package/dist/frontend/provenance.js +4 -7
- package/dist/frontend/provenance.js.map +1 -1
- package/dist/frontend/resolve.d.ts +7 -2
- package/dist/frontend/resolve.js +12 -17
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/resolve.test.d.ts +1 -0
- package/dist/frontend/resolve.test.js +29 -0
- package/dist/frontend/resolve.test.js.map +1 -0
- package/dist/frontend/ts7/adapter.d.ts +2 -2
- package/dist/frontend/ts7/adapter.js +1 -1
- package/dist/frontend/ts7/adapter.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +40 -2
- package/dist/frontend/ts7/checker.js +182 -54
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/enums.js +2 -1
- package/dist/frontend/ts7/enums.js.map +1 -1
- package/dist/frontend/ts7/{program.js → program-adapter.js} +7 -6
- package/dist/frontend/ts7/program-adapter.js.map +1 -0
- package/dist/frontend/ts7/world-check.d.ts +1 -3
- package/dist/frontend/ts7/world-check.js +3 -1
- package/dist/frontend/ts7/world-check.js.map +1 -1
- package/dist/frontend/tsc-codes.d.ts +8 -0
- package/dist/frontend/tsc-codes.js +109 -0
- package/dist/frontend/tsc-codes.js.map +1 -0
- package/dist/frontend/{types.d.ts → type-mapper.d.ts} +2 -25
- package/dist/frontend/{types.js → type-mapper.js} +31 -52
- package/dist/frontend/type-mapper.js.map +1 -0
- package/dist/frontend/workspace-registry.d.ts +26 -0
- package/dist/frontend/workspace-registry.js +71 -0
- package/dist/frontend/workspace-registry.js.map +1 -0
- package/dist/index.d.ts +115 -30
- package/dist/index.js +650 -146
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +37 -0
- package/dist/ir/analysis.js +118 -0
- package/dist/ir/analysis.js.map +1 -0
- package/dist/ir/analysis.test.d.ts +1 -0
- package/dist/ir/analysis.test.js +21 -0
- package/dist/ir/analysis.test.js.map +1 -0
- package/dist/ir/build.d.ts +9 -0
- package/dist/ir/build.js +33 -0
- package/dist/ir/build.js.map +1 -0
- package/dist/ir/integer-loops.d.ts +1 -1
- package/dist/ir/{nodes.d.ts → ir.d.ts} +60 -26
- package/dist/ir/{nodes.js → ir.js} +173 -141
- package/dist/ir/ir.js.map +1 -0
- package/dist/ir/ir.test.d.ts +1 -0
- package/dist/ir/ir.test.js +17 -0
- package/dist/ir/ir.test.js.map +1 -0
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +2 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/validate.d.ts +1 -1
- package/dist/ir/validate.js +16 -5
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/cache-primitives.d.ts +24 -0
- package/dist/library/cache-primitives.js +83 -0
- package/dist/library/cache-primitives.js.map +1 -0
- package/dist/library/cache-reset.test.d.ts +1 -0
- package/dist/library/cache-reset.test.js +47 -0
- package/dist/library/cache-reset.test.js.map +1 -0
- package/dist/library/compiler-self-identity.d.ts +23 -0
- package/dist/library/compiler-self-identity.js +84 -0
- package/dist/library/compiler-self-identity.js.map +1 -0
- package/dist/library/fence-eval.d.ts +3 -1
- package/dist/library/fence-eval.js +5 -1
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.d.ts +1 -36
- package/dist/library/int-infer.js +17 -17
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
- package/dist/library/{early-cache.js → library-cache.js} +37 -111
- package/dist/library/library-cache.js.map +1 -0
- package/dist/library/library-cache.test.d.ts +1 -0
- package/dist/library/{early-cache.test.js → library-cache.test.js} +2 -2
- package/dist/library/library-cache.test.js.map +1 -0
- package/dist/library/{profile.d.ts → library-profile.d.ts} +4 -7
- package/dist/library/{profile.js → library-profile.js} +18 -11
- package/dist/library/library-profile.js.map +1 -0
- package/dist/library/semantic-source.js +2 -1
- package/dist/library/semantic-source.js.map +1 -1
- package/dist/library/sidecar.d.ts +5 -2
- package/dist/library/sidecar.js +11 -5
- package/dist/library/sidecar.js.map +1 -1
- package/dist/startup-cache.d.ts +6 -0
- package/dist/startup-cache.js +6 -0
- package/dist/startup-cache.js.map +1 -0
- package/package.json +7 -2
- package/surface-manifest.json +1 -1
- package/dist/backend/cc-cache.test.js.map +0 -1
- package/dist/backend/cc.js.map +0 -1
- package/dist/backend/emission/emit-async.js.map +0 -1
- package/dist/backend/emission/emit-exprs.d.ts +0 -13
- package/dist/backend/emission/emit-exprs.js +0 -7407
- package/dist/backend/emission/emit-exprs.js.map +0 -1
- package/dist/backend/emission/emit-island.js.map +0 -1
- package/dist/backend/emission/emit-shapes.js.map +0 -1
- package/dist/backend/emission/emit-stmts.js.map +0 -1
- package/dist/backend/emission/emit-types.js.map +0 -1
- package/dist/backend/emission/emit-walkers.js.map +0 -1
- package/dist/backend/emission/emitter.js.map +0 -1
- package/dist/backend/emission/may-throw.js.map +0 -1
- package/dist/backend/library-identity.js.map +0 -1
- package/dist/ffi/profile.js.map +0 -1
- package/dist/frontend/lowering/lower-emitter.js.map +0 -1
- package/dist/frontend/shared.d.ts +0 -82
- package/dist/frontend/shared.js +0 -308
- package/dist/frontend/shared.js.map +0 -1
- package/dist/frontend/ts7/program.js.map +0 -1
- package/dist/frontend/types.js.map +0 -1
- package/dist/ir/nodes.js.map +0 -1
- package/dist/library/early-cache.js.map +0 -1
- package/dist/library/early-cache.test.js.map +0 -1
- package/dist/library/profile.js.map +0 -1
- /package/dist/backend/{cc-cache.test.d.ts → c/types.test.d.ts} +0 -0
- /package/dist/{library/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
- /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
import { InternalCompilerError } from "../../errors.js";
|
|
1
2
|
import { mangleField, mangleGlobal, mangleLocal, mangleRawParam } from "../mangle.js";
|
|
2
|
-
import { BOOL, CAUGHT, RUNTIME_ERROR_CLASSES, isRefCounted } from "../../ir/
|
|
3
|
-
import { boxAccess, cDecl, cStringLiteral, elemAccess, vAdapters } from "./
|
|
4
|
-
import { OVERFLOW_MEMBER } from "./
|
|
5
|
-
import { emitBytesReceiver } from "./
|
|
3
|
+
import { BOOL, CAUGHT, RUNTIME_ERROR_CLASSES, isRefCounted } from "../../ir/ir.js";
|
|
4
|
+
import { boxAccess, cDecl, cStringLiteral, elemAccess, vAdapters } from "./types.js";
|
|
5
|
+
import { OVERFLOW_MEMBER } from "./shapes.js";
|
|
6
|
+
import { emitBytesReceiver } from "./exprs.js";
|
|
6
7
|
import { matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
import { endsWithJump, matchStringSelfConcat } from "../../ir/analysis.js";
|
|
9
|
+
export function emitFunction(emitter, fn) {
|
|
10
|
+
emitter.tempCounter = 0;
|
|
11
|
+
emitter.frames = [];
|
|
12
|
+
emitter.scopes = [];
|
|
13
|
+
emitter.jumpTargets = [];
|
|
14
|
+
emitter.tryStack = [];
|
|
15
|
+
emitter.finallyStack = [];
|
|
16
|
+
emitter.currentReturnType = fn.returnType;
|
|
17
|
+
emitter.currentGenerator = fn.generator ?? null;
|
|
18
|
+
emitter.labelCounter = 0;
|
|
19
|
+
emitter.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
|
|
20
|
+
emitter.captureIds = new Set((fn.captures ?? []).map((c) => c.localId));
|
|
21
|
+
emitter.integerLoopBindings.clear();
|
|
22
|
+
emitter.line(`${emitter.signature(fn)} {${emitter.srcComment(fn.loc)}`);
|
|
23
|
+
emitter.indent++;
|
|
22
24
|
// The pending-return slot: a `return` crossing a finally computes its
|
|
23
25
|
// value FIRST (before the finally runs — snapshotting it here is what
|
|
24
26
|
// makes finally mutations of returned locals invisible, Node-exact),
|
|
@@ -26,54 +28,54 @@ export function emitFunction(E, fn) {
|
|
|
26
28
|
// the slot. Declared only when some return actually crosses a finally.
|
|
27
29
|
if (fn.returnType.kind !== "void" && returnCrossesFinally(fn.body)) {
|
|
28
30
|
const init = isRefCounted(fn.returnType) ? "NULL" : "0";
|
|
29
|
-
|
|
31
|
+
emitter.line(`${cDecl(fn.returnType, "sc_pret")} = ${init}; /* pending return (through finally) */`);
|
|
30
32
|
}
|
|
31
33
|
// Captured bindings come in through the environment — borrowed for the
|
|
32
34
|
// whole call (the closure owns them): bound here, never released here.
|
|
33
35
|
(fn.captures ?? []).forEach((c, i) => {
|
|
34
|
-
|
|
36
|
+
emitter.line(`ScrBox *${mangleLocal(c.localId)} = sc_env->caps[${i}]; /* captured ${c.name} */`);
|
|
35
37
|
});
|
|
36
38
|
const paramIds = new Set(fn.params.map((p) => p.localId));
|
|
37
39
|
for (const local of fn.locals) {
|
|
38
|
-
if (paramIds.has(local.id) ||
|
|
40
|
+
if (paramIds.has(local.id) || emitter.captureIds.has(local.id))
|
|
39
41
|
continue;
|
|
40
42
|
if (local.boxed) {
|
|
41
|
-
|
|
43
|
+
emitter.line(`ScrBox *${mangleLocal(local.id)} = NULL; /* ${local.name} (boxed) */`);
|
|
42
44
|
}
|
|
43
45
|
else {
|
|
44
46
|
const init = isRefCounted(local.type) ? " = NULL" : "";
|
|
45
|
-
|
|
47
|
+
emitter.line(`${cDecl(local.type, mangleLocal(local.id))}${init}; /* ${local.name} */`);
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
// Function scope owns refcounted params (callees own their params).
|
|
49
51
|
// Boxed params: allocate the shared binding and move the raw value in.
|
|
50
52
|
const fnScope = [];
|
|
51
53
|
for (const p of fn.params) {
|
|
52
|
-
const local =
|
|
54
|
+
const local = emitter.currentLocals.get(p.localId);
|
|
53
55
|
if (local.boxed) {
|
|
54
56
|
const box = mangleLocal(p.localId);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
emitter.line(`ScrBox *${box} = ${emitter.boxNewC(p.type)}; /* ${p.name} (boxed param) */`);
|
|
58
|
+
emitter.line(`scr_box_set_${boxAccess(p.type)}(${box}, ${mangleRawParam(p.localId)});`);
|
|
57
59
|
fnScope.push({ name: box, type: p.type, boxed: true });
|
|
58
60
|
}
|
|
59
61
|
else if (isRefCounted(p.type)) {
|
|
60
62
|
fnScope.push({ name: mangleLocal(p.localId), type: p.type });
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
emitter.scopes.push(fnScope);
|
|
66
|
+
emitter.emitStmts(fn.body);
|
|
65
67
|
// Implicit exit of a void function: release function-scope refcounted
|
|
66
68
|
// locals (unless the body already ended in an explicit return or a
|
|
67
69
|
// throw, whose unwind released everything down to depth 0).
|
|
68
70
|
const last = fn.body[fn.body.length - 1]?.kind;
|
|
69
71
|
const endedWithReturn = last === "return" || last === "throw" || last === "rethrow" || last === "runtimeFence";
|
|
70
72
|
if (fn.returnType.kind === "void" && !endedWithReturn) {
|
|
71
|
-
|
|
73
|
+
emitter.releaseFrame(emitter.scopes[0]);
|
|
72
74
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
emitter.scopes.pop();
|
|
76
|
+
emitter.indent--;
|
|
77
|
+
emitter.line(`}`);
|
|
78
|
+
emitter.line(``);
|
|
77
79
|
}
|
|
78
80
|
/** The statement bodies nested directly under a statement — the shared
|
|
79
81
|
* walk for returnCrossesFinally. */
|
|
@@ -120,29 +122,29 @@ function returnCrossesFinally(stmts) {
|
|
|
120
122
|
* end). `setup` runs after the scope opens, before the statements — the
|
|
121
123
|
* catch-binding hook: it may emit prelude lines and register entries the
|
|
122
124
|
* scope owns (released on every exit, jumps and unwinds included). */
|
|
123
|
-
export function emitBlock(
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
export function emitBlock(emitter, stmts, setup) {
|
|
126
|
+
emitter.line(`{`);
|
|
127
|
+
emitter.indent++;
|
|
126
128
|
const scope = [];
|
|
127
|
-
|
|
129
|
+
emitter.scopes.push(scope);
|
|
128
130
|
setup?.(scope);
|
|
129
|
-
|
|
130
|
-
const endedWithJump =
|
|
131
|
-
|
|
131
|
+
emitter.emitStmts(stmts);
|
|
132
|
+
const endedWithJump = endsWithJump(stmts);
|
|
133
|
+
emitter.scopes.pop();
|
|
132
134
|
if (!endedWithJump)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
emitter.releaseFrame(scope);
|
|
136
|
+
emitter.indent--;
|
|
137
|
+
emitter.line(`}`);
|
|
136
138
|
}
|
|
137
|
-
export function emitStmts(
|
|
139
|
+
export function emitStmts(emitter, stmts) {
|
|
138
140
|
for (const s of stmts)
|
|
139
|
-
|
|
141
|
+
emitter.emitStmt(s);
|
|
140
142
|
}
|
|
141
|
-
export function emitStmt(
|
|
142
|
-
|
|
143
|
+
export function emitStmt(emitter, s) {
|
|
144
|
+
emitter.frames.push([]);
|
|
143
145
|
switch (s.kind) {
|
|
144
146
|
case "varDecl": {
|
|
145
|
-
const local =
|
|
147
|
+
const local = emitter.currentLocals.get(s.localId);
|
|
146
148
|
const target = mangleLocal(s.localId);
|
|
147
149
|
if (s.init === null) {
|
|
148
150
|
// Declared, uninitialized (`let x: number;`). tsc's TS2454 rejects
|
|
@@ -163,13 +165,13 @@ export function emitStmt(E, s) {
|
|
|
163
165
|
// bit pattern to spend on it.
|
|
164
166
|
const boxNew = local.tdz && boxAccess(local.type) !== "ref"
|
|
165
167
|
? "scr_box_new(SCR_BOX_ARR)"
|
|
166
|
-
:
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
: emitter.boxNewC(local.type);
|
|
169
|
+
emitter.line(`${target} = ${boxNew};${emitter.srcComment(s.loc)} /* let ${local.name}; */`);
|
|
170
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
|
|
169
171
|
}
|
|
170
172
|
else if (isRefCounted(local.type)) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
emitter.line(`${target} = NULL;${emitter.srcComment(s.loc)} /* let ${local.name}; */`);
|
|
174
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type });
|
|
173
175
|
}
|
|
174
176
|
// Scalars need nothing: the C local exists from the prologue and
|
|
175
177
|
// no read happens before an assign writes it.
|
|
@@ -178,203 +180,235 @@ export function emitStmt(E, s) {
|
|
|
178
180
|
if (local.boxed) {
|
|
179
181
|
// Box FIRST, then evaluate the initializer: a named function
|
|
180
182
|
// expression's closure captures this box during init evaluation.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const v =
|
|
183
|
+
emitter.line(`${target} = ${emitter.boxNewC(local.type)};${emitter.srcComment(s.loc)}`);
|
|
184
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: local.type, boxed: true });
|
|
185
|
+
const v = emitter.emitExpr(s.init);
|
|
184
186
|
if (isRefCounted(v.type))
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
emitter.moveTemp(v); // the box takes ownership
|
|
188
|
+
emitter.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});`);
|
|
187
189
|
break;
|
|
188
190
|
}
|
|
189
|
-
const v =
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
const v = emitter.emitExpr(s.init);
|
|
192
|
+
emitter.moveTemp(v);
|
|
193
|
+
emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
192
194
|
if (isRefCounted(v.type)) {
|
|
193
|
-
|
|
195
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: target, type: v.type });
|
|
194
196
|
}
|
|
195
197
|
break;
|
|
196
198
|
}
|
|
197
199
|
case "assign": {
|
|
198
|
-
const local =
|
|
200
|
+
const local = emitter.currentLocals.get(s.localId);
|
|
201
|
+
const concat = s.value;
|
|
202
|
+
const suffix = matchStringSelfConcat(s.localId, concat);
|
|
203
|
+
if (suffix && concat.kind === "strConcat") {
|
|
204
|
+
// Snapshot the old left value before evaluating the suffix. The
|
|
205
|
+
// snapshot is a normal frame-owned +1: the suffix may reassign the
|
|
206
|
+
// destination or throw, in which case unwinding must still release
|
|
207
|
+
// it while leaving the original binding intact.
|
|
208
|
+
const snapshot = emitter.emitExpr(concat.left);
|
|
209
|
+
const right = emitter.emitExpr(suffix);
|
|
210
|
+
const target = local ? mangleLocal(s.localId) : mangleGlobal(s.localId);
|
|
211
|
+
if (local?.boxed) {
|
|
212
|
+
// set_ref unlinks then releases the binding's CURRENT value. It
|
|
213
|
+
// may differ from snapshot when the suffix itself assigned target.
|
|
214
|
+
emitter.line(`scr_box_set_ref(${target}, NULL);`);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
const old = `sc_t${emitter.tempCounter++}`;
|
|
218
|
+
emitter.line(`ScrStr *${old} = ${target};`);
|
|
219
|
+
emitter.line(`${target} = NULL;`);
|
|
220
|
+
emitter.releaseValue(old, snapshot.type);
|
|
221
|
+
}
|
|
222
|
+
const result = emitter.newTemp(s.value.type, `scr_str_concat(${snapshot.name}, ${right.name})`);
|
|
223
|
+
if (local?.boxed) {
|
|
224
|
+
emitter.moveTemp(result); // the box takes the concat result's +1
|
|
225
|
+
emitter.line(`scr_box_set_ref(${target}, ${result.name});${emitter.srcComment(s.loc)}`);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
emitter.moveTemp(result); // binding takes the concat result's +1
|
|
229
|
+
emitter.line(`${target} = ${result.name};${emitter.srcComment(s.loc)}`);
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
199
233
|
if (!local) {
|
|
200
234
|
// Module global: plain static storage, never boxed. Old-value
|
|
201
235
|
// release is NULL-tolerant (statics start NULL).
|
|
202
|
-
const g =
|
|
236
|
+
const g = emitter.globalsById.get(s.localId);
|
|
203
237
|
if (!g)
|
|
204
|
-
throw new
|
|
238
|
+
throw new InternalCompilerError(`emitter bug: assign to unknown binding ${s.localId}`);
|
|
205
239
|
const target = mangleGlobal(g.id);
|
|
206
|
-
const v =
|
|
207
|
-
|
|
240
|
+
const v = emitter.emitExpr(s.value);
|
|
241
|
+
emitter.moveTemp(v);
|
|
208
242
|
if (isRefCounted(v.type))
|
|
209
|
-
|
|
210
|
-
|
|
243
|
+
emitter.releaseValue(target, v.type);
|
|
244
|
+
emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
211
245
|
break;
|
|
212
246
|
}
|
|
213
247
|
const target = mangleLocal(s.localId);
|
|
214
|
-
const v =
|
|
248
|
+
const v = emitter.emitExpr(s.value);
|
|
215
249
|
if (local.boxed) {
|
|
216
250
|
// A scalar TDZ box (forward-captured const): the initializing
|
|
217
251
|
// write mints the one-element array cell — set_ref moves it in
|
|
218
252
|
// (and the empty-slot sentinel ends here).
|
|
219
253
|
if (local.tdz && boxAccess(local.type) !== "ref") {
|
|
220
254
|
const acc = boxAccess(local.type);
|
|
221
|
-
const cell = `sc_t${
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
255
|
+
const cell = `sc_t${emitter.tempCounter++}`;
|
|
256
|
+
emitter.line(`ScrArr *${cell} = ${emitter.arrNewC(local.type, 1)};${emitter.srcComment(s.loc)}`);
|
|
257
|
+
emitter.line(`scr_arr_push_${acc}(${cell}, ${v.name});`);
|
|
258
|
+
emitter.line(`scr_box_set_ref(${target}, ${cell});`);
|
|
225
259
|
break;
|
|
226
260
|
}
|
|
227
261
|
if (isRefCounted(v.type))
|
|
228
|
-
|
|
229
|
-
|
|
262
|
+
emitter.moveTemp(v); // set_ref releases the old value
|
|
263
|
+
emitter.line(`scr_box_set_${boxAccess(local.type)}(${target}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
230
264
|
break;
|
|
231
265
|
}
|
|
232
|
-
|
|
266
|
+
emitter.moveTemp(v);
|
|
233
267
|
if (isRefCounted(v.type))
|
|
234
|
-
|
|
235
|
-
|
|
268
|
+
emitter.releaseValue(target, v.type);
|
|
269
|
+
emitter.line(`${target} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
236
270
|
break;
|
|
237
271
|
}
|
|
238
272
|
case "exprStmt":
|
|
239
|
-
|
|
273
|
+
emitter.emitExpr(s.expr);
|
|
240
274
|
break;
|
|
241
275
|
case "if": {
|
|
242
|
-
const cond =
|
|
243
|
-
|
|
244
|
-
|
|
276
|
+
const cond = emitter.emitCondition(s.cond);
|
|
277
|
+
emitter.line(`if (${cond}) `);
|
|
278
|
+
emitter.mergeBrace(() => emitter.emitBlock(s.then));
|
|
245
279
|
if (s.else_) {
|
|
246
|
-
|
|
247
|
-
|
|
280
|
+
emitter.line(`else `);
|
|
281
|
+
emitter.mergeBrace(() => emitter.emitBlock(s.else_));
|
|
248
282
|
}
|
|
249
283
|
break;
|
|
250
284
|
}
|
|
251
285
|
case "while": {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const cond =
|
|
255
|
-
|
|
286
|
+
emitter.line(`for (;;) {${emitter.srcComment(s.loc)}`);
|
|
287
|
+
emitter.indent++;
|
|
288
|
+
const cond = emitter.emitCondition(s.cond);
|
|
289
|
+
emitter.line(`if (!(${cond})) break;`);
|
|
256
290
|
// C continue re-evaluates the condition at the top: exactly right
|
|
257
291
|
// for the unlabeled loop. A LABELED while allocates a continue
|
|
258
292
|
// label placed at the END of the body (falling off it re-enters
|
|
259
293
|
// the condition — the same point) so a labeled continue from a
|
|
260
294
|
// NESTED loop can goto it, and a lazy end label for labeled break.
|
|
261
|
-
const loop =
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
295
|
+
const loop = emitter.loopTarget(null, s.labels);
|
|
296
|
+
emitter.jumpTargets.push(loop);
|
|
297
|
+
emitter.emitBlock(s.body);
|
|
298
|
+
emitter.jumpTargets.pop();
|
|
265
299
|
if (loop.usedContinue && loop.continueLabel)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
300
|
+
emitter.line(`${loop.continueLabel}:;`);
|
|
301
|
+
emitter.indent--;
|
|
302
|
+
emitter.line(`}`);
|
|
269
303
|
if (loop.usedEnd)
|
|
270
|
-
|
|
304
|
+
emitter.line(`${loop.endLabel}:;`);
|
|
271
305
|
break;
|
|
272
306
|
}
|
|
273
307
|
case "doWhile": {
|
|
274
308
|
// `for (;;) { body; cont: cond; if (!cond) break; }` — the body runs
|
|
275
309
|
// before the first condition check (at least once), and `continue`
|
|
276
310
|
// routes through the label so the condition still evaluates.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const loop =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
311
|
+
emitter.line(`for (;;) {${emitter.srcComment(s.loc)}`);
|
|
312
|
+
emitter.indent++;
|
|
313
|
+
const loop = emitter.loopTarget(`sc_cont_${emitter.labelCounter++}`, s.labels);
|
|
314
|
+
emitter.jumpTargets.push(loop);
|
|
315
|
+
emitter.emitBlock(s.body);
|
|
316
|
+
emitter.jumpTargets.pop();
|
|
283
317
|
if (loop.usedContinue)
|
|
284
|
-
|
|
285
|
-
const cond =
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
318
|
+
emitter.line(`${loop.continueLabel}:;`);
|
|
319
|
+
const cond = emitter.emitCondition(s.cond);
|
|
320
|
+
emitter.line(`if (!(${cond})) break;`);
|
|
321
|
+
emitter.indent--;
|
|
322
|
+
emitter.line(`}`);
|
|
289
323
|
if (loop.usedEnd)
|
|
290
|
-
|
|
324
|
+
emitter.line(`${loop.endLabel}:;`);
|
|
291
325
|
break;
|
|
292
326
|
}
|
|
293
327
|
case "switch":
|
|
294
|
-
|
|
328
|
+
emitter.emitSwitch(s);
|
|
295
329
|
break;
|
|
296
330
|
case "for": {
|
|
297
331
|
// Desugared in place; the init's scope wraps the whole loop, so
|
|
298
332
|
// break/continue must NOT release it (scopeDepth captured after).
|
|
299
|
-
const integerLoop = matchIntegerBytesForLoop(s,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
333
|
+
const integerLoop = matchIntegerBytesForLoop(s, emitter.currentLocals);
|
|
334
|
+
emitter.line(`{${emitter.srcComment(s.loc)}`);
|
|
335
|
+
emitter.indent++;
|
|
336
|
+
emitter.scopes.push([]);
|
|
303
337
|
let integerShadow = null;
|
|
304
338
|
if (integerLoop) {
|
|
305
|
-
integerShadow = `sc_i${
|
|
306
|
-
|
|
307
|
-
|
|
339
|
+
integerShadow = `sc_i${emitter.tempCounter++}`;
|
|
340
|
+
emitter.line(`uint64_t ${integerShadow} = 0; /* integer induction ${emitter.currentLocals.get(integerLoop.localId).name} */`);
|
|
341
|
+
emitter.integerLoopBindings.set(integerLoop.localId, integerShadow);
|
|
308
342
|
}
|
|
309
343
|
else if (s.init) {
|
|
310
|
-
|
|
344
|
+
emitter.emitStmt(s.init);
|
|
311
345
|
}
|
|
312
|
-
|
|
313
|
-
|
|
346
|
+
emitter.line(`for (;;) {`);
|
|
347
|
+
emitter.indent++;
|
|
314
348
|
if (integerLoop && integerShadow) {
|
|
315
|
-
const receiver = emitBytesReceiver(
|
|
316
|
-
|
|
349
|
+
const receiver = emitBytesReceiver(emitter, integerLoop.limitReceiver, []);
|
|
350
|
+
emitter.line(`if (!(${integerShadow} < ${receiver.name}->len)) break;`);
|
|
317
351
|
}
|
|
318
352
|
else if (s.cond) {
|
|
319
|
-
const cond =
|
|
320
|
-
|
|
353
|
+
const cond = emitter.emitCondition(s.cond);
|
|
354
|
+
emitter.line(`if (!(${cond})) break;`);
|
|
321
355
|
}
|
|
322
356
|
// C continue would skip the update; route it through a label instead.
|
|
323
|
-
const loop =
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
357
|
+
const loop = emitter.loopTarget(`sc_cont_${emitter.labelCounter++}`, s.labels);
|
|
358
|
+
emitter.jumpTargets.push(loop);
|
|
359
|
+
emitter.emitBlock(s.body);
|
|
360
|
+
emitter.jumpTargets.pop();
|
|
327
361
|
if (loop.usedContinue)
|
|
328
|
-
|
|
362
|
+
emitter.line(`${loop.continueLabel}:;`);
|
|
329
363
|
// JS `for (let i ...)`: each iteration gets a FRESH binding holding a
|
|
330
364
|
// copy of the previous one, and the update mutates the fresh binding
|
|
331
365
|
// — that's why closures made in iteration k keep seeing iteration
|
|
332
366
|
// k's value. Only observable (and only emitted) when captured.
|
|
333
367
|
if (s.init?.kind === "varDecl") {
|
|
334
|
-
const initLocal =
|
|
368
|
+
const initLocal = emitter.currentLocals.get(s.init.localId);
|
|
335
369
|
if (initLocal?.boxed) {
|
|
336
370
|
const box = mangleLocal(initLocal.id);
|
|
337
|
-
const fresh = `sc_t${
|
|
371
|
+
const fresh = `sc_t${emitter.tempCounter++}`;
|
|
338
372
|
const acc = boxAccess(initLocal.type);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
373
|
+
emitter.line(`ScrBox *${fresh} = ${emitter.boxNewC(initLocal.type)}; /* per-iteration ${initLocal.name} */`);
|
|
374
|
+
emitter.line(`scr_box_set_${acc}(${fresh}, scr_box_get_${acc}(${box}));`);
|
|
375
|
+
emitter.line(`scr_box_release(${box});`);
|
|
376
|
+
emitter.line(`${box} = ${fresh};`);
|
|
343
377
|
// The wrapper scope's entry releases whatever `box` points to at
|
|
344
378
|
// loop exit — which is now the freshest binding. Nothing to fix.
|
|
345
379
|
}
|
|
346
380
|
}
|
|
347
381
|
if (integerLoop && integerShadow)
|
|
348
|
-
|
|
382
|
+
emitter.line(`${integerShadow}++;`);
|
|
349
383
|
else if (s.update)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
384
|
+
emitter.emitStmt(s.update);
|
|
385
|
+
emitter.indent--;
|
|
386
|
+
emitter.line(`}`);
|
|
353
387
|
// A labeled break lands exactly where C break does: BEFORE the
|
|
354
388
|
// init scope's release (the goto path must run the same releases
|
|
355
389
|
// as the fall-through path).
|
|
356
390
|
if (loop.usedEnd)
|
|
357
|
-
|
|
358
|
-
|
|
391
|
+
emitter.line(`${loop.endLabel}:;`);
|
|
392
|
+
emitter.releaseFrame(emitter.scopes.pop());
|
|
359
393
|
if (integerLoop)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
394
|
+
emitter.integerLoopBindings.delete(integerLoop.localId);
|
|
395
|
+
emitter.indent--;
|
|
396
|
+
emitter.line(`}`);
|
|
363
397
|
break;
|
|
364
398
|
}
|
|
365
399
|
case "arraySet": {
|
|
366
400
|
// Evaluation order matches JS: array, index, then value. Ownership
|
|
367
401
|
// of a refcounted value moves into the array (the runtime releases
|
|
368
402
|
// the replaced element itself).
|
|
369
|
-
const arr =
|
|
370
|
-
const idx =
|
|
371
|
-
const v =
|
|
403
|
+
const arr = emitter.emitExpr(s.arr);
|
|
404
|
+
const idx = emitter.emitExpr(s.index);
|
|
405
|
+
const v = emitter.emitExpr(s.value);
|
|
372
406
|
if (s.arr.type.kind !== "array")
|
|
373
|
-
throw new
|
|
407
|
+
throw new InternalCompilerError("emitter bug: arraySet on non-array");
|
|
374
408
|
const acc = elemAccess(s.arr.type.elem);
|
|
375
409
|
if (acc === "ref")
|
|
376
|
-
|
|
377
|
-
|
|
410
|
+
emitter.moveTemp(v);
|
|
411
|
+
emitter.line(`scr_arr_set_${acc}(${arr.name}, ${idx.name}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
378
412
|
break;
|
|
379
413
|
}
|
|
380
414
|
case "bytesSet": {
|
|
@@ -383,13 +417,13 @@ export function emitStmt(E, s) {
|
|
|
383
417
|
// JS-exactly), so no ownership moves. Any invalid index traps — no
|
|
384
418
|
// append. The IR carries the element kind; do not rediscover it in
|
|
385
419
|
// the generic runtime accessor on every loop iteration.
|
|
386
|
-
const arr = emitBytesReceiver(
|
|
387
|
-
const integerIndex =
|
|
388
|
-
const idx = integerIndex === null ?
|
|
389
|
-
const v =
|
|
420
|
+
const arr = emitBytesReceiver(emitter, s.arr, [s.index, s.value]);
|
|
421
|
+
const integerIndex = emitter.integerLoopIndex(s.index);
|
|
422
|
+
const idx = integerIndex === null ? emitter.emitExpr(s.index).name : integerIndex;
|
|
423
|
+
const v = emitter.emitExpr(s.value);
|
|
390
424
|
if (s.arr.type.kind !== "bytes")
|
|
391
|
-
throw new
|
|
392
|
-
|
|
425
|
+
throw new InternalCompilerError("emitter bug: bytesSet on non-bytes");
|
|
426
|
+
emitter.line(`${emitter.bytesElementHelper("set", s.arr.type.elem, integerIndex !== null)}(${arr.name}, ${idx}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
393
427
|
break;
|
|
394
428
|
}
|
|
395
429
|
case "fieldSet":
|
|
@@ -401,31 +435,31 @@ export function emitStmt(E, s) {
|
|
|
401
435
|
// cycle collection, which must never see a heap edge whose count
|
|
402
436
|
// was already given up (scr_cycle.c). Classes and records share
|
|
403
437
|
// the struct layout, so one emission.
|
|
404
|
-
const obj =
|
|
405
|
-
const v =
|
|
438
|
+
const obj = emitter.emitExpr(s.obj);
|
|
439
|
+
const v = emitter.emitExpr(s.value);
|
|
406
440
|
// Runtime error classes use ScrError's own member names.
|
|
407
441
|
const member = s.kind === "fieldSet" && RUNTIME_ERROR_CLASSES.has(s.className)
|
|
408
442
|
? s.field
|
|
409
443
|
: mangleField(s.field);
|
|
410
444
|
const field = `${obj.name}->${member}`;
|
|
411
445
|
if (isRefCounted(v.type)) {
|
|
412
|
-
|
|
413
|
-
const old = `sc_t${
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
446
|
+
emitter.moveTemp(v);
|
|
447
|
+
const old = `sc_t${emitter.tempCounter++}`;
|
|
448
|
+
emitter.line(`${cDecl(v.type, old)} = ${field};`);
|
|
449
|
+
emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
450
|
+
emitter.releaseValue(old, v.type);
|
|
417
451
|
}
|
|
418
452
|
else {
|
|
419
|
-
|
|
453
|
+
emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
420
454
|
}
|
|
421
455
|
break;
|
|
422
456
|
}
|
|
423
457
|
case "recordKeyDelete": {
|
|
424
458
|
// `delete obj[k]` on a pure index-signature shape: a Map delete on
|
|
425
459
|
// the overflow (key and value released; absent keys no-op).
|
|
426
|
-
const obj =
|
|
427
|
-
const key =
|
|
428
|
-
|
|
460
|
+
const obj = emitter.emitExpr(s.obj);
|
|
461
|
+
const key = emitter.emitExpr(s.key);
|
|
462
|
+
emitter.line(`scr_map_delete_str(${obj.name}->${OVERFLOW_MEMBER}, ${key.name});${emitter.srcComment(s.loc)}`);
|
|
429
463
|
break;
|
|
430
464
|
}
|
|
431
465
|
case "recordKeySet": {
|
|
@@ -434,25 +468,25 @@ export function emitStmt(E, s) {
|
|
|
434
468
|
// overflow map). Evaluation order: obj, key, value. The helper OWNS
|
|
435
469
|
// the value (+1 moves in). MAY THROW when a dyn value must validate
|
|
436
470
|
// against a declared field's type — the pending check runs then.
|
|
437
|
-
const obj =
|
|
438
|
-
const key =
|
|
439
|
-
const v =
|
|
471
|
+
const obj = emitter.emitExpr(s.obj);
|
|
472
|
+
const key = emitter.emitExpr(s.key);
|
|
473
|
+
const v = emitter.emitExpr(s.value);
|
|
440
474
|
if (isRefCounted(v.type))
|
|
441
|
-
|
|
475
|
+
emitter.moveTemp(v);
|
|
442
476
|
// A LITERAL key naming no declared field is a plain overflow map
|
|
443
477
|
// insert — no helper, no validation, no throw.
|
|
444
478
|
if (s.overflowOnly) {
|
|
445
479
|
const acc = v.type.kind === "f64" ? "f64" : v.type.kind === "bool" ? "bool" : "ref";
|
|
446
|
-
|
|
480
|
+
emitter.line(`scr_map_set_str_${acc}(${obj.name}->${OVERFLOW_MEMBER}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
447
481
|
break;
|
|
448
482
|
}
|
|
449
|
-
const helper =
|
|
450
|
-
|
|
451
|
-
const shape =
|
|
483
|
+
const helper = emitter.recordKeySetHelper(s.shapeId);
|
|
484
|
+
emitter.line(`${helper}(${obj.name}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
485
|
+
const shape = emitter.recordsById.get(s.shapeId);
|
|
452
486
|
// MAY THROW: a dyn value validating against a declared field, or a
|
|
453
487
|
// signature-free shape's key MISS (scr_record_key_miss).
|
|
454
488
|
if (shape && (!shape.indexValue || (shape.indexValue.kind === "dyn" && shape.fields.length > 0))) {
|
|
455
|
-
|
|
489
|
+
emitter.emitPendingCheck();
|
|
456
490
|
}
|
|
457
491
|
break;
|
|
458
492
|
}
|
|
@@ -463,72 +497,72 @@ export function emitStmt(E, s) {
|
|
|
463
497
|
// when the whole loop ends (and by `return`'s frame sweep). A real
|
|
464
498
|
// C for-loop makes plain `continue` correct: the update still runs.
|
|
465
499
|
if (s.iterable.type.kind !== "array")
|
|
466
|
-
throw new
|
|
500
|
+
throw new InternalCompilerError("emitter bug: forOf over non-array");
|
|
467
501
|
const elem = s.iterable.type.elem;
|
|
468
|
-
const arr =
|
|
469
|
-
const idx = `sc_t${
|
|
470
|
-
|
|
471
|
-
|
|
502
|
+
const arr = emitter.emitExpr(s.iterable);
|
|
503
|
+
const idx = `sc_t${emitter.tempCounter++}`;
|
|
504
|
+
emitter.line(`for (double ${idx} = 0; ${idx} < scr_arr_len(${arr.name}); ${idx} += 1) {${emitter.srcComment(s.loc)}`);
|
|
505
|
+
emitter.indent++;
|
|
472
506
|
// A real C for-loop makes plain `continue` correct (the update
|
|
473
507
|
// still runs); a LABELED forOf allocates a continue label placed at
|
|
474
508
|
// the END of the iteration (after the per-iteration scope release —
|
|
475
509
|
// the goto path released it itself) so nested loops can goto it.
|
|
476
|
-
const loop =
|
|
477
|
-
|
|
510
|
+
const loop = emitter.loopTarget(null, s.labels);
|
|
511
|
+
emitter.jumpTargets.push(loop);
|
|
478
512
|
// The loop variable is a fresh const per iteration: its scope opens
|
|
479
513
|
// here, holds the (for ref elements: owned +1) current element, and
|
|
480
514
|
// releases it at the end of each iteration.
|
|
481
|
-
|
|
515
|
+
emitter.scopes.push([]);
|
|
482
516
|
const local = mangleLocal(s.localId);
|
|
483
|
-
const localInfo =
|
|
517
|
+
const localInfo = emitter.currentLocals.get(s.localId);
|
|
484
518
|
if (localInfo?.boxed) {
|
|
485
519
|
// Captured loop variable: a fresh box per iteration, matching the
|
|
486
520
|
// fresh const binding (closures made in iteration k keep seeing
|
|
487
521
|
// iteration k's element). The box takes ownership of a ref
|
|
488
522
|
// element's +1 and is released with the iteration's scope.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
523
|
+
emitter.line(`${local} = ${emitter.boxNewC(elem)}; /* per-iteration ${localInfo.name} */`);
|
|
524
|
+
emitter.line(`scr_box_set_${boxAccess(elem)}(${local}, scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx}));`);
|
|
525
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem, boxed: true });
|
|
492
526
|
}
|
|
493
527
|
else {
|
|
494
|
-
|
|
528
|
+
emitter.line(`${local} = scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx});`);
|
|
495
529
|
if (isRefCounted(elem))
|
|
496
|
-
|
|
530
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem });
|
|
497
531
|
}
|
|
498
|
-
|
|
499
|
-
const endedWithJump =
|
|
500
|
-
const scope =
|
|
532
|
+
emitter.emitStmts(s.body);
|
|
533
|
+
const endedWithJump = endsWithJump(s.body);
|
|
534
|
+
const scope = emitter.scopes.pop();
|
|
501
535
|
if (!endedWithJump)
|
|
502
|
-
|
|
503
|
-
|
|
536
|
+
emitter.releaseFrame(scope);
|
|
537
|
+
emitter.jumpTargets.pop();
|
|
504
538
|
if (loop.usedContinue && loop.continueLabel)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
539
|
+
emitter.line(`${loop.continueLabel}:;`);
|
|
540
|
+
emitter.indent--;
|
|
541
|
+
emitter.line(`}`);
|
|
508
542
|
if (loop.usedEnd)
|
|
509
|
-
|
|
543
|
+
emitter.line(`${loop.endLabel}:;`);
|
|
510
544
|
break;
|
|
511
545
|
}
|
|
512
546
|
case "block": {
|
|
513
547
|
if (s.labels === undefined) {
|
|
514
|
-
|
|
548
|
+
emitter.emitBlock(s.body);
|
|
515
549
|
break;
|
|
516
550
|
}
|
|
517
551
|
// A labeled block: `break lbl` inside jumps to the end label
|
|
518
552
|
// (releasing the block's scope itself); nothing else can target it.
|
|
519
553
|
const target = {
|
|
520
554
|
kind: "block",
|
|
521
|
-
endLabel: `sc_end_${
|
|
555
|
+
endLabel: `sc_end_${emitter.labelCounter++}`,
|
|
522
556
|
usedEnd: false,
|
|
523
557
|
labels: s.labels,
|
|
524
|
-
scopeDepth:
|
|
525
|
-
frameDepth:
|
|
558
|
+
scopeDepth: emitter.scopes.length,
|
|
559
|
+
frameDepth: emitter.frames.length,
|
|
526
560
|
};
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
561
|
+
emitter.jumpTargets.push(target);
|
|
562
|
+
emitter.emitBlock(s.body);
|
|
563
|
+
emitter.jumpTargets.pop();
|
|
530
564
|
if (target.usedEnd)
|
|
531
|
-
|
|
565
|
+
emitter.line(`${target.endLabel}:;`);
|
|
532
566
|
break;
|
|
533
567
|
}
|
|
534
568
|
case "break": {
|
|
@@ -542,16 +576,16 @@ export function emitStmt(E, s) {
|
|
|
542
576
|
// loop's releases after the loop and a switch's after its end
|
|
543
577
|
// label are still on this jump's path.
|
|
544
578
|
let target;
|
|
545
|
-
for (let i =
|
|
546
|
-
const t =
|
|
579
|
+
for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
|
|
580
|
+
const t = emitter.jumpTargets[i];
|
|
547
581
|
if (s.label !== undefined ? t.labels?.includes(s.label) : t.kind !== "block") {
|
|
548
582
|
target = t;
|
|
549
583
|
break;
|
|
550
584
|
}
|
|
551
585
|
}
|
|
552
586
|
if (!target)
|
|
553
|
-
throw new
|
|
554
|
-
|
|
587
|
+
throw new InternalCompilerError("emitter bug: break target not found");
|
|
588
|
+
emitter.releaseForJump(target.frameDepth, target.scopeDepth);
|
|
555
589
|
if (target.kind !== "loop" || s.label !== undefined) {
|
|
556
590
|
// Switches are emitted as goto chains and blocks aren't C loops
|
|
557
591
|
// at all, so a C `break` cannot target either; and a LABELED
|
|
@@ -559,10 +593,10 @@ export function emitStmt(E, s) {
|
|
|
559
593
|
// All three jump to the target's end label (labeled loops always
|
|
560
594
|
// allocate one — loopTarget).
|
|
561
595
|
target.usedEnd = true;
|
|
562
|
-
|
|
596
|
+
emitter.line(`goto ${target.endLabel};${emitter.srcComment(s.loc)}`);
|
|
563
597
|
}
|
|
564
598
|
else {
|
|
565
|
-
|
|
599
|
+
emitter.line(`break;${emitter.srcComment(s.loc)}`);
|
|
566
600
|
}
|
|
567
601
|
break;
|
|
568
602
|
}
|
|
@@ -571,30 +605,30 @@ export function emitStmt(E, s) {
|
|
|
571
605
|
// labeled blocks in between (their scopes are still released — the
|
|
572
606
|
// jump exits them). Labeled: binds to the loop carrying the label.
|
|
573
607
|
let loop;
|
|
574
|
-
for (let i =
|
|
575
|
-
const t =
|
|
608
|
+
for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
|
|
609
|
+
const t = emitter.jumpTargets[i];
|
|
576
610
|
if (t.kind === "loop" && (s.label === undefined || t.labels?.includes(s.label))) {
|
|
577
611
|
loop = t;
|
|
578
612
|
break;
|
|
579
613
|
}
|
|
580
614
|
}
|
|
581
615
|
if (!loop)
|
|
582
|
-
throw new
|
|
583
|
-
|
|
616
|
+
throw new InternalCompilerError("emitter bug: continue target not found");
|
|
617
|
+
emitter.releaseForJump(loop.frameDepth, loop.scopeDepth);
|
|
584
618
|
if (loop.continueLabel) {
|
|
585
619
|
// Labeled loops always allocate one (a labeled continue may
|
|
586
620
|
// target an outer loop a C continue could never reach); for/
|
|
587
621
|
// do-while allocate one for their update/condition point.
|
|
588
622
|
loop.usedContinue = true;
|
|
589
|
-
|
|
623
|
+
emitter.line(`goto ${loop.continueLabel};${emitter.srcComment(s.loc)}`);
|
|
590
624
|
}
|
|
591
625
|
else {
|
|
592
|
-
|
|
626
|
+
emitter.line(`continue;${emitter.srcComment(s.loc)}`);
|
|
593
627
|
}
|
|
594
628
|
break;
|
|
595
629
|
}
|
|
596
630
|
case "return": {
|
|
597
|
-
const fin =
|
|
631
|
+
const fin = emitter.finallyStack[emitter.finallyStack.length - 1];
|
|
598
632
|
if (fin) {
|
|
599
633
|
// Crossing ≥1 finally: the value is computed and snapshotted
|
|
600
634
|
// FIRST (a finally mutating the returned local cannot change
|
|
@@ -602,26 +636,26 @@ export function emitStmt(E, s) {
|
|
|
602
636
|
// region releases and control runs that region's pending-return
|
|
603
637
|
// finally copy; its tail dispatches further out or returns.
|
|
604
638
|
if (s.value) {
|
|
605
|
-
const v =
|
|
606
|
-
|
|
607
|
-
|
|
639
|
+
const v = emitter.emitExpr(s.value);
|
|
640
|
+
emitter.moveTemp(v); // ownership parks in the slot until the dispatch returns it
|
|
641
|
+
emitter.line(`sc_pret = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
608
642
|
}
|
|
609
643
|
fin.used = true;
|
|
610
|
-
|
|
611
|
-
|
|
644
|
+
emitter.releaseForJump(fin.frameDepth, fin.scopeDepth);
|
|
645
|
+
emitter.line(`goto ${fin.label};${s.value ? "" : emitter.srcComment(s.loc)}`);
|
|
612
646
|
break;
|
|
613
647
|
}
|
|
614
648
|
if (s.value) {
|
|
615
|
-
const v =
|
|
616
|
-
|
|
649
|
+
const v = emitter.emitExpr(s.value);
|
|
650
|
+
emitter.moveTemp(v);
|
|
617
651
|
// Everything down to function depth releases; the moved result is
|
|
618
652
|
// exempt (already struck from its frame).
|
|
619
|
-
|
|
620
|
-
|
|
653
|
+
emitter.releaseForJump(0, 0);
|
|
654
|
+
emitter.line(`return ${v.name};${emitter.srcComment(s.loc)}`);
|
|
621
655
|
}
|
|
622
656
|
else {
|
|
623
|
-
|
|
624
|
-
|
|
657
|
+
emitter.releaseForJump(0, 0);
|
|
658
|
+
emitter.line(`return;${emitter.srcComment(s.loc)}`);
|
|
625
659
|
}
|
|
626
660
|
break;
|
|
627
661
|
}
|
|
@@ -629,34 +663,34 @@ export function emitStmt(E, s) {
|
|
|
629
663
|
// Evaluate, move ownership into the runtime's exception cell, then
|
|
630
664
|
// unwind unconditionally (the innermost try handler, or out of the
|
|
631
665
|
// function) — the same release path as return/break/continue.
|
|
632
|
-
const v =
|
|
666
|
+
const v = emitter.emitExpr(s.value);
|
|
633
667
|
const t = s.value.type;
|
|
634
668
|
if (isRefCounted(t))
|
|
635
|
-
|
|
669
|
+
emitter.moveTemp(v); // the cell takes ownership
|
|
636
670
|
if (t.kind === "date") {
|
|
637
|
-
throw new
|
|
671
|
+
throw new InternalCompilerError("emitter bug: Date throw reached backend");
|
|
638
672
|
}
|
|
639
673
|
else if (t.kind === "f64") {
|
|
640
|
-
|
|
674
|
+
emitter.line(`scr_throw_f64(${v.name});${emitter.srcComment(s.loc)}`);
|
|
641
675
|
}
|
|
642
676
|
else if (t.kind === "bool") {
|
|
643
|
-
|
|
677
|
+
emitter.line(`scr_throw_bool(${v.name});${emitter.srcComment(s.loc)}`);
|
|
644
678
|
}
|
|
645
679
|
else if (t.kind === "string") {
|
|
646
|
-
|
|
680
|
+
emitter.line(`scr_throw_str(${v.name});${emitter.srcComment(s.loc)}`);
|
|
647
681
|
}
|
|
648
|
-
else if (t.kind === "object" &&
|
|
682
|
+
else if (t.kind === "object" && emitter.classMeta.get(t.className)?.hierarchy) {
|
|
649
683
|
// Hierarchy instances carry a vtable word: the OBJ kind keeps the
|
|
650
684
|
// dynamic class inspectable (catch-binding instanceof, and the
|
|
651
685
|
// uncaught printer's "name: message" for Error instances).
|
|
652
686
|
const rc = vAdapters(t);
|
|
653
|
-
|
|
687
|
+
emitter.line(`scr_throw_obj(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
|
|
654
688
|
}
|
|
655
689
|
else {
|
|
656
690
|
const rc = vAdapters(t);
|
|
657
|
-
|
|
691
|
+
emitter.line(`scr_throw_ref(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
|
|
658
692
|
}
|
|
659
|
-
|
|
693
|
+
emitter.emitUnwind();
|
|
660
694
|
break;
|
|
661
695
|
}
|
|
662
696
|
case "runtimeFence": {
|
|
@@ -664,29 +698,29 @@ export function emitStmt(E, s) {
|
|
|
664
698
|
// the construct (message) with the SC code stamped on `code`,
|
|
665
699
|
// then unwind exactly like `throw`.
|
|
666
700
|
const bytes = Buffer.from(s.message, "utf8");
|
|
667
|
-
|
|
668
|
-
|
|
701
|
+
emitter.line(`scr_throw_error_msg_code(SCR_ERR_ERROR, ${cStringLiteral(bytes)}, ${bytes.length}, "${s.code}");${emitter.srcComment(s.loc)}`);
|
|
702
|
+
emitter.emitUnwind();
|
|
669
703
|
break;
|
|
670
704
|
}
|
|
671
705
|
case "rethrow":
|
|
672
706
|
// Re-raise the saved snapshot (payload retained — the binding local
|
|
673
707
|
// releases with its scope) and unwind like `throw`.
|
|
674
|
-
|
|
675
|
-
|
|
708
|
+
emitter.line(`scr_rethrow(${mangleLocal(s.localId)});${emitter.srcComment(s.loc)}`);
|
|
709
|
+
emitter.emitUnwind();
|
|
676
710
|
break;
|
|
677
711
|
case "tryCatch":
|
|
678
|
-
|
|
712
|
+
emitter.emitTryCatch(s);
|
|
679
713
|
break;
|
|
680
714
|
default: {
|
|
681
715
|
const _exhaustive = s;
|
|
682
716
|
void _exhaustive;
|
|
683
717
|
}
|
|
684
718
|
}
|
|
685
|
-
const frame =
|
|
719
|
+
const frame = emitter.frames.pop();
|
|
686
720
|
// return/throw already released their frames on the jump path; emitting
|
|
687
721
|
// the fall-through releases after them would be dead double-release code.
|
|
688
722
|
if (s.kind !== "return" && s.kind !== "throw" && s.kind !== "rethrow" && s.kind !== "runtimeFence")
|
|
689
|
-
|
|
723
|
+
emitter.releaseFrame(frame);
|
|
690
724
|
}
|
|
691
725
|
/** try/catch/finally via pending-flag unwinding. Entering a try emits NO
|
|
692
726
|
* code: the try context is compile-time state (tryStack) that redirects
|
|
@@ -719,8 +753,8 @@ export function emitStmt(E, s) {
|
|
|
719
753
|
* normal, exception, and pending-return are the only paths a finally
|
|
720
754
|
* must model; jumps out of PLAIN try/catch need nothing here —
|
|
721
755
|
* release-on-jump already walks the try scopes. */
|
|
722
|
-
export function emitTryCatch(
|
|
723
|
-
const id =
|
|
756
|
+
export function emitTryCatch(emitter, s) {
|
|
757
|
+
const id = emitter.labelCounter++;
|
|
724
758
|
const hasCatch = s.catchBody !== null;
|
|
725
759
|
const hasFinally = s.finallyBody !== null;
|
|
726
760
|
const catchLabel = `sc_catch_${id}`;
|
|
@@ -732,8 +766,8 @@ export function emitTryCatch(E, s) {
|
|
|
732
766
|
const handler = {
|
|
733
767
|
label: hasCatch ? catchLabel : finExcLabel,
|
|
734
768
|
used: false,
|
|
735
|
-
frameDepth:
|
|
736
|
-
scopeDepth:
|
|
769
|
+
frameDepth: emitter.frames.length,
|
|
770
|
+
scopeDepth: emitter.scopes.length,
|
|
737
771
|
};
|
|
738
772
|
// The pending-return region: returns inside tryBody/catchBody snapshot
|
|
739
773
|
// their value and jump here-ish (the pending-return finally copy below)
|
|
@@ -742,77 +776,77 @@ export function emitTryCatch(E, s) {
|
|
|
742
776
|
? {
|
|
743
777
|
label: `sc_finret_${id}`,
|
|
744
778
|
used: false,
|
|
745
|
-
frameDepth:
|
|
746
|
-
scopeDepth:
|
|
779
|
+
frameDepth: emitter.frames.length,
|
|
780
|
+
scopeDepth: emitter.scopes.length,
|
|
747
781
|
}
|
|
748
782
|
: null;
|
|
749
|
-
|
|
783
|
+
emitter.line(`/* try */${emitter.srcComment(s.loc)}`);
|
|
750
784
|
if (retEntry)
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
785
|
+
emitter.finallyStack.push(retEntry);
|
|
786
|
+
emitter.tryStack.push(handler);
|
|
787
|
+
emitter.emitBlock(s.tryBody);
|
|
788
|
+
emitter.tryStack.pop();
|
|
755
789
|
// Exceptions raised in the CATCH body unwind to the exception-path
|
|
756
790
|
// finally (pending stays set through it) when one exists.
|
|
757
791
|
const excHandler = {
|
|
758
792
|
label: finExcLabel,
|
|
759
793
|
used: !hasCatch && handler.used,
|
|
760
|
-
frameDepth:
|
|
761
|
-
scopeDepth:
|
|
794
|
+
frameDepth: emitter.frames.length,
|
|
795
|
+
scopeDepth: emitter.scopes.length,
|
|
762
796
|
};
|
|
763
797
|
if (hasCatch && handler.used) {
|
|
764
|
-
if (!
|
|
765
|
-
|
|
798
|
+
if (!endsWithJump(s.tryBody)) {
|
|
799
|
+
emitter.line(`goto ${afterTryLabel};`);
|
|
766
800
|
afterTryLabelUsed = true;
|
|
767
801
|
}
|
|
768
802
|
if (hasFinally)
|
|
769
|
-
|
|
803
|
+
emitter.tryStack.push(excHandler);
|
|
770
804
|
// Generator bodies: a pending GENRET sentinel (.return(v) injected at
|
|
771
805
|
// a yield) is a RETURN completion, not a throw — catch must not take
|
|
772
806
|
// it. Re-unwind past this handler (finally still runs — the unwind
|
|
773
807
|
// targets the exception-path finally or the enclosing context; the
|
|
774
808
|
// runtime depths here equal the handler's, so no double release).
|
|
775
809
|
const genretPrologue = () => {
|
|
776
|
-
if (
|
|
810
|
+
if (emitter.currentGenerator === null)
|
|
777
811
|
return;
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
812
|
+
emitter.line(`if (scr_exc_genret_pending()) { /* .return(): not catchable */`);
|
|
813
|
+
emitter.indent++;
|
|
814
|
+
emitter.emitUnwind();
|
|
815
|
+
emitter.indent--;
|
|
816
|
+
emitter.line(`}`);
|
|
783
817
|
};
|
|
784
818
|
if (s.catchLocalId !== null) {
|
|
785
819
|
// catch (e): the exception MOVES into the binding's snapshot box,
|
|
786
820
|
// owned by the catch body's scope (released on every exit — normal
|
|
787
821
|
// fall-through, jumps out, and unwinds from the body).
|
|
788
822
|
const binding = mangleLocal(s.catchLocalId);
|
|
789
|
-
|
|
823
|
+
emitter.line(`${catchLabel}:; /* catch (${emitter.currentLocals.get(s.catchLocalId)?.name ?? "e"}) — takes the exception */`);
|
|
790
824
|
genretPrologue();
|
|
791
|
-
|
|
792
|
-
|
|
825
|
+
emitter.emitBlock(s.catchBody, (scope) => {
|
|
826
|
+
emitter.line(`${binding} = scr_exc_take();`);
|
|
793
827
|
scope.push({ name: binding, type: CAUGHT });
|
|
794
828
|
});
|
|
795
829
|
}
|
|
796
830
|
else {
|
|
797
|
-
|
|
831
|
+
emitter.line(`${catchLabel}:; /* catch — takes the exception */`);
|
|
798
832
|
genretPrologue();
|
|
799
|
-
|
|
800
|
-
|
|
833
|
+
emitter.line(`scr_exc_clear();`);
|
|
834
|
+
emitter.emitBlock(s.catchBody);
|
|
801
835
|
}
|
|
802
836
|
if (hasFinally)
|
|
803
|
-
|
|
837
|
+
emitter.tryStack.pop();
|
|
804
838
|
// Normal completion of the catch falls through to afterTryLabel.
|
|
805
839
|
}
|
|
806
840
|
if (retEntry)
|
|
807
|
-
|
|
841
|
+
emitter.finallyStack.pop();
|
|
808
842
|
if (hasFinally) {
|
|
809
843
|
if (afterTryLabelUsed)
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
844
|
+
emitter.line(`${afterTryLabel}:;`);
|
|
845
|
+
emitter.line(`/* finally (normal path) */`);
|
|
846
|
+
emitter.emitBlock(s.finallyBody);
|
|
813
847
|
const needEnd = excHandler.used || retEntry.used;
|
|
814
848
|
if (needEnd)
|
|
815
|
-
|
|
849
|
+
emitter.line(`goto ${endLabel};`);
|
|
816
850
|
if (excHandler.used) {
|
|
817
851
|
// The pending exception is STASHED across the finally body (a
|
|
818
852
|
// ScrCaught snapshot, re-raised after) so the body runs with a
|
|
@@ -825,14 +859,14 @@ export function emitTryCatch(E, s) {
|
|
|
825
859
|
// JS's replace semantics); normal completion re-raises the stash
|
|
826
860
|
// and keeps propagating.
|
|
827
861
|
const stash = `sc_fexc_${id}`;
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
862
|
+
emitter.line(`${finExcLabel}:; /* finally (exception path — stashed) */`);
|
|
863
|
+
emitter.line(`ScrCaught *${stash} = scr_exc_take();`);
|
|
864
|
+
emitter.scopes.push([{ name: stash, type: CAUGHT }]);
|
|
865
|
+
emitter.emitBlock(s.finallyBody);
|
|
866
|
+
emitter.scopes.pop(); // normal completion keeps the stash for the re-raise
|
|
867
|
+
emitter.line(`scr_rethrow(${stash});`);
|
|
868
|
+
emitter.line(`scr_caught_release(${stash});`);
|
|
869
|
+
emitter.emitUnwind();
|
|
836
870
|
}
|
|
837
871
|
if (retEntry.used) {
|
|
838
872
|
// Pending-return path: a return in the try/catch body parked its
|
|
@@ -843,30 +877,30 @@ export function emitTryCatch(E, s) {
|
|
|
843
877
|
// actual return. A THROW inside this copy replaces the pending
|
|
844
878
|
// return (JS): the slot's owned value rides a synthetic scope
|
|
845
879
|
// entry so the unwind releases it.
|
|
846
|
-
|
|
847
|
-
const retT =
|
|
880
|
+
emitter.line(`${retEntry.label}:; /* finally (pending-return path) */`);
|
|
881
|
+
const retT = emitter.currentReturnType;
|
|
848
882
|
const own = isRefCounted(retT);
|
|
849
883
|
if (own)
|
|
850
|
-
|
|
851
|
-
|
|
884
|
+
emitter.scopes.push([{ name: "sc_pret", type: retT }]);
|
|
885
|
+
emitter.emitBlock(s.finallyBody);
|
|
852
886
|
if (own)
|
|
853
|
-
|
|
854
|
-
const outer =
|
|
887
|
+
emitter.scopes.pop();
|
|
888
|
+
const outer = emitter.finallyStack[emitter.finallyStack.length - 1];
|
|
855
889
|
if (outer) {
|
|
856
890
|
outer.used = true;
|
|
857
|
-
|
|
858
|
-
|
|
891
|
+
emitter.releaseForJump(outer.frameDepth, outer.scopeDepth);
|
|
892
|
+
emitter.line(`goto ${outer.label};`);
|
|
859
893
|
}
|
|
860
894
|
else {
|
|
861
|
-
|
|
862
|
-
|
|
895
|
+
emitter.releaseForJump(0, 0);
|
|
896
|
+
emitter.line(retT.kind === "void" ? `return;` : `return sc_pret;`);
|
|
863
897
|
}
|
|
864
898
|
}
|
|
865
899
|
if (needEnd)
|
|
866
|
-
|
|
900
|
+
emitter.line(`${endLabel}:;`);
|
|
867
901
|
}
|
|
868
902
|
else if (afterTryLabelUsed) {
|
|
869
|
-
|
|
903
|
+
emitter.line(`${endLabel}:;`);
|
|
870
904
|
}
|
|
871
905
|
}
|
|
872
906
|
/** JS-exact switch as a goto chain — C `switch` cannot express lazily
|
|
@@ -887,27 +921,27 @@ export function emitTryCatch(E, s) {
|
|
|
887
921
|
* it still holds the pointer a previous iteration's scope exit already
|
|
888
922
|
* released. The declarations are therefore NULL-reset up front; the
|
|
889
923
|
* scope-exit releases rely on the runtime's NULL-tolerant release calls. */
|
|
890
|
-
export function emitSwitch(
|
|
924
|
+
export function emitSwitch(emitter, s) {
|
|
891
925
|
if (s.disc.type.kind !== "f64" && s.disc.type.kind !== "string" && s.disc.type.kind !== "bool") {
|
|
892
|
-
throw new
|
|
926
|
+
throw new InternalCompilerError(`emitter bug: switch on ${s.disc.type.kind}`);
|
|
893
927
|
}
|
|
894
|
-
const id =
|
|
928
|
+
const id = emitter.labelCounter++;
|
|
895
929
|
const endLabel = `sc_swend_${id}`;
|
|
896
930
|
const caseLabel = (i) => `sc_swcase_${id}_${i}`;
|
|
897
931
|
// The disc temp lives in the whole statement's frame: for a string
|
|
898
932
|
// discriminant it stays alive across every test and body, released when
|
|
899
933
|
// the switch statement ends (break lands before that release; return
|
|
900
934
|
// sweeps frames itself).
|
|
901
|
-
const disc =
|
|
935
|
+
const disc = emitter.emitExpr(s.disc);
|
|
902
936
|
// NULL-reset refcounted/boxed locals declared at the top level of case
|
|
903
937
|
// bodies (nested blocks manage their own scopes on normal control flow).
|
|
904
938
|
for (const c of s.cases) {
|
|
905
939
|
for (const stmt of c.body) {
|
|
906
940
|
if (stmt.kind !== "varDecl")
|
|
907
941
|
continue;
|
|
908
|
-
const local =
|
|
942
|
+
const local = emitter.currentLocals.get(stmt.localId);
|
|
909
943
|
if (local.boxed || isRefCounted(local.type)) {
|
|
910
|
-
|
|
944
|
+
emitter.line(`${mangleLocal(local.id)} = NULL; /* case-scoped ${local.name} */`);
|
|
911
945
|
}
|
|
912
946
|
}
|
|
913
947
|
}
|
|
@@ -919,16 +953,16 @@ export function emitSwitch(E, s) {
|
|
|
919
953
|
defaultIdx = i;
|
|
920
954
|
return;
|
|
921
955
|
}
|
|
922
|
-
|
|
923
|
-
const t =
|
|
956
|
+
emitter.frames.push([]);
|
|
957
|
+
const t = emitter.emitExpr(c.test);
|
|
924
958
|
const cmp = c.test.type.kind === "string"
|
|
925
959
|
? `scr_str_eq(${disc.name}, ${t.name})`
|
|
926
960
|
: `${disc.name} == ${t.name}`;
|
|
927
|
-
const hit =
|
|
928
|
-
|
|
929
|
-
|
|
961
|
+
const hit = emitter.newTemp(BOOL, cmp);
|
|
962
|
+
emitter.releaseFrame(emitter.frames.pop());
|
|
963
|
+
emitter.line(`if (${hit.name}) goto ${caseLabel(i)};`);
|
|
930
964
|
});
|
|
931
|
-
|
|
965
|
+
emitter.line(`goto ${defaultIdx >= 0 ? caseLabel(defaultIdx) : endLabel};`);
|
|
932
966
|
// Bodies in source order: entering one falls through the rest (JS-exact)
|
|
933
967
|
// until a break jumps to the end label.
|
|
934
968
|
const target = {
|
|
@@ -936,33 +970,33 @@ export function emitSwitch(E, s) {
|
|
|
936
970
|
endLabel,
|
|
937
971
|
usedEnd: defaultIdx < 0,
|
|
938
972
|
...(s.labels !== undefined && { labels: s.labels }),
|
|
939
|
-
scopeDepth:
|
|
940
|
-
frameDepth:
|
|
973
|
+
scopeDepth: emitter.scopes.length,
|
|
974
|
+
frameDepth: emitter.frames.length,
|
|
941
975
|
};
|
|
942
|
-
|
|
943
|
-
|
|
976
|
+
emitter.jumpTargets.push(target);
|
|
977
|
+
emitter.scopes.push([]);
|
|
944
978
|
s.cases.forEach((c, i) => {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
979
|
+
emitter.line(`${caseLabel(i)}:;`);
|
|
980
|
+
emitter.indent++;
|
|
981
|
+
emitter.emitStmts(c.body);
|
|
982
|
+
emitter.indent--;
|
|
949
983
|
});
|
|
950
|
-
|
|
951
|
-
const scope =
|
|
984
|
+
emitter.jumpTargets.pop();
|
|
985
|
+
const scope = emitter.scopes.pop();
|
|
952
986
|
// Natural fall-off of the last body releases the shared scope here; a
|
|
953
987
|
// jump (break/return/continue/throw) already released it before jumping.
|
|
954
988
|
const lastBody = s.cases[s.cases.length - 1]?.body;
|
|
955
|
-
if (!lastBody || !
|
|
956
|
-
|
|
989
|
+
if (!lastBody || !endsWithJump(lastBody))
|
|
990
|
+
emitter.releaseFrame(scope);
|
|
957
991
|
if (target.usedEnd)
|
|
958
|
-
|
|
992
|
+
emitter.line(`${endLabel}:;`);
|
|
959
993
|
}
|
|
960
994
|
/** Emits `if (cond) ` followed by a block on the same line for readability. */
|
|
961
|
-
export function mergeBrace(
|
|
962
|
-
const head =
|
|
963
|
-
const before =
|
|
995
|
+
export function mergeBrace(emitter, emitBlockFn) {
|
|
996
|
+
const head = emitter.lines.pop();
|
|
997
|
+
const before = emitter.lines.length;
|
|
964
998
|
emitBlockFn();
|
|
965
|
-
|
|
999
|
+
emitter.lines[before] = head + emitter.lines[before].trimStart();
|
|
966
1000
|
}
|
|
967
1001
|
/** Evaluates `expr` in its own statement frame inside an already-open
|
|
968
1002
|
* branch and moves the result into the C lvalue `target`: the chosen
|
|
@@ -970,20 +1004,20 @@ export function mergeBrace(E, emitBlockFn) {
|
|
|
970
1004
|
* releases inside the branch. The shared core of the lazily-branched
|
|
971
1005
|
* expressions (`logical`, `ternary`); the caller owns the surrounding
|
|
972
1006
|
* braces/indentation and registers `target` in ITS frame. */
|
|
973
|
-
export function emitBranchInto(
|
|
974
|
-
|
|
975
|
-
const v =
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1007
|
+
export function emitBranchInto(emitter, target, expr) {
|
|
1008
|
+
emitter.frames.push([]);
|
|
1009
|
+
const v = emitter.emitExpr(expr);
|
|
1010
|
+
emitter.moveTemp(v);
|
|
1011
|
+
emitter.line(`${target} = ${v.name};`);
|
|
1012
|
+
emitter.releaseFrame(emitter.frames.pop());
|
|
979
1013
|
}
|
|
980
1014
|
/** Evaluates a condition; its string temps are released before the branch,
|
|
981
1015
|
* which is safe because the result is a scalar bool. */
|
|
982
|
-
export function emitCondition(
|
|
983
|
-
const t =
|
|
984
|
-
const frame =
|
|
985
|
-
|
|
1016
|
+
export function emitCondition(emitter, cond) {
|
|
1017
|
+
const t = emitter.emitExpr(cond);
|
|
1018
|
+
const frame = emitter.currentFrame();
|
|
1019
|
+
emitter.releaseFrame(frame);
|
|
986
1020
|
frame.length = 0;
|
|
987
1021
|
return t.name;
|
|
988
1022
|
}
|
|
989
|
-
//# sourceMappingURL=
|
|
1023
|
+
//# sourceMappingURL=stmts.js.map
|