@scriptc/compiler 0.0.7 → 0.0.9

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 (94) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +13 -0
  2. package/dist/backend/cc.js +14 -0
  3. package/dist/backend/cc.js.map +1 -1
  4. package/dist/backend/emission/emit-exprs.js +155 -6
  5. package/dist/backend/emission/emit-exprs.js.map +1 -1
  6. package/dist/backend/emission/emit-island.js +9 -1
  7. package/dist/backend/emission/emit-island.js.map +1 -1
  8. package/dist/backend/emission/emit-stmts.js +3 -1
  9. package/dist/backend/emission/emit-stmts.js.map +1 -1
  10. package/dist/backend/emission/emit-types.d.ts +3 -0
  11. package/dist/backend/emission/emit-types.js +12 -0
  12. package/dist/backend/emission/emit-types.js.map +1 -1
  13. package/dist/backend/emission/emit-walkers.d.ts +7 -5
  14. package/dist/backend/emission/emit-walkers.js +45 -18
  15. package/dist/backend/emission/emit-walkers.js.map +1 -1
  16. package/dist/backend/emission/emitter.d.ts +1 -1
  17. package/dist/backend/emission/emitter.js +35 -10
  18. package/dist/backend/emission/emitter.js.map +1 -1
  19. package/dist/backend/emission/may-throw.js +4 -3
  20. package/dist/backend/emission/may-throw.js.map +1 -1
  21. package/dist/backend/llvm/emitter.js +300 -18
  22. package/dist/backend/llvm/emitter.js.map +1 -1
  23. package/dist/diagnostics/diagnostic.d.ts +98 -11
  24. package/dist/diagnostics/diagnostic.js +185 -25
  25. package/dist/diagnostics/diagnostic.js.map +1 -1
  26. package/dist/frontend/lib-contract.d.ts +24 -6
  27. package/dist/frontend/lib-contract.js +125 -44
  28. package/dist/frontend/lib-contract.js.map +1 -1
  29. package/dist/frontend/lowering/lower-assert.js +16 -0
  30. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  31. package/dist/frontend/lowering/lower-builtins.d.ts +11 -0
  32. package/dist/frontend/lowering/lower-builtins.js +127 -4
  33. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  34. package/dist/frontend/lowering/lower-calls.d.ts +77 -18
  35. package/dist/frontend/lowering/lower-calls.js +978 -44
  36. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  37. package/dist/frontend/lowering/lower-classes.d.ts +14 -1
  38. package/dist/frontend/lowering/lower-classes.js +112 -16
  39. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  40. package/dist/frontend/lowering/lower-containers.d.ts +4 -2
  41. package/dist/frontend/lowering/lower-containers.js +236 -44
  42. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  43. package/dist/frontend/lowering/lower-emitter.js +55 -1
  44. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  45. package/dist/frontend/lowering/lower-exprs.d.ts +26 -3
  46. package/dist/frontend/lowering/lower-exprs.js +507 -47
  47. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  48. package/dist/frontend/lowering/lower-island.d.ts +7 -0
  49. package/dist/frontend/lowering/lower-island.js +71 -10
  50. package/dist/frontend/lowering/lower-island.js.map +1 -1
  51. package/dist/frontend/lowering/lower-mixins.d.ts +1 -1
  52. package/dist/frontend/lowering/lower-mixins.js +1 -1
  53. package/dist/frontend/lowering/lower-modules.js +95 -4
  54. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  55. package/dist/frontend/lowering/lower-stmts.js +866 -56
  56. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  57. package/dist/frontend/lowering/lower-stream.js +28 -2
  58. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  59. package/dist/frontend/lowering/lowerer.d.ts +85 -17
  60. package/dist/frontend/lowering/lowerer.js +459 -37
  61. package/dist/frontend/lowering/lowerer.js.map +1 -1
  62. package/dist/frontend/lowering/surfaces.js +20 -3
  63. package/dist/frontend/lowering/surfaces.js.map +1 -1
  64. package/dist/frontend/npm-static-rewrite.d.ts +7 -2
  65. package/dist/frontend/npm-static-rewrite.js +566 -138
  66. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  67. package/dist/frontend/npm-static.js +11 -2
  68. package/dist/frontend/npm-static.js.map +1 -1
  69. package/dist/frontend/program.js +5 -5
  70. package/dist/frontend/program.js.map +1 -1
  71. package/dist/frontend/shared.d.ts +6 -1
  72. package/dist/frontend/shared.js +46 -1
  73. package/dist/frontend/shared.js.map +1 -1
  74. package/dist/frontend/types.d.ts +28 -1
  75. package/dist/frontend/types.js +304 -10
  76. package/dist/frontend/types.js.map +1 -1
  77. package/dist/index.d.ts +2 -1
  78. package/dist/index.js +181 -26
  79. package/dist/index.js.map +1 -1
  80. package/dist/ir/nodes.d.ts +159 -9
  81. package/dist/ir/nodes.js +76 -6
  82. package/dist/ir/nodes.js.map +1 -1
  83. package/dist/ir/validate.js +93 -14
  84. package/dist/ir/validate.js.map +1 -1
  85. package/dist/library/profile.d.ts +17 -3
  86. package/dist/library/profile.js +38 -9
  87. package/dist/library/profile.js.map +1 -1
  88. package/dist/library/sidecar.js +162 -43
  89. package/dist/library/sidecar.js.map +1 -1
  90. package/dist/library/trap-teaching.d.ts +11 -0
  91. package/dist/library/trap-teaching.js +49 -0
  92. package/dist/library/trap-teaching.js.map +1 -0
  93. package/package.json +2 -2
  94. package/surface-manifest.json +46 -4
