@scriptc/compiler 0.0.9 → 0.0.11

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 (97) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +54 -9
  2. package/dist/backend/emission/emit-exprs.js +170 -14
  3. package/dist/backend/emission/emit-exprs.js.map +1 -1
  4. package/dist/backend/emission/emit-walkers.js +29 -2
  5. package/dist/backend/emission/emit-walkers.js.map +1 -1
  6. package/dist/backend/emission/emitter.js +25 -1
  7. package/dist/backend/emission/emitter.js.map +1 -1
  8. package/dist/backend/llvm/dyn.d.ts +1 -0
  9. package/dist/backend/llvm/dyn.js +83 -1
  10. package/dist/backend/llvm/dyn.js.map +1 -1
  11. package/dist/backend/llvm/emitter.js +210 -13
  12. package/dist/backend/llvm/emitter.js.map +1 -1
  13. package/dist/coverage/surface-manifest.js +16 -2
  14. package/dist/coverage/surface-manifest.js.map +1 -1
  15. package/dist/diagnostics/diagnostic.d.ts +41 -14
  16. package/dist/diagnostics/diagnostic.js +79 -27
  17. package/dist/diagnostics/diagnostic.js.map +1 -1
  18. package/dist/diagnostics/render.js +8 -0
  19. package/dist/diagnostics/render.js.map +1 -1
  20. package/dist/frontend/lowering/lib-boundary.js +11 -1
  21. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  22. package/dist/frontend/lowering/lower-builtins.d.ts +69 -0
  23. package/dist/frontend/lowering/lower-builtins.js +380 -4
  24. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  25. package/dist/frontend/lowering/lower-calls.d.ts +41 -0
  26. package/dist/frontend/lowering/lower-calls.js +559 -11
  27. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  28. package/dist/frontend/lowering/lower-classes.d.ts +7 -0
  29. package/dist/frontend/lowering/lower-classes.js +51 -1
  30. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  31. package/dist/frontend/lowering/lower-containers.d.ts +21 -0
  32. package/dist/frontend/lowering/lower-containers.js +262 -17
  33. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  34. package/dist/frontend/lowering/lower-dgram.js +92 -17
  35. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  36. package/dist/frontend/lowering/lower-emitter.d.ts +70 -3
  37. package/dist/frontend/lowering/lower-emitter.js +436 -29
  38. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  39. package/dist/frontend/lowering/lower-exprs.d.ts +80 -5
  40. package/dist/frontend/lowering/lower-exprs.js +651 -23
  41. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  42. package/dist/frontend/lowering/lower-modules.d.ts +8 -5
  43. package/dist/frontend/lowering/lower-modules.js +144 -19
  44. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  45. package/dist/frontend/lowering/lower-namespaces.d.ts +39 -11
  46. package/dist/frontend/lowering/lower-namespaces.js +166 -24
  47. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  48. package/dist/frontend/lowering/lower-server.js +211 -4
  49. package/dist/frontend/lowering/lower-server.js.map +1 -1
  50. package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
  51. package/dist/frontend/lowering/lower-stmts.js +293 -10
  52. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  53. package/dist/frontend/lowering/lower-stream.js +178 -10
  54. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  55. package/dist/frontend/lowering/lowerer.d.ts +53 -1
  56. package/dist/frontend/lowering/lowerer.js +210 -19
  57. package/dist/frontend/lowering/lowerer.js.map +1 -1
  58. package/dist/frontend/lowering/surfaces.d.ts +44 -0
  59. package/dist/frontend/lowering/surfaces.js +234 -3
  60. package/dist/frontend/lowering/surfaces.js.map +1 -1
  61. package/dist/frontend/npm.d.ts +12 -0
  62. package/dist/frontend/npm.js +30 -0
  63. package/dist/frontend/npm.js.map +1 -1
  64. package/dist/frontend/program.d.ts +25 -0
  65. package/dist/frontend/program.js +144 -135
  66. package/dist/frontend/program.js.map +1 -1
  67. package/dist/frontend/shared.d.ts +1 -1
  68. package/dist/frontend/shared.js +1 -1
  69. package/dist/frontend/shared.js.map +1 -1
  70. package/dist/frontend/types.d.ts +13 -0
  71. package/dist/frontend/types.js +84 -7
  72. package/dist/frontend/types.js.map +1 -1
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.js +157 -12
  75. package/dist/index.js.map +1 -1
  76. package/dist/ir/nodes.d.ts +163 -13
  77. package/dist/ir/nodes.js +65 -6
  78. package/dist/ir/nodes.js.map +1 -1
  79. package/dist/ir/validate.js +64 -5
  80. package/dist/ir/validate.js.map +1 -1
  81. package/dist/library/fence-eval.d.ts +77 -0
  82. package/dist/library/fence-eval.js +395 -0
  83. package/dist/library/fence-eval.js.map +1 -0
  84. package/dist/library/int-infer.d.ts +119 -0
  85. package/dist/library/int-infer.js +1301 -0
  86. package/dist/library/int-infer.js.map +1 -0
  87. package/dist/library/int-infer.test.d.ts +1 -0
  88. package/dist/library/int-infer.test.js +279 -0
  89. package/dist/library/int-infer.test.js.map +1 -0
  90. package/dist/library/profile.d.ts +43 -6
  91. package/dist/library/profile.js +179 -31
  92. package/dist/library/profile.js.map +1 -1
  93. package/dist/library/sidecar.d.ts +23 -0
  94. package/dist/library/sidecar.js +150 -16
  95. package/dist/library/sidecar.js.map +1 -1
  96. package/package.json +2 -2
  97. package/surface-manifest.json +208 -10
