@scriptc/compiler 0.0.22 → 0.0.24

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 (93) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +139 -14
  2. package/dist/backend/cc.d.ts +13 -0
  3. package/dist/backend/cc.js +11 -0
  4. package/dist/backend/cc.js.map +1 -1
  5. package/dist/backend/emission/emit-async.d.ts +4 -0
  6. package/dist/backend/emission/emit-async.js +34 -2
  7. package/dist/backend/emission/emit-async.js.map +1 -1
  8. package/dist/backend/emission/emit-exprs.d.ts +10 -0
  9. package/dist/backend/emission/emit-exprs.js +272 -22
  10. package/dist/backend/emission/emit-exprs.js.map +1 -1
  11. package/dist/backend/emission/emit-shapes.js +1 -0
  12. package/dist/backend/emission/emit-shapes.js.map +1 -1
  13. package/dist/backend/emission/emit-stmts.js +36 -9
  14. package/dist/backend/emission/emit-stmts.js.map +1 -1
  15. package/dist/backend/emission/emit-types.js +14 -1
  16. package/dist/backend/emission/emit-types.js.map +1 -1
  17. package/dist/backend/emission/emitter.d.ts +19 -1
  18. package/dist/backend/emission/emitter.js +81 -2
  19. package/dist/backend/emission/emitter.js.map +1 -1
  20. package/dist/backend/llvm/emitter.js +578 -36
  21. package/dist/backend/llvm/emitter.js.map +1 -1
  22. package/dist/backend/llvm/shapes.js +12 -3
  23. package/dist/backend/llvm/shapes.js.map +1 -1
  24. package/dist/backend/mangle.d.ts +3 -0
  25. package/dist/backend/mangle.js +5 -0
  26. package/dist/backend/mangle.js.map +1 -1
  27. package/dist/compat/fetch-profile.d.ts +10 -0
  28. package/dist/compat/fetch-profile.js +55 -6
  29. package/dist/compat/fetch-profile.js.map +1 -1
  30. package/dist/coverage/surface-manifest.js +16 -1
  31. package/dist/coverage/surface-manifest.js.map +1 -1
  32. package/dist/diagnostics/diagnostic.d.ts +10 -0
  33. package/dist/diagnostics/diagnostic.js +27 -1
  34. package/dist/diagnostics/diagnostic.js.map +1 -1
  35. package/dist/frontend/lowering/lower-builtins.d.ts +17 -16
  36. package/dist/frontend/lowering/lower-builtins.js +817 -117
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.js +3 -1
  39. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  40. package/dist/frontend/lowering/lower-classes.js +28 -8
  41. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  42. package/dist/frontend/lowering/lower-containers.d.ts +2 -1
  43. package/dist/frontend/lowering/lower-containers.js +99 -32
  44. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  45. package/dist/frontend/lowering/lower-exprs.d.ts +1 -1
  46. package/dist/frontend/lowering/lower-exprs.js +78 -6
  47. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  48. package/dist/frontend/lowering/lower-generators.js +7 -1
  49. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  50. package/dist/frontend/lowering/lower-inspect.js +59 -1
  51. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  52. package/dist/frontend/lowering/lower-island.d.ts +21 -0
  53. package/dist/frontend/lowering/lower-island.js +284 -10
  54. package/dist/frontend/lowering/lower-island.js.map +1 -1
  55. package/dist/frontend/lowering/lower-server.d.ts +5 -0
  56. package/dist/frontend/lowering/lower-server.js +1 -1
  57. package/dist/frontend/lowering/lower-server.js.map +1 -1
  58. package/dist/frontend/lowering/lower-stmts.d.ts +6 -2
  59. package/dist/frontend/lowering/lower-stmts.js +53 -14
  60. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  61. package/dist/frontend/lowering/lowerer.d.ts +3 -2
  62. package/dist/frontend/lowering/lowerer.js +17 -8
  63. package/dist/frontend/lowering/lowerer.js.map +1 -1
  64. package/dist/frontend/lowering/surfaces.js +108 -25
  65. package/dist/frontend/lowering/surfaces.js.map +1 -1
  66. package/dist/frontend/program.d.ts +4 -4
  67. package/dist/frontend/program.js +264 -46
  68. package/dist/frontend/program.js.map +1 -1
  69. package/dist/frontend/resolve.d.ts +10 -0
  70. package/dist/frontend/resolve.js +37 -0
  71. package/dist/frontend/resolve.js.map +1 -1
  72. package/dist/frontend/ts7/enums.d.ts +9 -0
  73. package/dist/frontend/ts7/enums.js +8 -6
  74. package/dist/frontend/ts7/enums.js.map +1 -1
  75. package/dist/frontend/ts7/program.js +4 -1
  76. package/dist/frontend/ts7/program.js.map +1 -1
  77. package/dist/frontend/types.d.ts +7 -4
  78. package/dist/frontend/types.js +103 -8
  79. package/dist/frontend/types.js.map +1 -1
  80. package/dist/index.js +8 -1
  81. package/dist/index.js.map +1 -1
  82. package/dist/ir/integer-loops.d.ts +23 -0
  83. package/dist/ir/integer-loops.js +82 -0
  84. package/dist/ir/integer-loops.js.map +1 -0
  85. package/dist/ir/nodes.d.ts +104 -28
  86. package/dist/ir/nodes.js +89 -1
  87. package/dist/ir/nodes.js.map +1 -1
  88. package/dist/ir/validate.js +136 -25
  89. package/dist/ir/validate.js.map +1 -1
  90. package/dist/library/fence-eval.js +4 -3
  91. package/dist/library/fence-eval.js.map +1 -1
  92. package/package.json +2 -2
  93. package/surface-manifest.json +186 -29
