@scriptc/compiler 0.3.3 → 0.3.5
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 +844 -36
- 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/array-search.js +1 -1
- package/dist/backend/llvm/array-search.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +11 -1
- package/dist/backend/llvm/call-lifetimes.js +30 -3
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +31 -1
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +5 -0
- package/dist/backend/llvm/common.js +7 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
- package/dist/backend/llvm/constant-callbacks.js +36 -219
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +22 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +9 -0
- package/dist/backend/llvm/dense-array-access.js +29 -3
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +46 -1
- package/dist/backend/llvm/dyn.js +218 -33
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +87 -1
- package/dist/backend/llvm/emitter.js +568 -61
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +17 -7
- 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 +159 -64
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
- package/dist/backend/llvm/expr-callbacks.js +53 -0
- 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 +137 -3
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +63 -29
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +9 -1
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +4 -0
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/integer-clones.d.ts +103 -0
- package/dist/backend/llvm/integer-clones.js +1336 -0
- package/dist/backend/llvm/integer-clones.js.map +1 -0
- package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
- package/dist/backend/llvm/integer-clones.test.js +219 -0
- package/dist/backend/llvm/integer-clones.test.js.map +1 -0
- 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 +24 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +96 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +51 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +16 -0
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +24 -0
- 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 +114 -3
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +87 -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/lib-tls.js +6 -0
- package/dist/backend/llvm/lib-tls.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +1 -1
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
- package/dist/backend/llvm/map-entry-fusion.js +233 -0
- package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
- package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
- package/dist/backend/llvm/map-number-lookup.d.ts +6 -0
- package/dist/backend/llvm/map-number-lookup.js +23 -1
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +60 -5
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +11 -0
- package/dist/backend/llvm/map-read-lifetimes.js +92 -1
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +131 -3
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +21 -0
- package/dist/backend/llvm/publish.js +101 -11
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/publish.test.d.ts +1 -0
- package/dist/backend/llvm/publish.test.js +94 -0
- package/dist/backend/llvm/publish.test.js.map +1 -0
- package/dist/backend/llvm/record-results.js +76 -2
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/record-sources.d.ts +7 -0
- package/dist/backend/llvm/record-sources.js +14 -0
- package/dist/backend/llvm/record-sources.js.map +1 -0
- package/dist/backend/llvm/reference-writes.js +5 -2
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/regions.d.ts +4 -1
- package/dist/backend/llvm/regions.js +12 -3
- package/dist/backend/llvm/regions.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +9 -3
- package/dist/backend/llvm/shapes.js +18 -14
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +5 -3
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +75 -1
- package/dist/backend/llvm/string-lifetimes.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 +17 -0
- package/dist/backend/llvm/walkers.js +123 -0
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +4 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +5 -1
- package/dist/backend/native/executable.js +16 -6
- 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 +1 -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/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 +7 -0
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/warm-cache.js +1 -0
- package/dist/backend/warm-cache.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/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/builtin-calls.js +3 -0
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/callable-aliases.js +54 -8
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
- package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
- package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
- package/dist/frontend/lowering/builtins/compression.js +175 -2
- 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 +111 -1
- 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 +2 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +5 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.js +60 -0
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
- package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
- package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-calls.js +5 -1
- package/dist/frontend/lowering/builtins/module-calls.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/call-signatures.js +6 -0
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +216 -20
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +33 -12
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/devirtualize.js +20 -7
- package/dist/frontend/lowering/devirtualize.js.map +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-assert.js +700 -61
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.js +11 -2
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +75 -6
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +3 -0
- package/dist/frontend/lowering/lower-classes.js +43 -0
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +132 -67
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
- package/dist/frontend/lowering/lower-event-emitter.js +78 -0
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
- package/dist/frontend/lowering/lower-exprs.js +144 -58
- 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 +138 -39
- package/dist/frontend/lowering/lower-inspect.js.map +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.js +7 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +4 -0
- package/dist/frontend/lowering/lower-server.js +448 -30
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +35 -8
- 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 +794 -27
- 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/lowerer.d.ts +25 -1
- package/dist/frontend/lowering/lowerer.js +74 -9
- package/dist/frontend/lowering/lowerer.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/record-sources.d.ts +15 -0
- package/dist/frontend/lowering/record-sources.js +46 -0
- package/dist/frontend/lowering/record-sources.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +4 -0
- package/dist/frontend/lowering/surfaces.js +94 -16
- 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/pipeline.js +5 -3
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program.js +6 -1
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.d.ts +4 -0
- package/dist/frontend/resolve.js +14 -0
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/tsc-codes.js +1 -0
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +8 -0
- package/dist/frontend/type-mapper.js +155 -9
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +10 -0
- package/dist/ir/analysis.js +35 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +69 -1
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/builtin-effects.js +72 -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 +238 -15
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/capture-values.d.ts +107 -0
- package/dist/ir/capture-values.js +850 -0
- package/dist/ir/capture-values.js.map +1 -0
- package/dist/ir/capture-values.test.d.ts +1 -0
- package/dist/ir/capture-values.test.js +268 -0
- package/dist/ir/capture-values.test.js.map +1 -0
- package/dist/ir/field-values.d.ts +16 -0
- package/dist/ir/field-values.js +128 -0
- package/dist/ir/field-values.js.map +1 -0
- package/dist/ir/field-values.test.d.ts +1 -0
- package/dist/ir/field-values.test.js +160 -0
- package/dist/ir/field-values.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +4 -1
- package/dist/ir/final-fields.js +11 -3
- package/dist/ir/final-fields.js.map +1 -1
- package/dist/ir/function-references.test.js +1 -1
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/init-only-globals.d.ts +16 -0
- package/dist/ir/init-only-globals.js +121 -0
- package/dist/ir/init-only-globals.js.map +1 -0
- package/dist/ir/init-only-globals.test.d.ts +1 -0
- package/dist/ir/init-only-globals.test.js +115 -0
- package/dist/ir/init-only-globals.test.js.map +1 -0
- package/dist/ir/initializer-bindings.d.ts +18 -1
- package/dist/ir/initializer-bindings.js +91 -1
- package/dist/ir/initializer-bindings.js.map +1 -1
- package/dist/ir/initializer-bindings.test.js +57 -2
- package/dist/ir/initializer-bindings.test.js.map +1 -1
- package/dist/ir/int32-slots.d.ts +22 -0
- package/dist/ir/int32-slots.js +376 -13
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +91 -8
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loop-facts.d.ts +19 -1
- package/dist/ir/integer-loop-facts.js +155 -7
- package/dist/ir/integer-loop-facts.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +8 -5
- package/dist/ir/integer-ranges.js +147 -55
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +225 -7
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +29 -2
- package/dist/ir/ir.js +17 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/property-bags.d.ts +14 -0
- package/dist/ir/property-bags.js +121 -0
- package/dist/ir/property-bags.js.map +1 -0
- package/dist/ir/receiver-readers.d.ts +21 -0
- package/dist/ir/receiver-readers.js +217 -0
- package/dist/ir/receiver-readers.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +1 -0
- package/dist/ir/runtime-features.js +34 -2
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/validate.js +221 -5
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +21 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/int-infer.js +3 -0
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/ir-policy.js +1 -0
- package/dist/library/ir-policy.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 +1 -0
- 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 +896 -49
|
@@ -36,7 +36,11 @@ 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
38
|
import { sideEffectFreeOptionValue } from "./surfaces.js";
|
|
39
|
-
import {
|
|
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";
|
|
40
44
|
const BYTES = BYTES_U8;
|
|
41
45
|
/** An expression that only reads bindings and properties (no calls,
|
|
42
46
|
* assignments or construction): reading it a step later observes the
|
|
@@ -155,6 +159,8 @@ export const STREAM_FORCED_EVENT_NAMES = new Set([
|
|
|
155
159
|
"finish",
|
|
156
160
|
"pipe",
|
|
157
161
|
"unpipe",
|
|
162
|
+
"open",
|
|
163
|
+
"ready",
|
|
158
164
|
]);
|
|
159
165
|
/** The per-base FORCED event tuples (runtime-emitted payloads): consulted
|
|
160
166
|
* by the emitter spoke BEFORE the program-global table, so a stream's
|
|
@@ -164,6 +170,8 @@ export function streamForcedTuple(lowerer, info, name) {
|
|
|
164
170
|
const sides = streamSidesOf(lowerer, info);
|
|
165
171
|
if (!sides)
|
|
166
172
|
return null;
|
|
173
|
+
// 'open' (the fd) and 'ready' are fs.ReadStream / fs.WriteStream's
|
|
174
|
+
// (scr_fs_stream.c).
|
|
167
175
|
const readable = {
|
|
168
176
|
data: [BYTES],
|
|
169
177
|
end: [],
|
|
@@ -171,8 +179,12 @@ export function streamForcedTuple(lowerer, info, name) {
|
|
|
171
179
|
readable: [],
|
|
172
180
|
pause: [],
|
|
173
181
|
resume: [],
|
|
182
|
+
open: [F64],
|
|
183
|
+
ready: [],
|
|
174
184
|
};
|
|
175
185
|
const writable = {
|
|
186
|
+
open: [F64],
|
|
187
|
+
ready: [],
|
|
176
188
|
drain: [],
|
|
177
189
|
prefinish: [],
|
|
178
190
|
finish: [],
|
|
@@ -1111,12 +1123,14 @@ export function lowerStreamUnderscoreAssign(lowerer, expr) {
|
|
|
1111
1123
|
};
|
|
1112
1124
|
}
|
|
1113
1125
|
/* ── the static surface (Readable.from) ───────────────────────────────── */
|
|
1114
|
-
/** `Readable.from(iterable)
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1126
|
+
/** `Readable.from(iterable, options)`: string[] / Buffer[] sources
|
|
1127
|
+
* become a readable that pushes one element per _read (whole entries in
|
|
1128
|
+
* object mode, hwm 1), and a single string/Buffer argument is a
|
|
1129
|
+
* one-chunk stream (from.js's special case, the mode's default hwm). The
|
|
1130
|
+
* options lower when they are a literal of `objectMode` and
|
|
1131
|
+
* `highWaterMark`; the JS lane and `any` sources take the runtime's
|
|
1132
|
+
* checked-dynamic form. Called from the method-call chain once the
|
|
1133
|
+
* receiver resolved to a stream class value. */
|
|
1120
1134
|
export function lowerStreamStaticCall(lowerer, call, access) {
|
|
1121
1135
|
if (call.questionDotToken || access.questionDotToken)
|
|
1122
1136
|
return null;
|
|
@@ -1165,37 +1179,223 @@ export function lowerStreamStaticCall(lowerer, call, access) {
|
|
|
1165
1179
|
lowerer.noLowering(`${cls.slice(1)}.from`, call, "Readable.from is the lowered form");
|
|
1166
1180
|
}
|
|
1167
1181
|
const args = call.arguments;
|
|
1168
|
-
if (args.length
|
|
1169
|
-
lowerer.noLowering(`Readable.from with ${args.length} arguments`, call, "
|
|
1182
|
+
if (args.length > 2) {
|
|
1183
|
+
lowerer.noLowering(`Readable.from with ${args.length} arguments`, call, "Readable.from(iterable, options) is the supported form");
|
|
1170
1184
|
}
|
|
1171
|
-
const srcT = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
|
|
1172
1185
|
const type = { kind: "object", className: "%Readable" };
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1186
|
+
const js = isJsSourceFile(call.getSourceFile());
|
|
1187
|
+
const srcNode = args[0];
|
|
1188
|
+
const optsNode = args[1];
|
|
1189
|
+
const srcT = srcNode ? lowerer.mapTypeOf(lowerer.typeOf(srcNode)) : null;
|
|
1190
|
+
const typedElem = (t) => t?.kind === "string" ? "string" : t?.kind === "bytes" && t.elem === "u8" ? "bytes" : null;
|
|
1191
|
+
const single = typedElem(srcT);
|
|
1192
|
+
const elem = srcT?.kind === "array" ? typedElem(srcT.elem) : null;
|
|
1193
|
+
const opts = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
|
|
1194
|
+
if (srcNode && srcT?.kind === "generator" && opts && fromGenChunk(lowerer, srcT.yieldT)) {
|
|
1195
|
+
// A compiled generator: the runtime pulls it through interned helpers.
|
|
1196
|
+
const gen = lowerer.lowerExpr(srcNode);
|
|
1197
|
+
const helpers = fromGenHelpers(lowerer, srcT, loc);
|
|
1198
|
+
if (helpers) {
|
|
1199
|
+
const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
|
|
1200
|
+
return {
|
|
1201
|
+
kind: "libCall",
|
|
1202
|
+
fn: srcT.async ? "readable.fromAsyncGen" : "readable.fromGen",
|
|
1203
|
+
args: [gen, ...helpers, numLit(opts.flags, loc), hwm],
|
|
1204
|
+
type,
|
|
1205
|
+
loc,
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
if (srcNode && (single || elem) && opts) {
|
|
1210
|
+
const v = lowerer.lowerExpr(srcNode);
|
|
1211
|
+
const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
|
|
1212
|
+
const arr = single ? { kind: "arrayLit", elems: [v], type: arrayOf(v.type), loc } : v;
|
|
1213
|
+
// SCR_FROM_STRINGS 1, SCR_FROM_SINGLE 2 (scr_runtime.h); the options
|
|
1214
|
+
// add SCR_FROM_BYTE_MODE 4 and SCR_FROM_HAS_HWM 8.
|
|
1215
|
+
const flags = ((single ?? elem) === "string" ? 1 : 0) | (single ? 2 : 0) | opts.flags;
|
|
1177
1216
|
return {
|
|
1178
1217
|
kind: "libCall",
|
|
1179
1218
|
fn: "readable.fromArr",
|
|
1180
|
-
args: [arr,
|
|
1219
|
+
args: [arr, numLit(flags, loc), hwm],
|
|
1181
1220
|
type,
|
|
1182
1221
|
loc,
|
|
1183
1222
|
};
|
|
1184
1223
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1224
|
+
const anySrc = srcT?.kind === "dyn" ||
|
|
1225
|
+
(srcNode !== undefined &&
|
|
1226
|
+
srcT === null &&
|
|
1227
|
+
(lowerer.typeOf(srcNode).flags & ts.TypeFlags.Any) !== 0);
|
|
1228
|
+
if (js || anySrc) {
|
|
1229
|
+
// The checked-dynamic form: the runtime takes from.js's ladder
|
|
1230
|
+
// (ERR_INVALID_ARG_TYPE for a non-iterable, the options, null values).
|
|
1231
|
+
const src = srcNode ? lowerer.lowerExprExpecting(srcNode, DYN) : dynUndefinedExpr(loc);
|
|
1232
|
+
const o = lowerOperatorValue(lowerer, optsNode, "Readable.from options", loc, true);
|
|
1233
|
+
return { kind: "libCall", fn: "readable.fromDyn", args: [src, o], type, loc };
|
|
1234
|
+
}
|
|
1235
|
+
if (srcNode && (single || elem)) {
|
|
1236
|
+
lowerer.noLowering("Readable.from with these options", optsNode, "an object literal with 'objectMode' (true or false) and a number 'highWaterMark' is supported");
|
|
1237
|
+
}
|
|
1238
|
+
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");
|
|
1239
|
+
}
|
|
1240
|
+
/** Whether a generator's yields are stream chunks: strings, Buffers, a
|
|
1241
|
+
* union of them (null included: the runtime destroys the stream with
|
|
1242
|
+
* ERR_STREAM_NULL_VALUES), or checked-dynamic values (checked when
|
|
1243
|
+
* pushed). */
|
|
1244
|
+
function fromGenChunk(lowerer, t) {
|
|
1245
|
+
const chunk = (a) => a.kind === "string" || (a.kind === "bytes" && a.elem === "u8") || a.kind === "nullT";
|
|
1246
|
+
if (t.kind === "dyn" || (chunk(t) && t.kind !== "nullT"))
|
|
1247
|
+
return true;
|
|
1248
|
+
if (t.kind !== "union")
|
|
1249
|
+
return false;
|
|
1250
|
+
return lowerer.unions.get(t.unionId)?.arms.every(chunk) ?? false;
|
|
1251
|
+
}
|
|
1252
|
+
/** The helpers Readable.from pulls a compiled generator through, as
|
|
1253
|
+
* closures in libcall order: a sync generator's next/return/throw answer
|
|
1254
|
+
* the next value as a checked-dynamic value or the done marker
|
|
1255
|
+
* (readable.fromDone); an async generator's next/return/throw answer the
|
|
1256
|
+
* resume's promise, followed by `read`, which maps its IteratorResult the
|
|
1257
|
+
* same way. Interned per generator type. Null when the result record has
|
|
1258
|
+
* no lowering. */
|
|
1259
|
+
function fromGenHelpers(lowerer, gen, loc) {
|
|
1260
|
+
const recT = genResultRecord(gen.yieldT, gen.retT, lowerer.shapes, lowerer.unions);
|
|
1261
|
+
const valueT = recT && lowerer.shapes.get(recT.shapeId)?.fields.find((f) => f.name === "value")?.type;
|
|
1262
|
+
if (!recT || !valueT)
|
|
1263
|
+
return null;
|
|
1264
|
+
const done = () => ({
|
|
1265
|
+
kind: "libCall",
|
|
1266
|
+
fn: "readable.fromDone",
|
|
1267
|
+
args: [],
|
|
1268
|
+
type: DYN,
|
|
1269
|
+
loc,
|
|
1270
|
+
});
|
|
1271
|
+
// `r.done ? done : r.value` over a record local.
|
|
1272
|
+
const readRecord = (localId) => {
|
|
1273
|
+
const r = varRef(localId, recT, loc);
|
|
1274
|
+
const value = extractIteratorValue(lowerer, gen.yieldT, valueT, { kind: "recordGet", obj: r, shapeId: recT.shapeId, field: "value", type: valueT, loc }, loc);
|
|
1275
|
+
if (!value)
|
|
1276
|
+
return null;
|
|
1277
|
+
return [
|
|
1278
|
+
{
|
|
1279
|
+
kind: "if",
|
|
1280
|
+
cond: { kind: "recordGet", obj: r, shapeId: recT.shapeId, field: "done", type: BOOL, loc },
|
|
1281
|
+
then: [{ kind: "return", value: done(), loc }],
|
|
1282
|
+
else_: null,
|
|
1283
|
+
loc,
|
|
1284
|
+
},
|
|
1285
|
+
{ kind: "return", value: lowerer.coerceToExpected(value, DYN), loc },
|
|
1286
|
+
];
|
|
1287
|
+
};
|
|
1288
|
+
const promiseT = { kind: "promise", inner: recT };
|
|
1289
|
+
const define = (role, params, returnType, body, locals = []) => {
|
|
1290
|
+
const key = `streamFromGen:${role}:${typeKey(gen)}`;
|
|
1291
|
+
let name = lowerer.valueHelpers.get(key);
|
|
1292
|
+
if (!name) {
|
|
1293
|
+
name = `%stream.fromGen.${role}.${lowerer.valueHelpers.size}`;
|
|
1294
|
+
lowerer.valueHelpers.set(key, name);
|
|
1295
|
+
lowerer.liftedFns.push({
|
|
1296
|
+
name,
|
|
1297
|
+
params: params.map((p) => ({ localId: p.id, name: p.id.split(".")[0], type: p.type })),
|
|
1298
|
+
returnType,
|
|
1299
|
+
locals: [...params, ...locals].map((l) => ({
|
|
1300
|
+
id: l.id,
|
|
1301
|
+
name: l.id.split(".")[0],
|
|
1302
|
+
type: l.type,
|
|
1303
|
+
mutable: false,
|
|
1304
|
+
})),
|
|
1305
|
+
body,
|
|
1306
|
+
loc,
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1190
1309
|
return {
|
|
1191
|
-
kind: "
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
type,
|
|
1310
|
+
kind: "closure",
|
|
1311
|
+
fnName: name,
|
|
1312
|
+
captures: [],
|
|
1313
|
+
type: funcOf(params.map((p) => p.type), returnType),
|
|
1195
1314
|
loc,
|
|
1196
1315
|
};
|
|
1316
|
+
};
|
|
1317
|
+
const g = { id: "gen.0", type: gen };
|
|
1318
|
+
const e = { id: "err.0", type: DYN };
|
|
1319
|
+
const r = { id: "res.0", type: recT };
|
|
1320
|
+
const genRef = varRef("gen.0", gen, loc);
|
|
1321
|
+
const resume = (mode) => ({
|
|
1322
|
+
kind: "genResume",
|
|
1323
|
+
mode,
|
|
1324
|
+
gen: genRef,
|
|
1325
|
+
arg: mode === "throw" ? varRef("err.0", DYN, loc) : null,
|
|
1326
|
+
type: gen.async ? promiseT : recT,
|
|
1327
|
+
loc,
|
|
1328
|
+
});
|
|
1329
|
+
const read = readRecord("res.0");
|
|
1330
|
+
if (!read)
|
|
1331
|
+
return null;
|
|
1332
|
+
if (gen.async) {
|
|
1333
|
+
const ret = (mode) => [
|
|
1334
|
+
{ kind: "return", value: resume(mode), loc },
|
|
1335
|
+
];
|
|
1336
|
+
return [
|
|
1337
|
+
define("anext", [g], promiseT, ret("next")),
|
|
1338
|
+
define("aread", [r], DYN, read),
|
|
1339
|
+
define("areturn", [g], promiseT, ret("return")),
|
|
1340
|
+
define("athrow", [g, e], promiseT, ret("throw")),
|
|
1341
|
+
];
|
|
1342
|
+
}
|
|
1343
|
+
const viaRecord = (mode) => [
|
|
1344
|
+
{ kind: "varDecl", localId: "res.0", init: resume(mode), loc },
|
|
1345
|
+
...read,
|
|
1346
|
+
];
|
|
1347
|
+
const next = stepDrivable(gen)
|
|
1348
|
+
? [
|
|
1349
|
+
{
|
|
1350
|
+
kind: "if",
|
|
1351
|
+
cond: genStep(genRef, loc),
|
|
1352
|
+
then: [{ kind: "return", value: done(), loc }],
|
|
1353
|
+
else_: null,
|
|
1354
|
+
loc,
|
|
1355
|
+
},
|
|
1356
|
+
{ kind: "return", value: lowerer.coerceToExpected(genValue(genRef, loc), DYN), loc },
|
|
1357
|
+
]
|
|
1358
|
+
: viaRecord("next");
|
|
1359
|
+
const withRecord = stepDrivable(gen) ? [] : [r];
|
|
1360
|
+
return [
|
|
1361
|
+
define("next", [g], DYN, next, withRecord),
|
|
1362
|
+
define("return", [g], DYN, viaRecord("return"), [r]),
|
|
1363
|
+
define("throw", [g, e], DYN, viaRecord("throw"), [r]),
|
|
1364
|
+
];
|
|
1365
|
+
}
|
|
1366
|
+
/** Readable.from's typed options: an object literal of `objectMode`
|
|
1367
|
+
* (a boolean literal) and `highWaterMark` (a number), as SCR_FROM_* flag
|
|
1368
|
+
* bits and the hwm expression; null for any other shape. */
|
|
1369
|
+
function fromOptions(lowerer, node) {
|
|
1370
|
+
if (!ts.isObjectLiteralExpression(node))
|
|
1371
|
+
return null;
|
|
1372
|
+
let flags = 0;
|
|
1373
|
+
let hwm = null;
|
|
1374
|
+
for (const prop of node.properties) {
|
|
1375
|
+
if (!ts.isPropertyAssignment(prop) ||
|
|
1376
|
+
!(ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name))) {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
const value = prop.initializer;
|
|
1380
|
+
if (prop.name.text === "objectMode") {
|
|
1381
|
+
if (value.kind === ts.SyntaxKind.FalseKeyword)
|
|
1382
|
+
flags |= 4;
|
|
1383
|
+
else if (value.kind === ts.SyntaxKind.TrueKeyword)
|
|
1384
|
+
flags &= ~4;
|
|
1385
|
+
else
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
else if (prop.name.text === "highWaterMark") {
|
|
1389
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(value))?.kind !== "f64")
|
|
1390
|
+
return null;
|
|
1391
|
+
flags |= 8;
|
|
1392
|
+
hwm = value;
|
|
1393
|
+
}
|
|
1394
|
+
else {
|
|
1395
|
+
return null;
|
|
1396
|
+
}
|
|
1197
1397
|
}
|
|
1198
|
-
|
|
1398
|
+
return { flags, hwm };
|
|
1199
1399
|
}
|
|
1200
1400
|
/** `const Writable = stream.Writable` — a runtime stream CLASS bound
|
|
1201
1401
|
* through a namespace member: alias plumbing with no storage (both
|
|
@@ -1273,7 +1473,7 @@ function lowerStreamArg(lowerer, node, what) {
|
|
|
1273
1473
|
argTypeThrow("stream", "an instance of ReadableStream, WritableStream, or Stream");
|
|
1274
1474
|
}
|
|
1275
1475
|
}
|
|
1276
|
-
lowerer.noLowering(`${what} over a '${lowerer.fmt(v.type)}'`, node, what === "pipeline"
|
|
1476
|
+
lowerer.noLowering(`${what} over a '${lowerer.fmt(v.type)}'`, node, what === "pipeline" || what === "compose"
|
|
1277
1477
|
? "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"
|
|
1278
1478
|
: "stream arguments are the lowered surface (iterables, generators, and plain functions have no lowering yet)");
|
|
1279
1479
|
}
|
|
@@ -1489,6 +1689,20 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1489
1689
|
? pipelineOptions(lowerer, lastArg)
|
|
1490
1690
|
: null;
|
|
1491
1691
|
const stageArgs = opts ? args.slice(0, -1) : args;
|
|
1692
|
+
if (stageArgs.some(isPipelineFunctionStage)) {
|
|
1693
|
+
if (opts) {
|
|
1694
|
+
lowerer.noLowering("pipeline with function stages and options", lastArg, "pipeline(source, async function* (source) { ... }, destination) without options is supported");
|
|
1695
|
+
}
|
|
1696
|
+
const staged = lowerPipelineStages(lowerer, stageArgs, loc);
|
|
1697
|
+
// A promise destination's value settles the result (same type).
|
|
1698
|
+
return staged.wrap({
|
|
1699
|
+
kind: "libCall",
|
|
1700
|
+
fn: "sp.pipelineStages",
|
|
1701
|
+
args: staged.args,
|
|
1702
|
+
type: staged.destPromise ?? { kind: "promise", inner: VOID },
|
|
1703
|
+
loc,
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1492
1706
|
let streams;
|
|
1493
1707
|
try {
|
|
1494
1708
|
streams = stageArgs.map((a) => lowerStreamArg(lowerer, a, "pipeline"));
|
|
@@ -1640,6 +1854,33 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1640
1854
|
if (args.length < 3) {
|
|
1641
1855
|
lowerer.noLowering(`pipeline with ${args.length} arguments`, call, "the supported form is pipeline(source, ...streams, callback)");
|
|
1642
1856
|
}
|
|
1857
|
+
if (args.slice(0, -1).some(isPipelineFunctionStage)) {
|
|
1858
|
+
const staged = lowerPipelineStages(lowerer, args.slice(0, -1), loc);
|
|
1859
|
+
if (staged.dest !== 0) {
|
|
1860
|
+
// callback(err, value): the destination's value reaches the
|
|
1861
|
+
// callback through the checked-dynamic path. Node answers an
|
|
1862
|
+
// object-mode PassThrough here; reading it has no lowering.
|
|
1863
|
+
if (!ts.isExpressionStatement(call.parent)) {
|
|
1864
|
+
lowerer.noLowering("using the PassThrough that pipeline() answers for a function destination", call, "read the destination's value in the callback");
|
|
1865
|
+
}
|
|
1866
|
+
const cb = lowerer.lowerExprExpecting(args[args.length - 1], DYN);
|
|
1867
|
+
return staged.wrap({
|
|
1868
|
+
kind: "libCall",
|
|
1869
|
+
fn: "stream.pipelineStagesDyn",
|
|
1870
|
+
args: [...staged.args, cb],
|
|
1871
|
+
type: staged.last,
|
|
1872
|
+
loc,
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
const { cb, dyn } = lowerEosCallback(lowerer, "pipeline", args[args.length - 1], staged.last);
|
|
1876
|
+
return staged.wrap({
|
|
1877
|
+
kind: "libCall",
|
|
1878
|
+
fn: dyn ? "stream.pipelineStagesDyn" : "stream.pipelineStages",
|
|
1879
|
+
args: [...staged.args, cb],
|
|
1880
|
+
type: staged.last,
|
|
1881
|
+
loc,
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1643
1884
|
let streams;
|
|
1644
1885
|
try {
|
|
1645
1886
|
streams = args.slice(0, -1).map((a) => lowerStreamArg(lowerer, a, "pipeline"));
|
|
@@ -1659,9 +1900,514 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
|
|
|
1659
1900
|
loc,
|
|
1660
1901
|
};
|
|
1661
1902
|
}
|
|
1903
|
+
if (bi.member === "compose")
|
|
1904
|
+
return lowerStreamCompose(lowerer, call, loc);
|
|
1662
1905
|
return null;
|
|
1663
1906
|
}
|
|
1907
|
+
/** A pipeline() argument written as a function: an async generator
|
|
1908
|
+
* function stage. */
|
|
1909
|
+
function isPipelineFunctionStage(node) {
|
|
1910
|
+
return ts.isFunctionExpression(node) || ts.isArrowFunction(node);
|
|
1911
|
+
}
|
|
1912
|
+
/** pipeline(...) with one run of function stages (pipeline.js). The run
|
|
1913
|
+
* may start the pipeline (a source function, called with `{ signal }`)
|
|
1914
|
+
* and may end it (a destination function: an async generator pumped into
|
|
1915
|
+
* a PassThrough, or an async function whose promise's value reaches the
|
|
1916
|
+
* callback or the promise). Each stage's `source` parameter is typed as
|
|
1917
|
+
* what the pipeline passes it: makeAsyncIterable answers the previous
|
|
1918
|
+
* stream itself (a Readable is async iterable) or the previous stage's
|
|
1919
|
+
* generator. */
|
|
1920
|
+
function lowerPipelineStages(lowerer, stageArgs, loc) {
|
|
1921
|
+
const first = stageArgs.findIndex(isPipelineFunctionStage);
|
|
1922
|
+
let end = first;
|
|
1923
|
+
while (end < stageArgs.length && isPipelineFunctionStage(stageArgs[end]))
|
|
1924
|
+
end++;
|
|
1925
|
+
if (stageArgs.slice(end).some(isPipelineFunctionStage)) {
|
|
1926
|
+
lowerer.noLowering("pipeline with function stages separated by streams", stageArgs[end], "one run of function stages is supported");
|
|
1927
|
+
}
|
|
1928
|
+
const source = first === 0;
|
|
1929
|
+
const destFn = end === stageArgs.length;
|
|
1930
|
+
const before = [];
|
|
1931
|
+
const after = [];
|
|
1932
|
+
try {
|
|
1933
|
+
for (const a of stageArgs.slice(0, first))
|
|
1934
|
+
before.push(lowerStreamArg(lowerer, a, "pipeline"));
|
|
1935
|
+
}
|
|
1936
|
+
catch (e) {
|
|
1937
|
+
if (e instanceof StreamArgTypeThrow)
|
|
1938
|
+
lowerer.noLowering("pipeline over this value", stageArgs[0]);
|
|
1939
|
+
throw e;
|
|
1940
|
+
}
|
|
1941
|
+
let srcT = source ? null : before[before.length - 1].type;
|
|
1942
|
+
const stages = [];
|
|
1943
|
+
let mask = 0;
|
|
1944
|
+
let dest = 0;
|
|
1945
|
+
let destPromise = null;
|
|
1946
|
+
for (let i = first; i < end; i++) {
|
|
1947
|
+
const fn = stageArgs[i];
|
|
1948
|
+
const isLast = destFn && i === end - 1;
|
|
1949
|
+
const isAsync = (fn.modifiers ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
|
|
1950
|
+
const isGen = ts.isFunctionExpression(fn) && fn.asteriskToken !== undefined;
|
|
1951
|
+
if (isLast && isGen) {
|
|
1952
|
+
// pipeline() pumps it into an object-mode PassThrough, whose
|
|
1953
|
+
// buffering decides when the pipeline finishes
|
|
1954
|
+
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) ... }");
|
|
1955
|
+
}
|
|
1956
|
+
if (!isAsync || (!isGen && !isLast)) {
|
|
1957
|
+
lowerer.noLowering(isLast
|
|
1958
|
+
? "a pipeline destination that is not an async function"
|
|
1959
|
+
: srcT === null
|
|
1960
|
+
? "a pipeline source function that is not an async generator function"
|
|
1961
|
+
: "pipeline stages that are not async generator functions", fn, "write the stage as async function* (source) { for await (const chunk of source) ... }");
|
|
1962
|
+
}
|
|
1963
|
+
const optionsAt = srcT === null ? 0 : 1;
|
|
1964
|
+
if (fn.parameters.length > optionsAt + 1) {
|
|
1965
|
+
lowerer.noLowering("pipeline stages with parameters after the options argument", fn.parameters[optionsAt + 1], "a stage takes the source and { signal }");
|
|
1966
|
+
}
|
|
1967
|
+
const lowered = lowerStageFunction(lowerer, fn, srcT);
|
|
1968
|
+
const params = lowered.closure.type.kind === "func" ? lowered.closure.type.params : [];
|
|
1969
|
+
if (params.length > optionsAt) {
|
|
1970
|
+
if (params[optionsAt].kind !== "dyn") {
|
|
1971
|
+
lowerer.noLowering("a pipeline stage's options argument with this type", fn.parameters[optionsAt], "type it as { signal: AbortSignal }");
|
|
1972
|
+
}
|
|
1973
|
+
mask |= 1 << (i - first);
|
|
1974
|
+
}
|
|
1975
|
+
stages.push(lowered.closure);
|
|
1976
|
+
if (lowered.out.kind === "promise") {
|
|
1977
|
+
dest = 2;
|
|
1978
|
+
destPromise = lowered.out;
|
|
1979
|
+
srcT = null;
|
|
1980
|
+
}
|
|
1981
|
+
else {
|
|
1982
|
+
srcT = lowered.out;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
try {
|
|
1986
|
+
for (const a of stageArgs.slice(end))
|
|
1987
|
+
after.push(lowerStreamArg(lowerer, a, "pipeline"));
|
|
1988
|
+
}
|
|
1989
|
+
catch (e) {
|
|
1990
|
+
if (e instanceof StreamArgTypeThrow)
|
|
1991
|
+
lowerer.noLowering("pipeline over this value", stageArgs[end]);
|
|
1992
|
+
throw e;
|
|
1993
|
+
}
|
|
1994
|
+
const helperArgs = [];
|
|
1995
|
+
if (dest !== 2) {
|
|
1996
|
+
// the generator pumped into the next stream or the PassThrough
|
|
1997
|
+
const lastGen = srcT;
|
|
1998
|
+
if (!fromGenChunk(lowerer, lastGen.yieldT)) {
|
|
1999
|
+
lowerer.noLowering(`a pipeline stage yielding '${lowerer.fmt(lastGen.yieldT)}'`, stageArgs[end - 1], "stage values written to a stream are strings or Buffers");
|
|
2000
|
+
}
|
|
2001
|
+
const helpers = fromGenHelpers(lowerer, lastGen, loc);
|
|
2002
|
+
if (!helpers)
|
|
2003
|
+
lowerer.noLowering("a pipeline stage with this generator type", stageArgs[end - 1]);
|
|
2004
|
+
helperArgs.push(helpers[0], helpers[1], helpers[2]);
|
|
2005
|
+
}
|
|
2006
|
+
else {
|
|
2007
|
+
const valueT = destPromise.inner;
|
|
2008
|
+
if (valueT.kind !== "void" &&
|
|
2009
|
+
!canConvertToDyn(valueT, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
2010
|
+
lowerer.noLowering(`a pipeline destination resolving to '${lowerer.fmt(valueT)}'`, stageArgs[end - 1]);
|
|
2011
|
+
}
|
|
2012
|
+
helperArgs.push(pipelineBoxHelper(lowerer, destPromise, loc));
|
|
2013
|
+
}
|
|
2014
|
+
const streams = [...before, ...after];
|
|
2015
|
+
// SCR_PIPE_* flags: bit 0 a source function, bits 1-2 the destination,
|
|
2016
|
+
// bit 3 the helpers, bit 4 the box, bit 5 the signal and abort.
|
|
2017
|
+
const flags = (source ? 1 : 0) | (dest << 1) | (dest !== 2 ? 8 : 16) | (mask !== 0 ? 32 : 0);
|
|
2018
|
+
const head = [
|
|
2019
|
+
numLit(streams.length, loc),
|
|
2020
|
+
numLit(before.length, loc),
|
|
2021
|
+
numLit(stages.length, loc),
|
|
2022
|
+
numLit(flags, loc),
|
|
2023
|
+
numLit(mask, loc),
|
|
2024
|
+
...streams,
|
|
2025
|
+
...stages,
|
|
2026
|
+
...helperArgs,
|
|
2027
|
+
];
|
|
2028
|
+
const last = destFn
|
|
2029
|
+
? { kind: "object", className: "%PassThrough" }
|
|
2030
|
+
: streams[streams.length - 1].type;
|
|
2031
|
+
if (mask === 0)
|
|
2032
|
+
return { args: head, last, dest, destPromise, wrap: (call) => call };
|
|
2033
|
+
// const ac = new AbortController(): its signal goes to the stages, and
|
|
2034
|
+
// finishImpl's ac.abort() runs through the abort closure.
|
|
2035
|
+
const ac = lowerer.declareHiddenLocal("%pipelineAbort", DYN);
|
|
2036
|
+
const acRef = { kind: "varRef", localId: ac.id, type: DYN, loc };
|
|
2037
|
+
const signal = {
|
|
2038
|
+
kind: "dynKeyGet",
|
|
2039
|
+
value: acRef,
|
|
2040
|
+
key: { kind: "strLit", value: "signal", type: STRING, loc },
|
|
2041
|
+
type: DYN,
|
|
2042
|
+
loc,
|
|
2043
|
+
};
|
|
2044
|
+
return {
|
|
2045
|
+
args: [...head, signal, pipelineAbortHelper(lowerer, acRef, loc)],
|
|
2046
|
+
last,
|
|
2047
|
+
dest,
|
|
2048
|
+
destPromise,
|
|
2049
|
+
wrap: (call) => ({
|
|
2050
|
+
kind: "seqExpr",
|
|
2051
|
+
stmts: [
|
|
2052
|
+
{
|
|
2053
|
+
kind: "varDecl",
|
|
2054
|
+
localId: ac.id,
|
|
2055
|
+
init: { kind: "libCall", fn: "fetch.abortControllerNew", args: [], type: DYN, loc },
|
|
2056
|
+
loc,
|
|
2057
|
+
},
|
|
2058
|
+
],
|
|
2059
|
+
result: call,
|
|
2060
|
+
type: call.type,
|
|
2061
|
+
loc,
|
|
2062
|
+
}),
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
/** `(p) => p` boxed: a promise destination's promise as a checked-dynamic
|
|
2066
|
+
* promise, whose payload converts when the destination settles. Interned
|
|
2067
|
+
* per promise type. */
|
|
2068
|
+
function pipelineBoxHelper(lowerer, promiseT, loc) {
|
|
2069
|
+
const key = `pipelineBox:${typeKey(promiseT)}`;
|
|
2070
|
+
let name = lowerer.valueHelpers.get(key);
|
|
2071
|
+
if (!name) {
|
|
2072
|
+
name = `%stream.pipelineBox.${lowerer.valueHelpers.size}`;
|
|
2073
|
+
lowerer.valueHelpers.set(key, name);
|
|
2074
|
+
lowerer.liftedFns.push({
|
|
2075
|
+
name,
|
|
2076
|
+
params: [{ localId: "p.0", name: "p", type: promiseT }],
|
|
2077
|
+
returnType: DYN,
|
|
2078
|
+
locals: [{ id: "p.0", name: "p", type: promiseT, mutable: false }],
|
|
2079
|
+
body: [
|
|
2080
|
+
{
|
|
2081
|
+
kind: "return",
|
|
2082
|
+
value: { kind: "dynFrom", value: varRef("p.0", promiseT, loc), type: DYN, loc },
|
|
2083
|
+
loc,
|
|
2084
|
+
},
|
|
2085
|
+
],
|
|
2086
|
+
loc,
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
return { kind: "closure", fnName: name, captures: [], type: funcOf([promiseT], DYN), loc };
|
|
2090
|
+
}
|
|
2091
|
+
/** `() => ac.abort()` over the pipeline's AbortController: an interned
|
|
2092
|
+
* lifted function takes the controller and answers the closure. */
|
|
2093
|
+
function pipelineAbortHelper(lowerer, ac, loc) {
|
|
2094
|
+
const key = "pipelineAbort";
|
|
2095
|
+
let name = lowerer.valueHelpers.get(key);
|
|
2096
|
+
const abortT = funcOf([], VOID);
|
|
2097
|
+
if (!name) {
|
|
2098
|
+
name = `%stream.pipelineAbort.${lowerer.valueHelpers.size}`;
|
|
2099
|
+
lowerer.valueHelpers.set(key, name);
|
|
2100
|
+
const acLocal = { id: "ac.0", name: "ac", type: DYN, mutable: false, boxed: true };
|
|
2101
|
+
const acRef = varRef(acLocal.id, DYN, loc);
|
|
2102
|
+
lowerer.liftedFns.push({
|
|
2103
|
+
name: `${name}.abort`,
|
|
2104
|
+
params: [],
|
|
2105
|
+
returnType: VOID,
|
|
2106
|
+
captures: [{ localId: acLocal.id, name: acLocal.name, type: DYN }],
|
|
2107
|
+
locals: [acLocal],
|
|
2108
|
+
body: [
|
|
2109
|
+
{
|
|
2110
|
+
kind: "exprStmt",
|
|
2111
|
+
expr: {
|
|
2112
|
+
kind: "dynInvoke",
|
|
2113
|
+
recv: acRef,
|
|
2114
|
+
method: "abort",
|
|
2115
|
+
calleeName: "ac.abort",
|
|
2116
|
+
args: [],
|
|
2117
|
+
type: DYN,
|
|
2118
|
+
loc,
|
|
2119
|
+
},
|
|
2120
|
+
loc,
|
|
2121
|
+
},
|
|
2122
|
+
],
|
|
2123
|
+
loc,
|
|
2124
|
+
});
|
|
2125
|
+
lowerer.liftedFns.push({
|
|
2126
|
+
name,
|
|
2127
|
+
params: [{ localId: acLocal.id, name: acLocal.name, type: DYN }],
|
|
2128
|
+
returnType: abortT,
|
|
2129
|
+
locals: [acLocal],
|
|
2130
|
+
body: [
|
|
2131
|
+
{
|
|
2132
|
+
kind: "return",
|
|
2133
|
+
value: {
|
|
2134
|
+
kind: "closure",
|
|
2135
|
+
fnName: `${name}.abort`,
|
|
2136
|
+
captures: [acLocal.id],
|
|
2137
|
+
type: abortT,
|
|
2138
|
+
loc,
|
|
2139
|
+
},
|
|
2140
|
+
loc,
|
|
2141
|
+
},
|
|
2142
|
+
],
|
|
2143
|
+
loc,
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
return { kind: "call", callee: name, args: [ac], type: abortT, loc };
|
|
2147
|
+
}
|
|
2148
|
+
/** A function stage, lowered with its `source` parameter (absent for a
|
|
2149
|
+
* source function, srcT null) typed as what the pipeline passes (a
|
|
2150
|
+
* stream or the previous stage's generator). The source may only head
|
|
2151
|
+
* `for await` loops. Answers the closure and what it returns: an async
|
|
2152
|
+
* generator, or a promise for a destination async function. */
|
|
2153
|
+
function lowerStageFunction(lowerer, fn, srcT) {
|
|
2154
|
+
const param = srcT === null ? undefined : fn.parameters[0];
|
|
2155
|
+
const symbol = param && ts.isIdentifier(param.name)
|
|
2156
|
+
? lowerer.checker.getSymbolAtLocation(param.name)
|
|
2157
|
+
: undefined;
|
|
2158
|
+
if (param && !symbol) {
|
|
2159
|
+
lowerer.noLowering("pipeline stage parameters that are patterns", param, "name the source parameter");
|
|
2160
|
+
}
|
|
2161
|
+
if (symbol && fn.body) {
|
|
2162
|
+
const visit = (node) => {
|
|
2163
|
+
if (ts.isIdentifier(node) &&
|
|
2164
|
+
node !== param.name &&
|
|
2165
|
+
lowerer.checker.getSymbolAtLocation(node) === symbol) {
|
|
2166
|
+
const parent = node.parent;
|
|
2167
|
+
if (!(parent &&
|
|
2168
|
+
ts.isForOfStatement(parent) &&
|
|
2169
|
+
parent.awaitModifier &&
|
|
2170
|
+
parent.expression === node)) {
|
|
2171
|
+
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)");
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
ts.forEachChild(node, visit);
|
|
2175
|
+
};
|
|
2176
|
+
visit(fn.body);
|
|
2177
|
+
}
|
|
2178
|
+
if (symbol)
|
|
2179
|
+
lowerer.stageSourceTypes.set(symbol, srcT);
|
|
2180
|
+
try {
|
|
2181
|
+
const closure = lowerer.lowerExpr(fn);
|
|
2182
|
+
const out = closure.type.kind === "func" ? closure.type.ret : null;
|
|
2183
|
+
if (!(out?.kind === "generator" && out.async) && out?.kind !== "promise") {
|
|
2184
|
+
lowerer.noLowering("a pipeline stage that does not return an async generator", fn);
|
|
2185
|
+
}
|
|
2186
|
+
return { closure, out: out };
|
|
2187
|
+
}
|
|
2188
|
+
finally {
|
|
2189
|
+
if (symbol)
|
|
2190
|
+
lowerer.stageSourceTypes.delete(symbol);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
/** `stream.compose(...streams)` over stream instances: a Duplex writing
|
|
2194
|
+
* to the first stream and reading from the last (scr_stream_compose). The
|
|
2195
|
+
* classes fix which positions can be readable and writable; a stream in
|
|
2196
|
+
* the wrong position, a single Readable or Writable (Duplex.from wraps
|
|
2197
|
+
* those), and functions, iterables or web streams have no lowering. */
|
|
2198
|
+
function lowerStreamCompose(lowerer, call, loc) {
|
|
2199
|
+
const args = call.arguments;
|
|
2200
|
+
const duplex = { kind: "object", className: "%Duplex" };
|
|
2201
|
+
if (args.some((a) => ts.isSpreadElement(a))) {
|
|
2202
|
+
lowerer.noLowering("compose with spread arguments", call, "pass the streams directly");
|
|
2203
|
+
}
|
|
2204
|
+
if (args.length === 0) {
|
|
2205
|
+
return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "streams" argument must be specified', duplex, loc);
|
|
2206
|
+
}
|
|
2207
|
+
let streams;
|
|
2208
|
+
try {
|
|
2209
|
+
streams = args.map((a) => lowerStreamArg(lowerer, a, "compose"));
|
|
2210
|
+
}
|
|
2211
|
+
catch (e) {
|
|
2212
|
+
if (e instanceof StreamArgTypeThrow)
|
|
2213
|
+
return e.expr;
|
|
2214
|
+
throw e;
|
|
2215
|
+
}
|
|
2216
|
+
const sides = streams.map((s) => s.type.kind === "object" ? streamSidesOf(lowerer, lowerer.classes.get(s.type.className)) : null);
|
|
2217
|
+
if (streams.length === 1) {
|
|
2218
|
+
// Duplex.from answers a duplex itself.
|
|
2219
|
+
if (sides[0] === "rw")
|
|
2220
|
+
return streams[0];
|
|
2221
|
+
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");
|
|
2222
|
+
}
|
|
2223
|
+
for (let i = 0; i < streams.length; i++) {
|
|
2224
|
+
const s = sides[i];
|
|
2225
|
+
const want = i < streams.length - 1 && s === "w" ? "readable" : i > 0 && s === "r" ? "writable" : null;
|
|
2226
|
+
if (want) {
|
|
2227
|
+
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`);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
return {
|
|
2231
|
+
kind: "libCall",
|
|
2232
|
+
fn: "stream.compose",
|
|
2233
|
+
args: [numLit(streams.length, loc), ...streams],
|
|
2234
|
+
type: duplex,
|
|
2235
|
+
loc,
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
1664
2238
|
/* ── the method surface ───────────────────────────────────────────────── */
|
|
2239
|
+
/* ── the Readable operators ──────────────────────────────────────────── */
|
|
2240
|
+
/** The Readable operators (scr_stream_ops.c — Node's operators.js). */
|
|
2241
|
+
export const STREAM_OPERATORS = new Set([
|
|
2242
|
+
"map",
|
|
2243
|
+
"filter",
|
|
2244
|
+
"flatMap",
|
|
2245
|
+
"drop",
|
|
2246
|
+
"take",
|
|
2247
|
+
"toArray",
|
|
2248
|
+
"forEach",
|
|
2249
|
+
"some",
|
|
2250
|
+
"every",
|
|
2251
|
+
"find",
|
|
2252
|
+
"reduce",
|
|
2253
|
+
]);
|
|
2254
|
+
/** An operator callback as a checked-dynamic function value. Callbacks
|
|
2255
|
+
* that declare the options argument ({ signal }) are refused: the
|
|
2256
|
+
* AbortSignal Node passes there has no representation. map and flatMap
|
|
2257
|
+
* callbacks must produce strings or Buffers (flatMap: arrays of them, or
|
|
2258
|
+
* strings) — or checked-dynamic values, which the runtime checks. */
|
|
2259
|
+
function lowerOperatorCallback(lowerer, node, member, maxParams) {
|
|
2260
|
+
const loc = locOf(node);
|
|
2261
|
+
const optionsParam = (at) => lowerer.noLowering(`${member} callbacks that declare the options argument`, at, "the { signal } argument has no lowering — take only the chunk");
|
|
2262
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
2263
|
+
node.parameters.length > maxParams) {
|
|
2264
|
+
optionsParam(node.parameters[maxParams]);
|
|
2265
|
+
}
|
|
2266
|
+
const v = lowerer.lowerExpr(node);
|
|
2267
|
+
if (v.type.kind === "dyn")
|
|
2268
|
+
return v;
|
|
2269
|
+
if (v.type.kind !== "func" &&
|
|
2270
|
+
isJsSourceFile(node.getSourceFile()) &&
|
|
2271
|
+
lowerer.dynConvertible(v.type)) {
|
|
2272
|
+
// JavaScript passes any value; Node's validateFunction throws.
|
|
2273
|
+
return { kind: "dynFrom", value: v, type: DYN, loc };
|
|
2274
|
+
}
|
|
2275
|
+
if (v.type.kind !== "func") {
|
|
2276
|
+
lowerer.noLowering(`${member} with a '${lowerer.fmt(v.type)}' callback`, node, "pass a function");
|
|
2277
|
+
}
|
|
2278
|
+
if (v.type.params.length > maxParams)
|
|
2279
|
+
optionsParam(node);
|
|
2280
|
+
if (member === "map" || member === "flatMap") {
|
|
2281
|
+
const ret = v.type.ret.kind === "promise" ? v.type.ret.inner : v.type.ret;
|
|
2282
|
+
const chunk = (t) => t.kind === "string" || t.kind === "dyn" || (t.kind === "bytes" && t.elem === "u8");
|
|
2283
|
+
const ok = member === "map"
|
|
2284
|
+
? chunk(ret)
|
|
2285
|
+
: ret.kind === "dyn" || ret.kind === "string" || (ret.kind === "array" && chunk(ret.elem));
|
|
2286
|
+
if (!ok) {
|
|
2287
|
+
lowerer.noLowering(`${member} callbacks that return '${lowerer.fmt(ret)}'`, node, member === "map"
|
|
2288
|
+
? "map results are stream chunks: strings or Buffers (object-mode streams of other values are not lowered)"
|
|
2289
|
+
: "flatMap results are arrays of strings or Buffers, or strings");
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
const getRecord = (id) => lowerer.shapes.get(id);
|
|
2293
|
+
const getUnion = (id) => lowerer.unions.get(id);
|
|
2294
|
+
if (!canBoxFuncIntoDyn(v.type, getRecord, getUnion)) {
|
|
2295
|
+
lowerer.noLowering(`${member} with this callback`, node, "the callback's parameter and result types must cross the checked-dynamic boundary");
|
|
2296
|
+
}
|
|
2297
|
+
return { kind: "dynFrom", value: v, type: DYN, loc };
|
|
2298
|
+
}
|
|
2299
|
+
/** An operator's options (or reduce's initial value): an object literal
|
|
2300
|
+
* becomes a checked-dynamic object, checked-dynamic values pass through,
|
|
2301
|
+
* absent arguments are undefined. */
|
|
2302
|
+
function lowerOperatorValue(lowerer, node, what, loc, literalObject) {
|
|
2303
|
+
if (node === undefined)
|
|
2304
|
+
return dynUndefinedExpr(loc);
|
|
2305
|
+
if (literalObject && ts.isObjectLiteralExpression(node))
|
|
2306
|
+
return lowerDynObjectLiteral(lowerer, node);
|
|
2307
|
+
const v = lowerer.lowerExpr(node);
|
|
2308
|
+
if (v.type.kind === "dyn")
|
|
2309
|
+
return v;
|
|
2310
|
+
if (literalObject && v.type.kind !== "undefinedT" && v.type.kind !== "nullT") {
|
|
2311
|
+
lowerer.noLowering(`${what} that are not an object literal`, node, "write the options inline, e.g. { concurrency: 2 }");
|
|
2312
|
+
}
|
|
2313
|
+
if (!lowerer.dynConvertible(v.type)) {
|
|
2314
|
+
lowerer.noLowering(`${what} of type '${lowerer.fmt(v.type)}'`, node);
|
|
2315
|
+
}
|
|
2316
|
+
return { kind: "dynFrom", value: v, type: DYN, loc: locOf(node) };
|
|
2317
|
+
}
|
|
2318
|
+
function lowerStreamOperator(lowerer, call, access, member) {
|
|
2319
|
+
const loc = locOf(call);
|
|
2320
|
+
const args = call.arguments;
|
|
2321
|
+
const recv = lowerer.lowerExpr(access.expression);
|
|
2322
|
+
const readable = { kind: "object", className: "%Readable" };
|
|
2323
|
+
const opts = (i) => lowerOperatorValue(lowerer, args[i], `${member} options`, loc, true);
|
|
2324
|
+
const fnArg = (maxParams) => {
|
|
2325
|
+
if (args[0] === undefined)
|
|
2326
|
+
return dynUndefinedExpr(loc);
|
|
2327
|
+
return lowerOperatorCallback(lowerer, args[0], member, maxParams);
|
|
2328
|
+
};
|
|
2329
|
+
const lib = (fn, a, type) => ({
|
|
2330
|
+
kind: "libCall",
|
|
2331
|
+
fn: fn,
|
|
2332
|
+
args: a,
|
|
2333
|
+
type,
|
|
2334
|
+
loc,
|
|
2335
|
+
});
|
|
2336
|
+
switch (member) {
|
|
2337
|
+
case "map":
|
|
2338
|
+
case "filter":
|
|
2339
|
+
case "flatMap": {
|
|
2340
|
+
const fn = fnArg(1);
|
|
2341
|
+
const fnName = member === "map"
|
|
2342
|
+
? "readable.opMap"
|
|
2343
|
+
: member === "filter"
|
|
2344
|
+
? "readable.opFilter"
|
|
2345
|
+
: "readable.opFlatMap";
|
|
2346
|
+
return lib(fnName, [recv, fn, opts(1)], readable);
|
|
2347
|
+
}
|
|
2348
|
+
case "drop":
|
|
2349
|
+
case "take": {
|
|
2350
|
+
const n = lowerOperatorValue(lowerer, args[0], `${member}'s count`, loc, false);
|
|
2351
|
+
return lib(member === "drop" ? "readable.opDrop" : "readable.opTake", [recv, n, opts(1)], readable);
|
|
2352
|
+
}
|
|
2353
|
+
case "toArray":
|
|
2354
|
+
return lib("readable.opToArray", [recv, opts(0)], { kind: "promise", inner: DYN });
|
|
2355
|
+
case "forEach":
|
|
2356
|
+
return lib("readable.opForEach", [recv, fnArg(1), opts(1)], { kind: "promise", inner: VOID });
|
|
2357
|
+
case "some":
|
|
2358
|
+
case "every": {
|
|
2359
|
+
const fn = fnArg(1);
|
|
2360
|
+
return lib(member === "some" ? "readable.opSome" : "readable.opEvery", [recv, fn, opts(1)], {
|
|
2361
|
+
kind: "promise",
|
|
2362
|
+
inner: BOOL,
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
case "find": {
|
|
2366
|
+
const t = lowerer.typeOf(call);
|
|
2367
|
+
const inner = lowerer.checker.getTypeArguments(t)[0];
|
|
2368
|
+
if (inner && !(inner.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))) {
|
|
2369
|
+
lowerer.noLowering("find with a type-guard callback", call, "the result is a checked-dynamic value — use a boolean predicate and narrow the result");
|
|
2370
|
+
}
|
|
2371
|
+
return lib("readable.opFind", [recv, fnArg(1), opts(1)], { kind: "promise", inner: DYN });
|
|
2372
|
+
}
|
|
2373
|
+
case "reduce": {
|
|
2374
|
+
const t = lowerer.typeOf(call);
|
|
2375
|
+
const resultTs = lowerer.checker.getTypeArguments(t)[0];
|
|
2376
|
+
let kind = 0;
|
|
2377
|
+
let inner = DYN;
|
|
2378
|
+
if (resultTs && !(resultTs.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))) {
|
|
2379
|
+
const mapped = lowerer.mapTypeOf(resultTs);
|
|
2380
|
+
if (mapped?.kind === "f64") {
|
|
2381
|
+
kind = 1;
|
|
2382
|
+
inner = F64;
|
|
2383
|
+
}
|
|
2384
|
+
else if (mapped?.kind === "bool") {
|
|
2385
|
+
kind = 2;
|
|
2386
|
+
inner = BOOL;
|
|
2387
|
+
}
|
|
2388
|
+
else if (mapped?.kind === "string") {
|
|
2389
|
+
kind = 3;
|
|
2390
|
+
inner = STRING;
|
|
2391
|
+
}
|
|
2392
|
+
else if (mapped?.kind !== "dyn") {
|
|
2393
|
+
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");
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
const fn = fnArg(2);
|
|
2397
|
+
const init = lowerOperatorValue(lowerer, args[1], "reduce's initial value", loc, false);
|
|
2398
|
+
return lib("readable.opReduce", [recv, fn, init, boolLit(args.length >= 2, loc), opts(2), numLit(kind, loc)], { kind: "promise", inner });
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
throw new InternalCompilerError(`unknown stream operator ${member}`);
|
|
2402
|
+
}
|
|
2403
|
+
/** The literal 'buffer' encoding on write()/end(): Node 24 takes it for a
|
|
2404
|
+
* Buffer chunk and throws ERR_UNKNOWN_ENCODING for a string chunk. */
|
|
2405
|
+
function isBufferEncoding(lowerer, arg) {
|
|
2406
|
+
if (arg === undefined)
|
|
2407
|
+
return false;
|
|
2408
|
+
const t = lowerer.typeOf(arg);
|
|
2409
|
+
return t.isStringLiteralType() && t.value === "buffer";
|
|
2410
|
+
}
|
|
1665
2411
|
/** The one supported encoding argument: utf8 (Node's default), as a
|
|
1666
2412
|
* compile-time literal or absent. */
|
|
1667
2413
|
function checkUtf8Encoding(lowerer, member, arg) {
|
|
@@ -1676,6 +2422,11 @@ function checkUtf8Encoding(lowerer, member, arg) {
|
|
|
1676
2422
|
* for members this spoke does not own. */
|
|
1677
2423
|
export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
1678
2424
|
const member = access.name.text;
|
|
2425
|
+
if (STREAM_OPERATORS.has(member)) {
|
|
2426
|
+
const opSides = streamSidesOf(lowerer, info);
|
|
2427
|
+
if (opSides === "r" || opSides === "rw")
|
|
2428
|
+
return lowerStreamOperator(lowerer, call, access, member);
|
|
2429
|
+
}
|
|
1679
2430
|
if (!STREAM_API_MEMBERS.has(member))
|
|
1680
2431
|
return null;
|
|
1681
2432
|
const sides = streamSidesOf(lowerer, info);
|
|
@@ -1968,7 +2719,12 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
|
1968
2719
|
// Disambiguate (chunk, cb?) vs (chunk, encoding, cb?) by the second
|
|
1969
2720
|
// argument's static type.
|
|
1970
2721
|
let cbArg;
|
|
1971
|
-
if (args.length
|
|
2722
|
+
if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
|
|
2723
|
+
if (kind !== "bytes")
|
|
2724
|
+
return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", BOOL, loc);
|
|
2725
|
+
cbArg = args[2];
|
|
2726
|
+
}
|
|
2727
|
+
else if (args.length === 2) {
|
|
1972
2728
|
const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
|
|
1973
2729
|
if (t?.kind === "string")
|
|
1974
2730
|
checkUtf8Encoding(lowerer, "write", args[1]);
|
|
@@ -2007,6 +2763,17 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
|
|
|
2007
2763
|
else
|
|
2008
2764
|
chunkNode = args[0];
|
|
2009
2765
|
}
|
|
2766
|
+
else if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
|
|
2767
|
+
chunkNode = args[0];
|
|
2768
|
+
const endKind = chunkKind(args[0]);
|
|
2769
|
+
if (endKind === "string") {
|
|
2770
|
+
const endT = lowerer.mapTypeOf(lowerer.typeOf(call)) ?? DYN;
|
|
2771
|
+
return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", endT, loc);
|
|
2772
|
+
}
|
|
2773
|
+
if (endKind !== "bytes")
|
|
2774
|
+
checkUtf8Encoding(lowerer, "end", args[1]);
|
|
2775
|
+
cbArg = args[2];
|
|
2776
|
+
}
|
|
2010
2777
|
else if (args.length === 2) {
|
|
2011
2778
|
chunkNode = args[0];
|
|
2012
2779
|
const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
|