@@ -549,8 +549,11 @@ export interface IrLibExport {
549
549
  symbol: string;
550
550
  /** IR function name (entry-file top-level, so unqualified). */
551
551
  fnName: string;
552
- params: ("f64" | "bool" | "string" | "bytes" | "u8" | "u32" | "i32")[];
553
- returns: "f64" | "bool" | "string" | "bytes" | "void";
552
+ /** i64/u64 (ask 4): int64_t/uint64_t at the C edge — inbound values
553
+ * range-check in the wrapper (`inboundIntTrap`), internal call sites
554
+ * and returns are compile-time proven before this lands on the IR. */
555
+ params: ("f64" | "bool" | "string" | "bytes" | "u8" | "u32" | "i32" | "i64" | "u64")[];
556
+ returns: "f64" | "bool" | "string" | "bytes" | "void" | "i64" | "u64";
554
557
  /** The exact sink-message bytes this wrapper passes to the inbound-bytes
555
558
  * marshalling helper's trap — present exactly when a parameter is
556
559
  * bytes-classed. Already the assembled structured trap-teaching form
@@ -559,6 +562,12 @@ export interface IrLibExport {
559
562
  * 0x1F when supplied. Assembled ONCE at export resolution so both
560
563
  * backends emit identical bytes by construction. */
561
564
  inboundBytesTrap?: string;
565
+ /** The sibling message for the inbound INTEGER host-contract trap
566
+ * (ask 4): present exactly when a parameter is i64/u64-classed, passed
567
+ * to the scr_library_i64_in/u64_in helpers, which trap when the inbound
568
+ * value cannot ride f64 exactly (|v| past 2^53−1). Same assembled
569
+ * structured form and the same SC4012 code — one host-contract story. */
570
+ inboundIntTrap?: string;
562
571
  }
563
572
  /** One runtime-trap overlay row: the profile's teaching (replaces the
564
573
  * baseline human line as field 0) and/or remediation (the optional fourth
@@ -1166,8 +1175,11 @@ export type IrStrIntrinsicMethod = "length" | "charCodeAt" | "charAt" | "indexOf
1166
1175
  * arrayGet — the write side is the bytesSet STATEMENT); `slice` takes
1167
1176
  * 0–2 f64 relative indices (omitted args are OMITTED from `args`, like
1168
1177
  * strIntrinsic — backends fill start 0 / end +Infinity) → a fresh
1169
- * same-elem bytes COPY (`subarray` lowers here too: copying is the
1170
- * documented divergence); `setFrom` (`dst.set(src, offset?)`) takes a
1178
+ * same-elem bytes COPY; `subarray` takes the same 0–2 f64 relative
1179
+ * indices → a same-elem VIEW aliasing the receiver's storage (JS's
1180
+ * TypedArray.prototype.subarray; Buffer's slice(), subarray's deprecated
1181
+ * Node alias, lowers here too — only plain typed arrays' slice copies);
1182
+ * `setFrom` (`dst.set(src, offset?)`) takes a
1171
1183
  * same-elem bytes src and an optional f64 offset (omitted = 0) → void,
1172
1184
  * THROWS Node's RangeError on overflow (may-throw seed); `toString` takes
1173
1185
  * one string encoding arg (the frontend completes an omitted one to
@@ -1204,7 +1216,7 @@ export type IrStrIntrinsicMethod = "length" | "charCodeAt" | "charAt" | "indexOf
1204
1216
  * constant RangeError on any bad offset; values coerce JS-exactly
1205
1217
  * (integer kinds by modular truncation, Float32 by double→float
1206
1218
  * rounding). No BIG setters exist — bigint arguments never lower. */
1207
- export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" | "setFrom" | "toString" | "readNum" | "writeNum" | "readNumVar" | "writeNumVar"
1219
+ export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" | "subarray" | "setFrom" | "toString" | "readNum" | "writeNum" | "readNumVar" | "writeNumVar"
1208
1220
  /** The comparison/search/mutation surface (u8 receivers only; see the
1209
1221
  * runtime contract): `equals` [bytes] → bool (never throws);
1210
1222
  * `compareBuf` [bytes, 0-4 f64 index args — omitted args OMITTED,
@@ -1219,7 +1231,14 @@ export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" |
1219
1231
  * f64 copied count, THROWS; `swap16/32/64` [] → the receiver (+1,
1220
1232
  * in-place), THROW; `writeStr` [string, strLit enc, f64 offset, f64
1221
1233
  * length?] → f64 bytes written, THROWS. */
