@scriptc/compiler 0.0.35 → 0.1.1
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 +14 -11
- package/ambient/scriptc-overrides.d.ts +0 -7
- package/ambient/scriptc.d.ts +1 -1
- 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 +7937 -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 +4 -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} +395 -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} +242 -304
- package/dist/backend/c/walkers.js.map +1 -0
- package/dist/backend/external-c.d.ts +33 -0
- package/dist/backend/external-c.js +51 -0
- package/dist/backend/external-c.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/link-plan.d.ts +37 -0
- package/dist/backend/link-plan.js +26 -0
- package/dist/backend/link-plan.js.map +1 -0
- package/dist/backend/linker.d.ts +22 -0
- package/dist/backend/linker.js +236 -0
- package/dist/backend/linker.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 +159 -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 +548 -9988
- 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 +637 -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 +153 -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 +642 -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 +420 -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/unsupported.d.ts +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -3
- package/dist/backend/llvm/walkers.js +195 -222
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +45 -0
- package/dist/backend/native-codegen.js +275 -0
- package/dist/backend/native-codegen.js.map +1 -0
- package/dist/backend/native-codegen.test.js +226 -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 +243 -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} +54 -34
- package/dist/backend/{cc.js → native-toolchain.js} +231 -810
- 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} +219 -7
- package/dist/backend/native-toolchain.test.js.map +1 -0
- package/dist/backend/object-localize.js +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-targets.test.d.ts +1 -0
- package/dist/backend/runtime-pack-targets.test.js +54 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -0
- package/dist/backend/runtime-pack.d.ts +112 -0
- package/dist/backend/runtime-pack.js +305 -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 +473 -0
- package/dist/backend/runtime-pack.test.js.map +1 -0
- package/dist/backend/targets.d.ts +76 -0
- package/dist/backend/targets.js +262 -0
- package/dist/backend/targets.js.map +1 -0
- package/dist/backend/targets.test.d.ts +1 -0
- package/dist/backend/targets.test.js +41 -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 +35 -33
- 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/{early-cache.d.ts → executable-cache.d.ts} +2 -2
- package/dist/executable/{early-cache.js → executable-cache.js} +36 -98
- package/dist/executable/executable-cache.js.map +1 -0
- package/dist/executable/executable-cache.test.d.ts +1 -0
- package/dist/executable/{early-cache.test.js → executable-cache.test.js} +3 -3
- package/dist/executable/executable-cache.test.js.map +1 -0
- package/dist/ffi/{profile.js → ffi-manifest.js} +1 -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/array-values.d.ts +8 -0
- package/dist/frontend/lowering/array-values.js +60 -0
- package/dist/frontend/lowering/array-values.js.map +1 -0
- 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-array-sort.d.ts +22 -0
- package/dist/frontend/lowering/lower-array-sort.js +619 -0
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
- 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 +1285 -1233
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +59 -192
- package/dist/frontend/lowering/lower-calls.js +1644 -1506
- 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 +1984 -2227
- 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 +60 -264
- package/dist/frontend/lowering/lower-exprs.js +2361 -1765
- 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 +273 -261
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +39 -49
- package/dist/frontend/lowering/lower-island.js +447 -513
- 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 +85 -85
- 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 +909 -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 +1463 -1285
- 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 +134 -22
- package/dist/frontend/lowering/lowerer.js +1277 -126
- 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 +24 -35
- package/dist/frontend/lowering/surfaces.js +78 -66
- 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 +9 -4
- 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.js +2 -36
- 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} +12 -11
- 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 +113 -31
- package/dist/index.js +536 -128
- 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} +119 -37
- package/dist/ir/{nodes.js → ir.js} +170 -166
- 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 +2 -2
- package/dist/ir/serialize.js +3 -2
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/validate.d.ts +1 -1
- package/dist/ir/validate.js +93 -41
- 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/{implementation-identity.js → compiler-self-identity.js} +1 -1
- 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 +8 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.d.ts +1 -36
- package/dist/library/int-infer.js +29 -18
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
- package/dist/library/{early-cache.js → library-cache.js} +34 -89
- 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} +7 -7
- 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 +11 -3
- package/dist/startup-cache.js +17 -2
- package/dist/startup-cache.js.map +1 -1
- package/package.json +19 -2
- package/surface-manifest.json +5 -5
- 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/executable/early-cache.js.map +0 -1
- package/dist/executable/early-cache.test.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/implementation-identity.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/{executable/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
- /package/dist/{library/early-cache.test.d.ts → backend/native-codegen.test.d.ts} +0 -0
- /package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +0 -0
- /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
- /package/dist/library/{implementation-identity.d.ts → compiler-self-identity.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,253 @@ 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)}`);
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
case "arraySetLength": {
|
|
415
|
+
const arr = emitter.emitExpr(s.arr);
|
|
416
|
+
const length = emitter.emitExpr(s.length);
|
|
417
|
+
if (s.arr.type.kind !== "array")
|
|
418
|
+
throw new InternalCompilerError("emitter bug: arraySetLength on non-array");
|
|
419
|
+
emitter.line(`scr_arr_set_len(${arr.name}, ${length.name});${emitter.srcComment(s.loc)}`);
|
|
420
|
+
emitter.emitPendingCheck();
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case "arraySetUndefined":
|
|
424
|
+
case "arrayDelete": {
|
|
425
|
+
const arr = emitter.emitExpr(s.arr);
|
|
426
|
+
const idx = emitter.emitExpr(s.index);
|
|
427
|
+
if (s.arr.type.kind !== "array")
|
|
428
|
+
throw new InternalCompilerError(`emitter bug: ${s.kind} on non-array`);
|
|
429
|
+
emitter.line(`${s.kind === "arraySetUndefined" ? "scr_arr_set_undefined" : "scr_arr_delete"}(${arr.name}, ${idx.name});${emitter.srcComment(s.loc)}`);
|
|
378
430
|
break;
|
|
379
431
|
}
|
|
380
432
|
case "bytesSet": {
|
|
@@ -383,13 +435,13 @@ export function emitStmt(E, s) {
|
|
|
383
435
|
// JS-exactly), so no ownership moves. Any invalid index traps — no
|
|
384
436
|
// append. The IR carries the element kind; do not rediscover it in
|
|
385
437
|
// the generic runtime accessor on every loop iteration.
|
|
386
|
-
const arr = emitBytesReceiver(
|
|
387
|
-
const integerIndex =
|
|
388
|
-
const idx = integerIndex === null ?
|
|
389
|
-
const v =
|
|
438
|
+
const arr = emitBytesReceiver(emitter, s.arr, [s.index, s.value]);
|
|
439
|
+
const integerIndex = emitter.integerLoopIndex(s.index);
|
|
440
|
+
const idx = integerIndex === null ? emitter.emitExpr(s.index).name : integerIndex;
|
|
441
|
+
const v = emitter.emitExpr(s.value);
|
|
390
442
|
if (s.arr.type.kind !== "bytes")
|
|
391
|
-
throw new
|
|
392
|
-
|
|
443
|
+
throw new InternalCompilerError("emitter bug: bytesSet on non-bytes");
|
|
444
|
+
emitter.line(`${emitter.bytesElementHelper("set", s.arr.type.elem, integerIndex !== null)}(${arr.name}, ${idx}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
393
445
|
break;
|
|
394
446
|
}
|
|
395
447
|
case "fieldSet":
|
|
@@ -401,31 +453,31 @@ export function emitStmt(E, s) {
|
|
|
401
453
|
// cycle collection, which must never see a heap edge whose count
|
|
402
454
|
// was already given up (scr_cycle.c). Classes and records share
|
|
403
455
|
// the struct layout, so one emission.
|
|
404
|
-
const obj =
|
|
405
|
-
const v =
|
|
456
|
+
const obj = emitter.emitExpr(s.obj);
|
|
457
|
+
const v = emitter.emitExpr(s.value);
|
|
406
458
|
// Runtime error classes use ScrError's own member names.
|
|
407
459
|
const member = s.kind === "fieldSet" && RUNTIME_ERROR_CLASSES.has(s.className)
|
|
408
460
|
? s.field
|
|
409
461
|
: mangleField(s.field);
|
|
410
462
|
const field = `${obj.name}->${member}`;
|
|
411
463
|
if (isRefCounted(v.type)) {
|
|
412
|
-
|
|
413
|
-
const old = `sc_t${
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
464
|
+
emitter.moveTemp(v);
|
|
465
|
+
const old = `sc_t${emitter.tempCounter++}`;
|
|
466
|
+
emitter.line(`${cDecl(v.type, old)} = ${field};`);
|
|
467
|
+
emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
468
|
+
emitter.releaseValue(old, v.type);
|
|
417
469
|
}
|
|
418
470
|
else {
|
|
419
|
-
|
|
471
|
+
emitter.line(`${field} = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
420
472
|
}
|
|
421
473
|
break;
|
|
422
474
|
}
|
|
423
475
|
case "recordKeyDelete": {
|
|
424
476
|
// `delete obj[k]` on a pure index-signature shape: a Map delete on
|
|
425
477
|
// the overflow (key and value released; absent keys no-op).
|
|
426
|
-
const obj =
|
|
427
|
-
const key =
|
|
428
|
-
|
|
478
|
+
const obj = emitter.emitExpr(s.obj);
|
|
479
|
+
const key = emitter.emitExpr(s.key);
|
|
480
|
+
emitter.line(`scr_map_delete_str(${obj.name}->${OVERFLOW_MEMBER}, ${key.name});${emitter.srcComment(s.loc)}`);
|
|
429
481
|
break;
|
|
430
482
|
}
|
|
431
483
|
case "recordKeySet": {
|
|
@@ -434,25 +486,25 @@ export function emitStmt(E, s) {
|
|
|
434
486
|
// overflow map). Evaluation order: obj, key, value. The helper OWNS
|
|
435
487
|
// the value (+1 moves in). MAY THROW when a dyn value must validate
|
|
436
488
|
// against a declared field's type — the pending check runs then.
|
|
437
|
-
const obj =
|
|
438
|
-
const key =
|
|
439
|
-
const v =
|
|
489
|
+
const obj = emitter.emitExpr(s.obj);
|
|
490
|
+
const key = emitter.emitExpr(s.key);
|
|
491
|
+
const v = emitter.emitExpr(s.value);
|
|
440
492
|
if (isRefCounted(v.type))
|
|
441
|
-
|
|
493
|
+
emitter.moveTemp(v);
|
|
442
494
|
// A LITERAL key naming no declared field is a plain overflow map
|
|
443
495
|
// insert — no helper, no validation, no throw.
|
|
444
496
|
if (s.overflowOnly) {
|
|
445
497
|
const acc = v.type.kind === "f64" ? "f64" : v.type.kind === "bool" ? "bool" : "ref";
|
|
446
|
-
|
|
498
|
+
emitter.line(`scr_map_set_str_${acc}(${obj.name}->${OVERFLOW_MEMBER}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
447
499
|
break;
|
|
448
500
|
}
|
|
449
|
-
const helper =
|
|
450
|
-
|
|
451
|
-
const shape =
|
|
501
|
+
const helper = emitter.recordKeySetHelper(s.shapeId);
|
|
502
|
+
emitter.line(`${helper}(${obj.name}, ${key.name}, ${v.name});${emitter.srcComment(s.loc)}`);
|
|
503
|
+
const shape = emitter.recordsById.get(s.shapeId);
|
|
452
504
|
// MAY THROW: a dyn value validating against a declared field, or a
|
|
453
505
|
// signature-free shape's key MISS (scr_record_key_miss).
|
|
454
506
|
if (shape && (!shape.indexValue || (shape.indexValue.kind === "dyn" && shape.fields.length > 0))) {
|
|
455
|
-
|
|
507
|
+
emitter.emitPendingCheck();
|
|
456
508
|
}
|
|
457
509
|
break;
|
|
458
510
|
}
|
|
@@ -463,72 +515,72 @@ export function emitStmt(E, s) {
|
|
|
463
515
|
// when the whole loop ends (and by `return`'s frame sweep). A real
|
|
464
516
|
// C for-loop makes plain `continue` correct: the update still runs.
|
|
465
517
|
if (s.iterable.type.kind !== "array")
|
|
466
|
-
throw new
|
|
518
|
+
throw new InternalCompilerError("emitter bug: forOf over non-array");
|
|
467
519
|
const elem = s.iterable.type.elem;
|
|
468
|
-
const arr =
|
|
469
|
-
const idx = `sc_t${
|
|
470
|
-
|
|
471
|
-
|
|
520
|
+
const arr = emitter.emitExpr(s.iterable);
|
|
521
|
+
const idx = `sc_t${emitter.tempCounter++}`;
|
|
522
|
+
emitter.line(`for (double ${idx} = 0; ${idx} < scr_arr_len(${arr.name}); ${idx} += 1) {${emitter.srcComment(s.loc)}`);
|
|
523
|
+
emitter.indent++;
|
|
472
524
|
// A real C for-loop makes plain `continue` correct (the update
|
|
473
525
|
// still runs); a LABELED forOf allocates a continue label placed at
|
|
474
526
|
// the END of the iteration (after the per-iteration scope release —
|
|
475
527
|
// the goto path released it itself) so nested loops can goto it.
|
|
476
|
-
const loop =
|
|
477
|
-
|
|
528
|
+
const loop = emitter.loopTarget(null, s.labels);
|
|
529
|
+
emitter.jumpTargets.push(loop);
|
|
478
530
|
// The loop variable is a fresh const per iteration: its scope opens
|
|
479
531
|
// here, holds the (for ref elements: owned +1) current element, and
|
|
480
532
|
// releases it at the end of each iteration.
|
|
481
|
-
|
|
533
|
+
emitter.scopes.push([]);
|
|
482
534
|
const local = mangleLocal(s.localId);
|
|
483
|
-
const localInfo =
|
|
535
|
+
const localInfo = emitter.currentLocals.get(s.localId);
|
|
484
536
|
if (localInfo?.boxed) {
|
|
485
537
|
// Captured loop variable: a fresh box per iteration, matching the
|
|
486
538
|
// fresh const binding (closures made in iteration k keep seeing
|
|
487
539
|
// iteration k's element). The box takes ownership of a ref
|
|
488
540
|
// element's +1 and is released with the iteration's scope.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
541
|
+
emitter.line(`${local} = ${emitter.boxNewC(elem)}; /* per-iteration ${localInfo.name} */`);
|
|
542
|
+
emitter.line(`scr_box_set_${boxAccess(elem)}(${local}, scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx}));`);
|
|
543
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem, boxed: true });
|
|
492
544
|
}
|
|
493
545
|
else {
|
|
494
|
-
|
|
546
|
+
emitter.line(`${local} = scr_arr_get_${elemAccess(elem)}(${arr.name}, ${idx});`);
|
|
495
547
|
if (isRefCounted(elem))
|
|
496
|
-
|
|
548
|
+
emitter.scopes[emitter.scopes.length - 1].push({ name: local, type: elem });
|
|
497
549
|
}
|
|
498
|
-
|
|
499
|
-
const endedWithJump =
|
|
500
|
-
const scope =
|
|
550
|
+
emitter.emitStmts(s.body);
|
|
551
|
+
const endedWithJump = endsWithJump(s.body);
|
|
552
|
+
const scope = emitter.scopes.pop();
|
|
501
553
|
if (!endedWithJump)
|
|
502
|
-
|
|
503
|
-
|
|
554
|
+
emitter.releaseFrame(scope);
|
|
555
|
+
emitter.jumpTargets.pop();
|
|
504
556
|
if (loop.usedContinue && loop.continueLabel)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
557
|
+
emitter.line(`${loop.continueLabel}:;`);
|
|
558
|
+
emitter.indent--;
|
|
559
|
+
emitter.line(`}`);
|
|
508
560
|
if (loop.usedEnd)
|
|
509
|
-
|
|
561
|
+
emitter.line(`${loop.endLabel}:;`);
|
|
510
562
|
break;
|
|
511
563
|
}
|
|
512
564
|
case "block": {
|
|
513
565
|
if (s.labels === undefined) {
|
|
514
|
-
|
|
566
|
+
emitter.emitBlock(s.body);
|
|
515
567
|
break;
|
|
516
568
|
}
|
|
517
569
|
// A labeled block: `break lbl` inside jumps to the end label
|
|
518
570
|
// (releasing the block's scope itself); nothing else can target it.
|
|
519
571
|
const target = {
|
|
520
572
|
kind: "block",
|
|
521
|
-
endLabel: `sc_end_${
|
|
573
|
+
endLabel: `sc_end_${emitter.labelCounter++}`,
|
|
522
574
|
usedEnd: false,
|
|
523
575
|
labels: s.labels,
|
|
524
|
-
scopeDepth:
|
|
525
|
-
frameDepth:
|
|
576
|
+
scopeDepth: emitter.scopes.length,
|
|
577
|
+
frameDepth: emitter.frames.length,
|
|
526
578
|
};
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
579
|
+
emitter.jumpTargets.push(target);
|
|
580
|
+
emitter.emitBlock(s.body);
|
|
581
|
+
emitter.jumpTargets.pop();
|
|
530
582
|
if (target.usedEnd)
|
|
531
|
-
|
|
583
|
+
emitter.line(`${target.endLabel}:;`);
|
|
532
584
|
break;
|
|
533
585
|
}
|
|
534
586
|
case "break": {
|
|
@@ -542,16 +594,16 @@ export function emitStmt(E, s) {
|
|
|
542
594
|
// loop's releases after the loop and a switch's after its end
|
|
543
595
|
// label are still on this jump's path.
|
|
544
596
|
let target;
|
|
545
|
-
for (let i =
|
|
546
|
-
const t =
|
|
597
|
+
for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
|
|
598
|
+
const t = emitter.jumpTargets[i];
|
|
547
599
|
if (s.label !== undefined ? t.labels?.includes(s.label) : t.kind !== "block") {
|
|
548
600
|
target = t;
|
|
549
601
|
break;
|
|
550
602
|
}
|
|
551
603
|
}
|
|
552
604
|
if (!target)
|
|
553
|
-
throw new
|
|
554
|
-
|
|
605
|
+
throw new InternalCompilerError("emitter bug: break target not found");
|
|
606
|
+
emitter.releaseForJump(target.frameDepth, target.scopeDepth);
|
|
555
607
|
if (target.kind !== "loop" || s.label !== undefined) {
|
|
556
608
|
// Switches are emitted as goto chains and blocks aren't C loops
|
|
557
609
|
// at all, so a C `break` cannot target either; and a LABELED
|
|
@@ -559,10 +611,10 @@ export function emitStmt(E, s) {
|
|
|
559
611
|
// All three jump to the target's end label (labeled loops always
|
|
560
612
|
// allocate one — loopTarget).
|
|
561
613
|
target.usedEnd = true;
|
|
562
|
-
|
|
614
|
+
emitter.line(`goto ${target.endLabel};${emitter.srcComment(s.loc)}`);
|
|
563
615
|
}
|
|
564
616
|
else {
|
|
565
|
-
|
|
617
|
+
emitter.line(`break;${emitter.srcComment(s.loc)}`);
|
|
566
618
|
}
|
|
567
619
|
break;
|
|
568
620
|
}
|
|
@@ -571,30 +623,30 @@ export function emitStmt(E, s) {
|
|
|
571
623
|
// labeled blocks in between (their scopes are still released — the
|
|
572
624
|
// jump exits them). Labeled: binds to the loop carrying the label.
|
|
573
625
|
let loop;
|
|
574
|
-
for (let i =
|
|
575
|
-
const t =
|
|
626
|
+
for (let i = emitter.jumpTargets.length - 1; i >= 0; i--) {
|
|
627
|
+
const t = emitter.jumpTargets[i];
|
|
576
628
|
if (t.kind === "loop" && (s.label === undefined || t.labels?.includes(s.label))) {
|
|
577
629
|
loop = t;
|
|
578
630
|
break;
|
|
579
631
|
}
|
|
580
632
|
}
|
|
581
633
|
if (!loop)
|
|
582
|
-
throw new
|
|
583
|
-
|
|
634
|
+
throw new InternalCompilerError("emitter bug: continue target not found");
|
|
635
|
+
emitter.releaseForJump(loop.frameDepth, loop.scopeDepth);
|
|
584
636
|
if (loop.continueLabel) {
|
|
585
637
|
// Labeled loops always allocate one (a labeled continue may
|
|
586
638
|
// target an outer loop a C continue could never reach); for/
|
|
587
639
|
// do-while allocate one for their update/condition point.
|
|
588
640
|
loop.usedContinue = true;
|
|
589
|
-
|
|
641
|
+
emitter.line(`goto ${loop.continueLabel};${emitter.srcComment(s.loc)}`);
|
|
590
642
|
}
|
|
591
643
|
else {
|
|
592
|
-
|
|
644
|
+
emitter.line(`continue;${emitter.srcComment(s.loc)}`);
|
|
593
645
|
}
|
|
594
646
|
break;
|
|
595
647
|
}
|
|
596
648
|
case "return": {
|
|
597
|
-
const fin =
|
|
649
|
+
const fin = emitter.finallyStack[emitter.finallyStack.length - 1];
|
|
598
650
|
if (fin) {
|
|
599
651
|
// Crossing ≥1 finally: the value is computed and snapshotted
|
|
600
652
|
// FIRST (a finally mutating the returned local cannot change
|
|
@@ -602,26 +654,26 @@ export function emitStmt(E, s) {
|
|
|
602
654
|
// region releases and control runs that region's pending-return
|
|
603
655
|
// finally copy; its tail dispatches further out or returns.
|
|
604
656
|
if (s.value) {
|
|
605
|
-
const v =
|
|
606
|
-
|
|
607
|
-
|
|
657
|
+
const v = emitter.emitExpr(s.value);
|
|
658
|
+
emitter.moveTemp(v); // ownership parks in the slot until the dispatch returns it
|
|
659
|
+
emitter.line(`sc_pret = ${v.name};${emitter.srcComment(s.loc)}`);
|
|
608
660
|
}
|
|
609
661
|
fin.used = true;
|
|
610
|
-
|
|
611
|
-
|
|
662
|
+
emitter.releaseForJump(fin.frameDepth, fin.scopeDepth);
|
|
663
|
+
emitter.line(`goto ${fin.label};${s.value ? "" : emitter.srcComment(s.loc)}`);
|
|
612
664
|
break;
|
|
613
665
|
}
|
|
614
666
|
if (s.value) {
|
|
615
|
-
const v =
|
|
616
|
-
|
|
667
|
+
const v = emitter.emitExpr(s.value);
|
|
668
|
+
emitter.moveTemp(v);
|
|
617
669
|
// Everything down to function depth releases; the moved result is
|
|
618
670
|
// exempt (already struck from its frame).
|
|
619
|
-
|
|
620
|
-
|
|
671
|
+
emitter.releaseForJump(0, 0);
|
|
672
|
+
emitter.line(`return ${v.name};${emitter.srcComment(s.loc)}`);
|
|
621
673
|
}
|
|
622
674
|
else {
|
|
623
|
-
|
|
624
|
-
|
|
675
|
+
emitter.releaseForJump(0, 0);
|
|
676
|
+
emitter.line(`return;${emitter.srcComment(s.loc)}`);
|
|
625
677
|
}
|
|
626
678
|
break;
|
|
627
679
|
}
|
|
@@ -629,34 +681,34 @@ export function emitStmt(E, s) {
|
|
|
629
681
|
// Evaluate, move ownership into the runtime's exception cell, then
|
|
630
682
|
// unwind unconditionally (the innermost try handler, or out of the
|
|
631
683
|
// function) — the same release path as return/break/continue.
|
|
632
|
-
const v =
|
|
684
|
+
const v = emitter.emitExpr(s.value);
|
|
633
685
|
const t = s.value.type;
|
|
634
686
|
if (isRefCounted(t))
|
|
635
|
-
|
|
687
|
+
emitter.moveTemp(v); // the cell takes ownership
|
|
636
688
|
if (t.kind === "date") {
|
|
637
|
-
throw new
|
|
689
|
+
throw new InternalCompilerError("emitter bug: Date throw reached backend");
|
|
638
690
|
}
|
|
639
691
|
else if (t.kind === "f64") {
|
|
640
|
-
|
|
692
|
+
emitter.line(`scr_throw_f64(${v.name});${emitter.srcComment(s.loc)}`);
|
|
641
693
|
}
|
|
642
694
|
else if (t.kind === "bool") {
|
|
643
|
-
|
|
695
|
+
emitter.line(`scr_throw_bool(${v.name});${emitter.srcComment(s.loc)}`);
|
|
644
696
|
}
|
|
645
697
|
else if (t.kind === "string") {
|
|
646
|
-
|
|
698
|
+
emitter.line(`scr_throw_str(${v.name});${emitter.srcComment(s.loc)}`);
|
|
647
699
|
}
|
|
648
|
-
else if (t.kind === "object" &&
|
|
700
|
+
else if (t.kind === "object" && emitter.classMeta.get(t.className)?.hierarchy) {
|
|
649
701
|
// Hierarchy instances carry a vtable word: the OBJ kind keeps the
|
|
650
702
|
// dynamic class inspectable (catch-binding instanceof, and the
|
|
651
703
|
// uncaught printer's "name: message" for Error instances).
|
|
652
704
|
const rc = vAdapters(t);
|
|
653
|
-
|
|
705
|
+
emitter.line(`scr_throw_obj(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
|
|
654
706
|
}
|
|
655
707
|
else {
|
|
656
708
|
const rc = vAdapters(t);
|
|
657
|
-
|
|
709
|
+
emitter.line(`scr_throw_ref(${v.name}, &${rc.retain}, &${rc.release}, ${emitter.traceArgC(t)});${emitter.srcComment(s.loc)}`);
|
|
658
710
|
}
|
|
659
|
-
|
|
711
|
+
emitter.emitUnwind();
|
|
660
712
|
break;
|
|
661
713
|
}
|
|
662
714
|
case "runtimeFence": {
|
|
@@ -664,29 +716,29 @@ export function emitStmt(E, s) {
|
|
|
664
716
|
// the construct (message) with the SC code stamped on `code`,
|
|
665
717
|
// then unwind exactly like `throw`.
|
|
666
718
|
const bytes = Buffer.from(s.message, "utf8");
|
|
667
|
-
|
|
668
|
-
|
|
719
|
+
emitter.line(`scr_throw_error_msg_code(SCR_ERR_ERROR, ${cStringLiteral(bytes)}, ${bytes.length}, "${s.code}");${emitter.srcComment(s.loc)}`);
|
|
720
|
+
emitter.emitUnwind();
|
|
669
721
|
break;
|
|
670
722
|
}
|
|
671
723
|
case "rethrow":
|
|
672
724
|
// Re-raise the saved snapshot (payload retained — the binding local
|
|
673
725
|
// releases with its scope) and unwind like `throw`.
|
|
674
|
-
|
|
675
|
-
|
|
726
|
+
emitter.line(`scr_rethrow(${mangleLocal(s.localId)});${emitter.srcComment(s.loc)}`);
|
|
727
|
+
emitter.emitUnwind();
|
|
676
728
|
break;
|
|
677
729
|
case "tryCatch":
|
|
678
|
-
|
|
730
|
+
emitter.emitTryCatch(s);
|
|
679
731
|
break;
|
|
680
732
|
default: {
|
|
681
733
|
const _exhaustive = s;
|
|
682
734
|
void _exhaustive;
|
|
683
735
|
}
|
|
684
736
|
}
|
|
685
|
-
const frame =
|
|
737
|
+
const frame = emitter.frames.pop();
|
|
686
738
|
// return/throw already released their frames on the jump path; emitting
|
|
687
739
|
// the fall-through releases after them would be dead double-release code.
|
|
688
740
|
if (s.kind !== "return" && s.kind !== "throw" && s.kind !== "rethrow" && s.kind !== "runtimeFence")
|
|
689
|
-
|
|
741
|
+
emitter.releaseFrame(frame);
|
|
690
742
|
}
|
|
691
743
|
/** try/catch/finally via pending-flag unwinding. Entering a try emits NO
|
|
692
744
|
* code: the try context is compile-time state (tryStack) that redirects
|
|
@@ -719,8 +771,8 @@ export function emitStmt(E, s) {
|
|
|
719
771
|
* normal, exception, and pending-return are the only paths a finally
|
|
720
772
|
* must model; jumps out of PLAIN try/catch need nothing here —
|
|
721
773
|
* release-on-jump already walks the try scopes. */
|
|
722
|
-
export function emitTryCatch(
|
|
723
|
-
const id =
|
|
774
|
+
export function emitTryCatch(emitter, s) {
|
|
775
|
+
const id = emitter.labelCounter++;
|
|
724
776
|
const hasCatch = s.catchBody !== null;
|
|
725
777
|
const hasFinally = s.finallyBody !== null;
|
|
726
778
|
const catchLabel = `sc_catch_${id}`;
|
|
@@ -732,8 +784,8 @@ export function emitTryCatch(E, s) {
|
|
|
732
784
|
const handler = {
|
|
733
785
|
label: hasCatch ? catchLabel : finExcLabel,
|
|
734
786
|
used: false,
|
|
735
|
-
frameDepth:
|
|
736
|
-
scopeDepth:
|
|
787
|
+
frameDepth: emitter.frames.length,
|
|
788
|
+
scopeDepth: emitter.scopes.length,
|
|
737
789
|
};
|
|
738
790
|
// The pending-return region: returns inside tryBody/catchBody snapshot
|
|
739
791
|
// their value and jump here-ish (the pending-return finally copy below)
|
|
@@ -742,77 +794,77 @@ export function emitTryCatch(E, s) {
|
|
|
742
794
|
? {
|
|
743
795
|
label: `sc_finret_${id}`,
|
|
744
796
|
used: false,
|
|
745
|
-
frameDepth:
|
|
746
|
-
scopeDepth:
|
|
797
|
+
frameDepth: emitter.frames.length,
|
|
798
|
+
scopeDepth: emitter.scopes.length,
|
|
747
799
|
}
|
|
748
800
|
: null;
|
|
749
|
-
|
|
801
|
+
emitter.line(`/* try */${emitter.srcComment(s.loc)}`);
|
|
750
802
|
if (retEntry)
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
803
|
+
emitter.finallyStack.push(retEntry);
|
|
804
|
+
emitter.tryStack.push(handler);
|
|
805
|
+
emitter.emitBlock(s.tryBody);
|
|
806
|
+
emitter.tryStack.pop();
|
|
755
807
|
// Exceptions raised in the CATCH body unwind to the exception-path
|
|
756
808
|
// finally (pending stays set through it) when one exists.
|
|
757
809
|
const excHandler = {
|
|
758
810
|
label: finExcLabel,
|
|
759
811
|
used: !hasCatch && handler.used,
|
|
760
|
-
frameDepth:
|
|
761
|
-
scopeDepth:
|
|
812
|
+
frameDepth: emitter.frames.length,
|
|
813
|
+
scopeDepth: emitter.scopes.length,
|
|
762
814
|
};
|
|
763
815
|
if (hasCatch && handler.used) {
|
|
764
|
-
if (!
|
|
765
|
-
|
|
816
|
+
if (!endsWithJump(s.tryBody)) {
|
|
817
|
+
emitter.line(`goto ${afterTryLabel};`);
|
|
766
818
|
afterTryLabelUsed = true;
|
|
767
819
|
}
|
|
768
820
|
if (hasFinally)
|
|
769
|
-
|
|
821
|
+
emitter.tryStack.push(excHandler);
|
|
770
822
|
// Generator bodies: a pending GENRET sentinel (.return(v) injected at
|
|
771
823
|
// a yield) is a RETURN completion, not a throw — catch must not take
|
|
772
824
|
// it. Re-unwind past this handler (finally still runs — the unwind
|
|
773
825
|
// targets the exception-path finally or the enclosing context; the
|
|
774
826
|
// runtime depths here equal the handler's, so no double release).
|
|
775
827
|
const genretPrologue = () => {
|
|
776
|
-
if (
|
|
828
|
+
if (emitter.currentGenerator === null)
|
|
777
829
|
return;
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
830
|
+
emitter.line(`if (scr_exc_genret_pending()) { /* .return(): not catchable */`);
|
|
831
|
+
emitter.indent++;
|
|
832
|
+
emitter.emitUnwind();
|
|
833
|
+
emitter.indent--;
|
|
834
|
+
emitter.line(`}`);
|
|
783
835
|
};
|
|
784
836
|
if (s.catchLocalId !== null) {
|
|
785
837
|
// catch (e): the exception MOVES into the binding's snapshot box,
|
|
786
838
|
// owned by the catch body's scope (released on every exit — normal
|
|
787
839
|
// fall-through, jumps out, and unwinds from the body).
|
|
788
840
|
const binding = mangleLocal(s.catchLocalId);
|
|
789
|
-
|
|
841
|
+
emitter.line(`${catchLabel}:; /* catch (${emitter.currentLocals.get(s.catchLocalId)?.name ?? "e"}) — takes the exception */`);
|
|
790
842
|
genretPrologue();
|
|
791
|
-
|
|
792
|
-
|
|
843
|
+
emitter.emitBlock(s.catchBody, (scope) => {
|
|
844
|
+
emitter.line(`${binding} = scr_exc_take();`);
|
|
793
845
|
scope.push({ name: binding, type: CAUGHT });
|
|
794
846
|
});
|
|
795
847
|
}
|
|
796
848
|
else {
|
|
797
|
-
|
|
849
|
+
emitter.line(`${catchLabel}:; /* catch — takes the exception */`);
|
|
798
850
|
genretPrologue();
|
|
799
|
-
|
|
800
|
-
|
|
851
|
+
emitter.line(`scr_exc_clear();`);
|
|
852
|
+
emitter.emitBlock(s.catchBody);
|
|
801
853
|
}
|
|
802
854
|
if (hasFinally)
|
|
803
|
-
|
|
855
|
+
emitter.tryStack.pop();
|
|
804
856
|
// Normal completion of the catch falls through to afterTryLabel.
|
|
805
857
|
}
|
|
806
858
|
if (retEntry)
|
|
807
|
-
|
|
859
|
+
emitter.finallyStack.pop();
|
|
808
860
|
if (hasFinally) {
|
|
809
861
|
if (afterTryLabelUsed)
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
862
|
+
emitter.line(`${afterTryLabel}:;`);
|
|
863
|
+
emitter.line(`/* finally (normal path) */`);
|
|
864
|
+
emitter.emitBlock(s.finallyBody);
|
|
813
865
|
const needEnd = excHandler.used || retEntry.used;
|
|
814
866
|
if (needEnd)
|
|
815
|
-
|
|
867
|
+
emitter.line(`goto ${endLabel};`);
|
|
816
868
|
if (excHandler.used) {
|
|
817
869
|
// The pending exception is STASHED across the finally body (a
|
|
818
870
|
// ScrCaught snapshot, re-raised after) so the body runs with a
|
|
@@ -825,14 +877,14 @@ export function emitTryCatch(E, s) {
|
|
|
825
877
|
// JS's replace semantics); normal completion re-raises the stash
|
|
826
878
|
// and keeps propagating.
|
|
827
879
|
const stash = `sc_fexc_${id}`;
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
880
|
+
emitter.line(`${finExcLabel}:; /* finally (exception path — stashed) */`);
|
|
881
|
+
emitter.line(`ScrCaught *${stash} = scr_exc_take();`);
|
|
882
|
+
emitter.scopes.push([{ name: stash, type: CAUGHT }]);
|
|
883
|
+
emitter.emitBlock(s.finallyBody);
|
|
884
|
+
emitter.scopes.pop(); // normal completion keeps the stash for the re-raise
|
|
885
|
+
emitter.line(`scr_rethrow(${stash});`);
|
|
886
|
+
emitter.line(`scr_caught_release(${stash});`);
|
|
887
|
+
emitter.emitUnwind();
|
|
836
888
|
}
|
|
837
889
|
if (retEntry.used) {
|
|
838
890
|
// Pending-return path: a return in the try/catch body parked its
|
|
@@ -843,30 +895,30 @@ export function emitTryCatch(E, s) {
|
|
|
843
895
|
// actual return. A THROW inside this copy replaces the pending
|
|
844
896
|
// return (JS): the slot's owned value rides a synthetic scope
|
|
845
897
|
// entry so the unwind releases it.
|
|
846
|
-
|
|
847
|
-
const retT =
|
|
898
|
+
emitter.line(`${retEntry.label}:; /* finally (pending-return path) */`);
|
|
899
|
+
const retT = emitter.currentReturnType;
|
|
848
900
|
const own = isRefCounted(retT);
|
|
849
901
|
if (own)
|
|
850
|
-
|
|
851
|
-
|
|
902
|
+
emitter.scopes.push([{ name: "sc_pret", type: retT }]);
|
|
903
|
+
emitter.emitBlock(s.finallyBody);
|
|
852
904
|
if (own)
|
|
853
|
-
|
|
854
|
-
const outer =
|
|
905
|
+
emitter.scopes.pop();
|
|
906
|
+
const outer = emitter.finallyStack[emitter.finallyStack.length - 1];
|
|
855
907
|
if (outer) {
|
|
856
908
|
outer.used = true;
|
|
857
|
-
|
|
858
|
-
|
|
909
|
+
emitter.releaseForJump(outer.frameDepth, outer.scopeDepth);
|
|
910
|
+
emitter.line(`goto ${outer.label};`);
|
|
859
911
|
}
|
|
860
912
|
else {
|
|
861
|
-
|
|
862
|
-
|
|
913
|
+
emitter.releaseForJump(0, 0);
|
|
914
|
+
emitter.line(retT.kind === "void" ? `return;` : `return sc_pret;`);
|
|
863
915
|
}
|
|
864
916
|
}
|
|
865
917
|
if (needEnd)
|
|
866
|
-
|
|
918
|
+
emitter.line(`${endLabel}:;`);
|
|
867
919
|
}
|
|
868
920
|
else if (afterTryLabelUsed) {
|
|
869
|
-
|
|
921
|
+
emitter.line(`${endLabel}:;`);
|
|
870
922
|
}
|
|
871
923
|
}
|
|
872
924
|
/** JS-exact switch as a goto chain — C `switch` cannot express lazily
|
|
@@ -887,27 +939,27 @@ export function emitTryCatch(E, s) {
|
|
|
887
939
|
* it still holds the pointer a previous iteration's scope exit already
|
|
888
940
|
* released. The declarations are therefore NULL-reset up front; the
|
|
889
941
|
* scope-exit releases rely on the runtime's NULL-tolerant release calls. */
|
|
890
|
-
export function emitSwitch(
|
|
942
|
+
export function emitSwitch(emitter, s) {
|
|
891
943
|
if (s.disc.type.kind !== "f64" && s.disc.type.kind !== "string" && s.disc.type.kind !== "bool") {
|
|
892
|
-
throw new
|
|
944
|
+
throw new InternalCompilerError(`emitter bug: switch on ${s.disc.type.kind}`);
|
|
893
945
|
}
|
|
894
|
-
const id =
|
|
946
|
+
const id = emitter.labelCounter++;
|
|
895
947
|
const endLabel = `sc_swend_${id}`;
|
|
896
948
|
const caseLabel = (i) => `sc_swcase_${id}_${i}`;
|
|
897
949
|
// The disc temp lives in the whole statement's frame: for a string
|
|
898
950
|
// discriminant it stays alive across every test and body, released when
|
|
899
951
|
// the switch statement ends (break lands before that release; return
|
|
900
952
|
// sweeps frames itself).
|
|
901
|
-
const disc =
|
|
953
|
+
const disc = emitter.emitExpr(s.disc);
|
|
902
954
|
// NULL-reset refcounted/boxed locals declared at the top level of case
|
|
903
955
|
// bodies (nested blocks manage their own scopes on normal control flow).
|
|
904
956
|
for (const c of s.cases) {
|
|
905
957
|
for (const stmt of c.body) {
|
|
906
958
|
if (stmt.kind !== "varDecl")
|
|
907
959
|
continue;
|
|
908
|
-
const local =
|
|
960
|
+
const local = emitter.currentLocals.get(stmt.localId);
|
|
909
961
|
if (local.boxed || isRefCounted(local.type)) {
|
|
910
|
-
|
|
962
|
+
emitter.line(`${mangleLocal(local.id)} = NULL; /* case-scoped ${local.name} */`);
|
|
911
963
|
}
|
|
912
964
|
}
|
|
913
965
|
}
|
|
@@ -919,16 +971,16 @@ export function emitSwitch(E, s) {
|
|
|
919
971
|
defaultIdx = i;
|
|
920
972
|
return;
|
|
921
973
|
}
|
|
922
|
-
|
|
923
|
-
const t =
|
|
974
|
+
emitter.frames.push([]);
|
|
975
|
+
const t = emitter.emitExpr(c.test);
|
|
924
976
|
const cmp = c.test.type.kind === "string"
|
|
925
977
|
? `scr_str_eq(${disc.name}, ${t.name})`
|
|
926
978
|
: `${disc.name} == ${t.name}`;
|
|
927
|
-
const hit =
|
|
928
|
-
|
|
929
|
-
|
|
979
|
+
const hit = emitter.newTemp(BOOL, cmp);
|
|
980
|
+
emitter.releaseFrame(emitter.frames.pop());
|
|
981
|
+
emitter.line(`if (${hit.name}) goto ${caseLabel(i)};`);
|
|
930
982
|
});
|
|
931
|
-
|
|
983
|
+
emitter.line(`goto ${defaultIdx >= 0 ? caseLabel(defaultIdx) : endLabel};`);
|
|
932
984
|
// Bodies in source order: entering one falls through the rest (JS-exact)
|
|
933
985
|
// until a break jumps to the end label.
|
|
934
986
|
const target = {
|
|
@@ -936,33 +988,33 @@ export function emitSwitch(E, s) {
|
|
|
936
988
|
endLabel,
|
|
937
989
|
usedEnd: defaultIdx < 0,
|
|
938
990
|
...(s.labels !== undefined && { labels: s.labels }),
|
|
939
|
-
scopeDepth:
|
|
940
|
-
frameDepth:
|
|
991
|
+
scopeDepth: emitter.scopes.length,
|
|
992
|
+
frameDepth: emitter.frames.length,
|
|
941
993
|
};
|
|
942
|
-
|
|
943
|
-
|
|
994
|
+
emitter.jumpTargets.push(target);
|
|
995
|
+
emitter.scopes.push([]);
|
|
944
996
|
s.cases.forEach((c, i) => {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
997
|
+
emitter.line(`${caseLabel(i)}:;`);
|
|
998
|
+
emitter.indent++;
|
|
999
|
+
emitter.emitStmts(c.body);
|
|
1000
|
+
emitter.indent--;
|
|
949
1001
|
});
|
|
950
|
-
|
|
951
|
-
const scope =
|
|
1002
|
+
emitter.jumpTargets.pop();
|
|
1003
|
+
const scope = emitter.scopes.pop();
|
|
952
1004
|
// Natural fall-off of the last body releases the shared scope here; a
|
|
953
1005
|
// jump (break/return/continue/throw) already released it before jumping.
|
|
954
1006
|
const lastBody = s.cases[s.cases.length - 1]?.body;
|
|
955
|
-
if (!lastBody || !
|
|
956
|
-
|
|
1007
|
+
if (!lastBody || !endsWithJump(lastBody))
|
|
1008
|
+
emitter.releaseFrame(scope);
|
|
957
1009
|
if (target.usedEnd)
|
|
958
|
-
|
|
1010
|
+
emitter.line(`${endLabel}:;`);
|
|
959
1011
|
}
|
|
960
1012
|
/** Emits `if (cond) ` followed by a block on the same line for readability. */
|
|
961
|
-
export function mergeBrace(
|
|
962
|
-
const head =
|
|
963
|
-
const before =
|
|
1013
|
+
export function mergeBrace(emitter, emitBlockFn) {
|
|
1014
|
+
const head = emitter.lines.pop();
|
|
1015
|
+
const before = emitter.lines.length;
|
|
964
1016
|
emitBlockFn();
|
|
965
|
-
|
|
1017
|
+
emitter.lines[before] = head + emitter.lines[before].trimStart();
|
|
966
1018
|
}
|
|
967
1019
|
/** Evaluates `expr` in its own statement frame inside an already-open
|
|
968
1020
|
* branch and moves the result into the C lvalue `target`: the chosen
|
|
@@ -970,20 +1022,20 @@ export function mergeBrace(E, emitBlockFn) {
|
|
|
970
1022
|
* releases inside the branch. The shared core of the lazily-branched
|
|
971
1023
|
* expressions (`logical`, `ternary`); the caller owns the surrounding
|
|
972
1024
|
* braces/indentation and registers `target` in ITS frame. */
|
|
973
|
-
export function emitBranchInto(
|
|
974
|
-
|
|
975
|
-
const v =
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1025
|
+
export function emitBranchInto(emitter, target, expr) {
|
|
1026
|
+
emitter.frames.push([]);
|
|
1027
|
+
const v = emitter.emitExpr(expr);
|
|
1028
|
+
emitter.moveTemp(v);
|
|
1029
|
+
emitter.line(`${target} = ${v.name};`);
|
|
1030
|
+
emitter.releaseFrame(emitter.frames.pop());
|
|
979
1031
|
}
|
|
980
1032
|
/** Evaluates a condition; its string temps are released before the branch,
|
|
981
1033
|
* which is safe because the result is a scalar bool. */
|
|
982
|
-
export function emitCondition(
|
|
983
|
-
const t =
|
|
984
|
-
const frame =
|
|
985
|
-
|
|
1034
|
+
export function emitCondition(emitter, cond) {
|
|
1035
|
+
const t = emitter.emitExpr(cond);
|
|
1036
|
+
const frame = emitter.currentFrame();
|
|
1037
|
+
emitter.releaseFrame(frame);
|
|
986
1038
|
frame.length = 0;
|
|
987
1039
|
return t.name;
|
|
988
1040
|
}
|
|
989
|
-
//# sourceMappingURL=
|
|
1041
|
+
//# sourceMappingURL=stmts.js.map
|