@scriptc/compiler 0.3.2 → 0.3.4
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 +1202 -64
- package/dist/backend/cycle-analysis.js +6 -1
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +5 -0
- package/dist/backend/cycle-mutability.js +62 -3
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/executable-features.js +1 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/library-pack.js +1 -0
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/llvm/alloc.js +24 -10
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +47 -1
- package/dist/backend/llvm/alloc.test.js.map +1 -1
- package/dist/backend/llvm/array-search.d.ts +8 -0
- package/dist/backend/llvm/array-search.js +52 -0
- package/dist/backend/llvm/array-search.js.map +1 -0
- package/dist/backend/llvm/array-search.test.d.ts +1 -0
- package/dist/backend/llvm/array-search.test.js +72 -0
- package/dist/backend/llvm/array-search.test.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +12 -1
- package/dist/backend/llvm/call-lifetimes.js +41 -11
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +85 -1
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/classes.js +87 -36
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +6 -1
- package/dist/backend/llvm/common.js +8 -1
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +5 -0
- package/dist/backend/llvm/dense-array-access.js +3 -3
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +44 -1
- package/dist/backend/llvm/dyn.js +251 -36
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +77 -14
- package/dist/backend/llvm/emitter.js +461 -108
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +26 -3
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +52 -1
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +9 -0
- package/dist/backend/llvm/expr-bytes.js +169 -63
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.js +16 -2
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +3 -1
- package/dist/backend/llvm/expr-calls.js +57 -2
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +57 -19
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +19 -8
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +28 -30
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +8 -4
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +35 -32
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +13 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +80 -5
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/inline-unions.d.ts +48 -0
- package/dist/backend/llvm/inline-unions.js +134 -0
- package/dist/backend/llvm/inline-unions.js.map +1 -0
- package/dist/backend/llvm/inline-unions.test.d.ts +1 -0
- package/dist/backend/llvm/inline-unions.test.js +124 -0
- package/dist/backend/llvm/inline-unions.test.js.map +1 -0
- package/dist/backend/llvm/integer-remainder.d.ts +28 -5
- package/dist/backend/llvm/integer-remainder.js +80 -9
- package/dist/backend/llvm/integer-remainder.js.map +1 -1
- package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
- package/dist/backend/llvm/intern-tables.test.js +77 -0
- package/dist/backend/llvm/intern-tables.test.js.map +1 -0
- package/dist/backend/llvm/lib-datagram.js +10 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +255 -29
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +176 -7
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +25 -6
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +2 -2
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.d.ts +5 -0
- package/dist/backend/llvm/lib-shared.js +212 -1
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +184 -0
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +9 -0
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +7 -3
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +6 -3
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.d.ts +2 -0
- package/dist/backend/llvm/local-union-storage.js +5 -0
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +1 -0
- package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
- package/dist/backend/llvm/loop-array-borrows.d.ts +8 -2
- package/dist/backend/llvm/loop-array-borrows.js +93 -13
- package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.d.ts +24 -0
- package/dist/backend/llvm/map-number-lookup.js +88 -0
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.d.ts +1 -0
- package/dist/backend/llvm/map-number-lookup.test.js +158 -0
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +9 -0
- package/dist/backend/llvm/map-read-lifetimes.js +90 -1
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +129 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +9 -0
- package/dist/backend/llvm/publish.js +25 -4
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/record-results.d.ts +8 -5
- package/dist/backend/llvm/record-results.js +20 -12
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/reference-effects.js +13 -0
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/reference-writes.js +19 -2
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/regions.d.ts +5 -1
- package/dist/backend/llvm/regions.js +24 -10
- package/dist/backend/llvm/regions.js.map +1 -1
- package/dist/backend/llvm/serialized-ir-emission.test.js +2 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +56 -10
- package/dist/backend/llvm/shapes.js +178 -39
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +61 -3
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/stack-objects.js +16 -4
- package/dist/backend/llvm/stack-objects.js.map +1 -1
- package/dist/backend/llvm/stack-objects.test.js +3 -0
- package/dist/backend/llvm/stack-objects.test.js.map +1 -1
- package/dist/backend/llvm/string-reads.js +2 -2
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/string-slices.js +2 -2
- package/dist/backend/llvm/string-slices.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +11 -0
- package/dist/backend/llvm/walkers.js +106 -10
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +13 -4
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +5 -2
- package/dist/backend/native/executable.js +27 -8
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +2 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +4 -4
- package/dist/backend/native-codegen-core.js +4 -6
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.test.js +7 -8
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +3 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +1 -1
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/publication.js +3 -1
- package/dist/backend/publication.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-targets.test.js +2 -1
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +2 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.js +11 -1
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +4 -1
- package/dist/backend/target-diagnostics.test.js.map +1 -1
- package/dist/backend/warm-cache.js +1 -0
- package/dist/backend/warm-cache.js.map +1 -1
- package/dist/compat/fetch-profile.js +4 -4
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/contracts/check.js +2 -0
- package/dist/contracts/check.js.map +1 -1
- package/dist/coverage/report.js +1 -1
- package/dist/coverage/report.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +6 -5
- package/dist/diagnostics/diagnostic.js +7 -6
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +1 -0
- package/dist/executable/executable-cache.js +1 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +1 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +1 -1
- package/dist/frontend/builtin-modules.js +1 -0
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/comptime-node.js +2 -2
- package/dist/frontend/comptime-node.js.map +1 -1
- package/dist/frontend/experimental-import.d.ts +5 -1
- package/dist/frontend/experimental-import.js +28 -3
- package/dist/frontend/experimental-import.js.map +1 -1
- package/dist/frontend/lowering/assert-instances.d.ts +38 -0
- package/dist/frontend/lowering/assert-instances.js +269 -0
- package/dist/frontend/lowering/assert-instances.js.map +1 -0
- package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
- package/dist/frontend/lowering/binding-analysis.js +1 -1
- package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
- package/dist/frontend/lowering/builtins/arguments.js +8 -4
- package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
- package/dist/frontend/lowering/builtins/blob.d.ts +20 -0
- package/dist/frontend/lowering/builtins/blob.js +167 -0
- package/dist/frontend/lowering/builtins/blob.js.map +1 -0
- package/dist/frontend/lowering/builtins/child-process-async.d.ts +2 -2
- package/dist/frontend/lowering/builtins/child-process-async.js +2 -2
- package/dist/frontend/lowering/builtins/child-process-methods.js +1 -1
- package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-sync.js +1 -1
- package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
- package/dist/frontend/lowering/builtins/compression.js +178 -4
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/constants.js +7 -2
- package/dist/frontend/lowering/builtins/constants.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
- package/dist/frontend/lowering/builtins/crypto.js +526 -121
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +23 -0
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +10 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +89 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +16 -7
- package/dist/frontend/lowering/builtins/filesystem.js +97 -15
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-glob.d.ts +23 -0
- package/dist/frontend/lowering/builtins/fs-glob.js +224 -0
- package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -0
- package/dist/frontend/lowering/builtins/key-object.d.ts +13 -0
- package/dist/frontend/lowering/builtins/key-object.js +56 -0
- package/dist/frontend/lowering/builtins/key-object.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-calls.js +44 -11
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/performance.d.ts +25 -3
- package/dist/frontend/lowering/builtins/performance.js +340 -5
- package/dist/frontend/lowering/builtins/performance.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.d.ts +2 -2
- package/dist/frontend/lowering/builtins/process.js +107 -14
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/properties.d.ts +0 -7
- package/dist/frontend/lowering/builtins/properties.js +39 -11
- package/dist/frontend/lowering/builtins/properties.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +23 -8
- package/dist/frontend/lowering/builtins/readline.js +266 -90
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
- package/dist/frontend/lowering/builtins/timers.js +109 -23
- package/dist/frontend/lowering/builtins/timers.js.map +1 -1
- package/dist/frontend/lowering/builtins/url.d.ts +8 -0
- package/dist/frontend/lowering/builtins/url.js +36 -0
- package/dist/frontend/lowering/builtins/url.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.js +1 -1
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/call-signatures.js +26 -2
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +2 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +171 -13
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-protocol-dispatch.d.ts +45 -0
- package/dist/frontend/lowering/class-protocol-dispatch.js +516 -0
- package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -0
- package/dist/frontend/lowering/coercions/structural-plans.js +2 -1
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +3 -3
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/collation-repertoire.js +6 -5
- package/dist/frontend/lowering/collation-repertoire.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +4 -7
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.d.ts +0 -7
- package/dist/frontend/lowering/containers/array-methods.js +43 -2
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +38 -26
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/for-of.d.ts +1 -1
- package/dist/frontend/lowering/containers/for-of.js +5 -1
- package/dist/frontend/lowering/containers/for-of.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
- package/dist/frontend/lowering/crypto-tables.js +77 -12
- package/dist/frontend/lowering/crypto-tables.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +10 -0
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +16 -12
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.d.ts +2 -2
- package/dist/frontend/lowering/generic-functions.js +2 -2
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/http2-constants.js +1 -1
- package/dist/frontend/lowering/intern-tables.d.ts +13 -0
- package/dist/frontend/lowering/intern-tables.js +536 -0
- package/dist/frontend/lowering/intern-tables.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +12 -1
- package/dist/frontend/lowering/lower-array-sort.js +561 -191
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.test.js +4 -2
- package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +702 -63
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.d.ts +6 -3
- package/dist/frontend/lowering/lower-async-iteration.js +259 -4
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +118 -12
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +11 -2
- package/dist/frontend/lowering/lower-classes.js +76 -9
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
- package/dist/frontend/lowering/lower-comptime.js +4 -4
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +77 -52
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-event-target.d.ts +63 -0
- package/dist/frontend/lowering/lower-event-target.js +362 -0
- package/dist/frontend/lowering/lower-event-target.js.map +1 -0
- package/dist/frontend/lowering/lower-expando.js +2 -2
- package/dist/frontend/lowering/lower-exprs.js +124 -22
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
- package/dist/frontend/lowering/lower-inspect.js +240 -49
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.js +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +11 -0
- package/dist/frontend/lowering/lower-mock.js +504 -0
- package/dist/frontend/lowering/lower-mock.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +1 -1
- package/dist/frontend/lowering/lower-modules.js +14 -3
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +2 -2
- package/dist/frontend/lowering/lower-namespaces.js +2 -2
- package/dist/frontend/lowering/lower-server.d.ts +3 -0
- package/dist/frontend/lowering/lower-server.js +419 -44
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.d.ts +7 -1
- package/dist/frontend/lowering/lower-stdlib.js +10 -3
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +2 -2
- package/dist/frontend/lowering/lower-stmts.js +69 -14
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +10 -6
- package/dist/frontend/lowering/lower-stream.js +1020 -49
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +86 -8
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lower-timers.js +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +45 -5
- package/dist/frontend/lowering/lowerer.js +317 -48
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/native-ffi.js +2 -2
- package/dist/frontend/lowering/native-ffi.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
- package/dist/frontend/lowering/pairs-snapshot.js +49 -0
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-records.d.ts +115 -0
- package/dist/frontend/lowering/runtime-optional-records.js +715 -0
- package/dist/frontend/lowering/runtime-optional-records.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-records.test.d.ts +1 -0
- package/dist/frontend/lowering/runtime-optional-records.test.js +175 -0
- package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +11 -3
- package/dist/frontend/lowering/surfaces.js +334 -37
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
- package/dist/frontend/lowering/zlib-constants.js +181 -0
- package/dist/frontend/lowering/zlib-constants.js.map +1 -0
- package/dist/frontend/mock-shapes.d.ts +10 -0
- package/dist/frontend/mock-shapes.js +76 -0
- package/dist/frontend/mock-shapes.js.map +1 -0
- package/dist/frontend/module-syntax.d.ts +1 -1
- package/dist/frontend/module-syntax.js +1 -1
- package/dist/frontend/npm-static-prune.js +1 -1
- package/dist/frontend/npm-static-prune.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-syntax.js +4 -3
- package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
- package/dist/frontend/pipeline.js +6 -4
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program.d.ts +3 -3
- package/dist/frontend/program.js +25 -18
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.d.ts +4 -0
- package/dist/frontend/resolve.js +15 -1
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/ts7/adapter.js +1 -1
- package/dist/frontend/ts7/ast-bytes.d.ts +1 -1
- package/dist/frontend/ts7/ast-bytes.js +1 -1
- package/dist/frontend/ts7/semantic-json.d.ts +1 -1
- package/dist/frontend/ts7/semantic-json.js +1 -1
- package/dist/frontend/ts7/semantic-json.js.map +1 -1
- package/dist/frontend/ts7/world-check.js +1 -1
- package/dist/frontend/tsc-codes.js +3 -2
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +21 -1
- package/dist/frontend/type-mapper.js +245 -27
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +12 -6
- package/dist/ir/analysis.js +26 -10
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +15 -3
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/builtin-effects.js +115 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +438 -46
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/int32-slots.js +1 -0
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/ir.d.ts +84 -17
- package/dist/ir/ir.js +54 -1
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +1 -0
- package/dist/ir/runtime-features.js +111 -7
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/traverse.js +1 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +295 -14
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +60 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/fence-eval.d.ts +1 -1
- package/dist/library/fence-eval.js +5 -4
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/ir-policy.js +11 -4
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/library/library-profile.js +13 -13
- package/dist/library/library-profile.js.map +1 -1
- package/dist/library/prepare.js +1 -1
- package/dist/library/prepare.js.map +1 -1
- package/dist/library/sidecar.js +3 -3
- package/dist/library/sidecar.js.map +1 -1
- package/dist/native/cli.js +1 -0
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.js +1 -3
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/prepare.js +4 -2
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.test.js +1 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +1279 -221
|
@@ -35,8 +35,33 @@ import { newFnCtx, own } from "./lowerer.js";
|
|
|
35
35
|
import { appendImplicitUndefinedReturn } from "./function-returns.js";
|
|
36
36
|
import { bufEncoding, knownBufEncoding } from "./containers/bytes.js";
|
|
37
37
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
38
|
-
import {
|
|
38
|
+
import { sideEffectFreeOptionValue } from "./surfaces.js";
|
|
39
|
+
import { lowerDynObjectLiteral } from "./expressions/object-literals.js";
|
|
40
|
+
import { dynUndefinedExpr, varRef } from "../../ir/build.js";
|
|
41
|
+
import { genResultRecord } from "../type-mapper.js";
|
|
42
|
+
import { extractIteratorValue, genStep, genValue, stepDrivable } from "./lower-generators.js";
|
|
43
|
+
import { BOOL, DYN, F64, RUNTIME_STREAM_CLASSES, STRING, VOID, arrayOf, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, funcOf, typeEquals, typeKey, } from "../../ir/ir.js";
|
|
39
44
|
const BYTES = BYTES_U8;
|
|
45
|
+
/** An expression that only reads bindings and properties (no calls,
|
|
46
|
+
* assignments or construction): reading it a step later observes the
|
|
47
|
+
* same values. */
|
|
48
|
+
function pureRead(node) {
|
|
49
|
+
if (ts.isParenthesizedExpression(node) ||
|
|
50
|
+
ts.isNonNullExpression(node) ||
|
|
51
|
+
ts.isAsExpression(node)) {
|
|
52
|
+
return pureRead(node.expression);
|
|
53
|
+
}
|
|
54
|
+
if (ts.isIdentifier(node) || node.kind === ts.SyntaxKind.ThisKeyword)
|
|
55
|
+
return true;
|
|
56
|
+
if (ts.isPropertyAccessExpression(node))
|
|
57
|
+
return pureRead(node.expression);
|
|
58
|
+
if (ts.isElementAccessExpression(node)) {
|
|
59
|
+
return ((ts.isStringLiteral(node.argumentExpression) ||
|
|
60
|
+
ts.isNumericLiteral(node.argumentExpression)) &&
|
|
61
|
+
pureRead(node.expression));
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
40
65
|
/** The stream sides of a receiver class: the nearest stream-class
|
|
41
66
|
* ancestor's, or null off the stream hierarchy. */
|
|
42
67
|
export function streamSidesOf(lowerer, info) {
|
|
@@ -466,6 +491,7 @@ fallbackCb) {
|
|
|
466
491
|
encoding: null,
|
|
467
492
|
badEncoding: null,
|
|
468
493
|
pushEncoding: null,
|
|
494
|
+
signal: null,
|
|
469
495
|
flags: 0,
|
|
470
496
|
cbs: [],
|
|
471
497
|
};
|
|
@@ -527,6 +553,12 @@ fallbackCb) {
|
|
|
527
553
|
present.set(name, lowerStreamCallback(lowerer, name, fnNode, thisType, tuple));
|
|
528
554
|
continue;
|
|
529
555
|
}
|
|
556
|
+
// `{ signal }` shorthand: the binding is the value.
|
|
557
|
+
if (name === "signal" && ts.isShorthandPropertyAssignment(prop)) {
|
|
558
|
+
if (ts.isIdentifier(prop.name))
|
|
559
|
+
out.signal = lowerer.lowerExprExpecting(prop.name, DYN);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
530
562
|
// Scalar options.
|
|
531
563
|
if (!ts.isPropertyAssignment(prop)) {
|
|
532
564
|
lowerer.unsupported("SC1090", prop, `the ${ctorName} option '${name}' as a shorthand/method member`);
|
|
@@ -609,9 +641,20 @@ fallbackCb) {
|
|
|
609
641
|
}
|
|
610
642
|
lowerer.noLowering(`the ${ctorName} option 'defaultEncoding'`, prop, "utf8 (the default) is the supported write-side string encoding");
|
|
611
643
|
break;
|
|
612
|
-
case "signal":
|
|
613
|
-
|
|
644
|
+
case "signal": {
|
|
645
|
+
// `if (options.signal) addAbortSignal(options.signal, this)`:
|
|
646
|
+
// applied over the fresh stream, so the value is read after the
|
|
647
|
+
// constructor — only values whose evaluation has no effects.
|
|
648
|
+
if (value.kind === ts.SyntaxKind.NullKeyword)
|
|
649
|
+
break;
|
|
650
|
+
if (ts.isIdentifier(value) && value.text === "undefined")
|
|
651
|
+
break;
|
|
652
|
+
if (!sideEffectFreeOptionValue(value) && !pureRead(value)) {
|
|
653
|
+
lowerer.noLowering(`the ${ctorName} option 'signal' with this value`, prop, "pass a variable or property read (const signal = controller.signal) — the signal is read after construction");
|
|
654
|
+
}
|
|
655
|
+
out.signal = lowerer.lowerExprExpecting(value, DYN);
|
|
614
656
|
break;
|
|
657
|
+
}
|
|
615
658
|
case "captureRejections": {
|
|
616
659
|
// `false` is the default — admit the literal; the rejection-
|
|
617
660
|
// capturing mode has no lowering (async listeners' promises are
|
|
@@ -691,6 +734,7 @@ function streamCtorArgs(lowerer, cls, arg, thisType, loc, fallbackCb) {
|
|
|
691
734
|
encoding: o.encoding,
|
|
692
735
|
badEncoding: o.badEncoding,
|
|
693
736
|
pushEncoding: o.pushEncoding,
|
|
737
|
+
signal: o.signal,
|
|
694
738
|
};
|
|
695
739
|
}
|
|
696
740
|
/** `new Readable(opts?)` and friends — called from lowerNew once the
|
|
@@ -736,14 +780,24 @@ export function lowerStreamNew(lowerer, expr, info) {
|
|
|
736
780
|
loc,
|
|
737
781
|
};
|
|
738
782
|
}
|
|
739
|
-
if (parsed.encoding
|
|
783
|
+
if (parsed.encoding !== null) {
|
|
784
|
+
// { encoding }: chain a setEncoding over the fresh stream (the operand
|
|
785
|
+
// temp releases with the frame; setEncoding answers the receiver +1).
|
|
786
|
+
built = {
|
|
787
|
+
kind: "libCall",
|
|
788
|
+
fn: "readable.setEncoding",
|
|
789
|
+
args: [built, strLit(parsed.encoding, loc)],
|
|
790
|
+
type: thisType,
|
|
791
|
+
loc,
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
if (parsed.signal === null)
|
|
740
795
|
return built;
|
|
741
|
-
// {
|
|
742
|
-
// temp releases with the frame; setEncoding answers the receiver +1).
|
|
796
|
+
// { signal }: addAbortSignal over the fresh stream (answers it +1).
|
|
743
797
|
return {
|
|
744
798
|
kind: "libCall",
|
|
745
|
-
fn: "
|
|
746
|
-
args: [built,
|
|
799
|
+
fn: "stream.addAbortSignal",
|
|
800
|
+
args: [built, parsed.signal],
|
|
747
801
|
type: thisType,
|
|
748
802
|
loc,
|
|
749
803
|
};
|
|
@@ -759,8 +813,8 @@ function streamMethodWrapper(lowerer, info, which, methodName, thisType, loc, bl
|
|
|
759
813
|
const found = lowerer.findMethodOn(info, methodName);
|
|
760
814
|
if (!found) {
|
|
761
815
|
// A DESCENDANT-only declaration (the base chain never declares it):
|
|
762
|
-
// this constructor cannot see it, and
|
|
763
|
-
// diverge from Node (which dispatches through the prototype chain).
|
|
816
|
+
// this constructor cannot see it, and binding nothing without a
|
|
817
|
+
// diagnostic would diverge from Node (which dispatches through the prototype chain).
|
|
764
818
|
if (lowerer.overrideBelow(info, methodName)) {
|
|
765
819
|
lowerer.noLowering(`a subclass of ${info.def.name.replace(/^%/, "")} declaring '${methodName}' below a base whose constructor cannot see it`, blame, `declare '${methodName}' on the class whose constructor calls the stream super(), and override it below`);
|
|
766
820
|
}
|
|
@@ -959,6 +1013,19 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
|
|
|
959
1013
|
loc,
|
|
960
1014
|
});
|
|
961
1015
|
}
|
|
1016
|
+
if (parsed.signal !== null) {
|
|
1017
|
+
out.push({
|
|
1018
|
+
kind: "exprStmt",
|
|
1019
|
+
expr: {
|
|
1020
|
+
kind: "libCall",
|
|
1021
|
+
fn: "stream.addAbortSignal",
|
|
1022
|
+
args: [thisRef(), parsed.signal],
|
|
1023
|
+
type: thisType,
|
|
1024
|
+
loc,
|
|
1025
|
+
},
|
|
1026
|
+
loc,
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
962
1029
|
return out;
|
|
963
1030
|
}
|
|
964
1031
|
/* ── the underscore-method assignment surface ─────────────────────────── */
|
|
@@ -1048,12 +1115,14 @@ export function lowerStreamUnderscoreAssign(lowerer, expr) {
|
|
|
1048
1115
|
};
|
|
1049
1116
|
}
|
|
1050
1117
|
/* ── the static surface (Readable.from) ───────────────────────────────── */
|
|
1051
|
-
/** `Readable.from(iterable)
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1118
|
+
/** `Readable.from(iterable, options)`: string[] / Buffer[] sources
|
|
1119
|
+
* become a readable that pushes one element per _read (whole entries in
|
|
1120
|
+
* object mode, hwm 1), and a single string/Buffer argument is a
|
|
1121
|
+
* one-chunk stream (from.js's special case, the mode's default hwm). The
|
|
1122
|
+
* options lower when they are a literal of `objectMode` and
|
|
1123
|
+
* `highWaterMark`; the JS lane and `any` sources take the runtime's
|
|
1124
|
+
* checked-dynamic form. Called from the method-call chain once the
|
|
1125
|
+
* receiver resolved to a stream class value. */
|
|
1057
1126
|
export function lowerStreamStaticCall(lowerer, call, access) {
|
|
1058
1127
|
if (call.questionDotToken || access.questionDotToken)
|
|
1059
1128
|
return null;
|
|
@@ -1102,37 +1171,223 @@ export function lowerStreamStaticCall(lowerer, call, access) {
|
|
|
1102
1171
|
lowerer.noLowering(`${cls.slice(1)}.from`, call, "Readable.from is the lowered form");
|
|
1103
1172
|
}
|
|
1104
1173
|
const args = call.arguments;
|
|
1105
|
-
if (args.length
|
|
1106
|
-
lowerer.noLowering(`Readable.from with ${args.length} arguments`, call, "
|
|
1174
|
+
if (args.length > 2) {
|
|
1175
|
+
lowerer.noLowering(`Readable.from with ${args.length} arguments`, call, "Readable.from(iterable, options) is the supported form");
|
|
1107
1176
|
}
|
|
1108
|
-
const srcT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
|
|
1109
1177
|
const type = { kind: "object", className: "%Readable" };
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1178
|
+
const js = isJsSourceFile(call.getSourceFile());
|
|
1179
|
+
const srcNode = args[0];
|
|
1180
|
+
const optsNode = args[1];
|
|
1181
|
+
const srcT = srcNode ? lowerer.mapTypeOf(lowerer.typeOf(srcNode)) : null;
|
|
1182
|
+
const typedElem = (t) => t?.kind === "string" ? "string" : t?.kind === "bytes" && t.elem === "u8" ? "bytes" : null;
|
|
1183
|
+
const single = typedElem(srcT);
|
|
1184
|
+
const elem = srcT?.kind === "array" ? typedElem(srcT.elem) : null;
|
|
1185
|
+
const opts = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
|
|
1186
|
+
if (srcNode && srcT?.kind === "generator" && opts && fromGenChunk(lowerer, srcT.yieldT)) {
|
|
1187
|
+
// A compiled generator: the runtime pulls it through interned helpers.
|
|
1188
|
+
const gen = lowerer.lowerExpr(srcNode);
|
|
1189
|
+
const helpers = fromGenHelpers(lowerer, srcT, loc);
|
|
1190
|
+
if (helpers) {
|
|
1191
|
+
const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
|
|
1192
|
+
return {
|
|
1193
|
+
kind: "libCall",
|
|
1194
|
+
fn: srcT.async ? "readable.fromAsyncGen" : "readable.fromGen",
|
|
1195
|
+
args: [gen, ...helpers, numLit(opts.flags, loc), hwm],
|
|
1196
|
+
type,
|
|
1197
|
+
loc,
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
if (srcNode && (single || elem) && opts) {
|
|
1202
|
+
const v = lowerer.lowerExpr(srcNode);
|
|
1203
|
+
const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
|
|
1204
|
+
const arr = single ? { kind: "arrayLit", elems: [v], type: arrayOf(v.type), loc } : v;
|
|
1205
|
+
// SCR_FROM_STRINGS 1, SCR_FROM_SINGLE 2 (scr_runtime.h); the options
|
|
1206
|
+
// add SCR_FROM_BYTE_MODE 4 and SCR_FROM_HAS_HWM 8.
|
|
1207
|
+
const flags = ((single ?? elem) === "string" ? 1 : 0) | (single ? 2 : 0) | opts.flags;
|
|
1114
1208
|
return {
|
|
1115
1209
|
kind: "libCall",
|
|
1116
1210
|
fn: "readable.fromArr",
|
|
1117
|
-
args: [arr,
|
|
1211
|
+
args: [arr, numLit(flags, loc), hwm],
|
|
1118
1212
|
type,
|
|
1119
1213
|
loc,
|
|
1120
1214
|
};
|
|
1121
1215
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1216
|
+
const anySrc = srcT?.kind === "dyn" ||
|
|
1217
|
+
(srcNode !== undefined &&
|
|
1218
|
+
srcT === null &&
|
|
1219
|
+
(lowerer.typeOf(srcNode).flags & ts.TypeFlags.Any) !== 0);
|
|
1220
|
+
if (js || anySrc) {
|
|
1221
|
+
// The checked-dynamic form: the runtime takes from.js's ladder
|
|
1222
|
+
// (ERR_INVALID_ARG_TYPE for a non-iterable, the options, null values).
|
|
1223
|
+
const src = srcNode ? lowerer.lowerExprExpecting(srcNode, DYN) : dynUndefinedExpr(loc);
|
|
1224
|
+
const o = lowerOperatorValue(lowerer, optsNode, "Readable.from options", loc, true);
|
|
1225
|
+
return { kind: "libCall", fn: "readable.fromDyn", args: [src, o], type, loc };
|
|
1226
|
+
}
|
|
1227
|
+
if (srcNode && (single || elem)) {
|
|
1228
|
+
lowerer.noLowering("Readable.from with these options", optsNode, "an object literal with 'objectMode' (true or false) and a number 'highWaterMark' is supported");
|
|
1229
|
+
}
|
|
1230
|
+
lowerer.noLowering(`Readable.from over a '${srcT ? lowerer.fmt(srcT) : "?"}' source`, srcNode ?? call, "string[] / Buffer[] arrays (and a single string or Buffer) are the supported sources — generators and async iterables have no lowering yet");
|
|
1231
|
+
}
|
|
1232
|
+
/** Whether a generator's yields are stream chunks: strings, Buffers, a
|
|
1233
|
+
* union of them (null included: the runtime destroys the stream with
|
|
1234
|
+
* ERR_STREAM_NULL_VALUES), or checked-dynamic values (checked when
|
|
1235
|
+
* pushed). */
|
|
1236
|
+
function fromGenChunk(lowerer, t) {
|
|
1237
|
+
const chunk = (a) => a.kind === "string" || (a.kind === "bytes" && a.elem === "u8") || a.kind === "nullT";
|
|
1238
|
+
if (t.kind === "dyn" || (chunk(t) && t.kind !== "nullT"))
|
|
1239
|
+
return true;
|
|
1240
|
+
if (t.kind !== "union")
|
|
1241
|
+
return false;
|
|
1242
|
+
return lowerer.unions.get(t.unionId)?.arms.every(chunk) ?? false;
|
|
1243
|
+
}
|
|
1244
|
+
/** The helpers Readable.from pulls a compiled generator through, as
|
|
1245
|
+
* closures in libcall order: a sync generator's next/return/throw answer
|
|
1246
|
+
* the next value as a checked-dynamic value or the done marker
|
|
1247
|
+
* (readable.fromDone); an async generator's next/return/throw answer the
|
|
1248
|
+
* resume's promise, followed by `read`, which maps its IteratorResult the
|
|
1249
|
+
* same way. Interned per generator type. Null when the result record has
|
|
1250
|
+
* no lowering. */
|
|
1251
|
+
function fromGenHelpers(lowerer, gen, loc) {
|
|
1252
|
+
const recT = genResultRecord(gen.yieldT, gen.retT, lowerer.shapes, lowerer.unions);
|
|
1253
|
+
const valueT = recT && lowerer.shapes.get(recT.shapeId)?.fields.find((f) => f.name === "value")?.type;
|
|
1254
|
+
if (!recT || !valueT)
|
|
1255
|
+
return null;
|
|
1256
|
+
const done = () => ({
|
|
1257
|
+
kind: "libCall",
|
|
1258
|
+
fn: "readable.fromDone",
|
|
1259
|
+
args: [],
|
|
1260
|
+
type: DYN,
|
|
1261
|
+
loc,
|
|
1262
|
+
});
|
|
1263
|
+
// `r.done ? done : r.value` over a record local.
|
|
1264
|
+
const readRecord = (localId) => {
|
|
1265
|
+
const r = varRef(localId, recT, loc);
|
|
1266
|
+
const value = extractIteratorValue(lowerer, gen.yieldT, valueT, { kind: "recordGet", obj: r, shapeId: recT.shapeId, field: "value", type: valueT, loc }, loc);
|
|
1267
|
+
if (!value)
|
|
1268
|
+
return null;
|
|
1269
|
+
return [
|
|
1270
|
+
{
|
|
1271
|
+
kind: "if",
|
|
1272
|
+
cond: { kind: "recordGet", obj: r, shapeId: recT.shapeId, field: "done", type: BOOL, loc },
|
|
1273
|
+
then: [{ kind: "return", value: done(), loc }],
|
|
1274
|
+
else_: null,
|
|
1275
|
+
loc,
|
|
1276
|
+
},
|
|
1277
|
+
{ kind: "return", value: lowerer.coerceToExpected(value, DYN), loc },
|
|
1278
|
+
];
|
|
1279
|
+
};
|
|
1280
|
+
const promiseT = { kind: "promise", inner: recT };
|
|
1281
|
+
const define = (role, params, returnType, body, locals = []) => {
|
|
1282
|
+
const key = `streamFromGen:${role}:${typeKey(gen)}`;
|
|
1283
|
+
let name = lowerer.valueHelpers.get(key);
|
|
1284
|
+
if (!name) {
|
|
1285
|
+
name = `%stream.fromGen.${role}.${lowerer.valueHelpers.size}`;
|
|
1286
|
+
lowerer.valueHelpers.set(key, name);
|
|
1287
|
+
lowerer.liftedFns.push({
|
|
1288
|
+
name,
|
|
1289
|
+
params: params.map((p) => ({ localId: p.id, name: p.id.split(".")[0], type: p.type })),
|
|
1290
|
+
returnType,
|
|
1291
|
+
locals: [...params, ...locals].map((l) => ({
|
|
1292
|
+
id: l.id,
|
|
1293
|
+
name: l.id.split(".")[0],
|
|
1294
|
+
type: l.type,
|
|
1295
|
+
mutable: false,
|
|
1296
|
+
})),
|
|
1297
|
+
body,
|
|
1298
|
+
loc,
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1127
1301
|
return {
|
|
1128
|
-
kind: "
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
type,
|
|
1302
|
+
kind: "closure",
|
|
1303
|
+
fnName: name,
|
|
1304
|
+
captures: [],
|
|
1305
|
+
type: funcOf(params.map((p) => p.type), returnType),
|
|
1132
1306
|
loc,
|
|
1133
1307
|
};
|
|
1308
|
+
};
|
|
1309
|
+
const g = { id: "gen.0", type: gen };
|
|
1310
|
+
const e = { id: "err.0", type: DYN };
|
|
1311
|
+
const r = { id: "res.0", type: recT };
|
|
1312
|
+
const genRef = varRef("gen.0", gen, loc);
|
|
1313
|
+
const resume = (mode) => ({
|
|
1314
|
+
kind: "genResume",
|
|
1315
|
+
mode,
|
|
1316
|
+
gen: genRef,
|
|
1317
|
+
arg: mode === "throw" ? varRef("err.0", DYN, loc) : null,
|
|
1318
|
+
type: gen.async ? promiseT : recT,
|
|
1319
|
+
loc,
|
|
1320
|
+
});
|
|
1321
|
+
const read = readRecord("res.0");
|
|
1322
|
+
if (!read)
|
|
1323
|
+
return null;
|
|
1324
|
+
if (gen.async) {
|
|
1325
|
+
const ret = (mode) => [
|
|
1326
|
+
{ kind: "return", value: resume(mode), loc },
|
|
1327
|
+
];
|
|
1328
|
+
return [
|
|
1329
|
+
define("anext", [g], promiseT, ret("next")),
|
|
1330
|
+
define("aread", [r], DYN, read),
|
|
1331
|
+
define("areturn", [g], promiseT, ret("return")),
|
|
1332
|
+
define("athrow", [g, e], promiseT, ret("throw")),
|
|
1333
|
+
];
|
|
1134
1334
|
}
|
|
1135
|
-
|
|
1335
|
+
const viaRecord = (mode) => [
|
|
1336
|
+
{ kind: "varDecl", localId: "res.0", init: resume(mode), loc },
|
|
1337
|
+
...read,
|
|
1338
|
+
];
|
|
1339
|
+
const next = stepDrivable(gen)
|
|
1340
|
+
? [
|
|
1341
|
+
{
|
|
1342
|
+
kind: "if",
|
|
1343
|
+
cond: genStep(genRef, loc),
|
|
1344
|
+
then: [{ kind: "return", value: done(), loc }],
|
|
1345
|
+
else_: null,
|
|
1346
|
+
loc,
|
|
1347
|
+
},
|
|
1348
|
+
{ kind: "return", value: lowerer.coerceToExpected(genValue(genRef, loc), DYN), loc },
|
|
1349
|
+
]
|
|
1350
|
+
: viaRecord("next");
|
|
1351
|
+
const withRecord = stepDrivable(gen) ? [] : [r];
|
|
1352
|
+
return [
|
|
1353
|
+
define("next", [g], DYN, next, withRecord),
|
|
1354
|
+
define("return", [g], DYN, viaRecord("return"), [r]),
|
|
1355
|
+
define("throw", [g, e], DYN, viaRecord("throw"), [r]),
|
|
1356
|
+
];
|
|
1357
|
+
}
|
|
1358
|
+
/** Readable.from's typed options: an object literal of `objectMode`
|
|
1359
|
+
* (a boolean literal) and `highWaterMark` (a number), as SCR_FROM_* flag
|
|
1360
|
+
* bits and the hwm expression; null for any other shape. */
|
|
1361
|
+
function fromOptions(lowerer, node) {
|
|
1362
|
+
if (!ts.isObjectLiteralExpression(node))
|
|
1363
|
+
return null;
|
|
1364
|
+
let flags = 0;
|
|
1365
|
+
let hwm = null;
|
|
1366
|
+
for (const prop of node.properties) {
|
|
1367
|
+
if (!ts.isPropertyAssignment(prop) ||
|
|
1368
|
+
!(ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name))) {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
const value = prop.initializer;
|
|
1372
|
+
if (prop.name.text === "objectMode") {
|
|
1373
|
+
if (value.kind === ts.SyntaxKind.FalseKeyword)
|
|
1374
|
+
flags |= 4;
|
|
1375
|
+
else if (value.kind === ts.SyntaxKind.TrueKeyword)
|
|
1376
|
+
flags &= ~4;
|
|
1377
|
+
else
|
|
1378
|
+
return null;
|
|
1379
|
+
}
|
|
1380
|
+
else if (prop.name.text === "highWaterMark") {
|
|
1381
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(value))?.kind !== "f64")
|
|
1382
|
+
return null;
|
|
1383
|
+
flags |= 8;
|
|
1384
|
+
hwm = value;
|
|
1385
|
+
}
|
|
1386
|
+
else {
|
|
1387
|
+
return null;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return { flags, hwm };
|
|
1136
1391
|
}
|
|
1137
1392
|
/** `const Writable = stream.Writable` — a runtime stream CLASS bound
|
|
1138
1393
|
* through a namespace member: alias plumbing with no storage (both
|
|
@@ -1210,7 +1465,7 @@ function lowerStreamArg(lowerer, node, what) {
|
|
|
1210
1465
|
argTypeThrow("stream", "an instance of ReadableStream, WritableStream, or Stream");
|
|
1211
1466
|
}
|
|
1212
1467
|
}
|
|
1213
|
-
lowerer.noLowering(`${what} over a '${lowerer.fmt(v.type)}'`, node, what === "pipeline"
|
|
1468
|
+
lowerer.noLowering(`${what} over a '${lowerer.fmt(v.type)}'`, node, what === "pipeline" || what === "compose"
|
|
1214
1469
|
? "stream stages are the lowered surface — Node also accepts iterables (strings, arrays), generators, plain functions, and { readable, writable } pairs, but those have no lowering yet"
|
|
1215
1470
|
: "stream arguments are the lowered surface (iterables, generators, and plain functions have no lowering yet)");
|
|
1216
1471
|
}
|
|
@@ -1284,6 +1539,85 @@ function lowerEosCallback(lowerer, which, node, thisType) {
|
|
|
1284
1539
|
}
|
|
1285
1540
|
lowerer.noLowering(`${which} with this callback value`, node, "write the callback inline, or pass a function value that crosses the checked-dynamic boundary");
|
|
1286
1541
|
}
|
|
1542
|
+
/** finished()'s options literal: readable/writable/error (and cleanup
|
|
1543
|
+
* for the promise form) as boolean literals, signal as any expression.
|
|
1544
|
+
* readable/writable answer -1 when absent (Node's default: whether the
|
|
1545
|
+
* stream has that side). */
|
|
1546
|
+
function eosOptions(lowerer, node, promiseForm) {
|
|
1547
|
+
const out = {
|
|
1548
|
+
readable: -1,
|
|
1549
|
+
writable: -1,
|
|
1550
|
+
error: true,
|
|
1551
|
+
cleanup: false,
|
|
1552
|
+
signal: null,
|
|
1553
|
+
};
|
|
1554
|
+
if (!ts.isObjectLiteralExpression(node)) {
|
|
1555
|
+
lowerer.noLowering("finished options that are not an object literal", node, "write the options inline: finished(stream, { readable, writable, error, signal })");
|
|
1556
|
+
}
|
|
1557
|
+
const literal = (p, key) => {
|
|
1558
|
+
if (p.initializer.kind === ts.SyntaxKind.TrueKeyword)
|
|
1559
|
+
return true;
|
|
1560
|
+
if (p.initializer.kind === ts.SyntaxKind.FalseKeyword)
|
|
1561
|
+
return false;
|
|
1562
|
+
lowerer.noLowering(`the finished option '${key}' with a non-literal value`, p.initializer, "pass true or false");
|
|
1563
|
+
};
|
|
1564
|
+
for (const p of node.properties) {
|
|
1565
|
+
const key = (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) && ts.isIdentifier(p.name)
|
|
1566
|
+
? p.name.text
|
|
1567
|
+
: null;
|
|
1568
|
+
if (key === "signal") {
|
|
1569
|
+
out.signal = ts.isShorthandPropertyAssignment(p)
|
|
1570
|
+
? lowerer.lowerExprExpecting(p.name, DYN)
|
|
1571
|
+
: lowerer.lowerExprExpecting(p.initializer, DYN);
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (key !== null && ts.isPropertyAssignment(p)) {
|
|
1575
|
+
if (key === "readable")
|
|
1576
|
+
out.readable = literal(p, key) ? 1 : 0;
|
|
1577
|
+
else if (key === "writable")
|
|
1578
|
+
out.writable = literal(p, key) ? 1 : 0;
|
|
1579
|
+
else if (key === "error")
|
|
1580
|
+
out.error = literal(p, key);
|
|
1581
|
+
else if (key === "cleanup" && promiseForm)
|
|
1582
|
+
out.cleanup = literal(p, key);
|
|
1583
|
+
else {
|
|
1584
|
+
lowerer.noLowering(`the finished option '${key}'`, p, promiseForm
|
|
1585
|
+
? "readable, writable, error, cleanup and signal are the supported options"
|
|
1586
|
+
: "readable, writable, error and signal are the supported options");
|
|
1587
|
+
}
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
lowerer.noLowering("finished options with this member", p, "write each option as a plain property");
|
|
1591
|
+
}
|
|
1592
|
+
return out;
|
|
1593
|
+
}
|
|
1594
|
+
/** pipeline()'s trailing options literal (the promise form): signal as
|
|
1595
|
+
* any expression, end as a boolean literal. */
|
|
1596
|
+
function pipelineOptions(lowerer, node) {
|
|
1597
|
+
const out = { end: true, signal: null };
|
|
1598
|
+
for (const p of node.properties) {
|
|
1599
|
+
const key = (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) && ts.isIdentifier(p.name)
|
|
1600
|
+
? p.name.text
|
|
1601
|
+
: null;
|
|
1602
|
+
if (key === "signal") {
|
|
1603
|
+
out.signal = ts.isShorthandPropertyAssignment(p)
|
|
1604
|
+
? lowerer.lowerExprExpecting(p.name, DYN)
|
|
1605
|
+
: lowerer.lowerExprExpecting(p.initializer, DYN);
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
if (key === "end" && ts.isPropertyAssignment(p)) {
|
|
1609
|
+
if (p.initializer.kind === ts.SyntaxKind.TrueKeyword)
|
|
1610
|
+
continue;
|
|
1611
|
+
if (p.initializer.kind === ts.SyntaxKind.FalseKeyword) {
|
|
1612
|
+
out.end = false;
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
lowerer.noLowering("the pipeline option 'end' with a non-literal value", p.initializer, "pass true or false");
|
|
1616
|
+
}
|
|
1617
|
+
lowerer.noLowering(key === null ? "pipeline options with this member" : `the pipeline option '${key}'`, p, "signal and end are the supported pipeline options");
|
|
1618
|
+
}
|
|
1619
|
+
return out;
|
|
1620
|
+
}
|
|
1287
1621
|
/** `finished(...)` / `pipeline(...)` / `getDefaultHighWaterMark(...)`
|
|
1288
1622
|
* imported from node:stream (named imports, destructured requires, and
|
|
1289
1623
|
* namespace-member calls all land here). Null for members this spoke
|
|
@@ -1296,10 +1630,8 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1296
1630
|
// ERR_STREAM_PREMATURE_CLOSE — the callback form's status, boxed
|
|
1297
1631
|
// through the promise instead). The options argument has no lowering.
|
|
1298
1632
|
if (bi.member === "finished") {
|
|
1299
|
-
if (args.length !== 1) {
|
|
1300
|
-
lowerer.noLowering(`stream/promises.finished with ${args.length} arguments`, call,
|
|
1301
|
-
? "the options argument has no lowering yet — the one-argument form is supported"
|
|
1302
|
-
: "the supported form is finished(stream)");
|
|
1633
|
+
if (args.length !== 1 && args.length !== 2) {
|
|
1634
|
+
lowerer.noLowering(`stream/promises.finished with ${args.length} arguments`, call, "the supported forms are finished(stream) and finished(stream, options)");
|
|
1303
1635
|
}
|
|
1304
1636
|
let recv;
|
|
1305
1637
|
try {
|
|
@@ -1310,6 +1642,24 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1310
1642
|
return e.expr;
|
|
1311
1643
|
throw e;
|
|
1312
1644
|
}
|
|
1645
|
+
const optsNode = args[1];
|
|
1646
|
+
if (optsNode !== undefined && optsNode.kind !== ts.SyntaxKind.NullKeyword) {
|
|
1647
|
+
const o = eosOptions(lowerer, optsNode, true);
|
|
1648
|
+
const head = [
|
|
1649
|
+
recv,
|
|
1650
|
+
numLit(o.readable, loc),
|
|
1651
|
+
numLit(o.writable, loc),
|
|
1652
|
+
boolLit(o.error, loc),
|
|
1653
|
+
boolLit(o.cleanup, loc),
|
|
1654
|
+
];
|
|
1655
|
+
return {
|
|
1656
|
+
kind: "libCall",
|
|
1657
|
+
fn: o.signal ? "sp.finishedOptsSignal" : "sp.finishedOpts",
|
|
1658
|
+
args: o.signal ? [...head, o.signal] : head,
|
|
1659
|
+
type: { kind: "promise", inner: VOID },
|
|
1660
|
+
loc,
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1313
1663
|
return {
|
|
1314
1664
|
kind: "libCall",
|
|
1315
1665
|
fn: "sp.finished",
|
|
@@ -1326,15 +1676,44 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1326
1676
|
if (args.length < 2) {
|
|
1327
1677
|
lowerer.noLowering(`stream/promises.pipeline with ${args.length} arguments`, call, "the supported form is pipeline(source, ...streams)");
|
|
1328
1678
|
}
|
|
1679
|
+
const lastArg = args[args.length - 1];
|
|
1680
|
+
const opts = ts.isObjectLiteralExpression(lastArg) && args.length >= 3
|
|
1681
|
+
? pipelineOptions(lowerer, lastArg)
|
|
1682
|
+
: null;
|
|
1683
|
+
const stageArgs = opts ? args.slice(0, -1) : args;
|
|
1684
|
+
if (stageArgs.some(isPipelineFunctionStage)) {
|
|
1685
|
+
if (opts) {
|
|
1686
|
+
lowerer.noLowering("pipeline with function stages and options", lastArg, "pipeline(source, async function* (source) { ... }, destination) without options is supported");
|
|
1687
|
+
}
|
|
1688
|
+
const staged = lowerPipelineStages(lowerer, stageArgs, loc);
|
|
1689
|
+
// A promise destination's value settles the result (same type).
|
|
1690
|
+
return staged.wrap({
|
|
1691
|
+
kind: "libCall",
|
|
1692
|
+
fn: "sp.pipelineStages",
|
|
1693
|
+
args: staged.args,
|
|
1694
|
+
type: staged.destPromise ?? { kind: "promise", inner: VOID },
|
|
1695
|
+
loc,
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1329
1698
|
let streams;
|
|
1330
1699
|
try {
|
|
1331
|
-
streams =
|
|
1700
|
+
streams = stageArgs.map((a) => lowerStreamArg(lowerer, a, "pipeline"));
|
|
1332
1701
|
}
|
|
1333
1702
|
catch (e) {
|
|
1334
1703
|
if (e instanceof StreamArgTypeThrow)
|
|
1335
1704
|
return e.expr;
|
|
1336
1705
|
throw e;
|
|
1337
1706
|
}
|
|
1707
|
+
if (opts) {
|
|
1708
|
+
const head = [numLit(streams.length, loc), ...streams, boolLit(opts.end, loc)];
|
|
1709
|
+
return {
|
|
1710
|
+
kind: "libCall",
|
|
1711
|
+
fn: opts.signal ? "sp.pipelineOptsSignal" : "sp.pipelineOpts",
|
|
1712
|
+
args: opts.signal ? [...head, opts.signal] : head,
|
|
1713
|
+
type: { kind: "promise", inner: VOID },
|
|
1714
|
+
loc,
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1338
1717
|
return {
|
|
1339
1718
|
kind: "libCall",
|
|
1340
1719
|
fn: "sp.pipeline",
|
|
@@ -1352,9 +1731,9 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1352
1731
|
// utf8 decode / the parsed JSON dyn tree / the concatenated bytes / an
|
|
1353
1732
|
// ArrayBuffer dyn over them) or rejects — with the stream's error,
|
|
1354
1733
|
// ERR_STREAM_PREMATURE_CLOSE on an early close, or json's SyntaxError
|
|
1355
|
-
// on malformed text, Node's own rejection set. blob returns null here
|
|
1356
|
-
//
|
|
1357
|
-
//
|
|
1734
|
+
// on malformed text, Node's own rejection set. blob returns null here,
|
|
1735
|
+
// so the module-qualified fence (with the pointed hint in
|
|
1736
|
+
// BUILTIN_MODULE_FENCE_HINTS) speaks.
|
|
1358
1737
|
if (bi.member === "text" ||
|
|
1359
1738
|
bi.member === "json" ||
|
|
1360
1739
|
bi.member === "buffer" ||
|
|
@@ -1400,11 +1779,33 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1400
1779
|
return numLit(16, loc);
|
|
1401
1780
|
lowerer.noLowering("getDefaultHighWaterMark with a non-literal argument", call, "the objectMode flag must be a compile-time boolean");
|
|
1402
1781
|
}
|
|
1403
|
-
if (bi.member === "
|
|
1782
|
+
if (bi.member === "addAbortSignal") {
|
|
1783
|
+
// addAbortSignal(signal, stream) → the stream: destroyed with an
|
|
1784
|
+
// AbortError when the signal aborts (now, if it already has).
|
|
1404
1785
|
if (args.length !== 2) {
|
|
1405
|
-
lowerer.noLowering(`
|
|
1406
|
-
|
|
1407
|
-
|
|
1786
|
+
lowerer.noLowering(`addAbortSignal with ${args.length} arguments`, call, "the supported form is addAbortSignal(signal, stream)");
|
|
1787
|
+
}
|
|
1788
|
+
const signal = lowerer.lowerExprExpecting(args[0], DYN);
|
|
1789
|
+
let stream;
|
|
1790
|
+
try {
|
|
1791
|
+
stream = lowerStreamArg(lowerer, args[1], "addAbortSignal");
|
|
1792
|
+
}
|
|
1793
|
+
catch (e) {
|
|
1794
|
+
if (e instanceof StreamArgTypeThrow)
|
|
1795
|
+
return e.expr;
|
|
1796
|
+
throw e;
|
|
1797
|
+
}
|
|
1798
|
+
return {
|
|
1799
|
+
kind: "libCall",
|
|
1800
|
+
fn: "stream.addAbortSignalFn",
|
|
1801
|
+
args: [signal, stream],
|
|
1802
|
+
type: stream.type,
|
|
1803
|
+
loc,
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
if (bi.member === "finished") {
|
|
1807
|
+
if (args.length !== 2 && args.length !== 3) {
|
|
1808
|
+
lowerer.noLowering(`finished with ${args.length} arguments`, call, "the supported forms are finished(stream, callback) and finished(stream, options, callback)");
|
|
1408
1809
|
}
|
|
1409
1810
|
let recv;
|
|
1410
1811
|
try {
|
|
@@ -1415,7 +1816,24 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1415
1816
|
return e.expr;
|
|
1416
1817
|
throw e;
|
|
1417
1818
|
}
|
|
1418
|
-
|
|
1819
|
+
if (args.length === 3 && args[1].kind !== ts.SyntaxKind.NullKeyword) {
|
|
1820
|
+
const o = eosOptions(lowerer, args[1], false);
|
|
1821
|
+
const { cb } = lowerEosCallback(lowerer, "finished", args[2], recv.type);
|
|
1822
|
+
const head = [
|
|
1823
|
+
recv,
|
|
1824
|
+
numLit(o.readable, loc),
|
|
1825
|
+
numLit(o.writable, loc),
|
|
1826
|
+
boolLit(o.error, loc),
|
|
1827
|
+
];
|
|
1828
|
+
return {
|
|
1829
|
+
kind: "libCall",
|
|
1830
|
+
fn: o.signal ? "stream.finishedOptsSignal" : "stream.finishedOpts",
|
|
1831
|
+
args: o.signal ? [...head, o.signal, cb] : [...head, cb],
|
|
1832
|
+
type: funcOf([], VOID),
|
|
1833
|
+
loc,
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
const { cb, dyn } = lowerEosCallback(lowerer, "finished", args[args.length - 1], recv.type);
|
|
1419
1837
|
return {
|
|
1420
1838
|
kind: "libCall",
|
|
1421
1839
|
fn: dyn ? "stream.finishedDyn" : "stream.finished",
|
|
@@ -1428,6 +1846,33 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1428
1846
|
if (args.length < 3) {
|
|
1429
1847
|
lowerer.noLowering(`pipeline with ${args.length} arguments`, call, "the supported form is pipeline(source, ...streams, callback)");
|
|
1430
1848
|
}
|
|
1849
|
+
if (args.slice(0, -1).some(isPipelineFunctionStage)) {
|
|
1850
|
+
const staged = lowerPipelineStages(lowerer, args.slice(0, -1), loc);
|
|
1851
|
+
if (staged.dest !== 0) {
|
|
1852
|
+
// callback(err, value): the destination's value reaches the
|
|
1853
|
+
// callback through the checked-dynamic path. Node answers an
|
|
1854
|
+
// object-mode PassThrough here; reading it has no lowering.
|
|
1855
|
+
if (!ts.isExpressionStatement(call.parent)) {
|
|
1856
|
+
lowerer.noLowering("using the PassThrough that pipeline() answers for a function destination", call, "read the destination's value in the callback");
|
|
1857
|
+
}
|
|
1858
|
+
const cb = lowerer.lowerExprExpecting(args[args.length - 1], DYN);
|
|
1859
|
+
return staged.wrap({
|
|
1860
|
+
kind: "libCall",
|
|
1861
|
+
fn: "stream.pipelineStagesDyn",
|
|
1862
|
+
args: [...staged.args, cb],
|
|
1863
|
+
type: staged.last,
|
|
1864
|
+
loc,
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
const { cb, dyn } = lowerEosCallback(lowerer, "pipeline", args[args.length - 1], staged.last);
|
|
1868
|
+
return staged.wrap({
|
|
1869
|
+
kind: "libCall",
|
|
1870
|
+
fn: dyn ? "stream.pipelineStagesDyn" : "stream.pipelineStages",
|
|
1871
|
+
args: [...staged.args, cb],
|
|
1872
|
+
type: staged.last,
|
|
1873
|
+
loc,
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1431
1876
|
let streams;
|
|
1432
1877
|
try {
|
|
1433
1878
|
streams = args.slice(0, -1).map((a) => lowerStreamArg(lowerer, a, "pipeline"));
|
|
@@ -1447,9 +1892,514 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1447
1892
|
loc,
|
|
1448
1893
|
};
|
|
1449
1894
|
}
|
|
1895
|
+
if (bi.member === "compose")
|
|
1896
|
+
return lowerStreamCompose(lowerer, call, loc);
|
|
1450
1897
|
return null;
|
|
1451
1898
|
}
|
|
1899
|
+
/** A pipeline() argument written as a function: an async generator
|
|
1900
|
+
* function stage. */
|
|
1901
|
+
function isPipelineFunctionStage(node) {
|
|
1902
|
+
return ts.isFunctionExpression(node) || ts.isArrowFunction(node);
|
|
1903
|
+
}
|
|
1904
|
+
/** pipeline(...) with one run of function stages (pipeline.js). The run
|
|
1905
|
+
* may start the pipeline (a source function, called with `{ signal }`)
|
|
1906
|
+
* and may end it (a destination function: an async generator pumped into
|
|
1907
|
+
* a PassThrough, or an async function whose promise's value reaches the
|
|
1908
|
+
* callback or the promise). Each stage's `source` parameter is typed as
|
|
1909
|
+
* what the pipeline passes it: makeAsyncIterable answers the previous
|
|
1910
|
+
* stream itself (a Readable is async iterable) or the previous stage's
|
|
1911
|
+
* generator. */
|
|
1912
|
+
function lowerPipelineStages(lowerer, stageArgs, loc) {
|
|
1913
|
+
const first = stageArgs.findIndex(isPipelineFunctionStage);
|
|
1914
|
+
let end = first;
|
|
1915
|
+
while (end < stageArgs.length && isPipelineFunctionStage(stageArgs[end]))
|
|
1916
|
+
end++;
|
|
1917
|
+
if (stageArgs.slice(end).some(isPipelineFunctionStage)) {
|
|
1918
|
+
lowerer.noLowering("pipeline with function stages separated by streams", stageArgs[end], "one run of function stages is supported");
|
|
1919
|
+
}
|
|
1920
|
+
const source = first === 0;
|
|
1921
|
+
const destFn = end === stageArgs.length;
|
|
1922
|
+
const before = [];
|
|
1923
|
+
const after = [];
|
|
1924
|
+
try {
|
|
1925
|
+
for (const a of stageArgs.slice(0, first))
|
|
1926
|
+
before.push(lowerStreamArg(lowerer, a, "pipeline"));
|
|
1927
|
+
}
|
|
1928
|
+
catch (e) {
|
|
1929
|
+
if (e instanceof StreamArgTypeThrow)
|
|
1930
|
+
lowerer.noLowering("pipeline over this value", stageArgs[0]);
|
|
1931
|
+
throw e;
|
|
1932
|
+
}
|
|
1933
|
+
let srcT = source ? null : before[before.length - 1].type;
|
|
1934
|
+
const stages = [];
|
|
1935
|
+
let mask = 0;
|
|
1936
|
+
let dest = 0;
|
|
1937
|
+
let destPromise = null;
|
|
1938
|
+
for (let i = first; i < end; i++) {
|
|
1939
|
+
const fn = stageArgs[i];
|
|
1940
|
+
const isLast = destFn && i === end - 1;
|
|
1941
|
+
const isAsync = (fn.modifiers ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
|
|
1942
|
+
const isGen = ts.isFunctionExpression(fn) && fn.asteriskToken !== undefined;
|
|
1943
|
+
if (isLast && isGen) {
|
|
1944
|
+
// pipeline() pumps it into an object-mode PassThrough, whose
|
|
1945
|
+
// buffering decides when the pipeline finishes
|
|
1946
|
+
lowerer.noLowering("a pipeline destination that is an async generator function", fn, "end the pipeline with a stream or an async function (source) { for await (const chunk of source) ... }");
|
|
1947
|
+
}
|
|
1948
|
+
if (!isAsync || (!isGen && !isLast)) {
|
|
1949
|
+
lowerer.noLowering(isLast
|
|
1950
|
+
? "a pipeline destination that is not an async function"
|
|
1951
|
+
: srcT === null
|
|
1952
|
+
? "a pipeline source function that is not an async generator function"
|
|
1953
|
+
: "pipeline stages that are not async generator functions", fn, "write the stage as async function* (source) { for await (const chunk of source) ... }");
|
|
1954
|
+
}
|
|
1955
|
+
const optionsAt = srcT === null ? 0 : 1;
|
|
1956
|
+
if (fn.parameters.length > optionsAt + 1) {
|
|
1957
|
+
lowerer.noLowering("pipeline stages with parameters after the options argument", fn.parameters[optionsAt + 1], "a stage takes the source and { signal }");
|
|
1958
|
+
}
|
|
1959
|
+
const lowered = lowerStageFunction(lowerer, fn, srcT);
|
|
1960
|
+
const params = lowered.closure.type.kind === "func" ? lowered.closure.type.params : [];
|
|
1961
|
+
if (params.length > optionsAt) {
|
|
1962
|
+
if (params[optionsAt].kind !== "dyn") {
|
|
1963
|
+
lowerer.noLowering("a pipeline stage's options argument with this type", fn.parameters[optionsAt], "type it as { signal: AbortSignal }");
|
|
1964
|
+
}
|
|
1965
|
+
mask |= 1 << (i - first);
|
|
1966
|
+
}
|
|
1967
|
+
stages.push(lowered.closure);
|
|
1968
|
+
if (lowered.out.kind === "promise") {
|
|
1969
|
+
dest = 2;
|
|
1970
|
+
destPromise = lowered.out;
|
|
1971
|
+
srcT = null;
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
srcT = lowered.out;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
try {
|
|
1978
|
+
for (const a of stageArgs.slice(end))
|
|
1979
|
+
after.push(lowerStreamArg(lowerer, a, "pipeline"));
|
|
1980
|
+
}
|
|
1981
|
+
catch (e) {
|
|
1982
|
+
if (e instanceof StreamArgTypeThrow)
|
|
1983
|
+
lowerer.noLowering("pipeline over this value", stageArgs[end]);
|
|
1984
|
+
throw e;
|
|
1985
|
+
}
|
|
1986
|
+
const helperArgs = [];
|
|
1987
|
+
if (dest !== 2) {
|
|
1988
|
+
// the generator pumped into the next stream or the PassThrough
|
|
1989
|
+
const lastGen = srcT;
|
|
1990
|
+
if (!fromGenChunk(lowerer, lastGen.yieldT)) {
|
|
1991
|
+
lowerer.noLowering(`a pipeline stage yielding '${lowerer.fmt(lastGen.yieldT)}'`, stageArgs[end - 1], "stage values written to a stream are strings or Buffers");
|
|
1992
|
+
}
|
|
1993
|
+
const helpers = fromGenHelpers(lowerer, lastGen, loc);
|
|
1994
|
+
if (!helpers)
|
|
1995
|
+
lowerer.noLowering("a pipeline stage with this generator type", stageArgs[end - 1]);
|
|
1996
|
+
helperArgs.push(helpers[0], helpers[1], helpers[2]);
|
|
1997
|
+
}
|
|
1998
|
+
else {
|
|
1999
|
+
const valueT = destPromise.inner;
|
|
2000
|
+
if (valueT.kind !== "void" &&
|
|
2001
|
+
!canConvertToDyn(valueT, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
2002
|
+
lowerer.noLowering(`a pipeline destination resolving to '${lowerer.fmt(valueT)}'`, stageArgs[end - 1]);
|
|
2003
|
+
}
|
|
2004
|
+
helperArgs.push(pipelineBoxHelper(lowerer, destPromise, loc));
|
|
2005
|
+
}
|
|
2006
|
+
const streams = [...before, ...after];
|
|
2007
|
+
// SCR_PIPE_* flags: bit 0 a source function, bits 1-2 the destination,
|
|
2008
|
+
// bit 3 the helpers, bit 4 the box, bit 5 the signal and abort.
|
|
2009
|
+
const flags = (source ? 1 : 0) | (dest << 1) | (dest !== 2 ? 8 : 16) | (mask !== 0 ? 32 : 0);
|
|
2010
|
+
const head = [
|
|
2011
|
+
numLit(streams.length, loc),
|
|
2012
|
+
numLit(before.length, loc),
|
|
2013
|
+
numLit(stages.length, loc),
|
|
2014
|
+
numLit(flags, loc),
|
|
2015
|
+
numLit(mask, loc),
|
|
2016
|
+
...streams,
|
|
2017
|
+
...stages,
|
|
2018
|
+
...helperArgs,
|
|
2019
|
+
];
|
|
2020
|
+
const last = destFn
|
|
2021
|
+
? { kind: "object", className: "%PassThrough" }
|
|
2022
|
+
: streams[streams.length - 1].type;
|
|
2023
|
+
if (mask === 0)
|
|
2024
|
+
return { args: head, last, dest, destPromise, wrap: (call) => call };
|
|
2025
|
+
// const ac = new AbortController(): its signal goes to the stages, and
|
|
2026
|
+
// finishImpl's ac.abort() runs through the abort closure.
|
|
2027
|
+
const ac = lowerer.declareHiddenLocal("%pipelineAbort", DYN);
|
|
2028
|
+
const acRef = { kind: "varRef", localId: ac.id, type: DYN, loc };
|
|
2029
|
+
const signal = {
|
|
2030
|
+
kind: "dynKeyGet",
|
|
2031
|
+
value: acRef,
|
|
2032
|
+
key: { kind: "strLit", value: "signal", type: STRING, loc },
|
|
2033
|
+
type: DYN,
|
|
2034
|
+
loc,
|
|
2035
|
+
};
|
|
2036
|
+
return {
|
|
2037
|
+
args: [...head, signal, pipelineAbortHelper(lowerer, acRef, loc)],
|
|
2038
|
+
last,
|
|
2039
|
+
dest,
|
|
2040
|
+
destPromise,
|
|
2041
|
+
wrap: (call) => ({
|
|
2042
|
+
kind: "seqExpr",
|
|
2043
|
+
stmts: [
|
|
2044
|
+
{
|
|
2045
|
+
kind: "varDecl",
|
|
2046
|
+
localId: ac.id,
|
|
2047
|
+
init: { kind: "libCall", fn: "fetch.abortControllerNew", args: [], type: DYN, loc },
|
|
2048
|
+
loc,
|
|
2049
|
+
},
|
|
2050
|
+
],
|
|
2051
|
+
result: call,
|
|
2052
|
+
type: call.type,
|
|
2053
|
+
loc,
|
|
2054
|
+
}),
|
|
2055
|
+
};
|
|
2056
|
+
}
|
|
2057
|
+
/** `(p) => p` boxed: a promise destination's promise as a checked-dynamic
|
|
2058
|
+
* promise, whose payload converts when the destination settles. Interned
|
|
2059
|
+
* per promise type. */
|
|
2060
|
+
function pipelineBoxHelper(lowerer, promiseT, loc) {
|
|
2061
|
+
const key = `pipelineBox:${typeKey(promiseT)}`;
|
|
2062
|
+
let name = lowerer.valueHelpers.get(key);
|
|
2063
|
+
if (!name) {
|
|
2064
|
+
name = `%stream.pipelineBox.${lowerer.valueHelpers.size}`;
|
|
2065
|
+
lowerer.valueHelpers.set(key, name);
|
|
2066
|
+
lowerer.liftedFns.push({
|
|
2067
|
+
name,
|
|
2068
|
+
params: [{ localId: "p.0", name: "p", type: promiseT }],
|
|
2069
|
+
returnType: DYN,
|
|
2070
|
+
locals: [{ id: "p.0", name: "p", type: promiseT, mutable: false }],
|
|
2071
|
+
body: [
|
|
2072
|
+
{
|
|
2073
|
+
kind: "return",
|
|
2074
|
+
value: { kind: "dynFrom", value: varRef("p.0", promiseT, loc), type: DYN, loc },
|
|
2075
|
+
loc,
|
|
2076
|
+
},
|
|
2077
|
+
],
|
|
2078
|
+
loc,
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
return { kind: "closure", fnName: name, captures: [], type: funcOf([promiseT], DYN), loc };
|
|
2082
|
+
}
|
|
2083
|
+
/** `() => ac.abort()` over the pipeline's AbortController: an interned
|
|
2084
|
+
* lifted function takes the controller and answers the closure. */
|
|
2085
|
+
function pipelineAbortHelper(lowerer, ac, loc) {
|
|
2086
|
+
const key = "pipelineAbort";
|
|
2087
|
+
let name = lowerer.valueHelpers.get(key);
|
|
2088
|
+
const abortT = funcOf([], VOID);
|
|
2089
|
+
if (!name) {
|
|
2090
|
+
name = `%stream.pipelineAbort.${lowerer.valueHelpers.size}`;
|
|
2091
|
+
lowerer.valueHelpers.set(key, name);
|
|
2092
|
+
const acLocal = { id: "ac.0", name: "ac", type: DYN, mutable: false, boxed: true };
|
|
2093
|
+
const acRef = varRef(acLocal.id, DYN, loc);
|
|
2094
|
+
lowerer.liftedFns.push({
|
|
2095
|
+
name: `${name}.abort`,
|
|
2096
|
+
params: [],
|
|
2097
|
+
returnType: VOID,
|
|
2098
|
+
captures: [{ localId: acLocal.id, name: acLocal.name, type: DYN }],
|
|
2099
|
+
locals: [acLocal],
|
|
2100
|
+
body: [
|
|
2101
|
+
{
|
|
2102
|
+
kind: "exprStmt",
|
|
2103
|
+
expr: {
|
|
2104
|
+
kind: "dynInvoke",
|
|
2105
|
+
recv: acRef,
|
|
2106
|
+
method: "abort",
|
|
2107
|
+
calleeName: "ac.abort",
|
|
2108
|
+
args: [],
|
|
2109
|
+
type: DYN,
|
|
2110
|
+
loc,
|
|
2111
|
+
},
|
|
2112
|
+
loc,
|
|
2113
|
+
},
|
|
2114
|
+
],
|
|
2115
|
+
loc,
|
|
2116
|
+
});
|
|
2117
|
+
lowerer.liftedFns.push({
|
|
2118
|
+
name,
|
|
2119
|
+
params: [{ localId: acLocal.id, name: acLocal.name, type: DYN }],
|
|
2120
|
+
returnType: abortT,
|
|
2121
|
+
locals: [acLocal],
|
|
2122
|
+
body: [
|
|
2123
|
+
{
|
|
2124
|
+
kind: "return",
|
|
2125
|
+
value: {
|
|
2126
|
+
kind: "closure",
|
|
2127
|
+
fnName: `${name}.abort`,
|
|
2128
|
+
captures: [acLocal.id],
|
|
2129
|
+
type: abortT,
|
|
2130
|
+
loc,
|
|
2131
|
+
},
|
|
2132
|
+
loc,
|
|
2133
|
+
},
|
|
2134
|
+
],
|
|
2135
|
+
loc,
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
return { kind: "call", callee: name, args: [ac], type: abortT, loc };
|
|
2139
|
+
}
|
|
2140
|
+
/** A function stage, lowered with its `source` parameter (absent for a
|
|
2141
|
+
* source function, srcT null) typed as what the pipeline passes (a
|
|
2142
|
+
* stream or the previous stage's generator). The source may only head
|
|
2143
|
+
* `for await` loops. Answers the closure and what it returns: an async
|
|
2144
|
+
* generator, or a promise for a destination async function. */
|
|
2145
|
+
function lowerStageFunction(lowerer, fn, srcT) {
|
|
2146
|
+
const param = srcT === null ? undefined : fn.parameters[0];
|
|
2147
|
+
const symbol = param && ts.isIdentifier(param.name)
|
|
2148
|
+
? lowerer.checker.getSymbolAtLocation(param.name)
|
|
2149
|
+
: undefined;
|
|
2150
|
+
if (param && !symbol) {
|
|
2151
|
+
lowerer.noLowering("pipeline stage parameters that are patterns", param, "name the source parameter");
|
|
2152
|
+
}
|
|
2153
|
+
if (symbol && fn.body) {
|
|
2154
|
+
const visit = (node) => {
|
|
2155
|
+
if (ts.isIdentifier(node) &&
|
|
2156
|
+
node !== param.name &&
|
|
2157
|
+
lowerer.checker.getSymbolAtLocation(node) === symbol) {
|
|
2158
|
+
const parent = node.parent;
|
|
2159
|
+
if (!(parent &&
|
|
2160
|
+
ts.isForOfStatement(parent) &&
|
|
2161
|
+
parent.awaitModifier &&
|
|
2162
|
+
parent.expression === node)) {
|
|
2163
|
+
lowerer.noLowering("a pipeline stage's source used outside a for await loop head", node, "iterate the source with for await (const chunk of source)");
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
ts.forEachChild(node, visit);
|
|
2167
|
+
};
|
|
2168
|
+
visit(fn.body);
|
|
2169
|
+
}
|
|
2170
|
+
if (symbol)
|
|
2171
|
+
lowerer.stageSourceTypes.set(symbol, srcT);
|
|
2172
|
+
try {
|
|
2173
|
+
const closure = lowerer.lowerExpr(fn);
|
|
2174
|
+
const out = closure.type.kind === "func" ? closure.type.ret : null;
|
|
2175
|
+
if (!(out?.kind === "generator" && out.async) && out?.kind !== "promise") {
|
|
2176
|
+
lowerer.noLowering("a pipeline stage that does not return an async generator", fn);
|
|
2177
|
+
}
|
|
2178
|
+
return { closure, out: out };
|
|
2179
|
+
}
|
|
2180
|
+
finally {
|
|
2181
|
+
if (symbol)
|
|
2182
|
+
lowerer.stageSourceTypes.delete(symbol);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
/** `stream.compose(...streams)` over stream instances: a Duplex writing
|
|
2186
|
+
* to the first stream and reading from the last (scr_stream_compose). The
|
|
2187
|
+
* classes fix which positions can be readable and writable; a stream in
|
|
2188
|
+
* the wrong position, a single Readable or Writable (Duplex.from wraps
|
|
2189
|
+
* those), and functions, iterables or web streams have no lowering. */
|
|
2190
|
+
function lowerStreamCompose(lowerer, call, loc) {
|
|
2191
|
+
const args = call.arguments;
|
|
2192
|
+
const duplex = { kind: "object", className: "%Duplex" };
|
|
2193
|
+
if (args.some((a) => ts.isSpreadElement(a))) {
|
|
2194
|
+
lowerer.noLowering("compose with spread arguments", call, "pass the streams directly");
|
|
2195
|
+
}
|
|
2196
|
+
if (args.length === 0) {
|
|
2197
|
+
return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "streams" argument must be specified', duplex, loc);
|
|
2198
|
+
}
|
|
2199
|
+
let streams;
|
|
2200
|
+
try {
|
|
2201
|
+
streams = args.map((a) => lowerStreamArg(lowerer, a, "compose"));
|
|
2202
|
+
}
|
|
2203
|
+
catch (e) {
|
|
2204
|
+
if (e instanceof StreamArgTypeThrow)
|
|
2205
|
+
return e.expr;
|
|
2206
|
+
throw e;
|
|
2207
|
+
}
|
|
2208
|
+
const sides = streams.map((s) => s.type.kind === "object" ? streamSidesOf(lowerer, lowerer.classes.get(s.type.className)) : null);
|
|
2209
|
+
if (streams.length === 1) {
|
|
2210
|
+
// Duplex.from answers a duplex itself.
|
|
2211
|
+
if (sides[0] === "rw")
|
|
2212
|
+
return streams[0];
|
|
2213
|
+
lowerer.noLowering(`compose of a single ${sides[0] === "r" ? "Readable" : "Writable"}`, args[0], "Duplex.from wraps a lone Readable or Writable, which has no lowering yet; one Duplex, Transform or PassThrough answers itself");
|
|
2214
|
+
}
|
|
2215
|
+
for (let i = 0; i < streams.length; i++) {
|
|
2216
|
+
const s = sides[i];
|
|
2217
|
+
const want = i < streams.length - 1 && s === "w" ? "readable" : i > 0 && s === "r" ? "writable" : null;
|
|
2218
|
+
if (want) {
|
|
2219
|
+
lowerer.noLowering(`compose with a stream that is not ${want} at position ${i}`, args[i], `Node throws ERR_INVALID_ARG_VALUE ('streams[${i}]' must be ${want}); every stream but the last must be readable and every stream but the first writable`);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
return {
|
|
2223
|
+
kind: "libCall",
|
|
2224
|
+
fn: "stream.compose",
|
|
2225
|
+
args: [numLit(streams.length, loc), ...streams],
|
|
2226
|
+
type: duplex,
|
|
2227
|
+
loc,
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
1452
2230
|
/* ── the method surface ───────────────────────────────────────────────── */
|
|
2231
|
+
/* ── the Readable operators ──────────────────────────────────────────── */
|
|
2232
|
+
/** The Readable operators (scr_stream_ops.c — Node's operators.js). */
|
|
2233
|
+
export const STREAM_OPERATORS = new Set([
|
|
2234
|
+
"map",
|
|
2235
|
+
"filter",
|
|
2236
|
+
"flatMap",
|
|
2237
|
+
"drop",
|
|
2238
|
+
"take",
|
|
2239
|
+
"toArray",
|
|
2240
|
+
"forEach",
|
|
2241
|
+
"some",
|
|
2242
|
+
"every",
|
|
2243
|
+
"find",
|
|
2244
|
+
"reduce",
|
|
2245
|
+
]);
|
|
2246
|
+
/** An operator callback as a checked-dynamic function value. Callbacks
|
|
2247
|
+
* that declare the options argument ({ signal }) are refused: the
|
|
2248
|
+
* AbortSignal Node passes there has no representation. map and flatMap
|
|
2249
|
+
* callbacks must produce strings or Buffers (flatMap: arrays of them, or
|
|
2250
|
+
* strings) — or checked-dynamic values, which the runtime checks. */
|
|
2251
|
+
function lowerOperatorCallback(lowerer, node, member, maxParams) {
|
|
2252
|
+
const loc = locOf(node);
|
|
2253
|
+
const optionsParam = (at) => lowerer.noLowering(`${member} callbacks that declare the options argument`, at, "the { signal } argument has no lowering — take only the chunk");
|
|
2254
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
2255
|
+
node.parameters.length > maxParams) {
|
|
2256
|
+
optionsParam(node.parameters[maxParams]);
|
|
2257
|
+
}
|
|
2258
|
+
const v = lowerer.lowerExpr(node);
|
|
2259
|
+
if (v.type.kind === "dyn")
|
|
2260
|
+
return v;
|
|
2261
|
+
if (v.type.kind !== "func" &&
|
|
2262
|
+
isJsSourceFile(node.getSourceFile()) &&
|
|
2263
|
+
lowerer.dynConvertible(v.type)) {
|
|
2264
|
+
// JavaScript passes any value; Node's validateFunction throws.
|
|
2265
|
+
return { kind: "dynFrom", value: v, type: DYN, loc };
|
|
2266
|
+
}
|
|
2267
|
+
if (v.type.kind !== "func") {
|
|
2268
|
+
lowerer.noLowering(`${member} with a '${lowerer.fmt(v.type)}' callback`, node, "pass a function");
|
|
2269
|
+
}
|
|
2270
|
+
if (v.type.params.length > maxParams)
|
|
2271
|
+
optionsParam(node);
|
|
2272
|
+
if (member === "map" || member === "flatMap") {
|
|
2273
|
+
const ret = v.type.ret.kind === "promise" ? v.type.ret.inner : v.type.ret;
|
|
2274
|
+
const chunk = (t) => t.kind === "string" || t.kind === "dyn" || (t.kind === "bytes" && t.elem === "u8");
|
|
2275
|
+
const ok = member === "map"
|
|
2276
|
+
? chunk(ret)
|
|
2277
|
+
: ret.kind === "dyn" || ret.kind === "string" || (ret.kind === "array" && chunk(ret.elem));
|
|
2278
|
+
if (!ok) {
|
|
2279
|
+
lowerer.noLowering(`${member} callbacks that return '${lowerer.fmt(ret)}'`, node, member === "map"
|
|
2280
|
+
? "map results are stream chunks: strings or Buffers (object-mode streams of other values are not lowered)"
|
|
2281
|
+
: "flatMap results are arrays of strings or Buffers, or strings");
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
const getRecord = (id) => lowerer.shapes.get(id);
|
|
2285
|
+
const getUnion = (id) => lowerer.unions.get(id);
|
|
2286
|
+
if (!canBoxFuncIntoDyn(v.type, getRecord, getUnion)) {
|
|
2287
|
+
lowerer.noLowering(`${member} with this callback`, node, "the callback's parameter and result types must cross the checked-dynamic boundary");
|
|
2288
|
+
}
|
|
2289
|
+
return { kind: "dynFrom", value: v, type: DYN, loc };
|
|
2290
|
+
}
|
|
2291
|
+
/** An operator's options (or reduce's initial value): an object literal
|
|
2292
|
+
* becomes a checked-dynamic object, checked-dynamic values pass through,
|
|
2293
|
+
* absent arguments are undefined. */
|
|
2294
|
+
function lowerOperatorValue(lowerer, node, what, loc, literalObject) {
|
|
2295
|
+
if (node === undefined)
|
|
2296
|
+
return dynUndefinedExpr(loc);
|
|
2297
|
+
if (literalObject && ts.isObjectLiteralExpression(node))
|
|
2298
|
+
return lowerDynObjectLiteral(lowerer, node);
|
|
2299
|
+
const v = lowerer.lowerExpr(node);
|
|
2300
|
+
if (v.type.kind === "dyn")
|
|
2301
|
+
return v;
|
|
2302
|
+
if (literalObject && v.type.kind !== "undefinedT" && v.type.kind !== "nullT") {
|
|
2303
|
+
lowerer.noLowering(`${what} that are not an object literal`, node, "write the options inline, e.g. { concurrency: 2 }");
|
|
2304
|
+
}
|
|
2305
|
+
if (!lowerer.dynConvertible(v.type)) {
|
|
2306
|
+
lowerer.noLowering(`${what} of type '${lowerer.fmt(v.type)}'`, node);
|
|
2307
|
+
}
|
|
2308
|
+
return { kind: "dynFrom", value: v, type: DYN, loc: locOf(node) };
|
|
2309
|
+
}
|
|
2310
|
+
function lowerStreamOperator(lowerer, call, access, member) {
|
|
2311
|
+
const loc = locOf(call);
|
|
2312
|
+
const args = call.arguments;
|
|
2313
|
+
const recv = lowerer.lowerExpr(access.expression);
|
|
2314
|
+
const readable = { kind: "object", className: "%Readable" };
|
|
2315
|
+
const opts = (i) => lowerOperatorValue(lowerer, args[i], `${member} options`, loc, true);
|
|
2316
|
+
const fnArg = (maxParams) => {
|
|
2317
|
+
if (args[0] === undefined)
|
|
2318
|
+
return dynUndefinedExpr(loc);
|
|
2319
|
+
return lowerOperatorCallback(lowerer, args[0], member, maxParams);
|
|
2320
|
+
};
|
|
2321
|
+
const lib = (fn, a, type) => ({
|
|
2322
|
+
kind: "libCall",
|
|
2323
|
+
fn: fn,
|
|
2324
|
+
args: a,
|
|
2325
|
+
type,
|
|
2326
|
+
loc,
|
|
2327
|
+
});
|
|
2328
|
+
switch (member) {
|
|
2329
|
+
case "map":
|
|
2330
|
+
case "filter":
|
|
2331
|
+
case "flatMap": {
|
|
2332
|
+
const fn = fnArg(1);
|
|
2333
|
+
const fnName = member === "map"
|
|
2334
|
+
? "readable.opMap"
|
|
2335
|
+
: member === "filter"
|
|
2336
|
+
? "readable.opFilter"
|
|
2337
|
+
: "readable.opFlatMap";
|
|
2338
|
+
return lib(fnName, [recv, fn, opts(1)], readable);
|
|
2339
|
+
}
|
|
2340
|
+
case "drop":
|
|
2341
|
+
case "take": {
|
|
2342
|
+
const n = lowerOperatorValue(lowerer, args[0], `${member}'s count`, loc, false);
|
|
2343
|
+
return lib(member === "drop" ? "readable.opDrop" : "readable.opTake", [recv, n, opts(1)], readable);
|
|
2344
|
+
}
|
|
2345
|
+
case "toArray":
|
|
2346
|
+
return lib("readable.opToArray", [recv, opts(0)], { kind: "promise", inner: DYN });
|
|
2347
|
+
case "forEach":
|
|
2348
|
+
return lib("readable.opForEach", [recv, fnArg(1), opts(1)], { kind: "promise", inner: VOID });
|
|
2349
|
+
case "some":
|
|
2350
|
+
case "every": {
|
|
2351
|
+
const fn = fnArg(1);
|
|
2352
|
+
return lib(member === "some" ? "readable.opSome" : "readable.opEvery", [recv, fn, opts(1)], {
|
|
2353
|
+
kind: "promise",
|
|
2354
|
+
inner: BOOL,
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
case "find": {
|
|
2358
|
+
const t = lowerer.typeOf(call);
|
|
2359
|
+
const inner = lowerer.checker.getTypeArguments(t)[0];
|
|
2360
|
+
if (inner && !(inner.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))) {
|
|
2361
|
+
lowerer.noLowering("find with a type-guard callback", call, "the result is a checked-dynamic value — use a boolean predicate and narrow the result");
|
|
2362
|
+
}
|
|
2363
|
+
return lib("readable.opFind", [recv, fnArg(1), opts(1)], { kind: "promise", inner: DYN });
|
|
2364
|
+
}
|
|
2365
|
+
case "reduce": {
|
|
2366
|
+
const t = lowerer.typeOf(call);
|
|
2367
|
+
const resultTs = lowerer.checker.getTypeArguments(t)[0];
|
|
2368
|
+
let kind = 0;
|
|
2369
|
+
let inner = DYN;
|
|
2370
|
+
if (resultTs && !(resultTs.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))) {
|
|
2371
|
+
const mapped = lowerer.mapTypeOf(resultTs);
|
|
2372
|
+
if (mapped?.kind === "f64") {
|
|
2373
|
+
kind = 1;
|
|
2374
|
+
inner = F64;
|
|
2375
|
+
}
|
|
2376
|
+
else if (mapped?.kind === "bool") {
|
|
2377
|
+
kind = 2;
|
|
2378
|
+
inner = BOOL;
|
|
2379
|
+
}
|
|
2380
|
+
else if (mapped?.kind === "string") {
|
|
2381
|
+
kind = 3;
|
|
2382
|
+
inner = STRING;
|
|
2383
|
+
}
|
|
2384
|
+
else if (mapped?.kind !== "dyn") {
|
|
2385
|
+
lowerer.noLowering(`reduce with a '${mapped ? lowerer.fmt(mapped) : lowerer.checker.typeToString(resultTs)}' result`, call, "reduce results are numbers, booleans, strings, or checked-dynamic values");
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
const fn = fnArg(2);
|
|
2389
|
+
const init = lowerOperatorValue(lowerer, args[1], "reduce's initial value", loc, false);
|
|
2390
|
+
return lib("readable.opReduce", [recv, fn, init, boolLit(args.length >= 2, loc), opts(2), numLit(kind, loc)], { kind: "promise", inner });
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
throw new InternalCompilerError(`unknown stream operator ${member}`);
|
|
2394
|
+
}
|
|
2395
|
+
/** The literal 'buffer' encoding on write()/end(): Node 24 takes it for a
|
|
2396
|
+
* Buffer chunk and throws ERR_UNKNOWN_ENCODING for a string chunk. */
|
|
2397
|
+
function isBufferEncoding(lowerer, arg) {
|
|
2398
|
+
if (arg === undefined)
|
|
2399
|
+
return false;
|
|
2400
|
+
const t = lowerer.typeOf(arg);
|
|
2401
|
+
return t.isStringLiteralType() && t.value === "buffer";
|
|
2402
|
+
}
|
|
1453
2403
|
/** The one supported encoding argument: utf8 (Node's default), as a
|
|
1454
2404
|
* compile-time literal or absent. */
|
|
1455
2405
|
function checkUtf8Encoding(lowerer, member, arg) {
|
|
@@ -1464,6 +2414,11 @@ function checkUtf8Encoding(lowerer, member, arg) {
|
|
|
1464
2414
|
* for members this spoke does not own. */
|
|
1465
2415
|
export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
1466
2416
|
const member = access.name.text;
|
|
2417
|
+
if (STREAM_OPERATORS.has(member)) {
|
|
2418
|
+
const opSides = streamSidesOf(lowerer, info);
|
|
2419
|
+
if (opSides === "r" || opSides === "rw")
|
|
2420
|
+
return lowerStreamOperator(lowerer, call, access, member);
|
|
2421
|
+
}
|
|
1467
2422
|
if (!STREAM_API_MEMBERS.has(member))
|
|
1468
2423
|
return null;
|
|
1469
2424
|
const sides = streamSidesOf(lowerer, info);
|
|
@@ -1756,7 +2711,12 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
|
1756
2711
|
// Disambiguate (chunk, cb?) vs (chunk, encoding, cb?) by the second
|
|
1757
2712
|
// argument's static type.
|
|
1758
2713
|
let cbArg;
|
|
1759
|
-
if (args.length
|
|
2714
|
+
if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
|
|
2715
|
+
if (kind !== "bytes")
|
|
2716
|
+
return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", BOOL, loc);
|
|
2717
|
+
cbArg = args[2];
|
|
2718
|
+
}
|
|
2719
|
+
else if (args.length === 2) {
|
|
1760
2720
|
const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
|
|
1761
2721
|
if (t?.kind === "string")
|
|
1762
2722
|
checkUtf8Encoding(lowerer, "write", args[1]);
|
|
@@ -1795,6 +2755,17 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
|
1795
2755
|
else
|
|
1796
2756
|
chunkNode = args[0];
|
|
1797
2757
|
}
|
|
2758
|
+
else if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
|
|
2759
|
+
chunkNode = args[0];
|
|
2760
|
+
const endKind = chunkKind(args[0]);
|
|
2761
|
+
if (endKind === "string") {
|
|
2762
|
+
const endT = lowerer.mapTypeOf(lowerer.typeOf(call)) ?? DYN;
|
|
2763
|
+
return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", endT, loc);
|
|
2764
|
+
}
|
|
2765
|
+
if (endKind !== "bytes")
|
|
2766
|
+
checkUtf8Encoding(lowerer, "end", args[1]);
|
|
2767
|
+
cbArg = args[2];
|
|
2768
|
+
}
|
|
1798
2769
|
else if (args.length === 2) {
|
|
1799
2770
|
chunkNode = args[0];
|
|
1800
2771
|
const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
|