1222
- | "equals" | "compareBuf" | "indexOf" | "lastIndexOf" | "includes" | "indexOfNum" | "lastIndexOfNum" | "includesNum" | "fill" | "fillNum" | "fillStr" | "copy" | "swap16" | "swap32" | "swap64" | "writeStr" | "byteOffset" | "dataViewNew" | "dvGetUint8" | "dvGetInt8" | "dvGetUint16" | "dvGetInt16" | "dvGetUint32" | "dvGetInt32" | "dvGetFloat32" | "dvGetFloat64" | "dvGetBigUint64Number" | "dvGetBigInt64Number" | "dvSetUint8" | "dvSetInt8" | "dvSetUint16" | "dvSetInt16" | "dvSetUint32" | "dvSetInt32" | "dvSetFloat32" | "dvSetFloat64";
1234
+ | "equals" | "compareBuf" | "indexOf" | "lastIndexOf" | "includes" | "indexOfNum" | "lastIndexOfNum" | "includesNum" | "fill" | "fillNum" | "fillStr"
1235
+ /** TypedArray.prototype.fill on NON-u8 receivers: [f64 value, 0-2 f64
1236
+ * relative indices] → the RECEIVER (+1, chaining); the value coerces
1237
+ * per element kind (the scr_bytes_set discipline), indices clamp like
1238
+ * slice, never throws. u8 receivers keep the Buffer fill family above
1239
+ * (same observable number-fill result; Buffer's throwing offset
1240
+ * validation). */
1241
+ | "fillElem" | "copy" | "swap16" | "swap32" | "swap64" | "writeStr" | "byteOffset" | "dataViewNew" | "dvGetUint8" | "dvGetInt8" | "dvGetUint16" | "dvGetInt16" | "dvGetUint32" | "dvGetInt32" | "dvGetFloat32" | "dvGetFloat64" | "dvGetBigUint64Number" | "dvGetBigInt64Number" | "dvSetUint8" | "dvSetInt8" | "dvSetUint16" | "dvSetInt16" | "dvSetUint32" | "dvSetInt32" | "dvSetFloat32" | "dvSetFloat64";
1223
1242
  /** The bytesIntrinsic methods that can raise a catchable error — backends'
1224
1243
  * may-throw analyses seed on these exactly like MAY_THROW_LIB_FNS. */
1225
1244
  export declare const MAY_THROW_BYTES_METHODS: ReadonlySet<IrBytesIntrinsicMethod>;
@@ -1303,11 +1322,22 @@ export type IrLibFn = "island.eval"
1303
1322
  * OBJ receiver sets the member (later writes win, insertion order
1304
1323
  * preserved — JS exactly); undefined/null throws Node's catchable
1305
1324
  * "Cannot set properties of undefined (setting 'k')"; every other kind
1306
- * throws Node's STRICT-mode "Cannot create property 'k' on <kind>"
1325
+ * throws Node's STRICT-mode "Cannot create property 'k' on <kind>" —
1326
+ * primitives quoting their rendering, V8's "on number '5'"
1307
1327
  * (sloppy mode would silently ignore — suite tests are 'use strict';
1308
1328
  * SEMANTICS.md notes the sloppy divergence: loud, never silent). Void
1309
1329
  * result; in the may-throw seed set. */
1310
1330
  | "dyn.keySet"
1331
+ /** Destructuring pack over a dyn DOM source — `const [a, b] = d`, a
1332
+ * destructured dyn callback param (args: the source and the STATIC
1333
+ * TypeError spelling, "" when the source has none — both borrowed;
1334
+ * result: a fresh DOM array, +1). Iterable kinds collect like spread
1335
+ * (arrays element-by-element, strings by code point, bytes by byte);
1336
+ * every other kind throws V8's destructuring TypeError — the spelling
1337
+ * verbatim when non-empty, else the runtime kind wording ("number 5 is
1338
+ * not iterable (cannot read property Symbol(Symbol.iterator))"). In the
1339
+ * may-throw seed set. */
1340
+ | "dyn.iterPack"
1311
1341
  /** Object.defineProperties over DOM values (args: target, descriptors —
1312
1342
  * both borrowed dyn; result: the target, +1 — JS's return value).
1313
1343
  * Value descriptors become plain own properties on OBJ and FUNC targets
@@ -1407,6 +1437,12 @@ export type IrLibFn = "island.eval"
1407
1437
  * round() is half-away-from-zero and floor(x+0.5) drifts at the
1408
1438
  * epsilon boundary). Borrow nothing; never throw. */
1409
1439
  | "math.abs" | "math.round"
1440
+ /** Math.trunc / Math.ceil — C trunc()/ceil() ARE the JS operations
1441
+ * (NaN/±0/±Infinity pass through bit-exactly; ceil(-0.5) is -0 in IEEE
1442
+ * round-toward-+Infinity exactly as ECMA says). Static like floor —
1443
+ * they are ask-4's wholeness-discharge operators, so the library
1444
+ * inference needs them compiled, not island-served. Never throw. */
1445
+ | "math.trunc" | "math.ceil"
1410
1446
  /** The static global parsers/tests (scr_string.c). num.parseInt is
1411
1447
  * ECMA-262 19.2.5 exactly — JS whitespace, sign, ToInt32 radix (the
1412
1448
  * frontend completes an omitted radix to 0 = the spec's "undefined":
@@ -1675,7 +1711,18 @@ export type IrLibFn = "island.eval"
1675
1711
  * (handshake-completion timing); on a server without deferred
1676
1712
  * connections (a plain net server) the registration never fires,
1677
1713
  * exactly Node's split. */
