@scriptc/compiler 0.3.5 → 0.3.6

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.
Files changed (181) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +278 -32
  2. package/dist/backend/llvm/dyn.js +31 -1
  3. package/dist/backend/llvm/dyn.js.map +1 -1
  4. package/dist/backend/llvm/emitter.d.ts +45 -1
  5. package/dist/backend/llvm/emitter.js +412 -104
  6. package/dist/backend/llvm/emitter.js.map +1 -1
  7. package/dist/backend/llvm/expr-dispatch.js +1 -0
  8. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  9. package/dist/backend/llvm/expr-dynamic.js +25 -1
  10. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  11. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  12. package/dist/backend/llvm/expr-primitives.js +11 -0
  13. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  14. package/dist/backend/llvm/lib-dispatch.js +28 -1
  15. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  16. package/dist/backend/llvm/lib-filesystem.js +61 -1
  17. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  18. package/dist/backend/llvm/lib-network.js +21 -3
  19. package/dist/backend/llvm/lib-network.js.map +1 -1
  20. package/dist/backend/llvm/lib-process.js +10 -0
  21. package/dist/backend/llvm/lib-process.js.map +1 -1
  22. package/dist/backend/llvm/lib-shared.js +43 -0
  23. package/dist/backend/llvm/lib-shared.js.map +1 -1
  24. package/dist/backend/llvm/lib-test.js +16 -3
  25. package/dist/backend/llvm/lib-test.js.map +1 -1
  26. package/dist/backend/llvm/nullable-unions.d.ts +6 -3
  27. package/dist/backend/llvm/nullable-unions.js +2 -0
  28. package/dist/backend/llvm/nullable-unions.js.map +1 -1
  29. package/dist/backend/llvm/record-results.d.ts +1 -1
  30. package/dist/backend/llvm/record-results.js +2 -2
  31. package/dist/backend/llvm/record-results.js.map +1 -1
  32. package/dist/backend/llvm/reference-writes.js +1 -0
  33. package/dist/backend/llvm/reference-writes.js.map +1 -1
  34. package/dist/backend/llvm/shapes.d.ts +3 -0
  35. package/dist/backend/llvm/shapes.js +5 -0
  36. package/dist/backend/llvm/shapes.js.map +1 -1
  37. package/dist/backend/llvm/speculative-integers.d.ts +74 -0
  38. package/dist/backend/llvm/speculative-integers.js +571 -0
  39. package/dist/backend/llvm/speculative-integers.js.map +1 -0
  40. package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
  41. package/dist/backend/llvm/speculative-integers.test.js +148 -0
  42. package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
  43. package/dist/backend/may-throw.js +2 -0
  44. package/dist/backend/may-throw.js.map +1 -1
  45. package/dist/backend/native/executable.js +3 -0
  46. package/dist/backend/native/executable.js.map +1 -1
  47. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  48. package/dist/backend/native/runtime-inputs.js +1 -0
  49. package/dist/backend/native/runtime-inputs.js.map +1 -1
  50. package/dist/backend/runtime-pack.d.ts +7 -3
  51. package/dist/backend/runtime-pack.js +12 -6
  52. package/dist/backend/runtime-pack.js.map +1 -1
  53. package/dist/backend/runtime-pack.test.js +15 -6
  54. package/dist/backend/runtime-pack.test.js.map +1 -1
  55. package/dist/contracts/check.js +1 -0
  56. package/dist/contracts/check.js.map +1 -1
  57. package/dist/coverage/surface-manifest.js +3 -3
  58. package/dist/coverage/surface-manifest.js.map +1 -1
  59. package/dist/diagnostics/diagnostic.d.ts +1 -1
  60. package/dist/diagnostics/diagnostic.js +6 -2
  61. package/dist/diagnostics/diagnostic.js.map +1 -1
  62. package/dist/frontend/lowering/builtin-calls.js +10 -0
  63. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  64. package/dist/frontend/lowering/builtins/callable-aliases.js +31 -3
  65. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
  66. package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
  67. package/dist/frontend/lowering/builtins/compression.js +145 -30
  68. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  69. package/dist/frontend/lowering/builtins/crypto.js +12 -1
  70. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  71. package/dist/frontend/lowering/builtins/errors.js +5 -3
  72. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  73. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +4 -0
  74. package/dist/frontend/lowering/builtins/filesystem-calls.js +11 -0
  75. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  76. package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
  77. package/dist/frontend/lowering/builtins/filesystem.js +139 -2
  78. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  79. package/dist/frontend/lowering/builtins/hash-stream.d.ts +12 -0
  80. package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
  81. package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
  82. package/dist/frontend/lowering/builtins/module-calls.js +13 -3
  83. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  84. package/dist/frontend/lowering/builtins/process.js +9 -2
  85. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  86. package/dist/frontend/lowering/builtins/readline.d.ts +45 -13
  87. package/dist/frontend/lowering/builtins/readline.js +812 -47
  88. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  89. package/dist/frontend/lowering/builtins/workers.d.ts +4 -0
  90. package/dist/frontend/lowering/builtins/workers.js +58 -0
  91. package/dist/frontend/lowering/builtins/workers.js.map +1 -1
  92. package/dist/frontend/lowering/class-protocols.d.ts +55 -0
  93. package/dist/frontend/lowering/class-protocols.js +735 -0
  94. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  95. package/dist/frontend/lowering/containers/array-from-async.d.ts +18 -0
  96. package/dist/frontend/lowering/containers/array-from-async.js +282 -0
  97. package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
  98. package/dist/frontend/lowering/containers/collection-grouping.js +2 -1
  99. package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
  100. package/dist/frontend/lowering/containers/collection-methods.js +27 -23
  101. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  102. package/dist/frontend/lowering/divergences.js +188 -15
  103. package/dist/frontend/lowering/divergences.js.map +1 -1
  104. package/dist/frontend/lowering/lower-calls.js +71 -22
  105. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  106. package/dist/frontend/lowering/lower-classes.js +39 -1
  107. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  108. package/dist/frontend/lowering/lower-event-emitter.js +10 -1
  109. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  110. package/dist/frontend/lowering/lower-exprs.js +107 -13
  111. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  112. package/dist/frontend/lowering/lower-inspect.js +23 -3
  113. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  114. package/dist/frontend/lowering/lower-mock.d.ts +11 -1
  115. package/dist/frontend/lowering/lower-mock.js +377 -61
  116. package/dist/frontend/lowering/lower-mock.js.map +1 -1
  117. package/dist/frontend/lowering/lower-modules.js +1 -0
  118. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  119. package/dist/frontend/lowering/lower-server.js +161 -16
  120. package/dist/frontend/lowering/lower-server.js.map +1 -1
  121. package/dist/frontend/lowering/lower-stmts.js +48 -7
  122. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  123. package/dist/frontend/lowering/lower-stream.d.ts +1 -3
  124. package/dist/frontend/lowering/lower-stream.js +317 -20
  125. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  126. package/dist/frontend/lowering/lower-test.js +147 -48
  127. package/dist/frontend/lowering/lower-test.js.map +1 -1
  128. package/dist/frontend/lowering/lowerer.d.ts +10 -0
  129. package/dist/frontend/lowering/lowerer.js +8 -0
  130. package/dist/frontend/lowering/lowerer.js.map +1 -1
  131. package/dist/frontend/lowering/null-prototype.d.ts +13 -0
  132. package/dist/frontend/lowering/null-prototype.js +33 -0
  133. package/dist/frontend/lowering/null-prototype.js.map +1 -0
  134. package/dist/frontend/lowering/surfaces.d.ts +3 -3
  135. package/dist/frontend/lowering/surfaces.js +27 -5
  136. package/dist/frontend/lowering/surfaces.js.map +1 -1
  137. package/dist/frontend/mock-shapes.d.ts +5 -0
  138. package/dist/frontend/mock-shapes.js +27 -2
  139. package/dist/frontend/mock-shapes.js.map +1 -1
  140. package/dist/frontend/program.js +5 -4
  141. package/dist/frontend/program.js.map +1 -1
  142. package/dist/frontend/type-mapper.js +95 -4
  143. package/dist/frontend/type-mapper.js.map +1 -1
  144. package/dist/index.js +18 -8
  145. package/dist/index.js.map +1 -1
  146. package/dist/ir/builtin-effects.js +36 -0
  147. package/dist/ir/builtin-effects.js.map +1 -1
  148. package/dist/ir/builtin-signatures.d.ts +1 -1
  149. package/dist/ir/builtin-signatures.js +167 -6
  150. package/dist/ir/builtin-signatures.js.map +1 -1
  151. package/dist/ir/function-references.test.js +1 -0
  152. package/dist/ir/function-references.test.js.map +1 -1
  153. package/dist/ir/int32-slots.js +22 -0
  154. package/dist/ir/int32-slots.js.map +1 -1
  155. package/dist/ir/int32-slots.test.js +28 -0
  156. package/dist/ir/int32-slots.test.js.map +1 -1
  157. package/dist/ir/integer-loop-facts.d.ts +14 -6
  158. package/dist/ir/integer-loop-facts.js +119 -35
  159. package/dist/ir/integer-loop-facts.js.map +1 -1
  160. package/dist/ir/integer-ranges.js +1 -5
  161. package/dist/ir/integer-ranges.js.map +1 -1
  162. package/dist/ir/integer-ranges.test.js +60 -0
  163. package/dist/ir/integer-ranges.test.js.map +1 -1
  164. package/dist/ir/ir.d.ts +13 -0
  165. package/dist/ir/ir.js +4 -0
  166. package/dist/ir/ir.js.map +1 -1
  167. package/dist/ir/runtime-features.d.ts +3 -1
  168. package/dist/ir/runtime-features.js +96 -6
  169. package/dist/ir/runtime-features.js.map +1 -1
  170. package/dist/ir/runtime-features.test.js +62 -0
  171. package/dist/ir/runtime-features.test.js.map +1 -1
  172. package/dist/ir/traverse.js +4 -0
  173. package/dist/ir/traverse.js.map +1 -1
  174. package/dist/ir/validate.js +45 -3
  175. package/dist/ir/validate.js.map +1 -1
  176. package/dist/ir/validate.test.js +38 -0
  177. package/dist/ir/validate.test.js.map +1 -1
  178. package/dist/library/ir-policy.js +5 -0
  179. package/dist/library/ir-policy.js.map +1 -1
  180. package/package.json +20 -20
  181. package/surface-manifest.json +31 -19
