@scriptc/compiler 0.0.8 → 0.0.10

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 (90) 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 +244 -17
  5. package/dist/backend/emission/emit-exprs.js.map +1 -1
  6. package/dist/backend/emission/emit-types.d.ts +3 -0
  7. package/dist/backend/emission/emit-types.js +12 -0
  8. package/dist/backend/emission/emit-types.js.map +1 -1
  9. package/dist/backend/emission/emit-walkers.d.ts +7 -5
  10. package/dist/backend/emission/emit-walkers.js +52 -12
  11. package/dist/backend/emission/emit-walkers.js.map +1 -1
  12. package/dist/backend/emission/emitter.d.ts +1 -1
  13. package/dist/backend/emission/emitter.js +30 -9
  14. package/dist/backend/emission/emitter.js.map +1 -1
  15. package/dist/backend/llvm/dyn.d.ts +1 -0
  16. package/dist/backend/llvm/dyn.js +83 -1
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.js +357 -20
  19. package/dist/backend/llvm/emitter.js.map +1 -1
  20. package/dist/diagnostics/diagnostic.d.ts +73 -14
  21. package/dist/diagnostics/diagnostic.js +112 -31
  22. package/dist/diagnostics/diagnostic.js.map +1 -1
  23. package/dist/diagnostics/render.js +8 -0
  24. package/dist/diagnostics/render.js.map +1 -1
  25. package/dist/frontend/lowering/lib-boundary.js +11 -1
  26. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  27. package/dist/frontend/lowering/lower-assert.js +16 -0
  28. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  29. package/dist/frontend/lowering/lower-builtins.d.ts +24 -0
  30. package/dist/frontend/lowering/lower-builtins.js +256 -3
  31. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  32. package/dist/frontend/lowering/lower-calls.d.ts +71 -11
  33. package/dist/frontend/lowering/lower-calls.js +942 -18
  34. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  35. package/dist/frontend/lowering/lower-classes.js +27 -1
  36. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  37. package/dist/frontend/lowering/lower-containers.d.ts +21 -2
  38. package/dist/frontend/lowering/lower-containers.js +386 -53
  39. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  40. package/dist/frontend/lowering/lower-dgram.js +92 -17
  41. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  42. package/dist/frontend/lowering/lower-emitter.js +54 -0
  43. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  44. package/dist/frontend/lowering/lower-exprs.js +231 -17
  45. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  46. package/dist/frontend/lowering/lower-modules.js +33 -2
  47. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  48. package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
  49. package/dist/frontend/lowering/lower-namespaces.js +50 -15
  50. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  51. package/dist/frontend/lowering/lower-server.js +211 -4
  52. package/dist/frontend/lowering/lower-server.js.map +1 -1
  53. package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
  54. package/dist/frontend/lowering/lower-stmts.js +660 -19
  55. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  56. package/dist/frontend/lowering/lower-stream.js +92 -5
  57. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  58. package/dist/frontend/lowering/lowerer.d.ts +102 -15
  59. package/dist/frontend/lowering/lowerer.js +378 -30
  60. package/dist/frontend/lowering/lowerer.js.map +1 -1
  61. package/dist/frontend/lowering/surfaces.js +20 -3
  62. package/dist/frontend/lowering/surfaces.js.map +1 -1
  63. package/dist/frontend/npm-static-rewrite.d.ts +7 -2
  64. package/dist/frontend/npm-static-rewrite.js +566 -138
  65. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  66. package/dist/frontend/npm-static.js +11 -2
  67. package/dist/frontend/npm-static.js.map +1 -1
  68. package/dist/frontend/program.js +5 -5
  69. package/dist/frontend/program.js.map +1 -1
  70. package/dist/frontend/shared.d.ts +6 -1
  71. package/dist/frontend/shared.js +46 -1
  72. package/dist/frontend/shared.js.map +1 -1
  73. package/dist/frontend/types.d.ts +13 -0
  74. package/dist/frontend/types.js +88 -9
  75. package/dist/frontend/types.js.map +1 -1
  76. package/dist/index.js +169 -32
  77. package/dist/index.js.map +1 -1
  78. package/dist/ir/nodes.d.ts +230 -12
  79. package/dist/ir/nodes.js +85 -6
  80. package/dist/ir/nodes.js.map +1 -1
  81. package/dist/ir/validate.js +109 -9
  82. package/dist/ir/validate.js.map +1 -1
  83. package/dist/library/fence-eval.d.ts +77 -0
  84. package/dist/library/fence-eval.js +385 -0
  85. package/dist/library/fence-eval.js.map +1 -0
  86. package/dist/library/profile.d.ts +11 -1
  87. package/dist/library/profile.js +102 -18
  88. package/dist/library/profile.js.map +1 -1
  89. package/package.json +2 -2
  90. package/surface-manifest.json +10 -3