1678
- | "net.serverOnSecureConnection" | "net.connect" | "net.connectCb"
1714
+ | "net.serverOnSecureConnection" | "net.connect"
1715
+ /** connect with a validated autoSelectFamilyAttemptTimeout option (the
1716
+ * budget runs Node's validateInt32-from-1 ladder and is then inert —
1717
+ * the single dial has nothing to time). May-throw. */
1718
+ | "net.connectAttempt"
1719
+ /** net.connect/createConnection over a RUNTIME option bag (computed
1720
+ * keys — the invalid-input probes): Node-order validation (the
1721
+ * objectMode trio's ERR_INVALID_ARG_VALUE, validatePort, host string,
1722
+ * autoSelectFamily boolean, the attempt budget), then the trailing
1723
+ * compiler-rendered fence — ALWAYS THROWS (the error.nodeThrow
1724
+ * polymorphic-result carve-out). May-throw seed. */
1725
+ | "net.connectOptsChk" | "net.connectCb"
1679
1726
  /** connect({ port, host, autoSelectFamily: true, lookup }) — the
1680
1727
  * caller-resolver dial (portless's createLoopbackConnection): args
1681
1728
  * [port, host, lookup]. The runtime creates the (connecting) socket
@@ -1717,7 +1764,13 @@ export type IrLibFn = "island.eval"
1717
1764
  * defers the callback to the next turn (SEMANTICS.md documents the
1718
1765
  * blocking divergence); its per-union adapter builds the
1719
1766
  * `Error | null` first argument. */
1720
- | "dgram.createSocket" | "dgram.bind" | "dgram.bindCb" | "dgram.connect" | "dgram.connectCb" | "dgram.sendStr" | "dgram.sendBytes" | "dgram.address" | "dgram.close" | "dgram.closeCb" | "dgram.unref" | "dgram.ref" | "dgram.onMessage" | "dgram.onError" | "dgram.onListening" | "dgram.onClose" | "dgram.onConnect" | "dns.lookup"
1767
+ | "dgram.createSocket" | "dgram.bind" | "dgram.bindCb" | "dgram.connect" | "dgram.connectCb" | "dgram.sendStr" | "dgram.sendBytes"
1768
+ /** The send argument-validation ladder over DOM arguments (Node's
1769
+ * signature shuffle: slice bounds, list/type contracts, port/address
1770
+ * validation, connected-state errors) — a fully-validated unconnected
1771
+ * single-payload send RUNS; callback/list/connected forms meet the
1772
+ * trailing fence. May-throw. */
1773
+ | "dgram.sendChk" | "dgram.address" | "dgram.close" | "dgram.closeCb" | "dgram.unref" | "dgram.ref" | "dgram.onMessage" | "dgram.onError" | "dgram.onListening" | "dgram.onClose" | "dgram.onConnect" | "dns.lookup"
1721
1774
  /** node:test (scr_test.c — linked only when one of these appears on
1722
1775
  * the IR; moduleUsesNodeTest is the switch, and the main epilogue asks
1723
1776
  * scr_test_exit_code() for the process's exit status). Strings are
@@ -1893,7 +1946,17 @@ export type IrLibFn = "island.eval"
1893
1946
  /** tls.createSecureContext({ cert, key }) — parses the PEM pair into an
1894
1947
  * opaque SecureContext handle (secureCtx kind) for SNI callbacks to
1895
1948
  * answer with; cert/key are PEM strings or Buffers like createServer's. */
1896
- | "tls.createSecureContext" | "https.createServer" | "https.request" | "https.requestCb"
1949
+ | "tls.createSecureContext"
1950
+ /** createSecureContext over a RUNTIME options record (the checked-
1951
+ * dynamic lane): Node's typed option validations first (the ciphers/
1952
+ * passphrase/engine/version/timeout/ticketKeys ladders), then the pem
1953
+ * walk — a validated { cert, key } bag builds the real context.
1954
+ * May-throw. */
1955
+ | "tls.createSecureContextDyn"
1956
+ /** tls.getCACertificates(type): validateString + the documented name
1957
+ * set, then the trailing compiler-rendered fence — ALWAYS THROWS (the
1958
+ * error.nodeThrow polymorphic-result carve-out). May-throw seed. */
1959
+ | "tls.caCertsChk" | "https.createServer" | "https.request" | "https.requestCb"
1897
1960
  /** A call through a `const requestFn = tls ? https.request :
1898
1961
  * http.request` binding — the module-function-as-value ternary between
1899
1962
  * the two known clients: the https.request row with a leading `secure`
@@ -2026,11 +2089,25 @@ export type IrLibFn = "island.eval"
2026
2089
  * finite numbers coerce (negatives answer now/1000, Node's shape);
2027
2090
  * everything else throws Node's ERR_INVALID_ARG_TYPE. May-throw. */
2028
2091
  | "fs.toUnixTimestamp"