@@ -1,6 +1,6 @@
1
1
  import * as ts from "../ts7/adapter.js";
2
2
  import type { Lowerer } from "./lowerer.js";
3
- import type { ClassInfo } from "./lower-classes.js";
3
+ import { type ClassInfo } from "./lower-classes.js";
4
4
  import { type IrExpr, type IrStmt, type IrType, type SrcLoc } from "../../ir/ir.js";
5
5
  /** The stream sides of a receiver class: the nearest stream-class
6
6
  * ancestor's, or null off the stream hierarchy. */
@@ -86,8 +86,6 @@ export declare function lowerStreamModuleCall(lowerer: Lowerer, call: ts.CallExp
86
86
  }, loc: SrcLoc): IrExpr | null;
87
87
  /** The Readable operators (scr_stream_ops.c — Node's operators.js). */
88
88
  export declare const STREAM_OPERATORS: ReadonlySet<string>;
89
- /** `recv.<member>(...)` over a stream-rooted receiver. Returns null only
90
- * for members this spoke does not own. */
91
89
  export declare function lowerStreamMethodCall(lowerer: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression, info: ClassInfo): IrExpr | null;
92
90
  export declare function lowerStreamStateProperty(lowerer: Lowerer, expr: ts.PropertyAccessExpression): IrExpr | null;