@@ -243,6 +243,7 @@ export type IrType = {
243
243
  params: IrType[];
244
244
  ret: IrType;
245
245
  rest?: true;
246
+ restAbi?: "jsval";
246
247
  } | {
247
248
  kind: "object";
248
249
  className: string;
@@ -436,8 +437,16 @@ export declare function isSupportedMapValue(t: IrType): boolean;
436
437
  /** The INDEX-SIGNATURE value fence (`{ [k: string]: V }` shapes): the map
437
438
  * VALUE kinds — the overflow portion IS a string-keyed map — plus dyn
438
439
  * (`unknown`, an unknown-valued pricing-table shape: overflow reads surface ordinary
439
- * dyn values validated by the usual checked casts). Shared frontend
440
- * (mapType) / validator. */
440
+ * dyn values validated by the usual checked casts) and three kinds the
441
+ * overflow store carries that user Maps don't admit yet:
442
+ * func — `Record<string, () => void>`, the command-registry pattern
443
+ * (scr_closure adapters; closures are cycle-headered and traced,
444
+ * so a handler capturing its own registry collects)
445
+ * map/set — `Record<string, Map<K, V>>`/`Record<string, Set<T>>`
446
+ * nested-container tables (scr_map adapters; a map value's own
447
+ * cycle capability propagates through the trace fixpoint)
448
+ * Nested index-signature RECORDS ride the record kind like any other.
449
+ * Shared frontend (mapType) / validator. */
441
450
  export declare function isSupportedIndexValue(t: IrType): boolean;
442
451
  export declare function funcOf(params: IrType[], ret: IrType): IrType;
443
452
  /** The union FUNC/SET-arm sibling rule, shared by the frontend's union
@@ -542,6 +551,24 @@ export interface IrLibExport {
542
551
  fnName: string;
543
552
  params: ("f64" | "bool" | "string" | "bytes" | "u8" | "u32" | "i32")[];
544
553
  returns: "f64" | "bool" | "string" | "bytes" | "void";
554
+ /** The exact sink-message bytes this wrapper passes to the inbound-bytes
555
+ * marshalling helper's trap — present exactly when a parameter is
556
+ * bytes-classed. Already the assembled structured trap-teaching form
557
+ * (library/trap-teaching.ts): 0x01, teaching text, 0x1F, SC4012, 0x1F,
558
+ * this export's C symbol, and the profile's remediation behind one more
559
+ * 0x1F when supplied. Assembled ONCE at export resolution so both
560
+ * backends emit identical bytes by construction. */
561
+ inboundBytesTrap?: string;
562
+ }
563
+ /** One runtime-trap overlay row: the profile's teaching (replaces the
564
+ * baseline human line as field 0) and/or remediation (the optional fourth
565
+ * field) for one runtime detected-trap code. At least one of the two is
566
+ * present, or the row is not emitted. Text is profile-validated free of
567
+ * the encoding's reserved bytes (SC4001). */
568
+ export interface IrLibTrapOverlay {
569
+ code: string;
570
+ teaching?: string;
571
+ remediation?: string;
545
572
  }
