@scriptc/compiler 0.0.21 → 0.0.22

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 (70) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +78 -34
  2. package/dist/backend/cc-cache.test.d.ts +1 -0
  3. package/dist/backend/cc-cache.test.js +2507 -0
  4. package/dist/backend/cc-cache.test.js.map +1 -0
  5. package/dist/backend/cc.d.ts +69 -11
  6. package/dist/backend/cc.js +1937 -222
  7. package/dist/backend/cc.js.map +1 -1
  8. package/dist/backend/emission/emit-exprs.js +355 -8
  9. package/dist/backend/emission/emit-exprs.js.map +1 -1
  10. package/dist/backend/emission/emit-walkers.js +108 -7
  11. package/dist/backend/emission/emit-walkers.js.map +1 -1
  12. package/dist/backend/emission/emitter.d.ts +16 -0
  13. package/dist/backend/emission/emitter.js +23 -2
  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 +305 -8
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.js +527 -2
  19. package/dist/backend/llvm/emitter.js.map +1 -1
  20. package/dist/compat/fetch-profile.d.ts +108 -0
  21. package/dist/compat/fetch-profile.js +482 -0
  22. package/dist/compat/fetch-profile.js.map +1 -0
  23. package/dist/coverage/surface-manifest.js +54 -0
  24. package/dist/coverage/surface-manifest.js.map +1 -1
  25. package/dist/frontend/lowering/lower-builtins.d.ts +21 -8
  26. package/dist/frontend/lowering/lower-builtins.js +137 -14
  27. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  28. package/dist/frontend/lowering/lower-calls.js +40 -0
  29. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  30. package/dist/frontend/lowering/lower-classes.js +4 -3
  31. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  32. package/dist/frontend/lowering/lower-exprs.d.ts +2 -2
  33. package/dist/frontend/lowering/lower-exprs.js +63 -12
  34. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  35. package/dist/frontend/lowering/lower-island.d.ts +102 -7
  36. package/dist/frontend/lowering/lower-island.js +1702 -26
  37. package/dist/frontend/lowering/lower-island.js.map +1 -1
  38. package/dist/frontend/lowering/lower-modules.js +17 -1
  39. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  40. package/dist/frontend/lowering/lower-stmts.js +25 -5
  41. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  42. package/dist/frontend/lowering/lowerer.d.ts +39 -0
  43. package/dist/frontend/lowering/lowerer.js +286 -18
  44. package/dist/frontend/lowering/lowerer.js.map +1 -1
  45. package/dist/frontend/lowering/surfaces.js +12 -0
  46. package/dist/frontend/lowering/surfaces.js.map +1 -1
  47. package/dist/frontend/program.d.ts +16 -0
  48. package/dist/frontend/program.js +130 -6
  49. package/dist/frontend/program.js.map +1 -1
  50. package/dist/frontend/types.d.ts +14 -7
  51. package/dist/frontend/types.js +95 -31
  52. package/dist/frontend/types.js.map +1 -1
  53. package/dist/index.d.ts +7 -1
  54. package/dist/index.js +70 -14
  55. package/dist/index.js.map +1 -1
  56. package/dist/ir/nodes.d.ts +32 -16
  57. package/dist/ir/nodes.js +36 -28
  58. package/dist/ir/nodes.js.map +1 -1
  59. package/dist/ir/validate.js +61 -1
  60. package/dist/ir/validate.js.map +1 -1
  61. package/dist/library/int-infer.js +7 -1
  62. package/dist/library/int-infer.js.map +1 -1
  63. package/dist/library/int-infer.test.js +80 -0
  64. package/dist/library/int-infer.test.js.map +1 -1
  65. package/dist/library/sidecar-validate.js +5 -0
  66. package/dist/library/sidecar-validate.js.map +1 -1
  67. package/dist/library/sidecar.d.ts +3 -0
  68. package/dist/library/sidecar.js.map +1 -1
  69. package/package.json +2 -2
  70. package/surface-manifest.json +859 -1