93
91
  /** Property reads on stream-rooted receivers (`r.readableEnded`,
@@ -1,4 +1,5 @@
1
1
  import { nodeThrowExpr, boolLit, numLit, strLit } from "../../ir/build.js";
2
+ import { hashStreamOf, isHashValueType } from "./builtins/hash-stream.js";
2
3
  import { InternalCompilerError } from "../../errors.js";
3
4
  /* The node:stream lowering (the spoke-module pattern, like
4
5
  * lower-event-emitter.ts): construction of the five runtime stream classes
@@ -30,6 +31,7 @@ import { InternalCompilerError } from "../../errors.js";
30
31
  * its Node signature (the emitter listener rule). */
31
32
  import * as ts from "../ts7/adapter.js";
32
33
  import { dynFallbackType } from "./lowerer.js";
34
+ import { accessorCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, } from "./lower-classes.js";
33
35
  import { isJsSourceFile, locOf } from "../program.js";
34
36
  import { newFnCtx, own } from "./lowerer.js";
35
37
  import { appendImplicitUndefinedReturn } from "./function-returns.js";
@@ -161,6 +163,7 @@ export const STREAM_FORCED_EVENT_NAMES = new Set([
161
163
  "unpipe",
162
164
  "open",
163
165
  "ready",
166
+ "keypress",
164
167
  ]);