546
573
  export interface IrLibSection {
547
574
  /** The profile's identity string (artifact header comments only). */
@@ -557,6 +584,15 @@ export interface IrLibSection {
557
584
  * posture (every entry prologue resets the arena). */
558
585
  resultResetSymbol: string | null;
559
586
  exports: IrLibExport[];
587
+ /** Profile-declared teaching/remediation overlays for the runtime
588
+ * detected-trap code family (SC4013–SC4019, diagnostics registry): both
589
+ * backends emit these as the program TU's overlay table
590
+ * (scr_library_trap_overlays — flat code/teaching/remediation triples)
591
+ * that the library trap funnel consults when it assembles a detected
592
+ * trap's structured sink message. Only declared codes appear, in the
593
+ * registry family's order, so the two emissions' data is identical by
594
+ * construction. */
595
+ trapOverlays: IrLibTrapOverlay[];
560
596
  /** The ask-2 identity getters (present exactly when the profile
561
597
  * declares a sidecar): pure data returns emitted with NO entry
562
598
  * prologue — exempt from the poisoned guard and every runtime touch
@@ -1162,7 +1198,12 @@ export type IrStrIntrinsicMethod = "length" | "charCodeAt" | "charAt" | "indexOf
1162
1198
  * DataView" RangeError on any bad offset. `dvGetBigUint64Number`/
1163
1199
  * `dvGetBigInt64Number` are the COMPOSED `Number(view.getBigUint64(...))`
1164
1200
  * lowerings — the bare bigint-returning calls are fenced, the wrapped
1165
- * form converts the 8-byte integer to double exactly as Number(bigint). */
1201
+ * form converts the 8-byte integer to double exactly as Number(bigint).
1202
+ * The `dvSet*` setters mirror the getters: [offset, value] plus the
1203
+ * optional bool littleEndian on the multi-byte kinds → void, the same
1204
+ * constant RangeError on any bad offset; values coerce JS-exactly
1205
+ * (integer kinds by modular truncation, Float32 by double→float
1206
+ * rounding). No BIG setters exist — bigint arguments never lower. */
1166
1207
  export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" | "setFrom" | "toString" | "readNum" | "writeNum" | "readNumVar" | "writeNumVar"
1167
1208
  /** The comparison/search/mutation surface (u8 receivers only; see the
1168
1209
  * runtime contract): `equals` [bytes] → bool (never throws);
@@ -1178,7 +1219,7 @@ export type IrBytesIntrinsicMethod = "length" | "byteLength" | "get" | "slice" |
1178
1219
  * f64 copied count, THROWS; `swap16/32/64` [] → the receiver (+1,
1179
1220
  * in-place), THROW; `writeStr` [string, strLit enc, f64 offset, f64
1180
1221
  * length?] → f64 bytes written, THROWS. */
1181
- | "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";
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";
1182
1223
  /** The bytesIntrinsic methods that can raise a catchable error — backends'
1183
1224
  * may-throw analyses seed on these exactly like MAY_THROW_LIB_FNS. */
1184
1225
  export declare const MAY_THROW_BYTES_METHODS: ReadonlySet<IrBytesIntrinsicMethod>;
@@ -1425,6 +1466,20 @@ export type IrLibFn = "island.eval"
1425
1466
  * result for negative fractions rounding to zero. The explicit-digits
1426
1467
  * forms keep their island lowering. Results +1; never throw. */
1427
1468
  | "num.toExponential" | "num.toFixed0"
1469
+ /** Object.is over two numbers — the spec's SameValue on doubles: NaN
1470
+ * equals NaN, +0 differs from -0, everything else is `===`. Plain bool
1471
+ * result; never throws. (Union-armed operands take unionEq's sameValue
1472
+ * flag instead — this is the both-f64 fast path.) */
1473
+ | "num.sameValue"
1474
+ /** `new Intl.NumberFormat("en-US").format(x)` and
1475
+ * `x.toLocaleString("en-US")` with DEFAULT options — the one locale
1476
+ * whose data the runtime embeds (Node's default-build locale): decimal
1477
+ * notation, 0–3 fraction digits rounded half-up on the SHORTEST
1478
+ * round-tripping decimal (ICU's rounding input, probed vs Node —
1479
+ * format(1.0005) is "1.001" though toFixed(3) answers "1.000"), ","
1480
+ * grouping every three integer digits, "∞"/"NaN" texts, and "-0" for
1481
+ * negative inputs rounding to zero. Result +1; never throws. */
1482
+ | "intl.numFormatEnUs"
1428
1483
  /** `delete process.env[NAME]` — unsetenv(3): the mutation is visible to
1429
1484
  * every later read (process.envGet asks getenv fresh) and inherited by
1430
1485
  * spawned children, exactly Node. Statement position only (JS's boolean
@@ -1952,6 +2007,37 @@ export type IrLibFn = "island.eval"
1952
2007
  * zero-padded to the total. THROWS Node's 'length' RangeError on a
1953
2008
  * negative/non-integer total (may-throw seed). */
1954
2009
  | "buffer.concatLen"
2010
+ /** The checked-dynamic compare/equals validators (scr_bytes_io.c) —
2011
+ * the lowered form when an argument is NOT statically bytes<u8> (the
2012
+ * invalid-input probes; a dyn from an untyped JS helper): Node's own
2013
+ * argument ladders run at runtime — ERR_INVALID_ARG_TYPE with the
2014
+ * API's argument name ("buf1"/"buf2", "otherBuffer", "target"; offsets
2015
+ * "of type number"), validateOffset's ERR_OUT_OF_RANGE for bad
2016
+ * numbers, undefined offsets taking their Node defaults — and a
2017
+ * well-typed value still computes the real answer. All args borrowed
2018
+ * dyn; compareChk's four offset slots pass the undefined dyn when
2019
+ * syntactically absent. May-throw seeds. */
2020
+ | "buffer.compareChk" | "bytes.equalsChk" | "bytes.compareChk"
2021
+ /** The deprecated `new Buffer(number, 'enc')` string-arm rejection:
2022
+ * always throws Node's ERR_INVALID_ARG_TYPE ("The \"string\" argument
2023
+ * must be of type string. Received ..."). Borrowed dyn; may-throw. */
2024
+ | "buffer.newStringFail"
2025
+ /** fs._toUnixTimestamp(time) over a DOM value: numeric strings and
2026
+ * finite numbers coerce (negatives answer now/1000, Node's shape);
2027
+ * everything else throws Node's ERR_INVALID_ARG_TYPE. May-throw. */
2028
+ | "fs.toUnixTimestamp"
2029
+ /** The compiler-resolved ERR_INVALID_ARG_TYPE throw with a RUNTIME-
2030
+ * rendered Received tail: args [argname, "of type ..." clause, the
2031
+ * offending DOM value]. ALWAYS THROWS; polymorphic result (the
2032
+ * error.nodeThrow pattern). May-throw seed. */
2033
+ | "error.argTypeThrow"
2034
+ /** The checked-dynamic max-listeners ladders: setMaxChk is the
2035
+ * instance form over a DOM n (non-numbers ERR_INVALID_ARG_TYPE,
2036
+ * negatives/NaN ERR_OUT_OF_RANGE; +1 receiver back — chaining);
2037
+ * setDefaultMaxChk is the static/property form, its second argument
2038
+ * naming the message slot ("setMaxListeners" for the static call,
2039
+ * "defaultMaxListeners" for the module-property assignment). */
2040
+ | "emitter.setMaxChk" | "emitter.setDefaultMaxChk"
1955
2041
  /** The Buffer forms of the fs quartet: readFileSync(path) with NO
1956
2042
  * encoding → bytes<u8> (+1), writeFileSync(path, bytes), and the
1957
2043
  * fs/promises readFile(path) no-encoding form (an already-settled
@@ -2176,6 +2262,20 @@ export type IrLibFn = "island.eval"
2176
2262
  * field to stamp. error.toString: borrowed `%Error`-typed receiver, +1
2177
2263
  * string in Node's "name: message" shape. None of the three throws. */
2178
2264
  | "error.new"
2265
+ /** The compiler-resolved Node-parity throw for always-throwing lowered
2266
+ * arms (ERR_INVALID_THIS receivers, ERR_MISSING_ARGS arity ladders,
2267
+ * the symbol-to-string TypeError): args are [error-kind f64 (the
2268
+ * SCR_ERR_* index: 0 Error, 1 TypeError, 2 RangeError), code (empty =
2269
+ * no code slot), message]. ALWAYS THROWS catchably; the result type is
2270
+ * the replaced expression's own (never materialized — the
2271
+ * global.undefRead pattern). May-throw seed. */
2272
+ | "error.nodeThrow"
2273
+ /** JS ToString over a DOM value WITH the object protocol (a user
2274
+ * toString/valueOf member is CALLED and its throw propagates;
2275
+ * exhaustion throws "Cannot convert object to primitive value"; units
2276
+ * render "null"/"undefined") — the WHATWG USVString conversions
2277
+ * (URLSearchParams names/values). Borrowed dyn; +1 string. May-throw. */
2278
+ | "dyn.toStringCoerce"
2179
2279
  /** A read of a `declare`d const NOTHING defines (the bundler-define
2180
2280
  * pattern — __VERSION__): always throws the catchable ReferenceError
2181
2281
  * Node raises at the access ("<name> is not defined"). args[0] is the
@@ -2230,7 +2330,7 @@ export type IrLibFn = "island.eval"
2230
2330
  * JS). Strings/arrays/bytes answer their index keys; other scalars an
2231
2331
  * empty array; null/undefined throw Node's catchable TypeError
2232
2332
  * ("Cannot convert undefined or null to object"). */
2233
- | "dyn.objKeys" | "dyn.objValues" | "dyn.objEntries"
2333
+ | "dyn.objKeys" | "dyn.hasOwn" | "dyn.assign" | "dyn.objValues" | "dyn.objEntries"
2234
2334
  /** structuredClone over the DOM (scr_json.c): the JSON-safe subset plus
2235
2335
  * bytes (a fresh copy — a Buffer clones as a plain Uint8Array, like
2236
2336
  * Node), deep. Functions and handle kinds throw the spec's catchable
@@ -2334,7 +2434,13 @@ export type IrLibFn = "island.eval"
2334
2434
  * propagates the first error by destroying the rest, calls cb after the
2335
2435
  * last 'close'; answers the destination +1. The Dyn twins take the
2336
2436
  * callback as a checked-dynamic VALUE (mustCall wrappers). */
2337
- | "stream.finished" | "stream.finishedDyn" | "stream.pipeline" | "stream.pipelineDyn" | "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"
2437
+ | "stream.finished" | "stream.finishedDyn" | "stream.pipeline" | "stream.pipelineDyn"
2438
+ /** node:stream/promises — the promise forms over the same machinery:
2439
+ * sp.finished: (s) → a pending void promise the terminal watcher
2440
+ * settles; sp.pipeline: (count, s1..sn) → the callback pipeline's
2441
+ * chaining/destroyer semantics settling a void promise (fulfilled on a
2442
+ * 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"
2338
2444
  /** for-await over a readable (the desugared loop's per-pass promise):
2339
2445
  * +1 promise of the next chunk — buffered content, the EOF sentinel
2340
2446
  * (empty Buffer / dyn undefined), or a rejection with the stream's
@@ -3558,12 +3664,26 @@ export type IrExpr = {
3558
3664
  * message exactly). A function callee calls through the boxed thunk:
3559
3665
  * per-arg validation against the boxed signature (mismatches throw the
3560
3666
  * path-annotated TypeError), result converted back to dyn. Callee and
3561
- * args are borrowed; the result is owned (+1). MAY THROW. */
3667
+ * args are borrowed; the result is owned (+1). MAY THROW.
3668
+ *
3669
+ * `spreads` (the runtime-arity form — `f(...args)`, the rest-forwarding
3670
+ * idiom): entries name indices into `args` whose DOM values FLATTEN into
3671
+ * the argument vector at the call — JS's spread over the DOM's iterable
3672
+ * kinds (arrays element-by-element, strings by code point, bytes by
3673
+ * byte; every other kind throws V8's exact spread-call TypeError,
3674
+ * catchably — `what` is the spread expression's source spelling, which
3675
+ * the nullish text spells), evaluated and flattened left-to-right (JS's
3676
+ * ArgumentListEvaluation). The emitters build one fresh argument array
3677
+ * and apply through it. */
3562
3678
  | {
3563
3679
  kind: "dynCall";
3564
3680
  callee: IrExpr;
3565
3681
  calleeName: string;
3566
3682
  args: IrExpr[];
3683
+ spreads?: {
3684
+ arg: number;
3685
+ what: string;
3686
+ }[];
3567
3687
  type: IrType;
3568
3688
  loc: SrcLoc;
3569
3689
  }
@@ -3932,11 +4052,15 @@ export type IrExpr = {
3932
4052
  * comparison (`u === "text"`) arrives here after the frontend wraps the
3933
4053
  * plain side (payload identity is preserved by the wrap, so ref-arm
3934
4054
  * semantics stay JS-exact). Operands are borrowed; result is a plain
3935
- * bool. `negated` is the `!==` spelling. */
4055
+ * bool. `negated` is the `!==` spelling. `sameValue` upgrades the f64
4056
+ * arm's compare from `===` to SameValue (NaN equals NaN, +0 differs
4057
+ * from -0) — the Object.is lowering; every other arm's compare is
4058
+ * shared between the two semantics. */
3936
4059
  | {
3937
4060
  kind: "unionEq";
3938
4061
  unionId: string;
3939
4062
  negated: boolean;
4063
+ sameValue: boolean;
3940
4064
  left: IrExpr;
3941
4065
  right: IrExpr;
3942
4066
  type: IrType;
@@ -4108,6 +4232,15 @@ export type IrJsOp = "add" | "sub" | "mul" | "div" | "mod" | "pow" | "neg" | "pl
4108
4232
  * engine, Symbol.hasInstance included; a non-object RHS throws the
4109
4233
  * engine's own TypeError, bridged catchably. */
4110
4234
  | "instanceOf" | "truthy" | "not" | "typeof" | "toStr" | "getProp" | "setProp" | "getIdx" | "setIdx" | "callMethod" | "callFn"
4235
+ /** Spread application on an island callee — `f(...pre, ...s)`, the
4236
+ * rest-forwarding idiom (`(...args) => g(...args)` under --dynamic).
4237
+ * Args are exactly (callee, pre, spread): `pre` is the engine array of
4238
+ * leading fixed arguments (jsOp arrLit), `spread` the spread source;
4239
+ * `name` carries the spread expression's source spelling (V8's nullish
4240
+ * spread-call TypeError spells it). The prelude helper uses REAL spread
4241
+ * syntax, so iterator protocols are the engine's own, with guards
4242
+ * front-running V8's exact spread-call TypeError texts. May throw. */
4243
+ | "callSpread"
4111
4244
  /** `new X(...)` where X is jsval-typed (package-declared classes):
4112
4245
  * JS_CallConstructor — args are the callee then the constructor
4113
4246
  * arguments, mirroring callFn. */
@@ -4122,6 +4255,23 @@ export type IrJsOp = "add" | "sub" | "mul" | "div" | "mod" | "pow" | "neg" | "pl
4122
4255
  * are alternating key/value jsvals (keys are marshaled strings), arrLit
4123
4256
  * args are the elements. Never throw. */
4124
4257
  | "objLit" | "arrLit"
4258
+ /** The engine-native TemplateStringsArray for an ISLAND TAG call: args
4259
+ * are 2n marshaled strings — n cooked then n raw — building a fresh
4260
+ * engine array whose `.raw` carries the raw spellings (tags dispatch on
4261
+ * it). Never throws. */
4262
+ | "tplStrings"
4263
+ /** Spread completion for an island-native object literal: copies
4264
+ * args[1]'s own enumerable properties onto args[0] (the spec's
4265
+ * CopyDataProperties — the engine's own Object.assign; null/undefined
4266
+ * sources spread nothing) and answers args[0] for chaining. May throw
4267
+ * (getters run). */
4268
+ | "objSpread"
4269
+ /** Accessor completion for an island-native object literal: defines a
4270
+ * GETTER property on args[0] (the object) — args are (obj, key string
4271
+ * marshal, getter function handle) — and answers the same object (the
4272
+ * chainable spelling: `defineGetter(objLit(...), k, f)`). The
4273
+ * self-referential doc-printer root-indent shape. Never throws. */
4274
+ | "defineGetter"
4125
4275
  /** The engine's own undefined / null as island values (zero args, never
4126
4276
  * throw): the unit arms of a union marshaling IN (`string | undefined`
4127
4277
  * into an 'any' slot — the undefined arm IS the engine undefined), and
@@ -4202,7 +4352,7 @@ export declare function isIslandCallbackParamType(t: IrType, getRecord: (shapeId
4202
4352
  * composites: still fenced). */
4203
4353
  export declare function islandCallbackRet(t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, getUnion: (unionId: string) => IrUnionDef | undefined): {
4204
4354
  async: boolean;
4205
- tag: "void" | "jsval" | "f64" | "bool" | "string" | "json";
4355
+ tag: "void" | "jsval" | "f64" | "bool" | "string" | "json" | "dyn";
4206
4356
  } | null;
4207
4357
  /** The TYPED extension of canMarshalFuncIntoIsland (a strict superset):
4208
4358
  * closures whose params are per-argument-convertible at call time
package/dist/ir/nodes.js CHANGED
@@ -143,6 +143,11 @@ export function isSupportedMapValue(t) {
143
143
  // references at all, so no trace, no cycles, ever.
144
144
  case "classval":
145
145
  return true;
146
+ // A regex (Map<string, RegExp> — the per-EOL pattern table): the
147
+ // array-element story (scr_regex retain/release adapters, no trace —
148
+ // a regex holds no references), map form.
149
+ case "regex":
150
+ return true;
146
151
  default:
147
152
  return false;
148
153
  }
@@ -150,10 +155,22 @@ export function isSupportedMapValue(t) {
150
155
  /** The INDEX-SIGNATURE value fence (`{ [k: string]: V }` shapes): the map
151
156
  * VALUE kinds — the overflow portion IS a string-keyed map — plus dyn
152
157
  * (`unknown`, an unknown-valued pricing-table shape: overflow reads surface ordinary
153
- * dyn values validated by the usual checked casts). Shared frontend
154
- * (mapType) / validator. */
158
+ * dyn values validated by the usual checked casts) and three kinds the
159
+ * overflow store carries that user Maps don't admit yet:
160
+ * func — `Record<string, () => void>`, the command-registry pattern
161
+ * (scr_closure adapters; closures are cycle-headered and traced,
162
+ * so a handler capturing its own registry collects)
163
+ * map/set — `Record<string, Map<K, V>>`/`Record<string, Set<T>>`
164
+ * nested-container tables (scr_map adapters; a map value's own
165
+ * cycle capability propagates through the trace fixpoint)
166
+ * Nested index-signature RECORDS ride the record kind like any other.
167
+ * Shared frontend (mapType) / validator. */
155
168
  export function isSupportedIndexValue(t) {
156
- return t.kind === "dyn" || isSupportedMapValue(t);
169
+ return (t.kind === "dyn" ||
170
+ t.kind === "func" ||
171
+ t.kind === "map" ||
172
+ t.kind === "set" ||
173
+ isSupportedMapValue(t));
157
174
  }
158
175
  export function funcOf(params, ret) {
159
176
  return { kind: "func", params, ret };
@@ -219,7 +236,7 @@ export function typeKey(t) {
219
236
  case "set":
220
237
  return `set<${typeKey(t.elem)}>`;
221
238
  case "func":
222
- return `func(${[...t.params.map(typeKey), ...(t.rest ? ["...dyn[]"] : [])].join(",")})=>${typeKey(t.ret)}`;
239
+ return `func(${[...t.params.map(typeKey), ...(t.rest ? [t.restAbi === "jsval" ? "...jsval[]" : "...dyn[]"] : [])].join(",")})=>${typeKey(t.ret)}`;
223
240
  case "object":
224
241
  return `object:${t.className}`;
225
242
  case "classval":
@@ -456,6 +473,14 @@ export const MAY_THROW_BYTES_METHODS = new Set([
456
473
  "dvGetFloat64",
457
474
  "dvGetBigUint64Number",
458
475
  "dvGetBigInt64Number",
476
+ "dvSetUint8",
477
+ "dvSetInt8",
478
+ "dvSetUint16",
479
+ "dvSetInt16",
480
+ "dvSetUint32",
481
+ "dvSetInt32",
482
+ "dvSetFloat32",
483
+ "dvSetFloat64",
459
484
  ]);
460
485
  /** Result-type rule for each island op (the validator enforces it; the
461
486
  * frontend constructs nodes with exactly these). */
@@ -473,10 +498,14 @@ export function jsOpResultKind(op) {
473
498
  case "getIdx":
474
499
  case "callMethod":
475
500
  case "callFn":
501
+ case "callSpread":
476
502
  case "construct":
477
503
  case "globalGet":
478
504
  case "objLit":
479
505
  case "arrLit":
506
+ case "defineGetter":
507
+ case "tplStrings":
508
+ case "objSpread":
480
509
  case "undefLit":
481
510
  case "nullLit":
482
511
  case "iterNew":
@@ -672,6 +701,7 @@ export function canCrossIslandBoundary(t, getRecord, getUnion) {
672
701
  export const MAX_ISLAND_CALLBACK_ARITY = 16;
673
702
  export function canMarshalFuncIntoIsland(t) {
674
703
  return (t.kind === "func" &&
704
+ t.rest !== true &&
675
705
  t.params.length <= MAX_ISLAND_CALLBACK_ARITY &&
676
706
  t.params.every((p) => p.kind === "jsval") &&
677
707
  (t.ret.kind === "jsval" || t.ret.kind === "void" ||
@@ -720,6 +750,13 @@ export function islandCallbackRet(t, getRecord, getUnion) {
720
750
  const tag = tagOf(t);
721
751
  if (tag)
722
752
  return { async: false, tag };
753
+ // A CHECKED-DYNAMIC result (a JS getter/callback whose inferred return
754
+ // degraded — the doc-printer root-indent getter): the DOM value deep-
755
+ // copies into the engine on return, exactly the jsMarshal dyn rule
756
+ // (data kinds only; boxed functions/handles throw the catchable
757
+ // TypeError). Sync only — no engine-promise tag exists for DOM values.
758
+ if (t.kind === "dyn")
759
+ return { async: false, tag: "dyn" };
723
760
  return isJsonSafeType(t, getRecord, getUnion) ? { async: false, tag: "json" } : null;
724
761
  }
725
762
  /** The TYPED extension of canMarshalFuncIntoIsland (a strict superset):
@@ -729,8 +766,22 @@ export function islandCallbackRet(t, getRecord, getUnion) {
729
766
  * buffer. Closures taking closures and 'unknown'-typed params stay fenced
730
767
  * (no per-type extraction exists for them inside a host call). */
731
768
  export function canMarshalTypedFuncIntoIsland(t, getRecord, getUnion) {
732
- return (t.kind === "func" &&
733
- t.params.length <= MAX_ISLAND_CALLBACK_ARITY &&
769
+ if (t.kind !== "func")
770
+ return false;
771
+ // The ISLAND-REST form (`async (...args) =>` in JS under --dynamic —
772
+ // the withPlugins wrapper): the trailing ABI param is the ENGINE array
773
+ // of the call's surplus arguments; leading params convert per argument
774
+ // like any typed callback. Plain rest signatures (dynRest, typed
775
+ // rests) stay out — no completed-ABI spelling exists for them here.
776
+ if (t.rest === true) {
777
+ return (t.restAbi === "jsval" &&
778
+ t.params.length >= 1 &&
779
+ t.params.length <= MAX_ISLAND_CALLBACK_ARITY &&
780
+ t.params[t.params.length - 1].kind === "jsval" &&
781
+ t.params.slice(0, -1).every((p) => isIslandCallbackParamType(p, getRecord, getUnion)) &&
782
+ islandCallbackRet(t.ret, getRecord, getUnion) !== null);
783
+ }
784
+ return (t.params.length <= MAX_ISLAND_CALLBACK_ARITY &&
734
785
  t.params.every((p) => isIslandCallbackParamType(p, getRecord, getUnion)) &&
735
786
  islandCallbackRet(t.ret, getRecord, getUnion) !== null);
736
787
  }
@@ -1119,6 +1170,7 @@ export function moduleUsesStream(mod) {
1119
1170
  node.fn.startsWith("passthrough.") ||
1120
1171
  node.fn === "stream.destroy" || node.fn === "stream.destroyErr" ||
1121
1172
  node.fn === "stream.prop" || node.fn === "stream.errored" ||
1173
+ node.fn === "sp.finished" || node.fn === "sp.pipeline" ||
1122
1174
  node.fn.startsWith("stream.set"))) {
1123
1175
  found = true;
1124
1176
  return;
@@ -1977,6 +2029,8 @@ export const MAY_THROW_LIB_FNS = new Set([
1977
2029
  "stream.finishedDyn",
1978
2030
  "stream.pipeline",
1979
2031
  "stream.pipelineDyn",
2032
+ "sp.finished",
2033
+ "sp.pipeline",
1980
2034
  "readable.newDyn",
1981
2035
  "writable.newDyn",
1982
2036
  "duplex.newDyn",
@@ -2028,6 +2082,10 @@ export const MAY_THROW_LIB_FNS = new Set([
2028
2082
  // A read of a declare-d const nothing defines: always throws Node's
2029
2083
  // catchable ReferenceError.
2030
2084
  "global.undefRead",
2085
+ // The compiler-resolved Node-parity throw: always throws, catchably.
2086
+ "error.nodeThrow",
2087
+ // USVString coercion runs user toString/valueOf — throws propagate.
2088
+ "dyn.toStringCoerce",
2031
2089
  "child.kill",
2032
2090
  // The caller's lookup runs synchronously inside the connect call — a
2033
2091
  // throw there propagates like Node's.
@@ -2072,6 +2130,8 @@ export const MAY_THROW_LIB_FNS = new Set([
2072
2130
  "dyn.cloneTransferFail",
2073
2131
  // the dyn Object walks throw on null/undefined receivers
2074
2132
  "dyn.objKeys",
2133
+ "dyn.hasOwn",
2134
+ "dyn.assign",
2075
2135
  "dyn.objValues",
2076
2136
  "dyn.objEntries",
2077
2137
  "error.domClone",
@@ -2107,6 +2167,16 @@ export const MAY_THROW_LIB_FNS = new Set([
2107
2167
  "crypto.randomBytesToString",
2108
2168
  "crypto.randomBytes",
2109
2169
  "buffer.concatLen",
2170
+ // The checked-dynamic compare/equals validators: Node's argument
2171
+ // ladders throw ERR_INVALID_ARG_TYPE / ERR_OUT_OF_RANGE catchably.
2172
+ "buffer.compareChk",
2173
+ "bytes.equalsChk",
2174
+ "bytes.compareChk",
2175
+ "buffer.newStringFail",
2176
+ "fs.toUnixTimestamp",
2177
+ "error.argTypeThrow",
2178
+ "emitter.setMaxChk",
2179
+ "emitter.setDefaultMaxChk",
2110
2180
  "fs.readFileSyncBytes",
2111
2181
  "fs.writeFileSyncBytes",
2112
2182
  "zlib.inflateSync",