2092
+ /** The fs argument-validation ladders (checked-dynamic lane): each Chk
2093
+ * replicates its API's Node-order validation over DOM values (Node's
2094
+ * exact typed errors — ERR_INVALID_ARG_TYPE/VALUE, ERR_OUT_OF_RANGE),
2095
+ * and a full pass meets the trailing compiler-rendered SC2020 fence
2096
+ * string — so the ALWAYS-THROW forms take the error.nodeThrow
2097
+ * polymorphic-result carve-out. mkdtempSyncChk and the lchmod sync/
2098
+ * promise pair run the REAL operation on a validated pass instead
2099
+ * (macOS lchmod(2); non-APPLE answers Node's not-a-function /
2100
+ * ERR_METHOD_NOT_IMPLEMENTED shapes). May-throw seeds, all of them. */
2101
+ | "fs.existsChk" | "fs.mkdtempChk" | "fs.mkdtempSyncChk" | "fs.readFileChk" | "fs.opendirChk" | "fs.watchFileChk" | "fs.lchmodChk" | "fs.lchmodSyncChk" | "fsp.lchmodChk" | "fs.readChk" | "fs.streamOptsChk"
2029
2102
  /** The compiler-resolved ERR_INVALID_ARG_TYPE throw with a RUNTIME-
2030
2103
  * rendered Received tail: args [argname, "of type ..." clause, the
2031
2104
  * offending DOM value]. ALWAYS THROWS; polymorphic result (the
2032
2105
  * error.nodeThrow pattern). May-throw seed. */
2033
2106
  | "error.argTypeThrow"
2107
+ /** The property flavor of argTypeThrow ("The \"options.x\" property
2108
+ * must be ..."): the option-bag ladders' provably-invalid arms. ALWAYS
2109
+ * THROWS; polymorphic result. May-throw seed. */
2110
+ | "error.propTypeThrow"
2034
2111
  /** The checked-dynamic max-listeners ladders: setMaxChk is the
2035
2112
  * instance form over a DOM n (non-numbers ERR_INVALID_ARG_TYPE,
2036
2113
  * negatives/NaN ERR_OUT_OF_RANGE; +1 receiver back — chaining);
@@ -2330,7 +2407,32 @@ export type IrLibFn = "island.eval"
2330
2407
  * JS). Strings/arrays/bytes answer their index keys; other scalars an
2331
2408
  * empty array; null/undefined throw Node's catchable TypeError
2332
2409
  * ("Cannot convert undefined or null to object"). */
2333
- | "dyn.objKeys" | "dyn.hasOwn" | "dyn.assign" | "dyn.objValues" | "dyn.objEntries"
2410
+ | "dyn.objKeys" | "dyn.hasOwn" | "dyn.assign"
2411
+ /** Variadic Object.assign over CHECKED-DYNAMIC targets (`Object.assign(
2412
+ * {}, ...arr.map(f), tail)` — the option-table merge): the lowering
2413
+ * builds one fresh DOM pack of sources (packPush retains a plain source
2414
+ * in; packPushSpread flattens a spread source through the spread-call
2415
+ * walk — V8's exact TypeError texts, the string arg spelling the spread
2416
+ * expression for the nullish form), so every source evaluates and
2417
+ * flattens BEFORE any copying (JS's ArgumentListEvaluation), then
2418
+ * assignAll copies each pack element's own enumerable keys onto the
2419
+ * target left to right and answers the TARGET (+1) — identity, like JS.
2420
+ * assignAll throws Node's ToObject TypeError on a nullish target. */
2421
+ | "dyn.packPush" | "dyn.packPushSpread"
2422
+ /** The iterated-path spread twin: V8 spells the optimized apply-path
2423
+ * texts (packPushSpread's — the expression named for nullish sources)
2424
+ * only for the SINGLE LAST argument's spread; any other spread position
2425
+ * drives the real iterator protocol, whose failure describes the VALUE
2426
+ * ("object null is not iterable (cannot read property
2427
+ * Symbol(Symbol.iterator))"). The frontend picks by position. */
2428
+ | "dyn.packPushSpreadIter" | "dyn.assignAll"
2429
+ /** `Object.create(null)` (scr_json.c): a fresh NULL-PROTOTYPE DOM
2430
+ * dictionary. The DOM's OBJ dispatch is already own-member-only —
2431
+ * Node's null-proto answer — so the flag's whole job is the observations
2432
+ * that SEE the prototype: inspect's "[Object: null prototype]" prefix
2433
+ * and deepStrictEqual's prototype gate. Never throws. Static builds
2434
+ * only; --dynamic routes Object.create through the engine instead. */
2435
+ | "dyn.objCreateNullProto" | "dyn.objValues" | "dyn.objEntries"
2334
2436
  /** structuredClone over the DOM (scr_json.c): the JSON-safe subset plus
2335
2437
  * bytes (a fresh copy — a Buffer clones as a plain Uint8Array, like
2336
2438
  * Node), deep. Functions and handle kinds throw the spec's catchable
@@ -2440,7 +2542,18 @@ export type IrLibFn = "island.eval"
2440
2542
  * settles; sp.pipeline: (count, s1..sn) → the callback pipeline's
2441
2543
  * chaining/destroyer semantics settling a void promise (fulfilled on a
2442
2544
  * clean finish, rejected with the finish status otherwise). */