165
168
  /** The per-base FORCED event tuples (runtime-emitted payloads): consulted
166
169
  * by the emitter spoke BEFORE the program-global table, so a stream's
@@ -181,6 +184,8 @@ export function streamForcedTuple(lowerer, info, name) {
181
184
  resume: [],
182
185
  open: [F64],
183
186
  ready: [],
187
+ // readline.emitKeypressEvents' (str, key), as checked-dynamic values
188
+ keypress: [DYN, DYN],
184
189
  };
185
190
  const writable = {
186
191
  open: [F64],
@@ -1191,21 +1196,66 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1191
1196
  const single = typedElem(srcT);
1192
1197
  const elem = srcT?.kind === "array" ? typedElem(srcT.elem) : null;
1193
1198
  const opts = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
1194
- if (srcNode && srcT?.kind === "generator" && opts && fromGenChunk(lowerer, srcT.yieldT)) {
1199
+ // A class whose [Symbol.iterator]() or [Symbol.asyncIterator]() is a
1200
+ // generator method: from.js calls the method when the stream is built,
1201
+ // then reads the generator like any other.
1202
+ const genMethod = srcT?.kind === "object" ? classGeneratorMethodOf(lowerer, srcT) : null;
1203
+ const genT = srcT?.kind === "generator" ? srcT : (genMethod?.gen ?? null);
1204
+ if (srcNode && genT && opts && fromGenChunk(lowerer, genT.yieldT)) {
1195
1205
  // A compiled generator: the runtime pulls it through interned helpers.
1196
- const gen = lowerer.lowerExpr(srcNode);
1197
- const helpers = fromGenHelpers(lowerer, srcT, loc);
1206
+ const recv = lowerer.lowerExpr(srcNode);
1207
+ const gen = genMethod && srcT?.kind === "object"
1208
+ ? accessorCall(lowerer, srcT.className, genMethod.method, recv, [], genT, loc)
1209
+ : recv;
1210
+ const helpers = fromGenHelpers(lowerer, genT, loc);
1198
1211
  if (helpers) {
1199
1212
  const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
1200
1213
  return {
1201
1214
  kind: "libCall",
1202
- fn: srcT.async ? "readable.fromAsyncGen" : "readable.fromGen",
1215
+ fn: genT.async ? "readable.fromAsyncGen" : "readable.fromGen",
1203
1216
  args: [gen, ...helpers, numLit(opts.flags, loc), hwm],
1204
1217
  type,
1205
1218
  loc,
1206
1219
  };
1207
1220
  }
1208
1221
  }
1222
+ // from.js prefers Symbol.asyncIterator: a class declaring one takes the
1223
+ // async route.
1224
+ const asyncOpen = srcT?.kind === "object" &&
1225
+ lowerer.classes.has(srcT.className) &&
1226
+ lowerer.findMethodOn(lowerer.classes.get(srcT.className), "sym:asyncIterator") !== null;
1227
+ const cit = srcT?.kind === "object" && !asyncOpen ? classIteratorOf(lowerer, srcT) : null;
1228
+ if (srcNode && cit && opts && fromGenChunk(lowerer, cit.valueT)) {
1229
+ // A class iterable: from.js takes the iterator when the stream is
1230
+ // built (the typed [Symbol.iterator]() call here), and the runtime
1231
+ // pulls it through a checked-dynamic { next } object. Class iterators
1232
+ // declare no return() or throw(), so destroy calls neither.
1233
+ const recv = lowerer.lowerExpr(srcNode);
1234
+ const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
1235
+ return {
1236
+ kind: "libCall",
1237
+ fn: "readable.fromIter",
1238
+ args: [
1239
+ classIteratorObject(lowerer, cit, classIteratorOpenCall(lowerer, cit, recv, loc), loc),
1240
+ numLit(opts.flags, loc),
1241
+ hwm,
1242
+ ],
1243
+ type,
1244
+ loc,
1245
+ };
1246
+ }
1247
+ const acit = srcT?.kind === "object" && asyncOpen ? classAsyncIteratorOf(lowerer, srcT) : null;
1248
+ if (srcNode && acit && opts && fromGenChunk(lowerer, acit.valueT)) {
1249
+ const recv = lowerer.lowerExpr(srcNode);
1250
+ const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
1251
+ return {
1252
+ kind: "libCall",
1253
+ fn: "readable.fromAsyncIter",
1254
+ args: [classAsyncIteratorObject(lowerer, acit, recv, loc), numLit(opts.flags, loc), hwm],
1255
+ type,
1256
+ loc,
1257
+ };
1258
+ }
1209
1259
  if (srcNode && (single || elem) && opts) {
1210
1260
  const v = lowerer.lowerExpr(srcNode);
1211
1261
  const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
@@ -1222,6 +1272,7 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1222
1272
  };
1223
1273
  }
1224
1274
  const anySrc = srcT?.kind === "dyn" ||
1275
+ (srcT?.kind === "set" && typedElem(srcT.elem) !== null) ||
1225
1276
  (srcNode !== undefined &&
1226
1277
  srcT === null &&
1227
1278
  (lowerer.typeOf(srcNode).flags & ts.TypeFlags.Any) !== 0);
@@ -1235,7 +1286,7 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1235
1286
  if (srcNode && (single || elem)) {
1236
1287
  lowerer.noLowering("Readable.from with these options", optsNode, "an object literal with 'objectMode' (true or false) and a number 'highWaterMark' is supported");
1237
1288
  }
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");
1289
+ lowerer.noLowering(`Readable.from over a '${srcT ? lowerer.fmt(srcT) : "?"}' source`, srcNode ?? call, "the supported sources are a string or Buffer, and arrays, Sets, generators and class iterables of strings or Buffers");
1239
1290
  }
1240
1291
  /** Whether a generator's yields are stream chunks: strings, Buffers, a
1241
1292
  * union of them (null included: the runtime destroys the stream with
@@ -1363,6 +1414,210 @@ function fromGenHelpers(lowerer, gen, loc) {
1363
1414
  define("throw", [g, e], DYN, viaRecord("throw"), [r]),
1364
1415
  ];
1365
1416
  }
1417
+ /** `{ next() { const r = it.next(); return { value: r.value, done: r.done }; } }`
1418
+ * over a class iterator `it`, as a checked-dynamic object: an interned
1419
+ * lifted function per iterator class takes the iterator and answers the
1420
+ * object, whose `next` closure captures it. */
1421
+ function classIteratorObject(lowerer, cit, iter, loc) {
1422
+ const key = `streamFromIter:${cit.iterT.className}`;
1423
+ let name = lowerer.valueHelpers.get(key);
1424
+ if (!name) {
1425
+ name = `%stream.fromIter.${lowerer.valueHelpers.size}`;
1426
+ lowerer.valueHelpers.set(key, name);
1427
+ const nextName = `${name}.next`;
1428
+ const nextT = funcOf([], DYN);
1429
+ const it = { id: "it.0", name: "it", type: cit.iterT, mutable: false, boxed: true };
1430
+ const r = { id: "res.0", name: "res", type: cit.resultT, mutable: false };
1431
+ const field = (f, t) => ({
1432
+ kind: "recordGet",
1433
+ obj: varRef(r.id, cit.resultT, loc),
1434
+ shapeId: cit.resultT.shapeId,
1435
+ field: f,
1436
+ type: t,
1437
+ loc,
1438
+ });
1439
+ const str = (value) => ({ kind: "strLit", value, type: STRING, loc });
1440
+ lowerer.liftedFns.push({
1441
+ name: nextName,
1442
+ params: [],
1443
+ returnType: DYN,
1444
+ captures: [{ localId: it.id, name: it.name, type: it.type }],
1445
+ locals: [it, r],
1446
+ body: [
1447
+ {
1448
+ kind: "varDecl",
1449
+ localId: r.id,
1450
+ init: classIteratorNextCall(lowerer, cit, varRef(it.id, cit.iterT, loc), loc),
1451
+ loc,
1452
+ },
1453
+ {
1454
+ kind: "return",
1455
+ value: {
1456
+ kind: "dynObjLit",
1457
+ fields: [
1458
+ {
1459
+ key: str("value"),
1460
+ value: lowerer.coerceToExpected(field("value", cit.valueT), DYN),
1461
+ },
1462
+ {
1463
+ key: str("done"),
1464
+ value: {
1465
+ kind: "dynFrom",
1466
+ value: cit.hasDone ? field("done", BOOL) : boolLit(false, loc),
1467
+ type: DYN,
1468
+ loc,
1469
+ },
1470
+ },
1471
+ ],
1472
+ type: DYN,
1473
+ loc,
1474
+ },
1475
+ loc,
1476
+ },
1477
+ ],
1478
+ loc,
1479
+ });
1480
+ lowerer.liftedFns.push({
1481
+ name,
1482
+ params: [{ localId: it.id, name: it.name, type: it.type }],
1483
+ returnType: DYN,
1484
+ locals: [it],
1485
+ body: [
1486
+ {
1487
+ kind: "return",
1488
+ value: {
1489
+ kind: "dynObjLit",
1490
+ fields: [
1491
+ {
1492
+ key: str("next"),
1493
+ value: {
1494
+ kind: "dynFrom",
1495
+ value: { kind: "closure", fnName: nextName, captures: [it.id], type: nextT, loc },
1496
+ type: DYN,
1497
+ loc,
1498
+ },
1499
+ },
1500
+ ],
1501
+ type: DYN,
1502
+ loc,
1503
+ },
1504
+ loc,
1505
+ },
1506
+ ],
1507
+ loc,
1508
+ });
1509
+ }
1510
+ return { kind: "call", callee: name, args: [iter], type: DYN, loc };
1511
+ }
1512
+ /** A class's zero-parameter `[Symbol.asyncIterator]()` (checked first, as
1513
+ * from.js does) or `[Symbol.iterator]()` method that returns a generator,
1514
+ * with its method slot. */
1515
+ function classGeneratorMethodOf(lowerer, t) {
1516
+ const info = lowerer.classes.get(t.className);
1517
+ if (!info)
1518
+ return null;
1519
+ for (const method of ["sym:asyncIterator", "sym:iterator"]) {
1520
+ const m = lowerer.findMethodOn(info, method);
1521
+ if (!m)
1522
+ continue;
1523
+ const ret = m.sig.ret;
1524
+ if (m.sig.abstract === true || m.sig.params.length !== 0 || ret.kind !== "generator")
1525
+ return null;
1526
+ return { method, gen: ret };
1527
+ }
1528
+ return null;
1529
+ }
1530
+ function classAsyncIteratorOf(lowerer, t) {
1531
+ const info = lowerer.classes.get(t.className);
1532
+ const open = info ? lowerer.findMethodOn(info, "sym:asyncIterator") : null;
1533
+ if (!open || open.sig.abstract === true || open.sig.params.length !== 0)
1534
+ return null;
1535
+ const iterT = open.sig.ret;
1536
+ if (iterT.kind !== "object")
1537
+ return null;
1538
+ const itInfo = lowerer.classes.get(iterT.className);
1539
+ if (!itInfo || lowerer.findMethodOn(itInfo, "throw"))
1540
+ return null;
1541
+ const record = (name) => {
1542
+ const m = lowerer.findMethodOn(itInfo, name);
1543
+ if (!m || m.sig.abstract === true || m.sig.params.length !== 0)
1544
+ return null;
1545
+ const ret = m.sig.ret;
1546
+ return ret.kind === "promise" && ret.inner.kind === "record" ? ret.inner : null;
1547
+ };
1548
+ const resultT = record("next");
1549
+ if (!resultT)
1550
+ return null;
1551
+ const shape = lowerer.shapes.get(resultT.shapeId);
1552
+ const value = shape?.fields.find((f) => f.name === "value");
1553
+ const done = shape?.fields.find((f) => f.name === "done");
1554
+ if (!value || (done && done.type.kind !== "bool"))
1555
+ return null;
1556
+ const hasReturn = lowerer.findMethodOn(itInfo, "return") !== null;
1557
+ if (hasReturn && !record("return"))
1558
+ return null;
1559
+ return { className: t.className, iterT, resultT, valueT: value.type, hasReturn };
1560
+ }
1561
+ /** The checked-dynamic iterator object over an async class iterable:
1562
+ * `recv[Symbol.asyncIterator]()` runs when the stream is built, and the
1563
+ * object's `next` (and `return`, when the class declares one) answer the
1564
+ * iterator's own promises boxed. */
1565
+ function classAsyncIteratorObject(lowerer, cit, recv, loc) {
1566
+ const key = `streamFromAsyncIter:${cit.className}`;
1567
+ let name = lowerer.valueHelpers.get(key);
1568
+ if (!name) {
1569
+ name = `%stream.fromAsyncIter.${lowerer.valueHelpers.size}`;
1570
+ lowerer.valueHelpers.set(key, name);
1571
+ const it = { id: "it.0", name: "it", type: cit.iterT, mutable: false, boxed: true };
1572
+ const src = {
1573
+ id: "src.0",
1574
+ name: "src",
1575
+ type: { kind: "object", className: cit.className },
1576
+ mutable: false,
1577
+ };
1578
+ const str = (value) => ({ kind: "strLit", value, type: STRING, loc });
1579
+ const method = (m) => {
1580
+ const fnName = `${name}.${m}`;
1581
+ const call = accessorCall(lowerer, cit.iterT.className, m, varRef(it.id, cit.iterT, loc), [], { kind: "promise", inner: cit.resultT }, loc);
1582
+ lowerer.liftedFns.push({
1583
+ name: fnName,
1584
+ params: [],
1585
+ returnType: DYN,
1586
+ captures: [{ localId: it.id, name: it.name, type: it.type }],
1587
+ locals: [it],
1588
+ body: [{ kind: "return", value: { kind: "dynFrom", value: call, type: DYN, loc }, loc }],
1589
+ loc,
1590
+ });
1591
+ return {
1592
+ key: str(m),
1593
+ value: {
1594
+ kind: "dynFrom",
1595
+ value: { kind: "closure", fnName, captures: [it.id], type: funcOf([], DYN), loc },
1596
+ type: DYN,
1597
+ loc,
1598
+ },
1599
+ };
1600
+ };
1601
+ const fields = [method("next"), ...(cit.hasReturn ? [method("return")] : [])];
1602
+ lowerer.liftedFns.push({
1603
+ name,
1604
+ params: [{ localId: src.id, name: src.name, type: src.type }],
1605
+ returnType: DYN,
1606
+ locals: [src, it],
1607
+ body: [
1608
+ {
1609
+ kind: "varDecl",
1610
+ localId: it.id,
1611
+ init: accessorCall(lowerer, cit.className, "sym:asyncIterator", varRef(src.id, src.type, loc), [], cit.iterT, loc),
1612
+ loc,
1613
+ },
1614
+ { kind: "return", value: { kind: "dynObjLit", fields, type: DYN, loc }, loc },
1615
+ ],
1616
+ loc,
1617
+ });
1618
+ }
1619
+ return { kind: "call", callee: name, args: [recv], type: DYN, loc };
1620
+ }
1366
1621
  /** Readable.from's typed options: an object literal of `objectMode`
1367
1622
  * (a boolean literal) and `highWaterMark` (a number), as SCR_FROM_* flag
1368
1623
  * bits and the hwm expression; null for any other shape. */
