@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
@@ -447,7 +447,10 @@ interface Buffer<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> extends
447
447
  }
448
448
  interface BufferConstructor {
449
449
  from(data: string, encoding?: BufferEncoding): Buffer;
450
- from(data: Uint8Array | ArrayBuffer | readonly number[]): Buffer;
450
+ /* The ArrayBuffer form is the VIEW construction: x.buffer with an
451
+ * optional byte offset/length shares x's storage (the subarray rule). */
452
+ from(data: ArrayBuffer, byteOffset?: number, length?: number): Buffer;
453
+ from(data: Uint8Array | readonly number[]): Buffer;
451
454
  alloc(size: number, fill?: string | number | Uint8Array, encoding?: BufferEncoding): Buffer;
452
455
  compare(buf1: Uint8Array, buf2: Uint8Array): number;
453
456
  /* alloc without the zero-fill guarantee — the lowering zero-fills
@@ -798,16 +801,38 @@ declare module "perf_hooks" {
798
801
  * performance.now() either way. */
799
802
  declare var performance: import("node:perf_hooks").Performance;
800
803
 
801
- /* node:module — the ADMIT-THEN-FENCE surface: the import compiles (the
802
- * module carries no evaluation), and every member keeps a per-site fence.
803
- * createRequire loads CommonJS from disk at runtime — a compiled
804
- * program's modules are fixed at build time, so the call's fence defers
805
- * to a runtime error in JS sources (the config-loader idiom is
806
- * reached only when a CJS config/plugin must load). Bare "module" stays a
807
- * package specifier (an npm package by that name exists); only the node:
808
- * spelling names the builtin. */
804
+ /* node:module. createRequire's lowered shape is the version/config-
805
+ * reading pattern real CLIs ship: a const binding over
806
+ * createRequire(import.meta.url) (or __filename) whose require calls
807
+ * take STATIC string literals — the indirection erases at compile time.
808
+ * A builtin spec makes the binding a namespace import in const clothing;
809
+ * a relative .json document bakes and parses (JSON.parse's `unknown`
810
+ * stance — validate with a checked cast); an installed npm package loads
811
+ * through the island's require-condition entry under --dynamic; a bare
812
+ * name nothing installed resolves compiles to Node's catchable
813
+ * MODULE_NOT_FOUND throw (the optional-dependency try/require pattern).
814
+ * Dynamic specifiers fence: a compiled binary's module graph is fixed at
815
+ * build time. builtinModules is the baked Node v24 list (a fresh
816
+ * mutable array per read where Node ships one frozen singleton);
817
+ * isBuiltin and syncBuiltinESMExports fence per site. Bare "module"
818
+ * stays a package specifier (an npm package by that name exists); only
819
+ * the node: spelling names the builtin. */
809
820
  declare module "node:module" {
810
821
  export function createRequire(filename: string | URL): (id: string) => unknown;
822
+ export const builtinModules: string[];
823
+ export function isBuiltin(moduleName: string): boolean;
824
+ export function syncBuiltinESMExports(): void;
825
+ }
826
+ /* import.meta: module-loader metadata with no value representation —
827
+ * every read fences (SC1090) EXCEPT as createRequire's base, where it
828
+ * only NAMES the containing file (import.meta.url, import.meta.filename,
829
+ * and __filename all mean "this file" there). Declared so the pattern
830
+ * typechecks under the fallback surface; @types/node's own augmentation
831
+ * stands in when adopted. */
832
+ interface ImportMeta {
833
+ url: string;
834
+ filename: string;
835
+ dirname: string;
811
836
  }
812
837
 
813
838
  /* The synchronous node:fs surface — utf8-only, no options objects, no
@@ -3148,3 +3173,23 @@ declare module "node:stream/promises" {
3148
3173
  import streamPromises = require("stream/promises");
3149
3174
  export = streamPromises;
3150
3175
  }
3176
+ declare module "stream/consumers" {
3177
+ /* The promise consumers over a readable: accumulate every chunk and
3178
+ * settle — text (the utf8 decode), json (the text through JSON.parse:
3179
+ * `unknown`, validated with a checked cast; malformed input rejects
3180
+ * with the parse's SyntaxError), buffer (the concatenated bytes;
3181
+ * string chunks contribute their utf8 bytes, Node's Blob rule).
3182
+ * Stream errors reject; an early close rejects with
3183
+ * ERR_STREAM_PREMATURE_CLOSE. arrayBuffer and blob fence per site:
3184
+ * neither value has a representation in a compiled binary. */
3185
+ function text(stream: unknown): Promise<string>;
3186
+ function json(stream: unknown): Promise<unknown>;
3187
+ function buffer(stream: unknown): Promise<Buffer>;
3188
+ function arrayBuffer(stream: unknown): Promise<ArrayBuffer>;
3189
+ function blob(stream: unknown): Promise<unknown>;
3190
+ export { arrayBuffer, blob, buffer, json, text };
3191
+ }
3192
+ declare module "node:stream/consumers" {
3193
+ import streamConsumers = require("stream/consumers");
3194
+ export = streamConsumers;
3195
+ }
@@ -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);
@@ -986,6 +1008,10 @@ export function emitExpr(E, e) {
986
1008
  // Omitted relative indices default like string slice: start 0,
987
1009
  // end +Infinity (math.h is always included). Fresh copy, +1.
988
1010
  return E.newTemp(e.type, `scr_bytes_slice(${r.name}, ${args[0]?.name ?? "0"}, ${args[1]?.name ?? "INFINITY"})`);
1011
+ case "subarray":
1012
+ // Same defaults; the result is a +1 VIEW aliasing the
1013
+ // receiver's storage (subarray / Buffer's slice).
1014
+ return E.newTemp(e.type, `scr_bytes_subarray(${r.name}, ${args[0]?.name ?? "0"}, ${args[1]?.name ?? "INFINITY"})`);
989
1015
  case "setFrom": {
990
1016
  // dst.set(src, offset?) — void; throws Node's RangeError on
991
1017
  // overflow (may-throw seed).
@@ -1041,6 +1067,10 @@ export function emitExpr(E, e) {
1041
1067
  E.emitPendingCheck();
1042
1068
  return t;
1043
1069
  }
1070
+ case "fillElem":
1071
+ // Per-element TypedArray fill (non-u8): slice-style index
1072
+ // defaults, never throws; the receiver comes back +1.
1073
+ return E.newTemp(e.type, `scr_bytes_fill_elem(${r.name}, ${args[0].name}, ${args[1]?.name ?? "0"}, ${args[2]?.name ?? "INFINITY"})`);
1044
1074
  case "fillStr": {
1045
1075
  const n = e.args.length - 2;
1046
1076
  const t = E.newTemp(e.type, `scr_bytes_fill_str(${r.name}, ${args[0].name}, ${args[1].name}, ${n}, ` +
@@ -1589,6 +1619,13 @@ export function emitExpr(E, e) {
1589
1619
  }
1590
1620
  return E.newTemp(e.type, `${E.toDynHelper(v.type)}(${v.name})`);
1591
1621
  }
1622
+ case "dynFromJsval": {
1623
+ // Island value → DOM: the by-reference wrap (scr_dyn_from_jsval
1624
+ // retains the cell in; engine scalars normalize to native DOM
1625
+ // kinds at wrap time). Operand borrowed, result +1, never throws.
1626
+ const v = E.emitExpr(e.value);
1627
+ return E.newTemp(e.type, `scr_dyn_from_jsval(${v.name})`);
1628
+ }
1592
1629
  case "dynCall": {
1593
1630
  // Calling a dyn value: args are already dyn (the lowering boxed or
1594
1631
  // converted them); everything is BORROWED by scr_dyn_call — the
@@ -1867,6 +1904,9 @@ export function emitExpr(E, e) {
1867
1904
  case "dynHasKey": {
1868
1905
  // `"k" in pkg`: a kind-guarded presence answer, computed against
1869
1906
  // the literal key at compile time — no allocation, borrowed box.
1907
+ // An ISLAND-held receiver fences loudly (Node asks the real
1908
+ // engine object — `false` would be a silent wrong answer), so
1909
+ // the temp rides the fallible path.
1870
1910
  const d = E.emitExpr(e.value);
1871
1911
  const keyBytes = Buffer.from(e.key, "utf8");
1872
1912
  const keyLit = cStringLiteral(keyBytes);
@@ -1876,8 +1916,8 @@ export function emitExpr(E, e) {
1876
1916
  : /^(0|[1-9][0-9]*)$/.test(e.key) && Number(e.key) <= Number.MAX_SAFE_INTEGER
1877
1917
  ? `${d.name}->v.arr.len > ${e.key}`
1878
1918
  : "false";
1879
- const test = `(${d.name}->kind == SCR_DYN_OBJ ? (${objTest}) : ${d.name}->kind == SCR_DYN_ARR ? (${arrTest}) : false)`;
1880
- return E.newTemp(e.type, e.negated ? `!${test}` : test);
1919
+ const test = `(${d.name}->kind == SCR_DYN_OBJ ? (${objTest}) : ${d.name}->kind == SCR_DYN_ARR ? (${arrTest}) : scr_dyn_isl_fence(${d.name}, "'in'"))`;
1920
+ return E.fallibleTemp(e.type, e.negated ? `!${test}` : test);
1881
1921
  }
1882
1922
  case "dynScalarEq": {
1883
1923
  // dyn vs scalar strict equality: kind test + payload compare.
@@ -1899,26 +1939,40 @@ export function emitExpr(E, e) {
1899
1939
  }
1900
1940
  case "dynTest": {
1901
1941
  // A pure kind compare on the DOM node — borrowed; only the truthy
1902
- // form also reads a scalar payload.
1942
+ // form also reads a scalar payload. ISLAND-held nodes (the jsval
1943
+ // kind — engine objects/arrays/functions only, scalars normalize
1944
+ // at wrap time) route the tests that depend on the engine's
1945
+ // answer through the scr_dyn_isl_* helpers (false on every other
1946
+ // kind, so the calls stay unconditional); narrowing never changes
1947
+ // representation (SEMANTICS.md).
1903
1948
  const d = E.emitExpr(e.value);
1904
1949
  const test = e.test === "nullish"
1905
1950
  ? `(${d.name}->kind == SCR_DYN_UNDEF || ${d.name}->kind == SCR_DYN_NULL)`
1906
1951
  : e.test === "object"
1907
1952
  ? // `typeof v === "object"`: objects, arrays, bytes, native
1908
- // handles, promises, AND null.
1909
- `(${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)`
1953
+ // handles, promises, AND null — engine-held objects by the
1954
+ // engine's own typeof.
1955
+ `(${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"))`
1910
1956
  : e.test === "truthy"
1911
1957
  ? // ToBoolean over the DOM: bool by value; number falsy for
1912
1958
  // 0, -0 (== 0 in C), and NaN (self-inequality); string
1913
1959
  // falsy when empty; obj/arr/bytes/func/handle always true;
1914
- // the remaining kinds (undefined, null) always false.
1915
- `(${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))`
1960
+ // JSVAL through the runtime's routed arm (the bigint 0n
1961
+ // edge); the remaining kinds (undefined, null) always false.
1962
+ `(${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))`
1916
1963
  : e.test === "error"
1917
1964
  ? // `u instanceof Error`: the DOM's error encoding — an
1918
1965
  // object carrying the reserved "%error" marker key
1919
- // (built by caughtToDyn for Error payloads).
1920
- `(${d.name}->kind == SCR_DYN_OBJ && scr_dyn_obj_get(${d.name}, "%error", 6) != NULL)`
1921
- : `${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]}`;
1966
+ // (built by caughtToDyn for Error payloads) — or a real
1967
+ // engine Error held by reference.
1968
+ `((${d.name}->kind == SCR_DYN_OBJ && scr_dyn_obj_get(${d.name}, "%error", 6) != NULL) || scr_dyn_isl_is_error(${d.name}))`
1969
+ : e.test === "array"
1970
+ ? // Array.isArray: the DOM's array kind, or the engine's
1971
+ // own answer for an engine-held value.
1972
+ `(${d.name}->kind == SCR_DYN_ARR || scr_dyn_isl_is_array(${d.name}))`
1973
+ : e.test === "function"
1974
+ ? `(${d.name}->kind == SCR_DYN_FUNC || scr_dyn_isl_typeof_is(${d.name}, "function"))`
1975
+ : `${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]}`;
1922
1976
  return E.newTemp(e.type, e.negated ? `!(${test})` : test);
1923
1977
  }
1924
1978
  case "unionEq": {
@@ -2188,13 +2242,20 @@ export function emitExpr(E, e) {
2188
2242
  // member retains the value in); throws Node's TypeErrors on
2189
2243
  // non-object receivers (may-throw seed set).
2190
2244
  return finish(`scr_dyn_key_set(${arg(0)}, ${arg(1)}, ${arg(2)})`);
2245
+ case "dyn.iterPack":
2246
+ // Destructuring pack over a dyn source: both borrowed, fresh
2247
+ // array +1; throws V8's destructuring TypeError on
2248
+ // non-iterable DOM kinds (may-throw seed set).
2249
+ return finish(`scr_dyn_iter_pack(${arg(0)}, ${arg(1)})`);
2191
2250
  case "dyn.typeof":
2192
2251
  // Bare typeof on a dyn value: the DOM kind's JS answer (+1).
2193
2252
  return finish(`scr_dyn_typeof(${arg(0)})`);
2194
2253
  case "dyn.toString":
2195
2254
  // Receiver-kind-dispatched toString (+1); throws Node's
2196
- // TypeError on undefined/null (may-throw seed set).
2197
- return finish(`scr_dyn_to_string(${arg(0)}, ${arg(1)})`);
2255
+ // TypeError on undefined/null and the "is not a function"
2256
+ // TypeError on null-prototype dictionaries (may-throw seed
2257
+ // set) — args[2] carries the call's source spelling.
2258
+ return finish(`scr_dyn_to_string_method(${arg(0)}, ${arg(1)}, ${arg(2)})`);
2198
2259
  case "fs.readFileSync":
2199
2260
  // args[1] is the (always-"utf8") encoding: evaluated for
2200
2261
  // JS-exact side-effect order, ignored by the runtime.
@@ -2424,10 +2485,14 @@ export function emitExpr(E, e) {
2424
2485
  return finish(`scr_math_max_arr(${arg(0)})`);
2425
2486
  case "math.minArr":
2426
2487
  return finish(`scr_math_min_arr(${arg(0)})`);
2427
- // Math.floor — C floor() IS the JS operation (math.h is always
2428
- // included). Borrows nothing; no throw.
2488
+ // Math.floor/trunc/ceil — the C functions ARE the JS operations
2489
+ // (math.h is always included). Borrow nothing; no throw.
2429
2490
  case "math.floor":
2430
2491
  return finish(`floor(${arg(0)})`);
2492
+ case "math.trunc":
2493
+ return finish(`trunc(${arg(0)})`);
2494
+ case "math.ceil":
2495
+ return finish(`ceil(${arg(0)})`);
2431
2496
  // Math.abs — C fabs IS the JS operation. Math.round — the JS
2432
2497
  // half-toward-+Infinity rule (scr_lib.c; C round() differs on
2433
2498
  // halves and naive floor(x+0.5) drifts at the epsilon boundary).
@@ -3041,6 +3106,15 @@ export function emitExpr(E, e) {
3041
3106
  case "net.connect":
3042
3107
  E.usesTimers = true; // a connecting/open socket holds the loop open
3043
3108
  return finish(`scr_net_connect(${arg(0)}, ${arg(1)}, NULL)`);
3109
+ case "net.connectAttempt":
3110
+ // The validated autoSelectFamilyAttemptTimeout form: Node's
3111
+ // range ladder runs first, the dial follows.
3112
+ E.usesTimers = true;
3113
+ return finish(`scr_net_connect_attempt(${arg(0)}, ${arg(1)}, ${arg(2)})`);
3114
+ case "net.connectOptsChk":
3115
+ // The runtime option-bag ladder (always throws — a validation
3116
+ // error or the trailing fence; the error.nodeThrow dummy).
3117
+ return finish(`(scr_net_connect_opts_chk(${arg(0)}, ${arg(1)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
3044
3118
  case "net.connectCb": {
3045
3119
  E.usesTimers = true;
3046
3120
  const cb = args[2];
@@ -3143,6 +3217,9 @@ export function emitExpr(E, e) {
3143
3217
  case "dgram.sendBytes":
3144
3218
  E.usesTimers = true;
3145
3219
  return finish(`scr_dgram_send_bytes(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`);
3220
+ case "dgram.sendChk":
3221
+ E.usesTimers = true; // a validated send implicit-binds
3222
+ return finish(`scr_dgram_send_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)})`);
3146
3223
  case "dgram.address": {
3147
3224
  // The AddressInfo record, built here from runtime parts (the
3148
3225
  // frontend pinned the {address, family, port} shape). The
@@ -3850,6 +3927,13 @@ export function emitExpr(E, e) {
3850
3927
  // SNI answer serves; bad material is the construction-time
3851
3928
  // print-and-die trap, like createServer's.
3852
3929
  return finish(`scr_tls_create_secure_context((const char *)${arg(0)}->data, ${arg(0)}->len, (const char *)${arg(1)}->data, ${arg(1)}->len)`);
3930
+ case "tls.createSecureContextDyn":
3931
+ // The runtime option-bag form: Node's typed validations, then
3932
+ // the pem walk (throws catchably on both ladders).
3933
+ return finish(`scr_tls_create_secure_context_dyn(${arg(0)})`);
3934
+ case "tls.caCertsChk":
3935
+ // Always throws (validation error or the trailing fence).
3936
+ return finish(`(scr_tls_ca_certs_chk(${arg(0)}, ${arg(1)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
3853
3937
  case "http.serverOnRequest": {
3854
3938
  const cbT = e.args[1].type;
3855
3939
  if (cbT.kind !== "func")
@@ -4278,10 +4362,41 @@ export function emitExpr(E, e) {
4278
4362
  return finish(`scr_buffer_new_string_fail(${arg(0)})`);
4279
4363
  case "fs.toUnixTimestamp":
4280
4364
  return finish(`scr_fs_to_unix_timestamp(${arg(0)})`);
4365
+ // The fs argument-validation ladders: the always-throw Chk
4366
+ // forms (validation error or the trailing fence) take the
4367
+ // error.nodeThrow dummy pattern; mkdtempSyncChk and the lchmod
4368
+ // pair answer real results on a validated pass.
4369
+ case "fs.existsChk":
4370
+ E.usesTimers = true; // the scheduled answer holds the loop open
4371
+ return finish(`scr_fs_exists_async(${arg(0)}, ${arg(1)})`);
4372
+ case "fs.mkdtempChk":
4373
+ return finish(`(scr_fs_mkdtemp_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4374
+ case "fs.mkdtempSyncChk":
4375
+ return finish(`scr_fs_mkdtemp_sync_chk(${arg(0)}, ${arg(1)}, ${arg(2)})`);
4376
+ case "fs.readFileChk":
4377
+ return finish(`(scr_fs_read_file_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4378
+ case "fs.opendirChk":
4379
+ return finish(`(scr_fs_opendir_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4380
+ case "fs.watchFileChk":
4381
+ return finish(`(scr_fs_watch_file_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4382
+ case "fs.lchmodChk":
4383
+ return finish(`(scr_fs_lchmod_chk(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4384
+ case "fs.lchmodSyncChk":
4385
+ return finish(`scr_fs_lchmod_sync_chk(${arg(0)}, ${arg(1)})`);
4386
+ case "fsp.lchmodChk":
4387
+ return finish(`scr_fsp_lchmod_chk(${arg(0)}, ${arg(1)})`);
4388
+ case "fs.readChk":
4389
+ 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"})`);
4390
+ case "fs.streamOptsChk":
4391
+ return finish(`(scr_fs_stream_opts_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4281
4392
  case "error.argTypeThrow":
4282
4393
  // Always throws with the runtime-rendered Received tail (the
4283
4394
  // error.nodeThrow dummy pattern). Borrows all three.
4284
4395
  return finish(`(scr_throw_arg_type(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4396
+ case "error.propTypeThrow":
4397
+ // The property flavor ("The \"options.x\" property must be
4398
+ // ...") — same always-throw dummy pattern.
4399
+ return finish(`(scr_throw_prop_type(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4285
4400
  // The fs Buffer forms (scr_bytes_io.c): the sync pair throws
4286
4401
  // like the utf8 forms (may-throw seed set); the promise form
4287
4402
  // rejects instead.
@@ -4706,6 +4821,27 @@ export function emitExpr(E, e) {
4706
4821
  // Object.assign over DOM values: own members copy, the target
4707
4822
  // returns (+1); non-object receivers throw like Node.
4708
4823
  return finish(`scr_dyn_assign(${arg(0)}, ${arg(1)})`);
4824
+ case "dyn.packPush":
4825
+ // Variadic Object.assign's source pack: a plain source
4826
+ // retains in (both args borrowed). Never throws.
4827
+ return finish(`scr_dyn_pack_push(${arg(0)}, ${arg(1)})`);
4828
+ case "dyn.packPushSpread":
4829
+ // A spread source flattens through the spread-call walk —
4830
+ // V8's exact TypeError texts (may-throw seed set); the string
4831
+ // spells the spread expression for the nullish form.
4832
+ return finish(`scr_dyn_pack_push_spread(${arg(0)}, ${arg(1)}, ${arg(2)})`);
4833
+ case "dyn.packPushSpreadIter":
4834
+ // The non-last/multi-spread positions: V8's iterator-protocol
4835
+ // failure texts describe the value (may-throw seed set).
4836
+ return finish(`scr_dyn_pack_push_spread_iter(${arg(0)}, ${arg(1)})`);
4837
+ case "dyn.assignAll":
4838
+ // The flattened pack copies onto the target left to right;
4839
+ // the target returns (+1). Nullish targets throw like Node.
4840
+ return finish(`scr_dyn_assign_all(${arg(0)}, ${arg(1)})`);
4841
+ case "dyn.objCreateNullProto":
4842
+ // Object.create(null): the fresh null-prototype dictionary
4843
+ // (+1). Never throws.
4844
+ return finish(`scr_dyn_new_obj_null_proto()`);
4709
4845
  case "dyn.hasOwn":
4710
4846
  // Object.hasOwn over a DOM receiver (throws on nullish, like
4711
4847
  // Node's ToObject).
@@ -4973,6 +5109,18 @@ export function emitExpr(E, e) {
4973
5109
  const list = Array.from({ length: n }, (_, i) => `(ScrStream *)${arg(1 + i)}`).join(", ");
4974
5110
  return finish(`scr_sp_pipeline(${n}, (ScrStream *[]){ ${list} })`);
4975
5111
  }
5112
+ case "sc.text":
5113
+ // stream/consumers: +1 pending promises the accumulate-and-
5114
+ // settle machinery resolves or rejects (the stream's
5115
+ // error / premature close / json's SyntaxError).
5116
+ E.usesTimers = true;
5117
+ return finish(`scr_sc_text((ScrStream *)${arg(0)})`);
5118
+ case "sc.json":
5119
+ E.usesTimers = true;
5120
+ return finish(`scr_sc_json((ScrStream *)${arg(0)})`);
5121
+ case "sc.buffer":
5122
+ E.usesTimers = true;
5123
+ return finish(`scr_sc_buffer((ScrStream *)${arg(0)})`);
4976
5124
  case "readable.newDyn":
4977
5125
  case "writable.newDyn":
4978
5126
  case "duplex.newDyn":
@@ -5028,6 +5176,14 @@ export function emitExpr(E, e) {
5028
5176
  case "readable.pushStr":
5029
5177
  E.usesTimers = true;
5030
5178
  return finish(`scr_stream_push_str((ScrStream *)${arg(0)}, ${arg(1)})`);
5179
+ case "readable.pushStrEnc":
5180
+ // push(chunk, enc) with a literal non-utf8 encoding.
5181
+ E.usesTimers = true;
5182
+ return finish(`scr_stream_push_str_enc((ScrStream *)${arg(0)}, ${arg(1)}, ${arg(2)})`);
5183
+ case "readable.pushEncoding":
5184
+ // The defaultEncoding option's push side (chaining, +1).
5185
+ E.usesTimers = true;
5186
+ return finish(`(${cType(e.type).trim()})scr_stream_set_push_encoding((ScrStream *)${arg(0)}, ${arg(1)})`);
5031
5187
  case "readable.pushNull":
5032
5188
  E.usesTimers = true;
5033
5189
  return finish(`scr_stream_push_null((ScrStream *)${arg(0)})`);