@scriptc/compiler 0.0.9 → 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 (62) hide show
  1. package/dist/backend/emission/emit-exprs.js +136 -12
  2. package/dist/backend/emission/emit-exprs.js.map +1 -1
  3. package/dist/backend/emission/emit-walkers.js +29 -2
  4. package/dist/backend/emission/emit-walkers.js.map +1 -1
  5. package/dist/backend/llvm/dyn.d.ts +1 -0
  6. package/dist/backend/llvm/dyn.js +83 -1
  7. package/dist/backend/llvm/dyn.js.map +1 -1
  8. package/dist/backend/llvm/emitter.js +151 -9
  9. package/dist/backend/llvm/emitter.js.map +1 -1
  10. package/dist/diagnostics/diagnostic.d.ts +21 -7
  11. package/dist/diagnostics/diagnostic.js +35 -16
  12. package/dist/diagnostics/diagnostic.js.map +1 -1
  13. package/dist/diagnostics/render.js +8 -0
  14. package/dist/diagnostics/render.js.map +1 -1
  15. package/dist/frontend/lowering/lib-boundary.js +11 -1
  16. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  17. package/dist/frontend/lowering/lower-builtins.d.ts +13 -0
  18. package/dist/frontend/lowering/lower-builtins.js +146 -1
  19. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  20. package/dist/frontend/lowering/lower-calls.d.ts +41 -0
  21. package/dist/frontend/lowering/lower-calls.js +524 -10
  22. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  23. package/dist/frontend/lowering/lower-containers.d.ts +17 -0
  24. package/dist/frontend/lowering/lower-containers.js +193 -10
  25. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  26. package/dist/frontend/lowering/lower-dgram.js +92 -17
  27. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  28. package/dist/frontend/lowering/lower-exprs.js +179 -10
  29. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  30. package/dist/frontend/lowering/lower-modules.js +33 -2
  31. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  32. package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
  33. package/dist/frontend/lowering/lower-namespaces.js +50 -15
  34. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  35. package/dist/frontend/lowering/lower-server.js +211 -4
  36. package/dist/frontend/lowering/lower-server.js.map +1 -1
  37. package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
  38. package/dist/frontend/lowering/lower-stmts.js +216 -7
  39. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  40. package/dist/frontend/lowering/lower-stream.js +65 -4
  41. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  42. package/dist/frontend/lowering/lowerer.d.ts +36 -1
  43. package/dist/frontend/lowering/lowerer.js +106 -3
  44. package/dist/frontend/lowering/lowerer.js.map +1 -1
  45. package/dist/frontend/types.d.ts +13 -0
  46. package/dist/frontend/types.js +84 -7
  47. package/dist/frontend/types.js.map +1 -1
  48. package/dist/index.js +20 -8
  49. package/dist/index.js.map +1 -1
  50. package/dist/ir/nodes.d.ts +99 -5
  51. package/dist/ir/nodes.js +44 -3
  52. package/dist/ir/nodes.js.map +1 -1
  53. package/dist/ir/validate.js +53 -3
  54. package/dist/ir/validate.js.map +1 -1
  55. package/dist/library/fence-eval.d.ts +77 -0
  56. package/dist/library/fence-eval.js +385 -0
  57. package/dist/library/fence-eval.js.map +1 -0
  58. package/dist/library/profile.d.ts +11 -1
  59. package/dist/library/profile.js +102 -18
  60. package/dist/library/profile.js.map +1 -1
  61. package/package.json +2 -2
  62. package/surface-manifest.json +1 -1