2443
- | "sp.finished" | "sp.pipeline" | "readable.newDyn" | "writable.newDyn" | "duplex.newDyn" | "transform.newDyn" | "passthrough.newDyn" | "readable.initDyn" | "writable.initDyn" | "duplex.initDyn" | "transform.initDyn" | "passthrough.initDyn" | "readable.push" | "readable.pushStr" | "readable.pushNull" | "readable.pushU" | "readable.pushDyn" | "readable.unshift" | "readable.unshiftStr" | "readable.read" | "readable.pause" | "readable.resume" | "readable.setEncoding"
2545
+ | "sp.finished" | "sp.pipeline"
2546
+ /** node:stream/consumers — the promise consumers over the readable
2547
+ * machinery: (s) → a pending promise settled at the terminal point
2548
+ * with the accumulated result (sc.text: the utf8 decode, sc.json: the
2549
+ * parsed DOM — malformed input rejects with the parse's SyntaxError,
2550
+ * sc.buffer: the concatenated bytes) or rejected with the stream's
2551
+ * error / ERR_STREAM_PREMATURE_CLOSE. */
2552
+ | "sc.text" | "sc.json" | "sc.buffer" | "readable.newDyn" | "writable.newDyn" | "duplex.newDyn" | "transform.newDyn" | "passthrough.newDyn" | "readable.initDyn" | "writable.initDyn" | "duplex.initDyn" | "transform.initDyn" | "passthrough.initDyn" | "readable.push" | "readable.pushStr" | "readable.pushNull" | "readable.pushU" | "readable.pushDyn" | "readable.unshift" | "readable.unshiftStr" | "readable.read" | "readable.pause" | "readable.resume" | "readable.setEncoding"
2553
+ /** push(chunk, enc) with a literal non-utf8 encoding, and the
2554
+ * defaultEncoding option's push side (how push(string) decodes —
2555
+ * Buffer.from(chunk, enc)); both carry the CANONICAL literal. */
2556
+ | "readable.pushStrEnc" | "readable.pushEncoding"
2444
2557
  /** for-await over a readable (the desugared loop's per-pass promise):
2445
2558
  * +1 promise of the next chunk — buffered content, the EOF sentinel
2446
2559
  * (empty Buffer / dyn undefined), or a rejection with the stream's
@@ -2846,9 +2959,18 @@ export type IrLibFn = "island.eval"
2846
2959
  * the rest as Int32) — backends emit the scr_bit_* runtime helpers. */
2847
2960
  export type IrNumBinOp = "+" | "-" | "*" | "/" | "%" | "**" | "&" | "|" | "^" | "<<" | ">>" | ">>>" | "<" | "<=" | ">" | ">=" | "===" | "!==";
2848
2961
  export type IrStrCmpOp = "<" | "<=" | ">" | ">=";
2849
- export type IrExpr = {
2962
+ export type IrExpr =
2963
+ /** `spelling` (ask 4's representability input) is the author's SOURCE
2964
+ * spelling of a decimal integer literal, present exactly when that
2965
+ * spelling does not round-trip f64 (`9007199254740993` reads back as
2966
+ * 9007199254740992) — the library integer-boundary check refuses on the
2967
+ * spelling, never on the already-rounded value. Round-tripping literals
2968
+ * and non-integer spellings carry nothing, so the IR is byte-identical
2969
+ * for every program that held its numbers. */
2970
+ {
2850
2971
  kind: "numLit";
2851
2972
  value: number;
2973
+ spelling?: string;
2852
2974
  type: IrType;
2853
2975
  loc: SrcLoc;
2854
2976
  } | {
@@ -3652,6 +3774,23 @@ export type IrExpr = {
3652
3774
  type: IrType;
3653
3775
  loc: SrcLoc;
3654
3776
  }
3777
+ /** Island value → dyn DOM conversion (`type` is always dyn; the operand
3778
+ * is always jsval): the jsval→DOM crossing — an 'any'-typed engine
3779
+ * value flowing into an 'unknown'/'object'/JS-residue slot wraps BY
3780
+ * REFERENCE as the DOM's SCR_DYN_JSVAL kind (scr_dyn_from_jsval).
3781
+ * Engine scalars (number/string/boolean/null/undefined) normalize to
3782
+ * the native DOM kinds at wrap time, so wrapped nodes only ever hold
3783
+ * engine objects/arrays/functions; typeof/truthiness/String()/=== on
3784
+ * the wrapped node route to the engine, un-armed DOM walks fence
3785
+ * loudly, and scr_jsval_from_dyn unwraps the SAME engine value back
3786
+ * (identity round trip). The operand is borrowed; the result is owned
3787
+ * (+1). Never throws. */
3788
+ | {
3789
+ kind: "dynFromJsval";
3790
+ value: IrExpr;
3791
+ type: IrType;
3792
+ loc: SrcLoc;
3793
+ }
3655
3794
  /** CALLING a dyn DOM value — `fn(a, b)` where fn is checked-dynamic (an
3656
3795
  * implicit-any JS binding, a dyn record member, a dynKeyGet result).
3657
3796
  * Arguments are ALREADY dyn-typed (typed values box through dynFrom at
@@ -4577,6 +4716,17 @@ export declare function moduleLibAsyncSurface(mod: IrModule): {
4577
4716
  surface: string;
4578
4717
  loc: SrcLoc;
4579
4718
  } | null;
4719
+ /** libCall families that demote `deterministic` (prefix match over
4720
+ * IrLibFn spellings). process.stdout/stderr writes are deliberately NOT
4721
+ * here: output is an effect, not a nondeterminism input, and console
4722
+ * policy is the profile's ask-5 business. process.platform/arch and the
4723
+ * version constants fold at compile time, so they are per-binary
4724
+ * constants, not ambient reads. Exported for the attestation-parity test
4725
+ * (tests/harness/surface-manifest.test.ts): every spelling this table
4726
+ * demotes on must be deniable by a manifest-id fence, or the ask-5 §4
4727
+ * invariant (compiles under full fences ⇒ deterministic) cannot be
4728
+ * stated. */
4729
+ export declare const LIB_NONDETERMINISTIC_PREFIXES: readonly [string, string][];
4580
4730
  /** First ambient-nondeterminism or ambient-authority surface the module
4581
4731
  * graph reaches, or null when the graph is clean (the sidecar then
4582
4732
  * attests `deterministic: true`). */
package/dist/ir/nodes.js CHANGED
@@ -870,7 +870,12 @@ export function canConvertToDyn(t, getRecord, getUnion) {
870
870
  }
871
871
  if (t.kind === "union") {
872
872
  const def = getUnion(t.unionId);
873
- return !!def && def.arms.every((a) => a.kind === "undefinedT" || isJsonSafeType(a, getRecord, getUnion));
873
+ // JSON-safe arms box as before; BOXABLE FUNCTION arms join them (the
874
+ // invalid-input probes iterate `[1, null, () => {}, true]` — the
875
+ // union's func arm crosses through the checked-dynamic function
876
+ // boundary exactly like a bare func dynFrom).
877
+ return !!def && def.arms.every((a) => a.kind === "undefinedT" || isJsonSafeType(a, getRecord, getUnion) ||
878
+ (a.kind === "func" && canBoxFuncIntoDyn(a, getRecord, getUnion)));
874
879
  }
875
880
  return false;
876
881
  }
@@ -946,8 +951,15 @@ export function canDynCheckTo(t, getRecord, getUnion) {
946
951
  * back). */
947
952
  export function canBoxFuncIntoDyn(t, getRecord, getUnion) {
948
953
  return (t.kind === "func" &&
949
- t.params.every((p) => p.kind === "dyn" || canDynCheckTo(p, getRecord, getUnion)) &&
950
- (t.ret.kind === "void" || t.ret.kind === "dyn" || canConvertToDyn(t.ret, getRecord, getUnion)));
954
+ // A jsval (island) param converts through scr_jsval_from_dyn in the
955
+ // thunk (wrapped cells unwrap by reference, DOM data deep-copies) —
956
+ // the checker-'any' callback params of the routed-dispatch lane
957
+ // (`bag.list.map((x) => ...)` with x typed any).
958
+ t.params.every((p) => p.kind === "dyn" || p.kind === "jsval" || canDynCheckTo(p, getRecord, getUnion)) &&
959
+ // A jsval return converts through the by-reference wrap
960
+ // (dynFromJsval — the thunk's result conversion), so engine-returning
961
+ // callbacks box too: the routed-dispatch lane's flatMap shape.
962
+ (t.ret.kind === "void" || t.ret.kind === "dyn" || t.ret.kind === "jsval" || canConvertToDyn(t.ret, getRecord, getUnion)));
951
963
  }