@@ -287,6 +287,59 @@ function dynPromiseAdapter(E, inner) {
287
287
  E.walkerDefs.push(`${sig} { /* checked-dynamic promise exit ${key} */`, ` ScrDyn *sc_d = (ScrDyn *)scr_promise_payload_ref(sc_src);`, ` ${cDecl(inner, "sc_v")} = ${E.dynCheckHelper(inner)}(sc_d, NULL);`, ` scr_dyn_release(sc_d);`, ` if (scr_exc_pending()) {`, ` scr_promise_reject_pending(sc_dst);`, ` return;`, ` }`, ` ${fulfill}`, `}`, ``);
288
288
  return sym;
289
289
  }
290
+ /** True when evaluating an index/value expression cannot overwrite the bytes
291
+ * receiver binding. This deliberately small whitelist enables borrowed
292
+ * receivers in typed-array hot loops while side-effecting/calling shapes
293
+ * retain the full snapshot ownership required by JS evaluation order. */
294
+ export function isStableBytesOperand(e, receiverLocalId) {
295
+ switch (e.kind) {
296
+ case "numLit":
297
+ case "boolLit":
298
+ case "varRef":
299
+ case "incDec":
300
+ return true;
301
+ case "assignExpr":
302
+ // An assignment nested under truthiness/ternary can still produce the
303
+ // numeric index/value while overwriting the bytes-typed receiver.
304
+ return e.localId !== receiverLocalId && isStableBytesOperand(e.value, receiverLocalId);
305
+ case "bin":
306
+ return (isStableBytesOperand(e.left, receiverLocalId) &&
307
+ isStableBytesOperand(e.right, receiverLocalId));
308
+ case "unary":
309
+ case "toBool":
310
+ return isStableBytesOperand(e.operand, receiverLocalId);
311
+ case "logical":
312
+ return (isStableBytesOperand(e.left, receiverLocalId) &&
313
+ isStableBytesOperand(e.right, receiverLocalId));
314
+ case "ternary":
315
+ return (isStableBytesOperand(e.cond, receiverLocalId) &&
316
+ isStableBytesOperand(e.then, receiverLocalId) &&
317
+ isStableBytesOperand(e.else_, receiverLocalId));
318
+ case "bytesIntrinsic":
319
+ return ((e.method === "get" || e.method === "length" || e.method === "byteLength") &&
320
+ e.receiver.kind === "varRef" &&
321
+ e.args.every((arg) => isStableBytesOperand(arg, receiverLocalId)));
322
+ default:
323
+ return false;
324
+ }
325
+ }
326
+ /** Evaluate a bytes receiver as a borrow when it is a direct, unboxed
327
+ * binding and all later operands are stable. The binding's scope/global
328
+ * owner then keeps the value alive, avoiding retain/release traffic around
329
+ * every indexed access. Any uncertain shape falls back to an owned temp. */
330
+ export function emitBytesReceiver(E, receiver, following) {
331
+ if (receiver.kind === "varRef" &&
332
+ following.every((operand) => isStableBytesOperand(operand, receiver.localId))) {
333
+ const local = E.currentLocals.get(receiver.localId);
334
+ if (local && !local.boxed) {
335
+ return E.newBorrowedTemp(receiver.type, mangleLocal(receiver.localId));
336
+ }
337
+ if (!local && E.globalsById.has(receiver.localId)) {
338
+ return E.newBorrowedTemp(receiver.type, mangleGlobal(receiver.localId));
339
+ }
340
+ }
341
+ return E.emitExpr(receiver);
342
+ }
290
343
  export function emitExpr(E, e) {
291
344
  switch (e.kind) {
292
345
  case "numLit":
@@ -302,6 +355,9 @@ export function emitExpr(E, e) {
302
355
  // tag-only); one reaching the generic dispatch escaped its wrap.
303
356
  throw new Error(`emitter bug: bare unitLit '${e.unit}'`);
304
357
  case "varRef": {
358
+ const integerLoopIndex = E.integerLoopIndex(e);
359
+ if (integerLoopIndex !== null)
360
+ return E.newTemp(e.type, `(double)${integerLoopIndex}`);
305
361
  const local = E.currentLocals.get(e.localId);
306
362
  if (!local && E.globalsById.has(e.localId)) {
307
363
  const gname = mangleGlobal(e.localId);
@@ -932,7 +988,7 @@ export function emitExpr(E, e) {
932
988
  case "trimEnd":
933
989
  return E.newTemp(e.type, `scr_str_trim_end(${r.name})`);
934
990
  case "split":
935
- return E.newTemp(e.type, `scr_str_split(${r.name}, ${args[0].name})`);
991
+ return E.newTemp(e.type, `scr_str_split_limit(${r.name}, ${args[0].name}, ${args[1].name})`);
936
992
  case "padStart":
937
993
  return E.newTemp(e.type, `scr_str_pad_start(${r.name}, ${args[0].name}, ${args[1].name})`);
938
994
  case "padEnd":
@@ -1035,7 +1091,7 @@ export function emitExpr(E, e) {
1035
1091
  case "replaceAll":
1036
1092
  return E.fallibleTemp(e.type, `scr_regex_replace_all(${r.name}, ${args[0].name}, ${args[1].name})`);
1037
1093
  case "split":
1038
- return E.fallibleTemp(e.type, `scr_regex_split(${r.name}, ${args[0].name})`);
1094
+ return E.fallibleTemp(e.type, `scr_regex_split_limit(${r.name}, ${args[0].name}, ${args[1].name})`);
1039
1095
  default: {
1040
1096
  const _exhaustive = method;
1041
1097
  void _exhaustive;
@@ -1152,6 +1208,25 @@ export function emitExpr(E, e) {
1152
1208
  E.line(`}`);
1153
1209
  return E.newTemp(e.type, `scr_arr_len(${r.name})`);
1154
1210
  }
1211
+ case "unshift": {
1212
+ // Like push, every argument evaluates before mutation. Apply
1213
+ // them from right to left so their final front order remains
1214
+ // the source order. Ref ownership moves into the array.
1215
+ const vs = e.args.map((a) => E.emitExpr(a));
1216
+ if (acc === "ref")
1217
+ vs.forEach((v) => E.moveTemp(v));
1218
+ let last;
1219
+ for (let i = vs.length - 1; i >= 0; i--) {
1220
+ last = E.newTemp(e.type, `scr_arr_unshift_${acc}(${r.name}, ${vs[i].name})`);
1221
+ }
1222
+ return last ?? E.newTemp(e.type, `scr_arr_len(${r.name})`);
1223
+ }
1224
+ case "unshiftSpread": {
1225
+ // The runtime snapshots and retains the borrowed source,
1226
+ // including the aliasing `a.unshift(...a)` case.
1227
+ const src = E.emitExpr(e.args[0]);
1228
+ return E.newTemp(e.type, `scr_arr_unshift_spread(${r.name}, ${src.name})`);
1229
+ }
1155
1230
  case "pop":
1156
1231
  // Ownership of a refcounted element moves OUT of the array to
1157
1232
  // this temp (+1 to us, the runtime does not release it).
@@ -1188,6 +1263,10 @@ export function emitExpr(E, e) {
1188
1263
  }
1189
1264
  case "toReversed":
1190
1265
  return E.newTemp(e.type, `scr_arr_to_reversed(${r.name})`);
1266
+ case "reverse":
1267
+ // Mutates in place and returns a retained reference to the
1268
+ // receiver, preserving Array.prototype.reverse identity.
1269
+ return E.newTemp(e.type, `scr_arr_reverse(${r.name})`);
1191
1270
  case "toSpliced": {
1192
1271
  const start = E.emitExpr(e.args[0]);
1193
1272
  const count = E.emitExpr(e.args[1]);
@@ -1303,17 +1382,27 @@ export function emitExpr(E, e) {
1303
1382
  E.emitPendingCheck();
1304
1383
  return t;
1305
1384
  }
1306
- const r = E.emitExpr(e.receiver);
1307
- const args = e.args.map((a) => E.emitExpr(a));
1308
1385
  const method = e.method;
1386
+ const directElementAccess = method === "length" || method === "byteLength" || method === "get";
1387
+ const r = directElementAccess
1388
+ ? emitBytesReceiver(E, e.receiver, e.args)
1389
+ : E.emitExpr(e.receiver);
1390
+ const integerIndex = method === "get" ? E.integerLoopIndex(e.args[0]) : null;
1391
+ const args = integerIndex === null ? e.args.map((a) => E.emitExpr(a)) : [];
1309
1392
  switch (method) {
1310
1393
  case "length":
1311
- return E.newTemp(e.type, `scr_bytes_len(${r.name})`);
1394
+ return E.newTemp(e.type, `(double)${r.name}->len`);
1312
1395
  case "byteLength":
1313
- return E.newTemp(e.type, `scr_bytes_byte_len(${r.name})`);
1396
+ if (e.receiver.type.kind !== "bytes") {
1397
+ throw new Error("emitter bug: bytesIntrinsic byteLength on non-bytes");
1398
+ }
1399
+ return E.newTemp(e.type, `(double)(${r.name}->len * ${e.receiver.type.elem === "u8" ? "1" : "4"})`);
1314
1400
  case "get":
1315
1401
  // Any invalid index traps (the array runtime's discipline).
1316
- return E.newTemp(e.type, `scr_bytes_get(${r.name}, ${args[0].name})`);
1402
+ if (e.receiver.type.kind !== "bytes") {
1403
+ throw new Error("emitter bug: bytesIntrinsic get on non-bytes");
1404
+ }
1405
+ return E.newTemp(e.type, `${E.bytesElementHelper("get", e.receiver.type.elem, integerIndex !== null)}(${r.name}, ${integerIndex ?? args[0].name})`);
1317
1406
  case "slice":
1318
1407
  // Omitted relative indices default like string slice: start 0,
1319
1408
  // end +Infinity (math.h is always included). Fresh copy, +1.
@@ -1341,18 +1430,30 @@ export function emitExpr(E, e) {
1341
1430
  return { name: "", type: e.type };
1342
1431
  }
1343
1432
  case "toString":
1433
+ case "toStringVar": {
1344
1434
  // The encoding arg is always present (the frontend completes
1345
- // an omitted one to "utf8"). Never throws; +1 string. Range
1346
- // forms: [enc, start] decodes to the buffer's end; [enc,
1347
- // start, end] clamps the explicit end (negatives empty,
1348
- // Node's slice-then-decode).
1435
+ // an omitted one to "utf8"). The literal path is already
1436
+ // canonical and cannot throw; toStringVar validates a runtime
1437
+ // encoding and may throw ERR_UNKNOWN_ENCODING. Both return a
1438
+ // +1 string. Range forms: [enc, start] decodes to the buffer's
1439
+ // end; [enc, start, end] clamps the explicit end (negatives
1440
+ // empty, Node's slice-then-decode).
1441
+ const checked = method === "toStringVar";
1442
+ const stem = checked ? "scr_bytes_to_str_checked" : "scr_bytes_to_str";
1443
+ let out;
1349
1444
  if (args.length === 3) {
1350
- return E.newTemp(e.type, `scr_bytes_to_str_range(${r.name}, ${args[0].name}, ${args[1].name}, ${args[2].name})`);
1445
+ out = E.newTemp(e.type, `${stem}_range(${r.name}, ${args[0].name}, ${args[1].name}, ${args[2].name})`);
1351
1446
  }
1352
- if (args.length === 2) {
1353
- return E.newTemp(e.type, `scr_bytes_to_str_range(${r.name}, ${args[0].name}, ${args[1].name}, (double)${r.name}->len)`);
1447
+ else if (args.length === 2) {
1448
+ out = E.newTemp(e.type, `${stem}_range(${r.name}, ${args[0].name}, ${args[1].name}, (double)${r.name}->len)`);
1354
1449
  }
1355
- return E.newTemp(e.type, `scr_bytes_to_str(${r.name}, ${args[0].name})`);
1450
+ else {
1451
+ out = E.newTemp(e.type, `${stem}(${r.name}, ${args[0].name})`);
1452
+ }
1453
+ if (checked)
1454
+ E.emitPendingCheck();
1455
+ return out;
1456
+ }
1356
1457
  case "equals":
1357
1458
  return E.newTemp(e.type, `scr_bytes_equals(${r.name}, ${args[0].name})`);
1358
1459
  case "compareBuf": {
@@ -2503,6 +2604,7 @@ export function emitExpr(E, e) {
2503
2604
  const t = e.args[0].type;
2504
2605
  switch (t.kind) {
2505
2606
  case "f64":
2607
+ case "date":
2506
2608
  E.line(`scr_promise_fulfill_f64(${p.name}, ${v.name});${E.srcComment(e.loc)}`);
2507
2609
  break;
2508
2610
  case "bool":
@@ -2588,6 +2690,8 @@ export function emitExpr(E, e) {
2588
2690
  case "fetch.start":
2589
2691
  E.usesTimers = true;
2590
2692
  return finish(`scr_fetch_static(${arg(0)}, ${arg(1)})`);
2693
+ case "fetch.responseNew":
2694
+ return finish(`scr_fetch_response_new(${arg(0)}, ${arg(1)})`);
2591
2695
  case "fetch.responseJson":
2592
2696
  return finish(`scr_fetch_response_json(${arg(0)})`);
2593
2697
  case "fetch.responseText":
@@ -2604,6 +2708,8 @@ export function emitExpr(E, e) {
2604
2708
  E.line(`scr_promise_race_add(${result.name}, ${source.name}, &${adapter});${E.srcComment(e.loc)}`);
2605
2709
  return result;
2606
2710
  }
2711
+ case "fetch.abortControllerNew":
2712
+ return finish(`scr_fetch_abort_controller_new()`);
2607
2713
  case "fetch.abortTimeout":
2608
2714
  E.usesTimers = true;
2609
2715
  return finish(`scr_fetch_abort_timeout(${arg(0)})`);
@@ -3157,6 +3263,10 @@ export function emitExpr(E, e) {
3157
3263
  E.line(`scr_qs_parse_into(${dict.name}->${OVERFLOW_MEMBER}, ${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${strTag}, ${arrTag});${E.srcComment(e.loc)}`);
3158
3264
  return dict;
3159
3265
  }
3266
+ // node:util.parseArgs (scr_util.c): checked-dynamic config in,
3267
+ // checked-dynamic result out; may throw a coded TypeError.
3268
+ case "util.parseArgs":
3269
+ return finish(`scr_util_parse_args(${arg(0)})`);
3160
3270
  // Stats (scr_lib.c): statSync throws like the other sync fs
3161
3271
  // calls; the getters are pure reads.
3162
3272
  case "fs.openSync":
@@ -3164,7 +3274,11 @@ export function emitExpr(E, e) {
3164
3274
  // comes back as f64.
3165
3275
  return finish(`scr_fs_open(${arg(0)}, ${arg(1)})`);
3166
3276
  case "fs.readSync":
3167
- return finish(`scr_fs_read_sync(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`);
3277
+ return finish(`scr_fs_read_sync(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)})`);
3278
+ case "fs.writeSync":
3279
+ return finish(`scr_fs_write_sync(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)})`);
3280
+ case "fs.writeStrSync":
3281
+ return finish(`scr_fs_write_str_sync(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`);
3168
3282
  case "fs.closeSync":
3169
3283
  return finish(`scr_fs_close(${arg(0)})`);
3170
3284
  case "fs.watch":
@@ -3208,6 +3322,12 @@ export function emitExpr(E, e) {
3208
3322
  return finish(`scr_fs_stat(${arg(0)})`);
3209
3323
  case "stats.isSymbolicLink":
3210
3324
  return finish(`scr_stats_is_symlink(${arg(0)})`);
3325
+ case "stats.blocks":
3326
+ return finish(`scr_stats_blocks(${arg(0)})`);
3327
+ case "stats.nlink":
3328
+ return finish(`scr_stats_nlink(${arg(0)})`);
3329
+ case "stats.atimeMs":
3330
+ return finish(`scr_stats_atime_ms(${arg(0)})`);
3211
3331
  case "stats.mtimeMs":
3212
3332
  return finish(`scr_stats_mtime_ms(${arg(0)})`);
3213
3333
  case "stats.isFile":
@@ -4926,6 +5046,20 @@ export function emitExpr(E, e) {
4926
5046
  case "fs.existsChk":
4927
5047
  E.usesTimers = true; // the scheduled answer holds the loop open
4928
5048
  return finish(`scr_fs_exists_async(${arg(0)}, ${arg(1)})`);
5049
+ case "fs.renameCb": {
5050
+ // The callback MOVES into the scheduled operation. Its
5051
+ // adapter constructs the program-specific Error | null union
5052
+ // (or dyn error/null for the JS lane) when the timer fires.
5053
+ E.usesTimers = true;
5054
+ const cbT = e.args[2].type;
5055
+ if (cbT.kind !== "func")
5056
+ throw new Error("emitter bug: fs.rename callback not a func");
5057
+ const cb = args[2];
5058
+ E.moveTemp(cb);
5059
+ const adapter = E.fsRenameThunkFor(cbT);
5060
+ E.line(`scr_fs_rename_async(${arg(0)}, ${arg(1)}, ${cb.name}, &${adapter});${E.srcComment(e.loc)}`);
5061
+ return { name: "", type: e.type };
5062
+ }
4929
5063
  case "fs.mkdtempChk":
4930
5064
  return finish(`(scr_fs_mkdtemp_chk(${arg(0)}, ${arg(1)}, ${arg(2)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4931
5065
  case "fs.mkdtempSyncChk":
@@ -4970,9 +5104,28 @@ export function emitExpr(E, e) {
4970
5104
  case "zlib.inflateSync":
4971
5105
  return finish(`scr_zlib_inflate(${arg(0)})`);
4972
5106
  case "process.stdoutWriteBytes":
4973
- return finish(`scr_process_stdout_write_bytes(${arg(0)})`);
5107
+ return finish(`scr_process_stdout_write_bytes(${arg(0)}, ${arg(1)})`);
4974
5108
  case "process.stderrWriteBytes":
4975
- return finish(`scr_process_stderr_write_bytes(${arg(0)})`);
5109
+ return finish(`scr_process_stderr_write_bytes(${arg(0)}, ${arg(1)})`);
5110
+ case "process.stdoutWriteBytesCb":
5111
+ case "process.stderrWriteBytesCb": {
5112
+ // Submit the bytes only after every call argument evaluated,
5113
+ // then move the completion callback onto the next-tick queue.
5114
+ // The shared error-first adapter materializes success `null`.
5115
+ E.usesTimers = true;
5116
+ const cbT = e.args[2].type;
5117
+ if (cbT.kind !== "func")
5118
+ throw new Error("emitter bug: process write callback not a func");
5119
+ const cb = args[2];
5120
+ E.moveTemp(cb);
5121
+ const adapter = E.fsRenameThunkFor(cbT);
5122
+ const write = e.fn === "process.stdoutWriteBytesCb"
5123
+ ? "scr_process_stdout_write_bytes"
5124
+ : "scr_process_stderr_write_bytes";
5125
+ const out = E.newTemp(e.type, `${write}(${arg(0)}, ${arg(1)})`);
5126
+ E.line(`scr_process_write_callback(${cb.name}, &${adapter});${E.srcComment(e.loc)}`);
5127
+ return out;
5128
+ }
4976
5129
  case "tp.setTimeout":
4977
5130
  return finish(`scr_tp_set_timeout(${arg(0)})`);
4978
5131
  case "tp.setImmediate":
@@ -5072,6 +5225,8 @@ export function emitExpr(E, e) {
5072
5225
  return finish(`scr_fsp_read_file(${arg(0)})`);
5073
5226
  case "fsp.writeFile":
5074
5227
  return finish(`scr_fsp_write_file(${arg(0)}, ${arg(1)})`);
5228
+ case "fsp.writeFileMode":
5229
+ return finish(`scr_fsp_write_file_mode(${arg(0)}, ${arg(1)}, ${arg(2)})`);
5075
5230
  case "fsp.mkdir":
5076
5231
  return finish(`scr_fsp_mkdir(${arg(0)})`);
5077
5232
  case "fsp.mkdirMode":
@@ -5084,12 +5239,51 @@ export function emitExpr(E, e) {
5084
5239
  return finish(`scr_fsp_unlink(${arg(0)})`);
5085
5240
  case "fsp.chmod":
5086
5241
  return finish(`scr_fsp_chmod(${arg(0)}, ${arg(1)})`);
5242
+ case "fsp.rename":
5243
+ return finish(`scr_fsp_rename(${arg(0)}, ${arg(1)})`);
5087
5244
  case "fsp.readdir":
5088
5245
  return finish(`scr_fsp_readdir(${arg(0)})`);
5089
5246
  case "fsp.rm":
5090
5247
  return finish(`scr_fsp_rm(${arg(0)})`);
5091
5248
  case "fsp.stat":
5092
5249
  return finish(`scr_fsp_stat(${arg(0)})`);
5250
+ case "fsp.open":
5251
+ return finish(`scr_fsp_open(${arg(0)}, ${arg(1)}, ${arg(2)})`);
5252
+ case "fileHandle.fd":
5253
+ return finish(`scr_file_handle_fd(${arg(0)})`);
5254
+ case "fileHandle.close":
5255
+ return finish(`scr_file_handle_close_promise(${arg(0)})`);
5256
+ case "fileHandle.readFile":
5257
+ return finish(`scr_file_handle_read_file_promise(${arg(0)}, ${arg(1)})`);
5258
+ case "fileHandle.readFileBytes":
5259
+ return finish(`scr_file_handle_read_file_bytes_promise(${arg(0)}, ${arg(1)})`);
5260
+ case "fileHandle.writeFile":
5261
+ return finish(`scr_file_handle_write_file_promise(${arg(0)}, ${arg(1)}, ${arg(2)})`);
5262
+ case "fileHandle.writeFileBytes":
5263
+ return finish(`scr_file_handle_write_file_bytes_promise(${arg(0)}, ${arg(1)}, ${arg(2)})`);
5264
+ case "fileHandle.stat":
5265
+ return finish(`scr_file_handle_stat_promise(${arg(0)})`);
5266
+ case "fileHandle.read":
5267
+ case "fileHandle.writeBytes":
5268
+ case "fileHandle.writeStr": {
5269
+ if (e.type.kind !== "promise" || e.type.inner.kind !== "record") {
5270
+ throw new Error(`emitter bug: ${e.fn} result`);
5271
+ }
5272
+ const inner = e.type.inner;
5273
+ const countFn = e.fn === "fileHandle.read"
5274
+ ? `scr_file_handle_read(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)})`
5275
+ : e.fn === "fileHandle.writeBytes"
5276
+ ? `scr_file_handle_write_bytes(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)})`
5277
+ : `scr_file_handle_write_str(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`;
5278
+ const count = E.newTemp(F64, countFn);
5279
+ const row = E.newTemp(inner, `${mangleRecordNew(inner.shapeId)}()`);
5280
+ const countField = e.fn === "fileHandle.read" ? "bytesRead" : "bytesWritten";
5281
+ E.line(`${row.name}->${mangleField(countField)} = ${count.name};`);
5282
+ E.line(`${row.name}->${mangleField("buffer")} = ${retainCallC(e.args[1].type, arg(1))};`);
5283
+ const rc = vAdapters(inner);
5284
+ E.moveTemp(row); // promise fulfillment owns the result record
5285
+ return finish(`scr_promise_settled_ref(${row.name}, &${rc.retain}, &${rc.release}, ${E.traceArgC(inner)})`);
5286
+ }
5093
5287
  case "process.argv":
5094
5288
  return finish(`scr_process_argv()`);
5095
5289
  case "process.platform":
@@ -6132,7 +6326,17 @@ export function emitExpr(E, e) {
6132
6326
  case "date.now":
6133
6327
  // Node's integer milliseconds since epoch. Never throws.
6134
6328
  return finish(`scr_date_now()`);
6329
+ case "date.newNow":
6330
+ return finish(`scr_date_now()`);
6331
+ case "date.newMs":
6332
+ return finish(`scr_date_new_ms(${arg(0)})`);
6333
+ case "date.newString":
6334
+ return finish(`scr_date_parse_get_time(${arg(0)})`);
6335
+ case "date.getTime":
6336
+ case "date.valueOf":
6337
+ return finish(`${arg(0)}`);
6135
6338
  case "date.toISOString":
6339
+ case "date.toISOStringValue":
6136
6340
  // +1 string, or Node's "Invalid time value" RangeError
6137
6341
  // (may-throw seed set).
6138
6342
  return finish(`scr_date_to_iso(${arg(0)})`);
@@ -6144,10 +6348,47 @@ export function emitExpr(E, e) {
6144
6348
  // MakeDay/MakeTime/TimeClip over seven completed number
6145
6349
  // arguments; NaN outside the time range. Never throws.
6146
6350
  return finish(`scr_date_utc(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)})`);
6351
+ case "date.getFullYear":
6352
+ return finish(`scr_date_get_full_year(${arg(0)}, false)`);
6353
+ case "date.getUTCFullYear":
6354
+ return finish(`scr_date_get_full_year(${arg(0)}, true)`);
6355
+ case "date.getMonth":
6356
+ return finish(`scr_date_get_month(${arg(0)}, false)`);
6357
+ case "date.getUTCMonth":
6358
+ return finish(`scr_date_get_month(${arg(0)}, true)`);
6359
+ case "date.getDate":
6360
+ return finish(`scr_date_get_date(${arg(0)}, false)`);
6361
+ case "date.getUTCDate":
6362
+ return finish(`scr_date_get_date(${arg(0)}, true)`);
6363
+ case "date.getDay":
6364
+ return finish(`scr_date_get_day(${arg(0)}, false)`);
6365
+ case "date.getUTCDay":
6366
+ return finish(`scr_date_get_day(${arg(0)}, true)`);
6367
+ case "date.getHours":
6368
+ return finish(`scr_date_get_hours(${arg(0)}, false)`);
6369
+ case "date.getUTCHours":
6370
+ return finish(`scr_date_get_hours(${arg(0)}, true)`);
6371
+ case "date.getMinutes":
6372
+ return finish(`scr_date_get_minutes(${arg(0)}, false)`);
6373
+ case "date.getUTCMinutes":
6374
+ return finish(`scr_date_get_minutes(${arg(0)}, true)`);
6375
+ case "date.getSeconds":
6376
+ return finish(`scr_date_get_seconds(${arg(0)}, false)`);
6377
+ case "date.getUTCSeconds":
6378
+ return finish(`scr_date_get_seconds(${arg(0)}, true)`);
6379
+ case "date.getMilliseconds":
6380
+ case "date.getUTCMilliseconds":
6381
+ return finish(`scr_date_get_milliseconds(${arg(0)})`);
6382
+ case "date.getTimezoneOffset":
6383
+ return finish(`scr_date_get_timezone_offset(${arg(0)})`);
6147
6384
  case "text.decode":
6148
6385
  // WHATWG utf-8 decode with the leading BOM stripped
6149
6386
  // (scr_bytes.c). Borrowed bytes; +1 string; never throws.
6150
6387
  return finish(`scr_text_decode(${arg(0)})`);
6388
+ case "text.decodeLegacy":
6389
+ // Compile-time-labeled WHATWG legacy decode (scr_bytes.c).
6390
+ // Borrowed bytes + numeric encoding id; +1 string.
6391
+ return finish(`scr_text_decode_legacy(${arg(0)}, ${arg(1)})`);
6151
6392
  // The fs option forms (scr_lib.c) — all in the may-throw seed,
6152
6393
  // like the rest of sync fs.
6153
6394
  case "fs.mkdirRecursiveSync":
@@ -6170,6 +6411,8 @@ export function emitExpr(E, e) {
6170
6411
  return finish(`scr_fs_chown(${arg(0)}, ${arg(1)}, ${arg(2)})`);
6171
6412
  case "fs.copyFileSync":
6172
6413
  return finish(`scr_fs_copyfile(${arg(0)}, ${arg(1)})`);
6414
+ case "fs.renameSync":
6415
+ return finish(`scr_fs_rename(${arg(0)}, ${arg(1)})`);
6173
6416
  case "fs.lstatSync":
6174
6417
  return finish(`scr_fs_lstat(${arg(0)})`);
6175
6418
  case "fs.writeFileModeSync":
@@ -6302,7 +6545,7 @@ export function emitExpr(E, e) {
6302
6545
  throw new Error("emitter bug: yieldExpr with no operand (frontend fills undefined)");
6303
6546
  const v = E.emitExpr(e.value);
6304
6547
  const yt = e.value.type;
6305
- if (yt.kind === "f64") {
6548
+ if (yt.kind === "f64" || yt.kind === "date") {
6306
6549
  E.line(`scr_gen_yield_f64(${v.name});${E.srcComment(e.loc)}`);
6307
6550
  }
6308
6551
  else if (yt.kind === "bool") {
@@ -6319,6 +6562,7 @@ export function emitExpr(E, e) {
6319
6562
  // fences value-position yields on this channel).
6320
6563
  return { name: "", type: e.type };
6321
6564
  case "f64":
6565
+ case "date":
6322
6566
  return E.newTemp(e.type, `scr_gen_take_in_f64()`);
6323
6567
  case "bool":
6324
6568
  return E.newTemp(e.type, `scr_gen_take_in_bool()`);
@@ -6356,7 +6600,7 @@ export function emitExpr(E, e) {
6356
6600
  }
6357
6601
  else {
6358
6602
  const nt = e.arg.type;
6359
- sendArg((a) => nt.kind === "f64" ? `scr_gen_in_f64(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6603
+ sendArg((a) => nt.kind === "f64" || nt.kind === "date" ? `scr_gen_in_f64(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6360
6604
  : nt.kind === "bool" ? `scr_gen_in_bool(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6361
6605
  : `scr_gen_in_ref(${g.name}, ${a.name}, ${vAdapters(nt).release});${E.srcComment(e.loc)}`);
6362
6606
  }
@@ -6368,7 +6612,7 @@ export function emitExpr(E, e) {
6368
6612
  }
6369
6613
  else {
6370
6614
  const rt = e.arg.type;
6371
- sendArg((a) => rt.kind === "f64" ? `scr_gen_ret_f64(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6615
+ sendArg((a) => rt.kind === "f64" || rt.kind === "date" ? `scr_gen_ret_f64(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6372
6616
  : rt.kind === "bool" ? `scr_gen_ret_bool(${g.name}, ${a.name});${E.srcComment(e.loc)}`
6373
6617
  : `scr_gen_ret_ref(${g.name}, ${a.name}, ${vAdapters(rt).release});${E.srcComment(e.loc)}`);
6374
6618
  }
@@ -6385,7 +6629,10 @@ export function emitExpr(E, e) {
6385
6629
  const t = e.arg.type;
6386
6630
  if (isRefCounted(t))
6387
6631
  E.moveTemp(a); // the cell takes ownership
6388
- if (t.kind === "f64") {
6632
+ if (t.kind === "date") {
6633
+ throw new Error("emitter bug: Date generator throw reached backend");
6634
+ }
6635
+ else if (t.kind === "f64") {
6389
6636
  E.line(`scr_throw_f64(${a.name});${E.srcComment(e.loc)}`);
6390
6637
  }
6391
6638
  else if (t.kind === "bool") {
@@ -6418,6 +6665,7 @@ export function emitExpr(E, e) {
6418
6665
  let read;
6419
6666
  switch (e.type.kind) {
6420
6667
  case "f64":
6668
+ case "date":
6421
6669
  read = `scr_await_f64(${pr.name})`;
6422
6670
  break;
6423
6671
  case "bool":
@@ -6540,6 +6788,7 @@ export function emitExpr(E, e) {
6540
6788
  let mk;
6541
6789
  switch (inner.kind) {
6542
6790
  case "f64":
6791
+ case "date":
6543
6792
  mk = `scr_make_resolve(${p.name}, 0)`;
6544
6793
  break;
6545
6794
  case "bool":
@@ -6594,6 +6843,7 @@ export function emitExpr(E, e) {
6594
6843
  let mk;
6595
6844
  switch (inner.kind) {
6596
6845
  case "f64":
6846
+ case "date":
6597
6847
  mk = `scr_make_resolve(${p.name}, 0)`;
6598
6848
  break;
6599
6849
  case "bool":