@@ -197,6 +197,11 @@ const LIB_FN_SYMS = {
197
197
  "bytes.compareChk": "scr_bytes_compare_chk",
198
198
  "buffer.newStringFail": "scr_buffer_new_string_fail",
199
199
  "fs.toUnixTimestamp": "scr_fs_to_unix_timestamp",
200
+ "fs.existsChk": "scr_fs_exists_async",
201
+ "fs.mkdtempSyncChk": "scr_fs_mkdtemp_sync_chk",
202
+ "net.connectAttempt": "scr_net_connect_attempt",
203
+ "fs.lchmodSyncChk": "scr_fs_lchmod_sync_chk",
204
+ "fsp.lchmodChk": "scr_fsp_lchmod_chk",
200
205
  "fs.readFileSyncBuf": "scr_fs_read_file_bytes",
201
206
  "fs.readFileSyncBytes": "scr_fs_read_file_bytes",
202
207
  "fs.writeFileSyncBytes": "scr_fs_write_file_bytes",
@@ -342,9 +347,10 @@ const LIB_FN_SYMS = {
342
347
  // ambient-this read never throw. The fs dyn read is the sync-fs story.
343
348
  "json.parse": "scr_json_parse",
344
349
  "dyn.keySet": "scr_dyn_key_set",
350
+ "dyn.iterPack": "scr_dyn_iter_pack",
345
351
  "dyn.defineProps": "scr_dyn_define_props",
346
352
  "dyn.typeof": "scr_dyn_typeof",
347
- "dyn.toString": "scr_dyn_to_string",
353
+ "dyn.toString": "scr_dyn_to_string_method",
348
354
  "dyn.this": "scr_dyn_this_get",
349
355
  "insp.dyn": "scr_insp_dyn",
350
356
  "insp.dynS": "scr_insp_dyn_s",
@@ -559,6 +565,14 @@ const LIB_FN_SYMS = {
559
565
  "dyn.objKeys": "scr_dyn_obj_keys",
560
566
  "dyn.hasOwn": "scr_dyn_has_own",
561
567
  "dyn.assign": "scr_dyn_assign",
568
+ // variadic Object.assign: the source pack (push never throws; the
569
+ // spread flatten throws V8's spread-call TypeErrors) and the final
570
+ // left-to-right copy (ToObject TypeError on a nullish target).
571
+ "dyn.packPush": "scr_dyn_pack_push",
572
+ "dyn.packPushSpread": "scr_dyn_pack_push_spread",
573
+ "dyn.packPushSpreadIter": "scr_dyn_pack_push_spread_iter",
574
+ "dyn.assignAll": "scr_dyn_assign_all",
575
+ "dyn.objCreateNullProto": "scr_dyn_new_obj_null_proto",
562
576
  "dyn.objValues": "scr_dyn_obj_values",
563
577
  "dyn.objEntries": "scr_dyn_obj_entries",
564
578
  "dyn.structuredClone": "scr_structured_clone",
@@ -603,7 +617,8 @@ const USES_TIMERS_LIB_FNS = new Set([
603
617
  "stream.finished", "stream.finishedDyn", "stream.pipeline", "stream.pipelineDyn",
604
618
  "sp.finished", "sp.pipeline",
605
619
  "net.listen", "net.listenCb", "net.listenOpts", "net.listenOptsCb",
606
- "net.connect", "net.connectCb", "net.connectLookup",
620
+ "net.connect", "net.connectCb", "net.connectLookup", "net.connectAttempt",
621
+ "fs.existsChk",
607
622
  "http.createServer", "http.createServerEmpty",
608
623
  "http.request", "http.requestCb", "http.requestUrl", "http.requestUrlCb",
609
624
  "http.requestConn", "http.requestConnCb",
@@ -4178,6 +4193,33 @@ class LlEmitter {
4178
4193
  B.line(`${t} = load ptr, ptr ${slot}`);
4179
4194
  return this.own({ name: t, type: e.type });
4180
4195
  }
4196
+ if (e.left.type.kind === "dyn") {
4197
+ // The checked-dynamic form: the runtime kind decides (UNDEF/
4198
+ // NULL take the default; a wrapped island value asks the
4199
+ // engine); the right runs lazily in its branch (already dyn).
4200
+ const l = this.emitExpr(e.left);
4201
+ this.moveTemp(l);
4202
+ this.declare(`declare zeroext i1 @scr_dyn_is_nullish(ptr)`);
4203
+ const slot = B.slot();
4204
+ B.entryAllocas.push(`${slot} = alloca ptr`);
4205
+ const isN = B.tmp();
4206
+ B.line(`${isN} = call zeroext i1 @scr_dyn_is_nullish(ptr ${l.name})`);
4207
+ const lu = B.newLabel("nuld.u");
4208
+ const lv = B.newLabel("nuld.v");
4209
+ const lj = B.newLabel("nuld.j");
4210
+ B.condBr(isN, lu, lv);
4211
+ B.startBlock(lu);
4212
+ this.releaseValue(l.name, e.left.type);
4213
+ this.emitBranchInto(slot, e.right);
4214
+ B.br(lj);
4215
+ B.startBlock(lv);
4216
+ B.line(`store ptr ${l.name}, ptr ${slot}`);
4217
+ B.br(lj);
4218
+ B.startBlock(lj);
4219
+ const t = B.tmp();
4220
+ B.line(`${t} = load ptr, ptr ${slot}`);
4221
+ return this.own({ name: t, type: e.type });
4222
+ }
4181
4223
  if (e.left.type.kind !== "union")
4182
4224
  throw new Error("llvm emitter bug: nullish left is not a union");
4183
4225
  const def = this.unionsById.get(e.left.type.unionId);
@@ -5500,6 +5542,16 @@ class LlEmitter {
5500
5542
  B.line(`${t} = call ptr @${conv}(${valTy} ${v.name})`);
5501
5543
  return this.own({ name: t, type: e.type });
5502
5544
  }
5545
+ case "dynFromJsval": {
5546
+ // Island value → DOM: the by-reference wrap (scr_dyn_from_jsval
5547
+ // retains the cell in; engine scalars normalize to native DOM
5548
+ // kinds at wrap time). Operand borrowed, result +1, never throws.
5549
+ const v = this.emitExpr(e.value);
5550
+ this.declare(`declare ptr @scr_dyn_from_jsval(ptr)`);
5551
+ const t = B.tmp();
5552
+ B.line(`${t} = call ptr @scr_dyn_from_jsval(ptr ${v.name})`);
5553
+ return this.own({ name: t, type: e.type });
5554
+ }
5503
5555
  case "caughtToDyn": {
5504
5556
  // A catch binding flowing into an `unknown` slot: the snapshot's
5505
5557
  // runtime kind converts through the interned helper (+1 fresh
@@ -5681,7 +5733,8 @@ class LlEmitter {
5681
5733
  B.startBlock(lNotObj);
5682
5734
  const isArr = B.tmp();
5683
5735
  B.line(`${isArr} = icmp eq i32 ${kd}, ${DK.ARR}`);
5684
- B.condBr(isArr, lArr, lj);
5736
+ const lNotArr = B.newLabel("dhk.na");
5737
+ B.condBr(isArr, lArr, lNotArr);
5685
5738
  B.startBlock(lArr);
5686
5739
  if (e.key === "length") {
5687
5740
  B.line(`store i1 true, ptr ${slot}`);
@@ -5696,9 +5749,20 @@ class LlEmitter {
5696
5749
  B.line(`store i1 ${inR}, ptr ${slot}`);
5697
5750
  }
5698
5751
  B.br(lj);
5752
+ // An ISLAND-held receiver fences loudly (Node asks the real
5753
+ // engine object — `false` would be a silent wrong answer); the
5754
+ // helper answers false for every other kind, so this arm is a
5755
+ // plain unconditional call.
5756
+ B.startBlock(lNotArr);
5757
+ this.declare(`declare zeroext i1 @scr_dyn_isl_fence(ptr, ptr)`);
5758
+ const fenced = B.tmp();
5759
+ B.line(`${fenced} = call zeroext i1 @scr_dyn_isl_fence(ptr ${d.name}, ptr ${this.cstr("'in'")})`);
5760
+ B.line(`store i1 ${fenced}, ptr ${slot}`);
5761
+ B.br(lj);
5699
5762
  B.startBlock(lj);
5700
5763
  const raw = B.tmp();
5701
5764
  B.line(`${raw} = load i1, ptr ${slot}`);
5765
+ this.emitPendingCheck();
5702
5766
  if (!e.negated)
5703
5767
  return { name: raw, type: e.type };
5704
5768
  const neg = B.tmp();
@@ -5778,13 +5842,18 @@ class LlEmitter {
5778
5842
  }
5779
5843
  else if (e.test === "error") {
5780
5844
  // `u instanceof Error`: the DOM's error encoding — an object
5781
- // carrying the reserved "%error" marker key.
5845
+ // carrying the reserved "%error" marker key — or a real engine
5846
+ // Error held by reference (the isl helper answers false for
5847
+ // every non-JSVAL kind, so the call is unconditional).
5782
5848
  const kd = this.dynKind(d.name);
5783
5849
  const isObj = B.tmp();
5784
5850
  B.line(`${isObj} = icmp eq i32 ${kd}, ${DK.OBJ}`);
5785
5851
  const slot = B.slot();
5786
5852
  B.entryAllocas.push(`${slot} = alloca i1`);
5787
- B.line(`store i1 false, ptr ${slot}`);
5853
+ this.declare(`declare zeroext i1 @scr_dyn_isl_is_error(ptr)`);
5854
+ const isl = B.tmp();
5855
+ B.line(`${isl} = call zeroext i1 @scr_dyn_isl_is_error(ptr ${d.name})`);
5856
+ B.line(`store i1 ${isl}, ptr ${slot}`);
5788
5857
  const lObj = B.newLabel("dts.o");
5789
5858
  const lj = B.newLabel("dts.j");
5790
5859
  B.condBr(isObj, lObj, lj);
@@ -5818,13 +5887,33 @@ class LlEmitter {
5818
5887
  }
5819
5888
  return acc;
5820
5889
  };
5890
+ // ISLAND-held nodes route the tests that depend on the engine's
5891
+ // answer through the scr_dyn_isl_* helpers (false on every
5892
+ // other kind — the calls stay unconditional and branch-free).
5893
+ const orIsl = (acc, helper, arg) => {
5894
+ this.declare(`declare zeroext i1 @${helper}(ptr${arg !== undefined ? ", ptr" : ""})`);
5895
+ const c = B.tmp();
5896
+ B.line(`${c} = call zeroext i1 @${helper}(ptr ${d.name}${arg !== undefined ? `, ptr ${arg}` : ""})`);
5897
+ const o = B.tmp();
5898
+ B.line(`${o} = or i1 ${acc}, ${c}`);
5899
+ return o;
5900
+ };
5821
5901
  if (e.test === "nullish") {
5822
5902
  test = oneOf([DK.UNDEF, DK.NULL]);
5823
5903
  }
5824
5904
  else if (e.test === "object") {
5825
5905
  // `typeof v === "object"`: objects, arrays, bytes, native
5826
- // handles, promises, AND null.
5827
- test = oneOf([DK.OBJ, DK.ARR, DK.BYTES, DK.HANDLE, DK.PROMISE, DK.NULL]);
5906
+ // handles, promises, AND null — engine-held objects by the
5907
+ // engine's own typeof.
5908
+ test = orIsl(oneOf([DK.OBJ, DK.ARR, DK.BYTES, DK.HANDLE, DK.PROMISE, DK.NULL]), "scr_dyn_isl_typeof_is", this.cstr("object"));
5909
+ }
5910
+ else if (e.test === "array") {
5911
+ // Array.isArray: the DOM's array kind, or the engine's own
5912
+ // answer for an engine-held value.
5913
+ test = orIsl(oneOf([DK.ARR]), "scr_dyn_isl_is_array");
5914
+ }
5915
+ else if (e.test === "function") {
5916
+ test = orIsl(oneOf([DK.FUNC]), "scr_dyn_isl_typeof_is", this.cstr("function"));
5828
5917
  }
5829
5918
  else {
5830
5919
  const kindOf = {
@@ -5834,8 +5923,6 @@ class LlEmitter {
5834
5923
  undefined: DK.UNDEF,
5835
5924
  null: DK.NULL,
5836
5925
  bytes: DK.BYTES,
5837
- array: DK.ARR,
5838
- function: DK.FUNC,
5839
5926
  };
5840
5927
  test = oneOf([kindOf[e.test]]);
5841
5928
  }
@@ -5947,6 +6034,13 @@ class LlEmitter {
5947
6034
  return simple("scr_jsval_from_bool", "i1", false);
5948
6035
  case "string":
5949
6036
  return simple("scr_jsval_from_str", "ptr", false);
6037
+ case "dyn":
6038
+ // A CHECKED-DYNAMIC (DOM) value entering the island: deep copy,
6039
+ // data kinds only — boxed functions/handles/promises throw the
6040
+ // catchable TypeError in the runtime, and a wrapped island value
6041
+ // unwraps to the SAME engine value (the identity round trip).
6042
+ // The C emitter's rule, mirrored.
6043
+ return simple("scr_jsval_from_dyn", "ptr", true);
5950
6044
  case "bytes":
5951
6045
  // A typed array crossing IN: a COPY (the boundary's copy stance).
5952
6046
  return simple("scr_jsval_from_bytes", "ptr", true);
@@ -8666,6 +8760,54 @@ class LlEmitter {
8666
8760
  this.emitPendingCheck();
8667
8761
  return out;
8668
8762
  }
8763
+ if (e.fn === "error.propTypeThrow") {
8764
+ // The property flavor of argTypeThrow — same always-throw shape.
8765
+ const an = this.emitExpr(e.args[0]);
8766
+ const ex = this.emitExpr(e.args[1]);
8767
+ const got = this.emitExpr(e.args[2]);
8768
+ this.declare(`declare void @scr_throw_prop_type(ptr, ptr, ptr)`);
8769
+ B.line(`call void @scr_throw_prop_type(ptr ${an.name}, ptr ${ex.name}, ptr ${got.name})`);
8770
+ const ty = this.llType(e.type);
8771
+ if (ty === "void") {
8772
+ this.emitPendingCheck();
8773
+ return { name: "", type: e.type };
8774
+ }
8775
+ const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
8776
+ const out = this.own({ name: dummy, type: e.type });
8777
+ this.emitPendingCheck();
8778
+ return out;
8779
+ }
8780
+ {
8781
+ // The fs validation-ladder Chk forms that ALWAYS throw (a
8782
+ // validation error or the trailing compiler-rendered fence): every
8783
+ // argument is a ptr (dyns + the fence string), and the typed dummy
8784
+ // is abandoned by the pending check's unwind.
8785
+ const FS_CHK_THROW_SYMS = {
8786
+ "fs.mkdtempChk": "scr_fs_mkdtemp_chk",
8787
+ "fs.readFileChk": "scr_fs_read_file_chk",
8788
+ "fs.opendirChk": "scr_fs_opendir_chk",
8789
+ "fs.watchFileChk": "scr_fs_watch_file_chk",
8790
+ "fs.lchmodChk": "scr_fs_lchmod_chk",
8791
+ "fs.readChk": "scr_fs_read_chk",
8792
+ "fs.streamOptsChk": "scr_fs_stream_opts_chk",
8793
+ "net.connectOptsChk": "scr_net_connect_opts_chk",
8794
+ };
8795
+ const sym = FS_CHK_THROW_SYMS[e.fn];
8796
+ if (sym !== undefined) {
8797
+ const args = e.args.map((a) => this.emitExpr(a));
8798
+ this.declare(`declare void @${sym}(${args.map(() => "ptr").join(", ")})`);
8799
+ B.line(`call void @${sym}(${args.map((a) => `ptr ${a.name}`).join(", ")})`);
8800
+ const ty = this.llType(e.type);
8801
+ if (ty === "void") {
8802
+ this.emitPendingCheck();
8803
+ return { name: "", type: e.type };
8804
+ }
8805
+ const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
8806
+ const out = this.own({ name: dummy, type: e.type });
8807
+ this.emitPendingCheck();
8808
+ return out;
8809
+ }
8810
+ }
8669
8811
  if (e.fn === "error.nodeThrow") {
8670
8812
  // The compiler-resolved Node-parity throw (always throws — the
8671
8813
  // typed dummy is abandoned by the pending check's unwind).