952
964
  /** A closure type a dyn function value can ADAPT to (dynCheck): every
953
965
  * param dyn or dyn-convertible (the adapter converts typed arguments into
@@ -1171,6 +1183,7 @@ export function moduleUsesStream(mod) {
1171
1183
  node.fn === "stream.destroy" || node.fn === "stream.destroyErr" ||
1172
1184
  node.fn === "stream.prop" || node.fn === "stream.errored" ||
1173
1185
  node.fn === "sp.finished" || node.fn === "sp.pipeline" ||
1186
+ node.fn.startsWith("sc.") ||
1174
1187
  node.fn.startsWith("stream.set"))) {
1175
1188
  found = true;
1176
1189
  return;
@@ -1730,6 +1743,10 @@ export function moduleUsesTls(mod) {
1730
1743
  /** libCall families a v1 library artifact refuses, with the surface name the SC4005
1731
1744
  * teaching uses. Prefix match over IrLibFn spellings. */
1732
1745
  const LIB_MODE_REFUSED_PREFIXES = [
1746
+ // fs.exists is the one CALLBACK-async fs op with a real implementation:
1747
+ // its fire rides the timer queue (scr_bytes_io.c), which library links
1748
+ // exclude — refuse the surface like the rest of the event-loop family.
1749
+ ["fs.existsChk", "the async fs callback surface (fs.exists)"],
1733
1750
  ["timers.", "the timers surface (setTimeout family)"],
1734
1751
  ["tp.", "the timers/promises surface"],
1735
1752
  ["cp.", "the child_process surface"],
@@ -1877,8 +1894,12 @@ export function moduleLibAsyncSurface(mod) {
1877
1894
  * here: output is an effect, not a nondeterminism input, and console
1878
1895
  * policy is the profile's ask-5 business. process.platform/arch and the
1879
1896
  * version constants fold at compile time, so they are per-binary
1880
- * constants, not ambient reads. */
1881
- const LIB_NONDETERMINISTIC_PREFIXES = [
1897
+ * constants, not ambient reads. Exported for the attestation-parity test
1898
+ * (tests/harness/surface-manifest.test.ts): every spelling this table
1899
+ * demotes on must be deniable by a manifest-id fence, or the ask-5 §4
1900
+ * invariant (compiles under full fences ⇒ deterministic) cannot be
1901
+ * stated. */
1902
+ export const LIB_NONDETERMINISTIC_PREFIXES = [
1882
1903
  ["math.random", "Math.random"],
1883
1904
  ["crypto.random", "crypto randomness"],
1884
1905
  ["date.", "the live clock (Date)"],
@@ -1893,7 +1914,16 @@ const LIB_NONDETERMINISTIC_PREFIXES = [
1893
1914
  ["process.execPath", "process identity"],
1894
1915
  ["process.uptime", "the live clock (process.uptime)"],
1895
1916
  ["process.availableMemory", "machine memory state"],
1896
- ["process.memoryUsage", "machine memory state"],
1917
+ ["process.constrainedMemory", "machine memory state"],
1918
+ // process.memoryUsage carries NO row: nothing lowers it — no IrLibFn
1919
+ // spelling exists for it, so a prefix here would be dead. If a lowering
1920
+ // ever lands, its spellings must join this table AND the manifest's
1921
+ // ambient projection (the parity test fails until both agree).
1922
+ ["process.rusage", "machine resource usage (process.resourceUsage)"],
1923
+ ["process.cpu", "the process CPU clock (process.cpuUsage)"],
1924
+ ["process.threadCpu", "the thread CPU clock (process.threadCpuUsage)"],
1925
+ ["process.isTTY", "terminal attachment (isTTY)"],
1926
+ ["process.columns", "terminal geometry (columns)"],
1897
1927
  ["process.kill", "process authority (kill)"],
1898
1928
  ["process.umask", "process authority (umask)"],
1899
1929
  ["process.exit", "process authority (exit)"],
@@ -1968,6 +1998,8 @@ export const MAY_THROW_LIB_FNS = new Set([
1968
1998
  // divergence-66 stance).
1969
1999
  "tls.pemDyn",
1970
2000
  "tls.createServerDyn",
2001
+ "tls.createSecureContextDyn",
2002
+ "tls.caCertsChk",
1971
2003
  "tls.createServerDynCb",
1972
2004
  "https.createServerDyn",
1973
2005
  "https.createServerDynCb",
@@ -2031,6 +2063,9 @@ export const MAY_THROW_LIB_FNS = new Set([
2031
2063
  "stream.pipelineDyn",
2032
2064
  "sp.finished",
2033
2065
  "sp.pipeline",
2066
+ "sc.text",
2067
+ "sc.json",
2068
+ "sc.buffer",
2034
2069
  "readable.newDyn",
2035
2070
  "writable.newDyn",
2036
2071
  "duplex.newDyn",
@@ -2043,6 +2078,7 @@ export const MAY_THROW_LIB_FNS = new Set([
2043
2078
  "passthrough.initDyn",
2044
2079
  "readable.push",
2045
2080
  "readable.pushStr",
2081
+ "readable.pushStrEnc",
2046
2082
  "readable.pushNull",
2047
2083
  "readable.pushU",
2048
2084
  "readable.pushDyn",
@@ -2132,6 +2168,11 @@ export const MAY_THROW_LIB_FNS = new Set([
2132
2168
  "dyn.objKeys",
2133
2169
  "dyn.hasOwn",
2134
2170
  "dyn.assign",
2171
+ // variadic Object.assign: spread flattening throws V8's spread-call
2172
+ // TypeErrors; the final copy throws ToObject on a nullish target
2173
+ "dyn.packPushSpread",
2174
+ "dyn.packPushSpreadIter",
2175
+ "dyn.assignAll",
2135
2176
  "dyn.objValues",
2136
2177
  "dyn.objEntries",
2137
2178
  "error.domClone",
@@ -2139,6 +2180,8 @@ export const MAY_THROW_LIB_FNS = new Set([
2139
2180
  // throws Node's catchable SyntaxError at construction.
2140
2181
  "regex.new",
2141
2182
  "dyn.keySet",
2183
+ // the destructuring pack throws V8's TypeError on non-iterable DOM kinds
2184
+ "dyn.iterPack",
2142
2185
  "dyn.toString",
2143
2186
  "dyn.defineProps",
2144
2187
  "process.chdir",
@@ -2174,7 +2217,22 @@ export const MAY_THROW_LIB_FNS = new Set([
2174
2217
  "bytes.compareChk",
2175
2218
  "buffer.newStringFail",
2176
2219
  "fs.toUnixTimestamp",
2220
+ "fs.existsChk",
2221
+ "fs.mkdtempChk",
2222
+ "fs.mkdtempSyncChk",
2223
+ "fs.readFileChk",
2224
+ "fs.opendirChk",
2225
+ "fs.watchFileChk",
2226
+ "fs.lchmodChk",
2227
+ "fs.lchmodSyncChk",
2228
+ "fsp.lchmodChk",
2229
+ "fs.readChk",
2230
+ "fs.streamOptsChk",
2231
+ "net.connectAttempt",
2232
+ "net.connectOptsChk",
2233
+ "net.setAutoSelTimeout",
2177
2234
  "error.argTypeThrow",
2235
+ "error.propTypeThrow",
2178
2236
  "emitter.setMaxChk",
2179
2237
  "emitter.setDefaultMaxChk",
2180
2238
  "fs.readFileSyncBytes",
@@ -2197,6 +2255,7 @@ export const MAY_THROW_LIB_FNS = new Set([
2197
2255
  "dgram.connectCb",
2198
2256
  "dgram.sendStr",
2199
2257
  "dgram.sendBytes",
2258
+ "dgram.sendChk",
2200
2259
  "dgram.address",
2201
2260
  "dgram.close",
2202
2261
  "dgram.closeCb",