@@ -1,9 +1,292 @@
1
- import { arrayOf, BOOL, BYTES_U8, bytesOf, canMarshalFuncIntoIsland, CHILDSTREAM_T, DYN, F64, islandPromisePayloadTag, 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, DV_SET_KIND_C, elemAccess, mapKeyAccess, mapKeyKindC, mapValKindC, retainCallC, vAdapters } from "./emit-types.js";
1
+ import { arrayOf, BOOL, BYTES_U8, bytesOf, canMarshalFuncIntoIsland, CHILDSTREAM_T, DYN, F64, islandPromisePayloadTag, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, RUNTIME_ERROR_CLASSES, STRING, typeEquals, typeKey } 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, DV_SET_KIND_C, elemAccess, mapKeyAccess, mapKeyKindC, mapValKindC, releaseCallC, 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";
6
6
  import { genResultThunkFor } from "./emit-async.js";
7
+ function streamTypedRefCommitAdapter(E, t, snapshot, defs) {
8
+ if (t.kind === "bytes") {
9
+ const commit = `${snapshot}_commit`;
10
+ E.walkerProtos.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d); /* commit live stream element ${typeKey(t)} */`);
11
+ defs.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d) {`, ` ScrBytes *sc_target = (ScrBytes *)sc_p;`, ` ScrBytes *sc_next = ${E.dynCheckHelper(t)}(sc_d, NULL);`, ` if (!sc_next) return;`, ` scr_bytes_copy_contents(sc_target, sc_next);`, ` scr_bytes_release(sc_next);`, `}`, ``);
12
+ return `&${commit}`;
13
+ }
14
+ if (t.kind === "array") {
15
+ const commit = `${snapshot}_commit`;
16
+ E.walkerProtos.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d); /* commit live stream element ${typeKey(t)} */`);
17
+ defs.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d) {`, ` ScrArr *sc_target = (ScrArr *)sc_p;`, ` ScrArr *sc_next = ${E.dynCheckHelper(t)}(sc_d, NULL);`, ` if (!sc_next) return;`, ` size_t sc_target_len = sc_target->len;`, ` size_t sc_target_cap = sc_target->cap;`, ` uint64_t *sc_target_data = sc_target->data;`, ` sc_target->len = sc_next->len;`, ` sc_target->cap = sc_next->cap;`, ` sc_target->data = sc_next->data;`, ` sc_next->len = sc_target_len;`, ` sc_next->cap = sc_target_cap;`, ` sc_next->data = sc_target_data;`, ` scr_arr_release(sc_next);`, `}`, ``);
18
+ return `&${commit}`;
19
+ }
20
+ if (t.kind !== "record")
21
+ return "NULL";
22
+ const shape = E.recordsById.get(t.shapeId);
23
+ if (!shape) {
24
+ throw new Error(`emitter bug: stream typed-ref commit of unknown shape ${t.shapeId}`);
25
+ }
26
+ const commit = `${snapshot}_commit`;
27
+ E.walkerProtos.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d); /* commit live stream element ${typeKey(t)} */`);
28
+ defs.push(`static void ${commit}(void *sc_p, const ScrDyn *sc_d) {`, ` ${cDecl(t, "sc_target")} = (${cType(t).trim()})sc_p;`, ` ${cDecl(t, "sc_next")} = ${E.dynCheckHelper(t)}(sc_d, NULL);`, ` if (!sc_next) return;`);
29
+ for (const field of shape.fields) {
30
+ const member = mangleField(field.name);
31
+ defs.push(` {`, ` ${cDecl(field.type, "sc_old")} = sc_target->${member};`, ` sc_target->${member} = sc_next->${member};`, ` sc_next->${member} = sc_old;`, ` }`);
32
+ }
33
+ if (shape.indexValue) {
34
+ defs.push(` {`, ` ScrMap *sc_old = sc_target->${OVERFLOW_MEMBER};`, ` sc_target->${OVERFLOW_MEMBER} = sc_next->${OVERFLOW_MEMBER};`, ` sc_next->${OVERFLOW_MEMBER} = sc_old;`, ` }`);
35
+ }
36
+ defs.push(` ${releaseCallC(t, "sc_next")};`, `}`, ``);
37
+ return `&${commit}`;
38
+ }
39
+ function streamTypedRefEligible(t) {
40
+ return t.kind === "record" || t.kind === "array" || t.kind === "bytes";
41
+ }
42
+ /** Build the live dyn view of one typed stream value. Mutable reference
43
+ * children are capsules of their own, so a write through `v.child.x` or
44
+ * `v.items[0]` commits directly to that child's static source instead of
45
+ * disappearing into the parent's detached snapshot. */
46
+ function streamTypedRefAdapter(E, t, ctx, preferredSnapshot) {
47
+ const key = typeKey(t);
48
+ const existing = ctx.adapters.get(key);
49
+ if (existing)
50
+ return existing;
51
+ const snapshot = preferredSnapshot ??
52
+ `${ctx.prefix}_nested_${ctx.adapters.size}`;
53
+ const adapter = { snapshot, commit: "NULL" };
54
+ /* Register before walking children: recursive record/array types refer
55
+ * back to this prototype without recursively generating helpers. */
56
+ ctx.adapters.set(key, adapter);
57
+ E.walkerProtos.push(`static ScrDyn *${snapshot}(void *sc_p); /* materialize live stream value ${key} */`);
58
+ adapter.commit = streamTypedRefCommitAdapter(E, t, snapshot, ctx.defs);
59
+ const box = (child, expr) => {
60
+ if (!streamTypedRefEligible(child)) {
61
+ return `${E.toDynHelper(child)}(${expr})`;
62
+ }
63
+ const nested = streamTypedRefAdapter(E, child, ctx);
64
+ const rc = vAdapters(child);
65
+ const childKey = typeKey(child);
66
+ const keyLit = cStringLiteral(Buffer.from(childKey, "utf8"));
67
+ return `scr_dyn_new_typed_ref(${expr}, &${rc.retain}, &${rc.release}, ${keyLit}, ${Buffer.byteLength(childKey, "utf8")}, &${nested.snapshot}, ${nested.commit})`;
68
+ };
69
+ const lines = [
70
+ `static ScrDyn *${snapshot}(void *sc_p) { /* materialize live stream value ${key} */`,
71
+ ` ${cDecl(t, "v")} = (${cType(t).trim()})sc_p;`,
72
+ ];
73
+ if (t.kind === "record") {
74
+ const shape = E.recordsById.get(t.shapeId);
75
+ if (!shape) {
76
+ throw new Error(`emitter bug: stream typed-ref materialize of unknown shape ${t.shapeId}`);
77
+ }
78
+ const ordinary = shape.indexValue || shape.fields.some((field) => field.name === "handleEvent" && field.type.kind === "func");
79
+ if (ordinary) {
80
+ lines.push(` return ${E.toDynHelper(t)}(v);`, `}`, ``);
81
+ ctx.defs.push(...lines);
82
+ return adapter;
83
+ }
84
+ if (shape.tuple) {
85
+ lines.push(` ScrDyn *d = scr_dyn_new_arr();`);
86
+ const fields = [...shape.fields].sort((a, b) => Number(a.name) - Number(b.name));
87
+ for (const field of fields) {
88
+ lines.push(` scr_dyn_arr_push(d, ${box(field.type, `v->${mangleField(field.name)}`)});`);
89
+ }
90
+ }
91
+ else {
92
+ lines.push(` ScrDyn *d = scr_dyn_new_obj();`);
93
+ const byName = new Map(shape.fields.map((field) => [field.name, field]));
94
+ const order = shape.declaredOrder ?? shape.fields.map((field) => field.name);
95
+ const inOrder = new Set(order);
96
+ const fields = [
97
+ ...order.map((name) => byName.get(name)).filter((field) => field !== undefined),
98
+ ...shape.fields.filter((field) => !inOrder.has(field.name)),
99
+ ];
100
+ for (const field of fields) {
101
+ const keyLit = cStringLiteral(Buffer.from(field.name, "utf8"));
102
+ lines.push(` scr_dyn_obj_set(d, ${keyLit}, ${Buffer.byteLength(field.name, "utf8")}, ${box(field.type, `v->${mangleField(field.name)}`)});`);
103
+ }
104
+ }
105
+ lines.push(` return d;`);
106
+ }
107
+ else if (t.kind === "array") {
108
+ const elem = t.elem;
109
+ lines.push(` ScrDyn *d = scr_dyn_new_arr();`, ` for (size_t sc_i = 0; sc_i < v->len; sc_i++) {`);
110
+ if (elem.kind === "f64") {
111
+ lines.push(` scr_dyn_arr_push(d, ${box(elem, "scr_arr_get_f64(v, (double)sc_i)")});`);
112
+ }
113
+ else if (elem.kind === "bool") {
114
+ lines.push(` scr_dyn_arr_push(d, ${box(elem, "scr_arr_get_bool(v, (double)sc_i)")});`);
115
+ }
116
+ else {
117
+ lines.push(` ${cDecl(elem, "sc_value")} = (${cType(elem).trim()})scr_arr_get_ref(v, (double)sc_i);`, ` scr_dyn_arr_push(d, ${box(elem, "sc_value")});`, ` ${releaseCallC(elem, "sc_value")};`);
118
+ }
119
+ lines.push(` }`, ` return d;`);
120
+ }
121
+ else {
122
+ lines.push(` return ${E.toDynHelper(t)}(v);`);
123
+ }
124
+ lines.push(`}`, ``);
125
+ ctx.defs.push(...lines);
126
+ return adapter;
127
+ }
128
+ /** One per-type capsule adapter for Web API arguments whose JavaScript
129
+ * contract preserves the exact input reference. */
130
+ function liveDynRefAdapter(E, t) {
131
+ const key = typeKey(t);
132
+ const existing = E.liveDynRefAdapters.get(key);
133
+ if (existing)
134
+ return existing;
135
+ if (!streamTypedRefEligible(t)) {
136
+ throw new Error(`emitter bug: live dyn ref of ${key}`);
137
+ }
138
+ const prefix = `sc_ldr_${E.liveDynRefAdapters.size}`;
139
+ const defs = [];
140
+ const adapter = streamTypedRefAdapter(E, t, { prefix, defs, adapters: new Map() }, `${prefix}_materialize`);
141
+ E.liveDynRefAdapters.set(key, adapter);
142
+ E.walkerDefs.push(...defs);
143
+ return adapter;
144
+ }
145
+ /** A union itself is only the tagged box; the identity Web APIs expose is
146
+ * the selected mutable arm. Dispatch on the tag and point the typed capsule
147
+ * directly at that arm's payload. Non-mutable arms keep ordinary dynFrom
148
+ * semantics. */
149
+ function liveDynUnionRefAdapter(E, t) {
150
+ const key = typeKey(t);
151
+ const existing = E.liveDynUnionRefAdapters.get(key);
152
+ if (existing)
153
+ return existing;
154
+ const union = E.unionsById.get(t.unionId);
155
+ if (!union) {
156
+ throw new Error(`emitter bug: live dyn ref of unknown union ${t.unionId}`);
157
+ }
158
+ const mutableArms = union.arms
159
+ .map((arm, tag) => ({ arm, tag }))
160
+ .filter(({ arm }) => streamTypedRefEligible(arm));
161
+ if (mutableArms.length === 0) {
162
+ throw new Error(`emitter bug: live dyn ref of immutable union ${key}`);
163
+ }
164
+ const sym = `sc_ldu_${E.liveDynUnionRefAdapters.size}`;
165
+ E.liveDynUnionRefAdapters.set(key, sym);
166
+ const sig = `static ScrDyn *${sym}(ScrUnion *sc_u)`;
167
+ E.walkerProtos.push(`${sig}; /* materialize live union value ${key} */`);
168
+ const defs = [];
169
+ const adapters = new Map();
170
+ for (const { arm, tag } of mutableArms) {
171
+ const prefix = `${sym}_${tag}`;
172
+ adapters.set(tag, streamTypedRefAdapter(E, arm, { prefix, defs, adapters: new Map() }, `${prefix}_materialize`));
173
+ }
174
+ defs.push(`${sig} {`, ` switch (sc_u->tag) {`);
175
+ for (const { arm, tag } of mutableArms) {
176
+ const adapter = adapters.get(tag);
177
+ const rc = vAdapters(arm);
178
+ const armKey = typeKey(arm);
179
+ const keyLit = cStringLiteral(Buffer.from(armKey, "utf8"));
180
+ defs.push(` case ${tag}:`, ` return scr_dyn_new_typed_ref(scr_union_peek(sc_u), &${rc.retain}, &${rc.release}, ${keyLit}, ${Buffer.byteLength(armKey, "utf8")}, &${adapter.snapshot}, ${adapter.commit});`);
181
+ }
182
+ defs.push(` default:`, ` return ${E.toDynHelper(t)}(sc_u);`, ` }`, `}`, ``);
183
+ E.walkerDefs.push(...defs);
184
+ return sym;
185
+ }
186
+ function streamFromArrayAdapter(E, t) {
187
+ const elem = t.elem;
188
+ const key = typeKey(elem);
189
+ const existing = E.streamFromArrayAdapters.get(key);
190
+ if (existing)
191
+ return existing;
192
+ const sym = `sc_sfa_${E.streamFromArrayAdapters.size}`;
193
+ E.streamFromArrayAdapters.set(key, sym);
194
+ const sig = `static ScrDyn *${sym}(ScrArr *sc_a, double sc_i)`;
195
+ E.walkerProtos.push(`${sig}; /* ReadableStream.from array<${key}> */`);
196
+ const unionDef = elem.kind === "union"
197
+ ? E.unionsById.get(elem.unionId)
198
+ : undefined;
199
+ if (elem.kind === "union" && !unionDef) {
200
+ throw new Error(`emitter bug: streamFrom of unknown union ${elem.unionId}`);
201
+ }
202
+ const unionRefArms = unionDef?.arms
203
+ .map((arm, tag) => ({ arm, tag }))
204
+ .filter(({ arm }) => isRefCounted(arm) && arm.kind !== "dyn" && arm.kind !== "string") ?? [];
205
+ const typedRef = isRefCounted(elem) &&
206
+ elem.kind !== "dyn" &&
207
+ elem.kind !== "string" &&
208
+ elem.kind !== "union";
209
+ const snapshot = `${sym}_materialize`;
210
+ const d = [];
211
+ let commit = "NULL";
212
+ if (typedRef) {
213
+ if (streamTypedRefEligible(elem)) {
214
+ const adapter = streamTypedRefAdapter(E, elem, { prefix: snapshot, defs: d, adapters: new Map() }, snapshot);
215
+ commit = adapter.commit;
216
+ }
217
+ else {
218
+ const snapshotSig = `static ScrDyn *${snapshot}(void *sc_p)`;
219
+ E.walkerProtos.push(`${snapshotSig}; /* materialize stream element ${key} */`);
220
+ d.push(`${snapshotSig} {`, ` return ${E.toDynHelper(elem)}((${cType(elem).trim()})sc_p);`, `}`, ``);
221
+ commit = streamTypedRefCommitAdapter(E, elem, snapshot, d);
222
+ }
223
+ }
224
+ const unionCommits = new Map();
225
+ for (const { arm, tag } of unionRefArms) {
226
+ const armKey = typeKey(arm);
227
+ const armSnapshot = `${snapshot}_${tag}`;
228
+ const snapshotSig = `static ScrDyn *${armSnapshot}(void *sc_p)`;
229
+ E.walkerProtos.push(`${snapshotSig}; /* materialize stream union arm ${armKey} */`);
230
+ d.push(`${snapshotSig} {`, ` return ${E.toDynHelper(arm)}((${cType(arm).trim()})sc_p);`, `}`, ``);
231
+ unionCommits.set(tag, streamTypedRefCommitAdapter(E, arm, armSnapshot, d));
232
+ }
233
+ d.push(`${sig} { /* ReadableStream.from array<${key}> */`);
234
+ if (elem.kind === "f64") {
235
+ d.push(` return ${E.toDynHelper(elem)}(scr_arr_get_f64(sc_a, sc_i));`);
236
+ }
237
+ else if (elem.kind === "bool") {
238
+ d.push(` return ${E.toDynHelper(elem)}(scr_arr_get_bool(sc_a, sc_i));`);
239
+ }
240
+ else {
241
+ d.push(` ${cDecl(elem, "sc_v")} = (${cType(elem).trim()})scr_arr_get_ref(sc_a, sc_i);`);
242
+ if (elem.kind === "union") {
243
+ d.push(` ScrDyn *sc_d;`, ` switch (sc_v->tag) {`);
244
+ for (const { arm, tag } of unionRefArms) {
245
+ const armKey = typeKey(arm);
246
+ const rc = vAdapters(arm);
247
+ const keyLit = cStringLiteral(Buffer.from(armKey, "utf8"));
248
+ d.push(` case ${tag}:`, ` sc_d = scr_dyn_new_typed_ref(scr_union_peek(sc_v), &${rc.retain}, &${rc.release}, ${keyLit}, ${Buffer.byteLength(armKey, "utf8")}, &${snapshot}_${tag}, ${unionCommits.get(tag) ?? "NULL"});`, ` break;`);
249
+ }
250
+ d.push(` default:`, ` sc_d = ${E.toDynHelper(elem)}(sc_v);`, ` break;`, ` }`);
251
+ }
252
+ else if (typedRef) {
253
+ const rc = vAdapters(elem);
254
+ const keyLit = cStringLiteral(Buffer.from(key, "utf8"));
255
+ const keyLen = Buffer.byteLength(key, "utf8");
256
+ d.push(` ScrDyn *sc_d = scr_dyn_new_typed_ref(sc_v, &${rc.retain}, &${rc.release}, ${keyLit}, ${keyLen}, &${snapshot}, ${commit});`);
257
+ }
258
+ else {
259
+ d.push(` ScrDyn *sc_d = ${E.toDynHelper(elem)}(sc_v);`);
260
+ }
261
+ d.push(` ${releaseCallC(elem, "sc_v")};`, ` return sc_d;`);
262
+ }
263
+ d.push(`}`, ``);
264
+ E.walkerDefs.push(...d);
265
+ return sym;
266
+ }
267
+ function dynPromiseAdapter(E, inner) {
268
+ if (!isRefCounted(inner) || inner.kind === "dyn") {
269
+ throw new Error(`dynamic promise adapter requires a concrete reference type, got ${typeKey(inner)}`);
270
+ }
271
+ const key = typeKey(inner);
272
+ const existing = E.dynPromiseAdapters.get(key);
273
+ if (existing)
274
+ return existing;
275
+ const sym = `sc_dpa_${E.dynPromiseAdapters.size}`;
276
+ E.dynPromiseAdapters.set(key, sym);
277
+ const sig = `static void ${sym}(ScrPromise *sc_dst, ScrPromise *sc_src)`;
278
+ E.walkerProtos.push(`${sig}; /* checked-dynamic promise exit ${key} */`);
279
+ let fulfill;
280
+ if (inner.kind === "string") {
281
+ fulfill = `scr_promise_fulfill_str(sc_dst, sc_v);`;
282
+ }
283
+ else {
284
+ const rc = vAdapters(inner);
285
+ fulfill = `scr_promise_fulfill_ref(sc_dst, sc_v, &${rc.retain}, &${rc.release}, ${E.traceArgC(inner)});`;
286
+ }
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
+ return sym;
289
+ }
7
290
  export function emitExpr(E, e) {
8
291
  switch (e.kind) {
9
292
  case "numLit":
@@ -1692,6 +1975,17 @@ export function emitExpr(E, e) {
1692
1975
  : "scr_dyn_new_null()");
1693
1976
  }
1694
1977
  const v = E.emitExpr(e.value);
1978
+ if (e.liveRef) {
1979
+ if (v.type.kind === "union") {
1980
+ const adapter = liveDynUnionRefAdapter(E, v.type);
1981
+ return E.newTemp(e.type, `${adapter}(${v.name})`);
1982
+ }
1983
+ const adapter = liveDynRefAdapter(E, v.type);
1984
+ const rc = vAdapters(v.type);
1985
+ const key = typeKey(v.type);
1986
+ const keyLit = cStringLiteral(Buffer.from(key, "utf8"));
1987
+ return E.newTemp(e.type, `scr_dyn_new_typed_ref(${v.name}, &${rc.retain}, &${rc.release}, ${keyLit}, ${Buffer.byteLength(key, "utf8")}, &${adapter.snapshot}, ${adapter.commit})`);
1988
+ }
1695
1989
  if (v.type.kind === "func") {
1696
1990
  // A closure boxes as the checked-dynamic tree's function kind: retained closure +
1697
1991
  // the per-signature call thunk + the interned signature key. The
@@ -2039,12 +2333,9 @@ export function emitExpr(E, e) {
2039
2333
  // engine's own typeof.
2040
2334
  `(${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"))`
2041
2335
  : e.test === "truthy"
2042
- ? // ToBoolean over the checked-dynamic tree: bool by value; number falsy for
2043
- // 0, -0 (== 0 in C), and NaN (self-inequality); string
2044
- // falsy when empty; obj/arr/bytes/func/handle always true;
2045
- // JSVAL through the runtime's routed arm (the bigint 0n
2046
- // edge); the remaining kinds (undefined, null) always false.
2047
- `(${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))`
2336
+ ? // Runtime ToBoolean includes typed-reference capsules and
2337
+ // keeps this backend in lockstep with LLVM.
2338
+ `scr_dyn_truthy(${d.name})`
2048
2339
  : e.test === "error"
2049
2340
  ? // `u instanceof Error`: the checked-dynamic tree's error encoding — an
2050
2341
  // object carrying the reserved "%error" marker key
@@ -2294,6 +2585,58 @@ export function emitExpr(E, e) {
2294
2585
  };
2295
2586
  const fn = e.fn;
2296
2587
  switch (fn) {
2588
+ case "fetch.start":
2589
+ E.usesTimers = true;
2590
+ return finish(`scr_fetch_static(${arg(0)}, ${arg(1)})`);
2591
+ case "fetch.responseJson":
2592
+ return finish(`scr_fetch_response_json(${arg(0)})`);
2593
+ case "fetch.responseText":
2594
+ case "fetch.responseBytes": {
2595
+ if (e.type.kind !== "promise") {
2596
+ throw new Error(`emitter bug: ${fn} result`);
2597
+ }
2598
+ const runtimeFn = fn === "fetch.responseText"
2599
+ ? "scr_fetch_response_text"
2600
+ : "scr_fetch_response_bytes";
2601
+ const source = E.newTemp({ kind: "promise", inner: DYN }, `${runtimeFn}(${arg(0)})`);
2602
+ const result = E.newTemp(e.type, `scr_promise_new()`);
2603
+ const adapter = dynPromiseAdapter(E, e.type.inner);
2604
+ E.line(`scr_promise_race_add(${result.name}, ${source.name}, &${adapter});${E.srcComment(e.loc)}`);
2605
+ return result;
2606
+ }
2607
+ case "fetch.abortTimeout":
2608
+ E.usesTimers = true;
2609
+ return finish(`scr_fetch_abort_timeout(${arg(0)})`);
2610
+ case "fetch.abortNow":
2611
+ return finish(`scr_fetch_abort_now(${arg(0)})`);
2612
+ case "fetch.abortAny":
2613
+ return finish(`scr_fetch_abort_any(${arg(0)})`);
2614
+ case "fetch.streamNew":
2615
+ E.usesTimers = true;
2616
+ return finish(`scr_fetch_stream_new(${arg(0)})`);
2617
+ case "fetch.streamFrom":
2618
+ E.usesTimers = true;
2619
+ if (e.args[0].type.kind === "array") {
2620
+ const adapter = streamFromArrayAdapter(E, e.args[0].type);
2621
+ return finish(`scr_fetch_stream_from_array(${arg(0)}, &${adapter})`);
2622
+ }
2623
+ if (e.args[0].type.kind === "bytes") {
2624
+ return finish(`scr_fetch_stream_from_bytes(${arg(0)})`);
2625
+ }
2626
+ if (e.args[0].type.kind === "string") {
2627
+ return finish(`scr_fetch_stream_from_string(${arg(0)})`);
2628
+ }
2629
+ return finish(`scr_fetch_stream_from(${arg(0)})`);
2630
+ case "fetch.readerRead": {
2631
+ if (e.type.kind !== "promise" || e.type.inner.kind !== "record") {
2632
+ throw new Error("emitter bug: fetch.readerRead result");
2633
+ }
2634
+ const source = E.newTemp({ kind: "promise", inner: DYN }, `scr_fetch_reader_read(${arg(0)})`);
2635
+ const result = E.newTemp(e.type, `scr_promise_new()`);
2636
+ const adapter = dynPromiseAdapter(E, e.type.inner);
2637
+ E.line(`scr_promise_race_add(${result.name}, ${source.name}, &${adapter});${E.srcComment(e.loc)}`);
2638
+ return result;
2639
+ }
2297
2640
  case "island.eval":
2298
2641
  // --dynamic builds only (the frontend fences the intrinsic, so
2299
2642
  // scr_island_eval is always linked when this emits). Borrows
@@ -6421,6 +6764,10 @@ export function emitExpr(E, e) {
6421
6764
  const pack = argPack(args.slice(1).map((x) => x.name));
6422
6765
  return finishFallible(`scr_jsval_call_method(${a(0)}, ${nameSym()}, ${args.length - 1}, ${pack})`);
6423
6766
  }
6767
+ case "callFnThis": {
6768
+ const pack = argPack(args.slice(2).map((x) => x.name));
6769
+ return finishFallible(`scr_jsval_call_this(${a(0)}, ${a(1)}, ${args.length - 2}, ${pack})`);
6770
+ }
6424
6771
  case "callFn": {
6425
6772
  const pack = argPack(args.slice(1).map((x) => x.name));
6426
6773
  return finishFallible(`scr_jsval_call(${a(0)}, ${args.length - 1}, ${pack})`);