@@ -1,5 +1,5 @@
1
1
  import { arrayOf, BOOL, BYTES_U8, bytesOf, canMarshalFuncIntoIsland, CHILDSTREAM_T, DYN, F64, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, RUNTIME_ERROR_CLASSES, STRING, typeEquals } from "../../ir/nodes.js";
2
- import { boxAccess, BYTES_NUM_KIND_C, BYTES_NUM_VAR_C, bytesElemKindC, cDecl, cFnPtrCast, cNumberLiteral, cStringLiteral, cType, DV_GET_KIND_C, elemAccess, mapKeyAccess, mapKeyKindC, mapValKindC, retainCallC, vAdapters } from "./emit-types.js";
2
+ import { boxAccess, BYTES_NUM_KIND_C, BYTES_NUM_VAR_C, bytesElemKindC, cDecl, cFnPtrCast, cNumberLiteral, cStringLiteral, cType, DV_GET_KIND_C, DV_SET_KIND_C, elemAccess, mapKeyAccess, mapKeyKindC, mapValKindC, retainCallC, vAdapters } from "./emit-types.js";
3
3
  import { mangleClassNew, mangleClassRetain, mangleClassStruct, mangleField, mangleFnClosure, mangleFunction, mangleGlobal, mangleLocal, mangleRecordNew, mangleRecordStruct, mangleVtStruct } from "../mangle.js";
4
4
  import { OVERFLOW_MEMBER } from "./emit-shapes.js";
5
5
  import { dynDestrCheckHelper, dynIterNHelper, dynKeyGetHelper } from "./emit-walkers.js";
@@ -489,6 +489,28 @@ export function emitExpr(E, e) {
489
489
  E.currentFrame().push({ name, type: e.type });
490
490
  return { name, type: e.type };
491
491
  }
492
+ if (e.left.type.kind === "dyn") {
493
+ // `a ?? b` on a checked-dynamic left: the runtime kind decides
494
+ // (UNDEF/NULL take the default; a wrapped island value asks the
495
+ // engine); the right runs lazily in its branch (already dyn).
496
+ const l = E.emitExpr(e.left);
497
+ E.moveTemp(l);
498
+ const name = `sc_t${E.tempCounter++}`;
499
+ E.line(`${cDecl(e.type, name)};`);
500
+ E.line(`if (scr_dyn_is_nullish(${l.name})) {`);
501
+ E.indent++;
502
+ E.releaseValue(l.name, e.left.type);
503
+ E.emitBranchInto(name, e.right);
504
+ E.indent--;
505
+ E.line(`} else {`);
506
+ E.indent++;
507
+ E.line(`${name} = ${l.name};`);
508
+ E.indent--;
509
+ E.line(`}`);
510
+ if (isRefCounted(e.type))
511
+ E.currentFrame().push({ name, type: e.type });
512
+ return { name, type: e.type };
513
+ }
492
514
  if (e.left.type.kind !== "union")
493
515
  throw new Error("emitter bug: nullish left is not a union");
494
516
  const def = E.unionsById.get(e.left.type.unionId);
@@ -1102,6 +1124,22 @@ export function emitExpr(E, e) {
1102
1124
  E.emitPendingCheck();
1103
1125
  return t;
1104
1126
  }
1127
+ case "dvSetUint8":
1128
+ case "dvSetInt8":
1129
+ case "dvSetUint16":
1130
+ case "dvSetInt16":
1131
+ case "dvSetUint32":
1132
+ case "dvSetInt32":
1133
+ case "dvSetFloat32":
1134
+ case "dvSetFloat64": {
1135
+ // DataView setters: [offset, value, littleEndian?] — void;
1136
+ // throw the getters' constant RangeError on a bad offset.
1137
+ const kind = DV_SET_KIND_C[method];
1138
+ E.line(`scr_dataview_set(${r.name}, ${args[0].name}, ${args[1].name}, ${kind}, ` +
1139
+ `${args[2]?.name ?? "false"});${E.srcComment(e.loc)}`);
1140
+ E.emitPendingCheck();
1141
+ return { name: "", type: e.type };
1142
+ }
1105
1143
  default: {
1106
1144
  const _exhaustive = method;
1107
1145
  void _exhaustive;
@@ -1573,6 +1611,13 @@ export function emitExpr(E, e) {
1573
1611
  }
1574
1612
  return E.newTemp(e.type, `${E.toDynHelper(v.type)}(${v.name})`);
1575
1613
  }