@@ -1429,7 +1684,12 @@ const PIPELINE_STAGE_EXPECTED = "of type function or an instance of Blob, Readab
1429
1684
  * { readable, writable } pairs — those shapes fence instead of throwing
1430
1685
  * a ladder Node never throws. */
1431
1686
  function lowerStreamArg(lowerer, node, what) {
1432
- const v = lowerer.lowerExpr(node);
1687
+ const lowered = lowerer.lowerExpr(node);
1688
+ // A Hash or Hmac stage is its Transform; pipeline and compose stages
1689
+ // keep the value alive until the stream settles.
1690
+ const v = isHashValueType(lowered.type)
1691
+ ? hashStreamOf(lowered, what === "pipeline" || what === "compose")
1692
+ : lowered;
1433
1693
  const info = v.type.kind === "object" ? lowerer.classes.get(v.type.className) : undefined;
1434
1694
  if (!streamSidesOf(lowerer, info)) {
1435
1695
  // A provably-non-stream value in a JS source (the invalid-input
@@ -2420,6 +2680,22 @@ function checkUtf8Encoding(lowerer, member, arg) {
2420
2680
  }
2421
2681
  /** `recv.<member>(...)` over a stream-rooted receiver. Returns null only
2422
2682
  * for members this spoke does not own. */
2683
+ /** pipe()'s `{ end }` option: true when absent. */
2684
+ function pipeEndOption(lowerer, options, loc) {
2685
+ let end = boolLit(true, loc);
2686
+ if (options === undefined)
2687
+ return end;
2688
+ if (!ts.isObjectLiteralExpression(options)) {
2689
+ lowerer.noLowering("pipe with a non-literal options argument", options, "{ end: <bool> } inline is the supported form");
2690
+ }
2691
+ for (const prop of options.properties) {
2692
+ if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || prop.name.text !== "end") {
2693
+ lowerer.noLowering("a pipe option other than 'end'", prop);
2694
+ }
2695
+ end = lowerer.lowerExprExpecting(prop.initializer, BOOL);
2696
+ }
2697
+ return end;
2698
+ }
2423
2699
  export function lowerStreamMethodCall(lowerer, call, access, info) {
2424
2700
  const member = access.name.text;
2425
2701
  if (STREAM_OPERATORS.has(member)) {
@@ -2604,26 +2880,47 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
2604
2880
  if (args.length === 0 || args.length > 2) {
2605
2881
  lowerer.noLowering(`pipe with ${args.length} arguments`, call, "the supported forms are (destination) and (destination, { end })");
2606
2882
  }
2883
+ // A Hash or Hmac destination pipes into its Transform, and pipe()
2884
+ // answers the Hash itself (the receiver evaluates first, as in JS).
2885
+ if (isHashValueType(lowerer.mapTypeOf(lowerer.typeOf(args[0])))) {
2886
+ const receiverValue = lowerer.lowerExpr(access.expression);
2887
+ const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type);
2888
+ const hashValue = lowerer.lowerExpr(args[0]);
2889
+ const hash = lowerer.declareHiddenLocal("%pipeHash", hashValue.type);
2890
+ const end = pipeEndOption(lowerer, args[1], loc);
2891
+ return {
2892
+ kind: "seqExpr",
2893
+ stmts: [
2894
+ { kind: "varDecl", localId: source.id, init: receiverValue, loc },
2895
+ { kind: "varDecl", localId: hash.id, init: hashValue, loc },
2896
+ {
2897
+ kind: "exprStmt",
2898
+ expr: {
2899
+ kind: "libCall",
2900
+ fn: "readable.pipe",
2901
+ args: [
2902
+ { kind: "varRef", localId: source.id, type: receiverValue.type, loc },
2903
+ hashStreamOf({ kind: "varRef", localId: hash.id, type: hashValue.type, loc }, true),
2904
+ end,
2905
+ ],
2906
+ type: { kind: "object", className: "%Transform" },
2907
+ loc,
2908
+ },
2909
+ loc,
2910
+ },
2911
+ ],
2912
+ result: { kind: "varRef", localId: hash.id, type: hashValue.type, loc },
2913
+ type: hashValue.type,
2914
+ loc,
2915
+ };
2916
+ }
2607
2917
  const dst = lowerer.lowerExpr(args[0]);
2608
2918
  const dstInfo = dst.type.kind === "object" ? lowerer.classes.get(dst.type.className) : undefined;
2609
2919
  const dstSides = streamSidesOf(lowerer, dstInfo);
2610
2920
  if (dstSides !== "w" && dstSides !== "rw") {
2611
2921
  lowerer.noLowering(`pipe into a '${lowerer.fmt(dst.type)}'`, args[0], "the destination must be a stream Writable/Duplex (process streams and sockets are not pipe destinations yet)");
2612
2922
  }
2613
- let end = boolLit(true, loc);
2614
- if (args[1] !== undefined) {
2615
- if (!ts.isObjectLiteralExpression(args[1])) {
2616
- lowerer.noLowering("pipe with a non-literal options argument", args[1], "{ end: <bool> } inline is the supported form");
2617
- }
2618
- for (const prop of args[1].properties) {
2619
- if (!ts.isPropertyAssignment(prop) ||
2620
- !ts.isIdentifier(prop.name) ||
2621
- prop.name.text !== "end") {
2622
- lowerer.noLowering("a pipe option other than 'end'", prop);
2623
- }
2624
- end = lowerer.lowerExprExpecting(prop.initializer, BOOL);
2625
- }
2626
- }
2923
+ const end = pipeEndOption(lowerer, args[1], loc);
2627
2924
  const receiver = lowerer.lowerExpr(access.expression);
2628
2925
  return {
2629
2926
  kind: "libCall",