1614
+ case "dynFromJsval": {
1615
+ // Island value → DOM: the by-reference wrap (scr_dyn_from_jsval
1616
+ // retains the cell in; engine scalars normalize to native DOM
1617
+ // kinds at wrap time). Operand borrowed, result +1, never throws.
1618
+ const v = E.emitExpr(e.value);
1619
+ return E.newTemp(e.type, `scr_dyn_from_jsval(${v.name})`);
1620
+ }
1576
1621
  case "dynCall": {
1577
1622
  // Calling a dyn value: args are already dyn (the lowering boxed or
1578
1623
  // converted them); everything is BORROWED by scr_dyn_call — the
@@ -1580,6 +1625,32 @@ export function emitExpr(E, e) {
1580
1625
  // with the frame as usual. The callee's source spelling rides
1581
1626
  // along for Node's "<name> is not a function" TypeError.
1582
1627
  const callee = E.emitExpr(e.callee);
1628
+ const what = cStringLiteral(Buffer.from(e.calleeName, "utf8"));
1629
+ if (e.spreads !== undefined && e.spreads.length > 0) {
1630
+ // The RUNTIME-ARITY form (`f(...args)`): one fresh DOM array
1631
+ // collects the arguments left-to-right — plain args move in
1632
+ // (push takes ownership), spread args FLATTEN (push_spread
1633
+ // retains elements in and throws V8's spread-call TypeError for
1634
+ // non-iterable DOM kinds, checked per spread — JS's
1635
+ // ArgumentListEvaluation order) — then apply calls through the
1636
+ // array's elements (borrowed, exactly scr_dyn_call).
1637
+ const spreadAt = new Map(e.spreads.map((s) => [s.arg, s.what]));
1638
+ const pack = E.newTemp(DYN, "scr_dyn_new_arr()");
1639
+ e.args.forEach((a, i) => {
1640
+ const v = E.emitExpr(a);
1641
+ const spreadWhat = spreadAt.get(i);
1642
+ if (spreadWhat !== undefined) {
1643
+ const w = cStringLiteral(Buffer.from(spreadWhat, "utf8"));
1644
+ E.line(`scr_dyn_arr_push_spread(${pack.name}, ${v.name}, ${w});`);
1645
+ E.emitPendingCheck();
1646
+ }
1647
+ else {
1648
+ E.moveTemp(v);
1649
+ E.line(`scr_dyn_arr_push(${pack.name}, ${v.name});`);
1650
+ }
1651
+ });
1652
+ return E.fallibleTemp(e.type, `scr_dyn_apply(${callee.name}, ${pack.name}, ${what})`);
1653
+ }
1583
1654
  const args = e.args.map((a) => E.emitExpr(a));
1584
1655
  let argsExpr = "NULL";
1585
1656
  if (args.length > 0) {
@@ -1587,7 +1658,6 @@ export function emitExpr(E, e) {
1587
1658
  E.line(`ScrDyn *${arr}[${args.length}] = { ${args.map((a) => a.name).join(", ")} };`);
1588
1659
  argsExpr = arr;
1589
1660
  }
1590
- const what = cStringLiteral(Buffer.from(e.calleeName, "utf8"));
1591
1661
  return E.fallibleTemp(e.type, `scr_dyn_call(${callee.name}, ${argsExpr}, ${args.length}, ${what})`);
1592
1662
  }
1593
1663
  case "dynInvoke": {
@@ -1826,6 +1896,9 @@ export function emitExpr(E, e) {
1826
1896
  case "dynHasKey": {
1827
1897
  // `"k" in pkg`: a kind-guarded presence answer, computed against
1828
1898
  // the literal key at compile time — no allocation, borrowed box.
1899
+ // An ISLAND-held receiver fences loudly (Node asks the real
1900
+ // engine object — `false` would be a silent wrong answer), so
1901
+ // the temp rides the fallible path.
1829
1902
  const d = E.emitExpr(e.value);
1830
1903
  const keyBytes = Buffer.from(e.key, "utf8");
1831
1904
  const keyLit = cStringLiteral(keyBytes);
@@ -1835,8 +1908,8 @@ export function emitExpr(E, e) {
1835
1908
  : /^(0|[1-9][0-9]*)$/.test(e.key) && Number(e.key) <= Number.MAX_SAFE_INTEGER
1836
1909
  ? `${d.name}->v.arr.len > ${e.key}`
1837
1910
  : "false";
1838
- const test = `(${d.name}->kind == SCR_DYN_OBJ ? (${objTest}) : ${d.name}->kind == SCR_DYN_ARR ? (${arrTest}) : false)`;
1839
- return E.newTemp(e.type, e.negated ? `!${test}` : test);
1911
+ const test = `(${d.name}->kind == SCR_DYN_OBJ ? (${objTest}) : ${d.name}->kind == SCR_DYN_ARR ? (${arrTest}) : scr_dyn_isl_fence(${d.name}, "'in'"))`;
1912
+ return E.fallibleTemp(e.type, e.negated ? `!${test}` : test);
1840
1913
  }
1841
1914
  case "dynScalarEq": {
1842
1915
  // dyn vs scalar strict equality: kind test + payload compare.
@@ -1858,34 +1931,50 @@ export function emitExpr(E, e) {
1858
1931
  }
1859
1932
  case "dynTest": {
1860
1933
  // A pure kind compare on the DOM node — borrowed; only the truthy
1861
- // form also reads a scalar payload.
1934
+ // form also reads a scalar payload. ISLAND-held nodes (the jsval
1935
+ // kind — engine objects/arrays/functions only, scalars normalize
1936
+ // at wrap time) route the tests that depend on the engine's
1937
+ // answer through the scr_dyn_isl_* helpers (false on every other
1938
+ // kind, so the calls stay unconditional); narrowing never changes
1939
+ // representation (SEMANTICS.md).
1862
1940
  const d = E.emitExpr(e.value);
1863
1941
  const test = e.test === "nullish"
1864
1942
  ? `(${d.name}->kind == SCR_DYN_UNDEF || ${d.name}->kind == SCR_DYN_NULL)`
1865
1943
  : e.test === "object"
1866
1944
  ? // `typeof v === "object"`: objects, arrays, bytes, native
1867
- // handles, promises, AND null.
1868
- `(${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE || ${d.name}->kind == SCR_DYN_NULL)`
1945
+ // handles, promises, AND null — engine-held objects by the
1946
+ // engine's own typeof.
1947
+ `(${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE || ${d.name}->kind == SCR_DYN_NULL || scr_dyn_isl_typeof_is(${d.name}, "object"))`
1869
1948
  : e.test === "truthy"
1870
1949
  ? // ToBoolean over the DOM: bool by value; number falsy for
1871
1950
  // 0, -0 (== 0 in C), and NaN (self-inequality); string
1872
1951
  // falsy when empty; obj/arr/bytes/func/handle always true;
1873
- // the remaining kinds (undefined, null) always false.
1874
- `(${d.name}->kind == SCR_DYN_BOOL ? ${d.name}->v.b : ${d.name}->kind == SCR_DYN_NUM ? (${d.name}->v.num == ${d.name}->v.num && ${d.name}->v.num != 0) : ${d.name}->kind == SCR_DYN_STR ? ${d.name}->v.str->len != 0 : (${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_FUNC || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE))`
1952
+ // JSVAL through the runtime's routed arm (the bigint 0n
1953
+ // edge); the remaining kinds (undefined, null) always false.
1954
+ `(${d.name}->kind == SCR_DYN_BOOL ? ${d.name}->v.b : ${d.name}->kind == SCR_DYN_NUM ? (${d.name}->v.num == ${d.name}->v.num && ${d.name}->v.num != 0) : ${d.name}->kind == SCR_DYN_STR ? ${d.name}->v.str->len != 0 : ${d.name}->kind == SCR_DYN_JSVAL ? scr_dyn_truthy(${d.name}) : (${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_FUNC || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE))`
1875
1955
  : e.test === "error"
1876
1956
  ? // `u instanceof Error`: the DOM's error encoding — an
1877
1957
  // object carrying the reserved "%error" marker key
1878
- // (built by caughtToDyn for Error payloads).
1879
- `(${d.name}->kind == SCR_DYN_OBJ && scr_dyn_obj_get(${d.name}, "%error", 6) != NULL)`
1880
- : `${d.name}->kind == ${{ string: "SCR_DYN_STR", number: "SCR_DYN_NUM", boolean: "SCR_DYN_BOOL", undefined: "SCR_DYN_UNDEF", null: "SCR_DYN_NULL", bytes: "SCR_DYN_BYTES", array: "SCR_DYN_ARR", function: "SCR_DYN_FUNC" }[e.test]}`;
1958
+ // (built by caughtToDyn for Error payloads) — or a real
1959
+ // engine Error held by reference.
1960
+ `((${d.name}->kind == SCR_DYN_OBJ && scr_dyn_obj_get(${d.name}, "%error", 6) != NULL) || scr_dyn_isl_is_error(${d.name}))`
1961
+ : e.test === "array"
1962
+ ? // Array.isArray: the DOM's array kind, or the engine's
1963
+ // own answer for an engine-held value.
1964
+ `(${d.name}->kind == SCR_DYN_ARR || scr_dyn_isl_is_array(${d.name}))`
1965
+ : e.test === "function"
1966
+ ? `(${d.name}->kind == SCR_DYN_FUNC || scr_dyn_isl_typeof_is(${d.name}, "function"))`
1967
+ : `${d.name}->kind == ${{ string: "SCR_DYN_STR", number: "SCR_DYN_NUM", boolean: "SCR_DYN_BOOL", undefined: "SCR_DYN_UNDEF", null: "SCR_DYN_NULL", bytes: "SCR_DYN_BYTES" }[e.test]}`;
1881
1968
  return E.newTemp(e.type, e.negated ? `!(${test})` : test);
1882
1969
  }
1883
1970
  case "unionEq": {
1884
- // Strict equality of the ARM values via the per-union helper (tag
1885
- // compare + per-arm payload compare). Both boxes are borrowed.
1971
+ // Strict equality (or Object.is's SameValue — the f64 arm's
1972
+ // compare is the one difference) of the ARM values via the
1973
+ // per-union helper (tag compare + per-arm payload compare). Both
1974
+ // boxes are borrowed.
1886
1975
  const l = E.emitExpr(e.left);
1887
1976
  const r = E.emitExpr(e.right);
1888
- const call = `${E.unionEqHelper(e.unionId)}(${l.name}, ${r.name})`;
1977
+ const call = `${E.unionEqHelper(e.unionId, e.sameValue)}(${l.name}, ${r.name})`;
1889
1978
  return E.newTemp(e.type, e.negated ? `!${call}` : call);
1890
1979
  }
1891
1980
  case "caughtTest": {
@@ -2145,13 +2234,20 @@ export function emitExpr(E, e) {
2145
2234
  // member retains the value in); throws Node's TypeErrors on
2146
2235
  // non-object receivers (may-throw seed set).
2147
2236
  return finish(`scr_dyn_key_set(${arg(0)}, ${arg(1)}, ${arg(2)})`);
2237
+ case "dyn.iterPack":
2238
+ // Destructuring pack over a dyn source: both borrowed, fresh
2239
+ // array +1; throws V8's destructuring TypeError on
2240
+ // non-iterable DOM kinds (may-throw seed set).
2241
+ return finish(`scr_dyn_iter_pack(${arg(0)}, ${arg(1)})`);
2148
2242
  case "dyn.typeof":
2149
2243
  // Bare typeof on a dyn value: the DOM kind's JS answer (+1).
2150
2244
  return finish(`scr_dyn_typeof(${arg(0)})`);
2151
2245
  case "dyn.toString":
2152
2246
  // Receiver-kind-dispatched toString (+1); throws Node's
2153
- // TypeError on undefined/null (may-throw seed set).
2154
- return finish(`scr_dyn_to_string(${arg(0)}, ${arg(1)})`);
2247
+ // TypeError on undefined/null and the "is not a function"
2248
+ // TypeError on null-prototype dictionaries (may-throw seed
2249
+ // set) — args[2] carries the call's source spelling.
2250
+ return finish(`scr_dyn_to_string_method(${arg(0)}, ${arg(1)}, ${arg(2)})`);
2155
2251
  case "fs.readFileSync":
2156
2252
  // args[1] is the (always-"utf8") encoding: evaluated for
2157
2253
  // JS-exact side-effect order, ignored by the runtime.
@@ -2440,6 +2536,13 @@ export function emitExpr(E, e) {
2440
2536
  return finish(`scr_num_to_exponential(${arg(0)})`);
2441
2537
  case "num.toFixed0":
2442
2538
  return finish(`scr_num_to_fixed0(${arg(0)})`);
2539
+ // Object.is over two numbers — SameValue on doubles. No throw.
2540
+ case "num.sameValue":
2541
+ return finish(`scr_num_same_value(${arg(0)}, ${arg(1)})`);
2542
+ // Intl.NumberFormat("en-US").format / toLocaleString("en-US")
2543
+ // with default options (scr_lib.c). +1 string; no throw.
2544
+ case "intl.numFormatEnUs":
2545
+ return finish(`scr_intl_num_format_en_us(${arg(0)})`);
2443
2546
  // The URL surface (scr_url.c): construction and the two
2444
2547
  // fileURLToPath receiver forms throw catchable TypeErrors
2445
2548
  // (may-throw seed set); the getters are pure reads. Receivers
@@ -2991,6 +3094,15 @@ export function emitExpr(E, e) {
2991
3094
  case "net.connect":
2992
3095
  E.usesTimers = true; // a connecting/open socket holds the loop open
2993
3096
  return finish(`scr_net_connect(${arg(0)}, ${arg(1)}, NULL)`);
3097
+ case "net.connectAttempt":
3098
+ // The validated autoSelectFamilyAttemptTimeout form: Node's
3099
+ // range ladder runs first, the dial follows.
3100
+ E.usesTimers = true;
3101
+ return finish(`scr_net_connect_attempt(${arg(0)}, ${arg(1)}, ${arg(2)})`);
3102
+ case "net.connectOptsChk":
3103
+ // The runtime option-bag ladder (always throws — a validation
3104
+ // error or the trailing fence; the error.nodeThrow dummy).
3105
+ return finish(`(scr_net_connect_opts_chk(${arg(0)}, ${arg(1)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
2994
3106
  case "net.connectCb": {
2995
3107
  E.usesTimers = true;
2996
3108
  const cb = args[2];
@@ -3093,6 +3205,9 @@ export function emitExpr(E, e) {
3093
3205
  case "dgram.sendBytes":
3094
3206
  E.usesTimers = true;
3095
3207
  return finish(`scr_dgram_send_bytes(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`);
3208
+ case "dgram.sendChk":
3209
+ E.usesTimers = true; // a validated send implicit-binds
3210
+ return finish(`scr_dgram_send_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)})`);
3096
3211
  case "dgram.address": {
3097
3212
  // The AddressInfo record, built here from runtime parts (the
3098
3213
  // frontend pinned the {address, family, port} shape). The
@@ -3800,6 +3915,13 @@ export function emitExpr(E, e) {
3800
3915
  // SNI answer serves; bad material is the construction-time
3801
3916
  // print-and-die trap, like createServer's.
3802
3917
  return finish(`scr_tls_create_secure_context((const char *)${arg(0)}->data, ${arg(0)}->len, (const char *)${arg(1)}->data, ${arg(1)}->len)`);
3918
+ case "tls.createSecureContextDyn":
3919
+ // The runtime option-bag form: Node's typed validations, then
3920
+ // the pem walk (throws catchably on both ladders).
3921
+ return finish(`scr_tls_create_secure_context_dyn(${arg(0)})`);
3922
+ case "tls.caCertsChk":
3923
+ // Always throws (validation error or the trailing fence).
3924
+ return finish(`(scr_tls_ca_certs_chk(${arg(0)}, ${arg(1)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
3803
3925
  case "http.serverOnRequest": {
3804
3926
  const cbT = e.args[1].type;
3805
3927
  if (cbT.kind !== "func")
@@ -4067,6 +4189,15 @@ export function emitExpr(E, e) {
4067
4189
  return finish(`scr_http2_stream_pending(${arg(0)})`);
4068
4190
  case "http2.streamSession":
4069
4191
  return finish(`scr_http2_stream_session(${arg(0)})`);
4192
+ case "dyn.toStringCoerce":
4193
+ // +1 string or NULL with the exception pending (user
4194
+ // toString/valueOf throws propagate). Borrows the dyn.
4195
+ return finish(`scr_dyn_string_coerce_js(${arg(0)})`);
4196
+ case "error.nodeThrow":
4197
+ // The compiler-resolved Node-parity throw (always throws —
4198
+ // the typed dummy is abandoned by the pending check's
4199
+ // unwind; releases are NULL-tolerant). Borrows both strings.
4200
+ return finish(`(scr_throw_node_coded(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4070
4201
  case "global.undefRead":
4071
4202
  // A declare-d const nothing defines: Node's catchable
4072
4203
  // ReferenceError at the access (always throws — the typed
@@ -4206,6 +4337,54 @@ export function emitExpr(E, e) {
4206
4337
  return finish(`scr_bytes_byte_length_str(${arg(0)}, ${arg(1)})`);
4207
4338
  case "buffer.isEncoding":
4208
4339
  return finish(`scr_bytes_is_encoding(${arg(0)})`);
4340
+ // The checked-dynamic compare/equals validators
4341
+ // (scr_bytes_io.c): Node's argument ladders throw catchably
4342
+ // (may-throw seed set); all dyn args borrowed.
4343
+ case "buffer.compareChk":
4344
+ return finish(`scr_buffer_compare_chk(${arg(0)}, ${arg(1)})`);
4345
+ case "bytes.equalsChk":
4346
+ return finish(`scr_bytes_equals_chk(${arg(0)}, ${arg(1)})`);
4347
+ case "bytes.compareChk":
4348
+ return finish(`scr_bytes_compare_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)})`);
4349
+ case "buffer.newStringFail":
4350
+ return finish(`scr_buffer_new_string_fail(${arg(0)})`);
4351
+ case "fs.toUnixTimestamp":
4352
+ return finish(`scr_fs_to_unix_timestamp(${arg(0)})`);
4353
+ // The fs argument-validation ladders: the always-throw Chk
4354
+ // forms (validation error or the trailing fence) take the
4355
+ // error.nodeThrow dummy pattern; mkdtempSyncChk and the lchmod
4356
+ // pair answer real results on a validated pass.
4357
+ case "fs.existsChk":
4358
+ E.usesTimers = true; // the scheduled answer holds the loop open
4359
+ return finish(`scr_fs_exists_async(${arg(0)}, ${arg(1)})`);
4360
+ case "fs.mkdtempChk":
4361
+ return finish(`(scr_fs_mkdtemp_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4362
+ case "fs.mkdtempSyncChk":
4363
+ return finish(`scr_fs_mkdtemp_sync_chk(${arg(0)}, ${arg(1)}, ${arg(2)})`);
4364
+ case "fs.readFileChk":
4365
+ return finish(`(scr_fs_read_file_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4366
+ case "fs.opendirChk":
4367
+ return finish(`(scr_fs_opendir_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4368
+ case "fs.watchFileChk":
4369
+ return finish(`(scr_fs_watch_file_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4370
+ case "fs.lchmodChk":
4371
+ return finish(`(scr_fs_lchmod_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4372
+ case "fs.lchmodSyncChk":
4373
+ return finish(`scr_fs_lchmod_sync_chk(${arg(0)}, ${arg(1)})`);
4374
+ case "fsp.lchmodChk":
4375
+ return finish(`scr_fsp_lchmod_chk(${arg(0)}, ${arg(1)})`);
4376
+ case "fs.readChk":
4377
+ return finish(`(scr_fs_read_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4378
+ case "fs.streamOptsChk":
4379
+ return finish(`(scr_fs_stream_opts_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4380
+ case "error.argTypeThrow":
4381
+ // Always throws with the runtime-rendered Received tail (the
4382
+ // error.nodeThrow dummy pattern). Borrows all three.
4383
+ return finish(`(scr_throw_arg_type(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4384
+ case "error.propTypeThrow":
4385
+ // The property flavor ("The \"options.x\" property must be
4386
+ // ...") — same always-throw dummy pattern.
4387
+ return finish(`(scr_throw_prop_type(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4209
4388
  // The fs Buffer forms (scr_bytes_io.c): the sync pair throws
4210
4389
  // like the utf8 forms (may-throw seed set); the promise form
4211
4390
  // rejects instead.
@@ -4630,6 +4809,27 @@ export function emitExpr(E, e) {
4630
4809
  // Object.assign over DOM values: own members copy, the target
4631
4810
  // returns (+1); non-object receivers throw like Node.
4632
4811
  return finish(`scr_dyn_assign(${arg(0)}, ${arg(1)})`);
4812
+ case "dyn.packPush":
4813
+ // Variadic Object.assign's source pack: a plain source
4814
+ // retains in (both args borrowed). Never throws.
4815
+ return finish(`scr_dyn_pack_push(${arg(0)}, ${arg(1)})`);
4816
+ case "dyn.packPushSpread":
4817
+ // A spread source flattens through the spread-call walk —
4818
+ // V8's exact TypeError texts (may-throw seed set); the string
4819
+ // spells the spread expression for the nullish form.
4820
+ return finish(`scr_dyn_pack_push_spread(${arg(0)}, ${arg(1)}, ${arg(2)})`);
4821
+ case "dyn.packPushSpreadIter":
4822
+ // The non-last/multi-spread positions: V8's iterator-protocol
4823
+ // failure texts describe the value (may-throw seed set).
4824
+ return finish(`scr_dyn_pack_push_spread_iter(${arg(0)}, ${arg(1)})`);
4825
+ case "dyn.assignAll":
4826
+ // The flattened pack copies onto the target left to right;
4827
+ // the target returns (+1). Nullish targets throw like Node.
4828
+ return finish(`scr_dyn_assign_all(${arg(0)}, ${arg(1)})`);
4829
+ case "dyn.objCreateNullProto":
4830
+ // Object.create(null): the fresh null-prototype dictionary
4831
+ // (+1). Never throws.
4832
+ return finish(`scr_dyn_new_obj_null_proto()`);
4633
4833
  case "dyn.hasOwn":
4634
4834
  // Object.hasOwn over a DOM receiver (throws on nullish, like
4635
4835
  // Node's ToObject).
@@ -4756,10 +4956,15 @@ export function emitExpr(E, e) {
4756
4956
  return finish(`scr_emitter_listeners((ScrEmitter *)${arg(0)}, ${arg(1)})`);
4757
4957
  case "emitter.setMax":
4758
4958
  return finish(`(${cType(e.type).trim()})scr_emitter_set_max((ScrEmitter *)${arg(0)}, ${arg(1)})`);
4959
+ case "emitter.setMaxChk":
4960
+ // The checked-dynamic ladder (may throw); +1 receiver back.
4961
+ return finish(`(${cType(e.type).trim()})scr_emitter_set_max_chk((ScrEmitter *)${arg(0)}, ${arg(1)})`);
4759
4962
  case "emitter.getMax":
4760
4963
  return finish(`scr_emitter_get_max((ScrEmitter *)${arg(0)})`);
4761
4964
  case "emitter.setDefaultMax":
4762
4965
  return finish(`scr_emitter_set_default_max(${arg(0)})`);
4966
+ case "emitter.setDefaultMaxChk":
4967
+ return finish(`scr_emitter_set_default_max_chk(${arg(0)}, ${arg(1)})`);
4763
4968
  case "emitter.getDefaultMax":
4764
4969
  return finish(`scr_emitter_get_default_max()`);
4765
4970
  // node:stream (scr_stream.c — linked exactly when these appear,
@@ -4876,6 +5081,22 @@ export function emitExpr(E, e) {
4876
5081
  const thunk = E.streamCbThunkFor("e", e.args[1 + n].type);
4877
5082
  return finish(`(${cType(e.type).trim()})scr_stream_pipeline(${n}, (ScrStream *[]){ ${list} }, ${cb.name}, &${thunk})`);
4878
5083
  }
5084
+ case "sp.finished":
5085
+ // The stream/promises form: a +1 pending promise the terminal
5086
+ // watcher settles — no callback, no cleanup exposure.
5087
+ E.usesTimers = true;
5088
+ return finish(`scr_sp_finished((ScrStream *)${arg(0)})`);
5089
+ case "sp.pipeline": {
5090
+ // pipeline(count, s1..sn) settling a void promise; the stream
5091
+ // list rides the callback form's compound literal.
5092
+ E.usesTimers = true;
5093
+ const countArg = e.args[0];
5094
+ if (countArg.kind !== "numLit")
5095
+ throw new Error(`emitter bug: ${fn} count not a literal`);
5096
+ const n = countArg.value;
5097
+ const list = Array.from({ length: n }, (_, i) => `(ScrStream *)${arg(1 + i)}`).join(", ");
5098
+ return finish(`scr_sp_pipeline(${n}, (ScrStream *[]){ ${list} })`);
5099
+ }
4879
5100
  case "readable.newDyn":
4880
5101
  case "writable.newDyn":
4881
5102
  case "duplex.newDyn":
@@ -5935,6 +6156,12 @@ export function emitExpr(E, e) {
5935
6156
  const pack = argPack(args.slice(1).map((x) => x.name));
5936
6157
  return finishFallible(`scr_jsval_call(${a(0)}, ${args.length - 1}, ${pack})`);
5937
6158
  }
6159
+ case "callSpread":
6160
+ // Spread application (`f(...pre, ...s)`): the prelude helper's
6161
+ // real spread syntax — iterator protocols are the engine's
6162
+ // own, the guards front-run V8's spread-call TypeError texts
6163
+ // (the name literal is the spread expression's spelling).
6164
+ return finishFallible(`scr_jsval_call_spread(${a(0)}, ${a(1)}, ${a(2)}, ${nameSym()})`);
5938
6165
  case "construct": {
5939
6166
  // `new X(...)` on an island callee: JS_CallConstructor.
5940
6167
  const pack = argPack(args.slice(1).map((x) => x.name));