@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.
- package/ambient/scriptc-node-fallback.d.ts +54 -9
- package/dist/backend/emission/emit-exprs.js +170 -14
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-walkers.js +29 -2
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.js +25 -1
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +83 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +210 -13
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/coverage/surface-manifest.js +16 -2
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +41 -14
- package/dist/diagnostics/diagnostic.js +79 -27
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js +8 -0
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +11 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +69 -0
- package/dist/frontend/lowering/lower-builtins.js +380 -4
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +41 -0
- package/dist/frontend/lowering/lower-calls.js +559 -11
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +7 -0
- package/dist/frontend/lowering/lower-classes.js +51 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +21 -0
- package/dist/frontend/lowering/lower-containers.js +262 -17
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +92 -17
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.d.ts +70 -3
- package/dist/frontend/lowering/lower-emitter.js +436 -29
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +80 -5
- package/dist/frontend/lowering/lower-exprs.js +651 -23
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +8 -5
- package/dist/frontend/lowering/lower-modules.js +144 -19
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +39 -11
- package/dist/frontend/lowering/lower-namespaces.js +166 -24
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +211 -4
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
- package/dist/frontend/lowering/lower-stmts.js +293 -10
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +178 -10
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +53 -1
- package/dist/frontend/lowering/lowerer.js +210 -19
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +44 -0
- package/dist/frontend/lowering/surfaces.js +234 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm.d.ts +12 -0
- package/dist/frontend/npm.js +30 -0
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.d.ts +25 -0
- package/dist/frontend/program.js +144 -135
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +1 -1
- package/dist/frontend/shared.js +1 -1
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +13 -0
- package/dist/frontend/types.js +84 -7
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +157 -12
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +163 -13
- package/dist/ir/nodes.js +65 -6
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +64 -5
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.d.ts +77 -0
- package/dist/library/fence-eval.js +395 -0
- package/dist/library/fence-eval.js.map +1 -0
- package/dist/library/int-infer.d.ts +119 -0
- package/dist/library/int-infer.js +1301 -0
- package/dist/library/int-infer.js.map +1 -0
- package/dist/library/int-infer.test.d.ts +1 -0
- package/dist/library/int-infer.test.js +279 -0
- package/dist/library/int-infer.test.js.map +1 -0
- package/dist/library/profile.d.ts +43 -6
- package/dist/library/profile.js +179 -31
- package/dist/library/profile.js.map +1 -1
- package/dist/library/sidecar.d.ts +23 -0
- package/dist/library/sidecar.js +150 -16
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +208 -10
|
@@ -274,6 +274,23 @@ export type ForOfIterProjection = "keys" | "values" | "entries";
|
|
|
274
274
|
* enter/exit bracketing: the pair list compacts immediately (no
|
|
275
275
|
* tombstones), so there is no iteration depth to keep exact. */
|
|
276
276
|
export declare function lowerForOfSearchParams(L: Lowerer, stmt: ts.ForOfStatement, iterable: IrExpr, proj?: ForOfIterProjection): IrStmt;
|
|
277
|
+
/** for-of over an ARRAY's keys()/entries() projections consumed directly
|
|
278
|
+
* by the head (`for (const [index, line] of lines.entries())` — the
|
|
279
|
+
* dominant formatter idiom): the LIVE index walk — the length re-reads
|
|
280
|
+
* every pass, exactly the array iterator's contract (elements appended
|
|
281
|
+
* mid-walk are visited; a shrink ends the loop early) — yielding the
|
|
282
|
+
* index (`keys`, a number) or the [index, element] pair (`entries`).
|
|
283
|
+
* `values` never lands here: lowerForOf's receiver unwrap owns it. A
|
|
284
|
+
* `[i, v]` head of plain identifiers binds straight from the reads (the
|
|
285
|
+
* tuple never materializes); identifier heads and the remaining
|
|
286
|
+
* patterns bind through the checker's own element type — the interned
|
|
287
|
+
* [number, T] tuple record. Stored iterator OBJECTS keep their fence
|
|
288
|
+
* (only the direct for-of position unwraps). */
|
|
289
|
+
export declare function lowerForOfArrayIter(L: Lowerer, stmt: ts.ForOfStatement, iterable: IrExpr & {
|
|
290
|
+
type: IrType & {
|
|
291
|
+
kind: "array";
|
|
292
|
+
};
|
|
293
|
+
}, proj: "keys" | "entries"): IrStmt;
|
|
277
294
|
export declare function lowerForOfMap(L: Lowerer, stmt: ts.ForOfStatement, iterable: IrExpr, mapT: IrType & {
|
|
278
295
|
kind: "map";
|
|
279
296
|
}, proj?: ForOfIterProjection): IrStmt;
|
|
@@ -327,6 +344,10 @@ export declare function lowerBytesNew(L: Lowerer, expr: ts.NewExpression, symbol
|
|
|
327
344
|
* else the lib declares (fill, indexOf, reverse, ...) falls through to
|
|
328
345
|
* the SC2020 member fence. Null when this isn't a bytes method call. */
|
|
329
346
|
export declare function lowerBytesMethodCall(L: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression): IrExpr | null;
|
|
347
|
+
/** A literal encoding's canonical name, or undefined for a spelling Node
|
|
348
|
+
* does not know — the ladder callers (stream options) turn unknown
|
|
349
|
+
* literals into Node's runtime ERR_UNKNOWN_ENCODING throw. */
|
|
350
|
+
export declare function knownBufEncoding(name: string): string | undefined;
|
|
330
351
|
/** The literal encoding argument of a Buffer surface, normalized — or a
|
|
331
352
|
* fence when it isn't a literal alias Node knows. */
|
|
332
353
|
export declare function bufEncoding(L: Lowerer, what: string, encNode: ts.Expression): string;
|
|
@@ -2649,23 +2649,27 @@ export function lowerIteratorHelperCall(L, call, access) {
|
|
|
2649
2649
|
const terminal = access.name.text;
|
|
2650
2650
|
if (!ITER_TERMINALS.has(terminal))
|
|
2651
2651
|
return null;
|
|
2652
|
-
// Walk receiver: stage* ← values() ← array-typed source
|
|
2652
|
+
// Walk receiver: stage* ← values()/entries() ← array-typed source
|
|
2653
|
+
// (entries seeds the chain with [index, element] pairs — the
|
|
2654
|
+
// checker's own tuple type).
|
|
2653
2655
|
const stages = [];
|
|
2654
2656
|
let cur = access.expression;
|
|
2655
2657
|
let source = null;
|
|
2658
|
+
let srcProj = "values";
|
|
2656
2659
|
for (;;) {
|
|
2657
2660
|
if (!ts.isCallExpression(cur) || !ts.isPropertyAccessExpression(cur.expression))
|
|
2658
2661
|
return null;
|
|
2659
2662
|
if (cur.questionDotToken || cur.expression.questionDotToken)
|
|
2660
2663
|
return null;
|
|
2661
2664
|
const name = cur.expression.name.text;
|
|
2662
|
-
if (name === "values" && cur.arguments.length === 0) {
|
|
2665
|
+
if ((name === "values" || name === "entries") && cur.arguments.length === 0) {
|
|
2663
2666
|
const recvIr = L.mapTypeOf(L.typeOf(cur.expression.expression));
|
|
2664
2667
|
if (recvIr?.kind !== "array")
|
|
2665
2668
|
return null;
|
|
2666
2669
|
if (!L.isStdlibMember(cur.expression))
|
|
2667
2670
|
return null;
|
|
2668
2671
|
source = cur.expression.expression;
|
|
2672
|
+
srcProj = name;
|
|
2669
2673
|
break;
|
|
2670
2674
|
}
|
|
2671
2675
|
if (!ITER_STAGES.has(name) || cur.arguments.length !== 1 || ts.isSpreadElement(cur.arguments[0]))
|
|
@@ -2687,7 +2691,12 @@ export function lowerIteratorHelperCall(L, call, access) {
|
|
|
2687
2691
|
const items = L.lowerExpr(source);
|
|
2688
2692
|
if (items.type.kind !== "array")
|
|
2689
2693
|
return null;
|
|
2690
|
-
|
|
2694
|
+
// The entries() seed: the interned [number, T] tuple — the same shape
|
|
2695
|
+
// the checker's own [number, T] maps to, so stage callbacks typed
|
|
2696
|
+
// against the lib's pairs intern equal.
|
|
2697
|
+
let elem = srcProj === "entries"
|
|
2698
|
+
? { kind: "record", shapeId: L.shapes.intern([{ name: "0", type: F64 }, { name: "1", type: items.type.elem }], true) }
|
|
2699
|
+
: items.type.elem;
|
|
2691
2700
|
const stageIrs = [];
|
|
2692
2701
|
for (const s of stages) {
|
|
2693
2702
|
if (s.name === "take" || s.name === "drop") {
|
|
@@ -2774,12 +2783,12 @@ export function lowerIteratorHelperCall(L, call, access) {
|
|
|
2774
2783
|
L.noLowering(`.${terminal} at this result type`, call, "the chain's element and result types must be representable — annotate the callbacks' types");
|
|
2775
2784
|
}
|
|
2776
2785
|
const stageKeys = stageIrs.map((s) => (s.kind === "take" || s.kind === "drop" ? s.kind : `${s.kind}:${typeKey(s.fn.type)}`));
|
|
2777
|
-
const key = `iter:${typeKey(items.type)}:${stageKeys.join(",")}:${terminal}:${termArgs.map((a) => typeKey(a.type)).join(",")}`;
|
|
2786
|
+
const key = `iter:${srcProj}:${typeKey(items.type)}:${stageKeys.join(",")}:${terminal}:${termArgs.map((a) => typeKey(a.type)).join(",")}`;
|
|
2778
2787
|
let helper = L.arrHofHelpers.get(key);
|
|
2779
2788
|
if (!helper) {
|
|
2780
2789
|
helper = `%iter.${terminal}.${L.arrHofHelpers.size}`;
|
|
2781
2790
|
L.arrHofHelpers.set(key, helper);
|
|
2782
|
-
L.liftedFns.push(buildIterChainFn(L, helper, items.type, stageIrs, terminal, termArgs.map((a) => a.type), resultT, loc));
|
|
2791
|
+
L.liftedFns.push(buildIterChainFn(L, helper, items.type, srcProj, stageIrs, terminal, termArgs.map((a) => a.type), resultT, loc));
|
|
2783
2792
|
}
|
|
2784
2793
|
const budgetOrFn = stageIrs.map((s) => (s.kind === "take" || s.kind === "drop" ? s.budget : s.fn));
|
|
2785
2794
|
return { kind: "call", callee: helper, args: [items, ...budgetOrFn, ...termArgs], type: resultT, loc };
|
|
@@ -2862,7 +2871,7 @@ function internBudgetChecker(L, loc) {
|
|
|
2862
2871
|
* source order, flatMap as an inner loop over its returned array.
|
|
2863
2872
|
* Pre-loop, a zero take budget marks done immediately — Node pulls
|
|
2864
2873
|
* nothing at all through a take(0). */
|
|
2865
|
-
function buildIterChainFn(L, name, itemsT, stages, terminal, termArgTs, resultT, loc) {
|
|
2874
|
+
function buildIterChainFn(L, name, itemsT, srcProj, stages, terminal, termArgTs, resultT, loc) {
|
|
2866
2875
|
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
2867
2876
|
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
2868
2877
|
const boolLit = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
@@ -2883,7 +2892,12 @@ function buildIterChainFn(L, name, itemsT, stages, terminal, termArgTs, resultT,
|
|
|
2883
2892
|
const doneId = addLocal("done", BOOL, true);
|
|
2884
2893
|
const done = () => ref(doneId, BOOL);
|
|
2885
2894
|
const setDone = { kind: "assign", localId: doneId, value: boolLit(true), loc };
|
|
2886
|
-
|
|
2895
|
+
// The entries() seed builds each pass's [index, element] pair — the
|
|
2896
|
+
// same interned tuple the caller computed its stage types against.
|
|
2897
|
+
const seedT = srcProj === "entries"
|
|
2898
|
+
? { kind: "record", shapeId: L.shapes.intern([{ name: "0", type: F64 }, { name: "1", type: itemsT.elem }], true) }
|
|
2899
|
+
: itemsT.elem;
|
|
2900
|
+
let elem = seedT;
|
|
2887
2901
|
const slots = [];
|
|
2888
2902
|
for (const s of stages) {
|
|
2889
2903
|
if (s.kind === "take" || s.kind === "drop") {
|
|
@@ -3128,7 +3142,19 @@ function buildIterChainFn(L, name, itemsT, stages, terminal, termArgTs, resultT,
|
|
|
3128
3142
|
}
|
|
3129
3143
|
}
|
|
3130
3144
|
const iId = addLocal("i", F64, true);
|
|
3131
|
-
const vId = addLocal("v",
|
|
3145
|
+
const vId = addLocal("v", seedT, false);
|
|
3146
|
+
const elemRead = () => ({ kind: "arrayGet", arr: ref("items.0", itemsT), index: ref(iId, F64), type: itemsT.elem, loc });
|
|
3147
|
+
const seedInit = srcProj === "entries"
|
|
3148
|
+
? {
|
|
3149
|
+
kind: "recordLit",
|
|
3150
|
+
fields: [
|
|
3151
|
+
{ name: "0", value: ref(iId, F64) },
|
|
3152
|
+
{ name: "1", value: elemRead() },
|
|
3153
|
+
],
|
|
3154
|
+
type: seedT,
|
|
3155
|
+
loc,
|
|
3156
|
+
}
|
|
3157
|
+
: elemRead();
|
|
3132
3158
|
const loop = {
|
|
3133
3159
|
kind: "for",
|
|
3134
3160
|
init: { kind: "varDecl", localId: iId, init: num(0), loc },
|
|
@@ -3142,8 +3168,8 @@ function buildIterChainFn(L, name, itemsT, stages, terminal, termArgTs, resultT,
|
|
|
3142
3168
|
},
|
|
3143
3169
|
update: { kind: "assign", localId: iId, value: { kind: "bin", op: "+", left: ref(iId, F64), right: num(1), type: F64, loc }, loc },
|
|
3144
3170
|
body: [
|
|
3145
|
-
{ kind: "varDecl", localId: vId, init:
|
|
3146
|
-
...emit(ref(vId,
|
|
3171
|
+
{ kind: "varDecl", localId: vId, init: seedInit, loc },
|
|
3172
|
+
...emit(ref(vId, seedT)),
|
|
3147
3173
|
],
|
|
3148
3174
|
loc,
|
|
3149
3175
|
};
|
|
@@ -3436,6 +3462,143 @@ export function lowerForOfSearchParams(L, stmt, iterable, proj) {
|
|
|
3436
3462
|
L.scopes.pop();
|
|
3437
3463
|
}
|
|
3438
3464
|
}
|
|
3465
|
+
/** for-of over an ARRAY's keys()/entries() projections consumed directly
|
|
3466
|
+
* by the head (`for (const [index, line] of lines.entries())` — the
|
|
3467
|
+
* dominant formatter idiom): the LIVE index walk — the length re-reads
|
|
3468
|
+
* every pass, exactly the array iterator's contract (elements appended
|
|
3469
|
+
* mid-walk are visited; a shrink ends the loop early) — yielding the
|
|
3470
|
+
* index (`keys`, a number) or the [index, element] pair (`entries`).
|
|
3471
|
+
* `values` never lands here: lowerForOf's receiver unwrap owns it. A
|
|
3472
|
+
* `[i, v]` head of plain identifiers binds straight from the reads (the
|
|
3473
|
+
* tuple never materializes); identifier heads and the remaining
|
|
3474
|
+
* patterns bind through the checker's own element type — the interned
|
|
3475
|
+
* [number, T] tuple record. Stored iterator OBJECTS keep their fence
|
|
3476
|
+
* (only the direct for-of position unwraps). */
|
|
3477
|
+
export function lowerForOfArrayIter(L, stmt, iterable, proj) {
|
|
3478
|
+
const loc = locOf(stmt);
|
|
3479
|
+
const arrT = iterable.type;
|
|
3480
|
+
const elemT = arrT.elem;
|
|
3481
|
+
const yieldsPair = proj === "entries";
|
|
3482
|
+
if (!ts.isVariableDeclarationList(stmt.initializer)) {
|
|
3483
|
+
L.unsupported("SC1090", stmt.initializer, "for-of over a pre-declared variable (declare the loop variable in the loop: for (const x of ...))");
|
|
3484
|
+
}
|
|
3485
|
+
const list = stmt.initializer;
|
|
3486
|
+
if ((list.flags & ts.NodeFlags.Using) !== 0) {
|
|
3487
|
+
L.unsupported("SC1090", list, "'using' declarations (dispose-at-scope-exit semantics)");
|
|
3488
|
+
}
|
|
3489
|
+
const isVar = (list.flags & ts.NodeFlags.BlockScoped) === 0;
|
|
3490
|
+
const isLet = (list.flags & ts.NodeFlags.Let) !== 0 || isVar;
|
|
3491
|
+
const decl = list.declarations[0]; // the grammar allows exactly one
|
|
3492
|
+
L.scopes.push(new Map());
|
|
3493
|
+
try {
|
|
3494
|
+
const arr = L.declareHiddenLocal("%arof", arrT);
|
|
3495
|
+
const i = L.declareHiddenLocal("%iterof", F64);
|
|
3496
|
+
i.mutable = true;
|
|
3497
|
+
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
3498
|
+
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
3499
|
+
const keyRead = () => ref(i.id, F64);
|
|
3500
|
+
const valRead = () => ({ kind: "arrayGet", arr: ref(arr.id, arrT), index: ref(i.id, F64), type: elemT, loc });
|
|
3501
|
+
const binds = [];
|
|
3502
|
+
const isPlainIdent = (el) => ts.isBindingElement(el) && el.name !== undefined && ts.isIdentifier(el.name) && !el.initializer && !el.dotDotDotToken;
|
|
3503
|
+
if (yieldsPair &&
|
|
3504
|
+
!isVar && // var pattern names assign hoisted slots — the generic desugar below owns them
|
|
3505
|
+
ts.isArrayBindingPattern(decl.name) &&
|
|
3506
|
+
decl.name.elements.length >= 1 && decl.name.elements.length <= 2 &&
|
|
3507
|
+
decl.name.elements.every(isPlainIdent)) {
|
|
3508
|
+
// `for (const [i, v] of xs.entries())` — bind straight from the
|
|
3509
|
+
// reads; the tuple never exists. `[i]` alone reads only the index.
|
|
3510
|
+
const els = decl.name.elements;
|
|
3511
|
+
const kLocal = L.declareLocal(els[0].name, els[0].name.text, F64, isLet);
|
|
3512
|
+
binds.push({ kind: "varDecl", localId: kLocal.id, init: keyRead(), loc });
|
|
3513
|
+
if (els[1]) {
|
|
3514
|
+
const vLocal = L.declareLocal(els[1].name, els[1].name.text, elemT, isLet);
|
|
3515
|
+
binds.push({ kind: "varDecl", localId: vLocal.id, init: valRead(), loc });
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
else {
|
|
3519
|
+
// Identifier heads and the remaining patterns bind through the
|
|
3520
|
+
// checker's own element type — [number, T] for pair yields,
|
|
3521
|
+
// number otherwise — the Map desugar's exact shape.
|
|
3522
|
+
const declT = L.mapTypeOf(L.checker.getTypeAtLocation(decl.name));
|
|
3523
|
+
if (yieldsPair) {
|
|
3524
|
+
const shape = declT?.kind === "record" ? L.shapes.get(declT.shapeId) : null;
|
|
3525
|
+
if (declT?.kind !== "record" || !shape?.tuple || shape.fields.length !== 2 ||
|
|
3526
|
+
shape.fields.find((f) => f.name === "0")?.type.kind !== "f64" ||
|
|
3527
|
+
!typeEquals(shape.fields.find((f) => f.name === "1")?.type ?? F64, elemT)) {
|
|
3528
|
+
L.badType(decl.name, L.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares [number, T]
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
else if (declT?.kind !== "f64") {
|
|
3532
|
+
L.badType(decl.name, L.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares number
|
|
3533
|
+
}
|
|
3534
|
+
const elemInit = yieldsPair
|
|
3535
|
+
? {
|
|
3536
|
+
kind: "recordLit",
|
|
3537
|
+
fields: [
|
|
3538
|
+
{ name: "0", value: keyRead() },
|
|
3539
|
+
{ name: "1", value: valRead() },
|
|
3540
|
+
],
|
|
3541
|
+
type: declT,
|
|
3542
|
+
loc,
|
|
3543
|
+
}
|
|
3544
|
+
: keyRead();
|
|
3545
|
+
if (ts.isIdentifier(decl.name)) {
|
|
3546
|
+
const varTarget = forOfVarTarget(L, decl);
|
|
3547
|
+
if (varTarget) {
|
|
3548
|
+
// `for (var x of ...)`: one function-scoped binding, assigned
|
|
3549
|
+
// per pass — closures made in the loop share it, and the value
|
|
3550
|
+
// persists after the loop (both Node-exact for var).
|
|
3551
|
+
const tmp = L.declareHiddenLocal("%vof", declT);
|
|
3552
|
+
binds.push({ kind: "varDecl", localId: tmp.id, init: elemInit, loc });
|
|
3553
|
+
binds.push({
|
|
3554
|
+
kind: "assign",
|
|
3555
|
+
localId: varTarget.id,
|
|
3556
|
+
value: L.coerceInto(decl.name, { kind: "varRef", localId: tmp.id, type: declT, loc }, varTarget.type),
|
|
3557
|
+
loc,
|
|
3558
|
+
});
|
|
3559
|
+
}
|
|
3560
|
+
else {
|
|
3561
|
+
const local = L.declareLocal(decl.name, decl.name.text, declT, isLet);
|
|
3562
|
+
binds.push({ kind: "varDecl", localId: local.id, init: elemInit, loc });
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
else {
|
|
3566
|
+
const tmp = L.declareHiddenLocal("%destr", declT);
|
|
3567
|
+
binds.push({ kind: "varDecl", localId: tmp.id, init: elemInit, loc });
|
|
3568
|
+
L.lowerBindingPattern(decl.name, () => ({ kind: "varRef", localId: tmp.id, type: declT, loc }), declT, isLet, binds);
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
const body = L.inCtl("loop", () => L.lowerScopedBlock(stmt.statement));
|
|
3572
|
+
const loop = {
|
|
3573
|
+
kind: "for",
|
|
3574
|
+
init: { kind: "varDecl", localId: i.id, init: num(0), loc },
|
|
3575
|
+
cond: {
|
|
3576
|
+
kind: "bin",
|
|
3577
|
+
op: "<",
|
|
3578
|
+
left: ref(i.id, F64),
|
|
3579
|
+
right: { kind: "arrIntrinsic", method: "length", receiver: ref(arr.id, arrT), args: [], type: F64, loc },
|
|
3580
|
+
type: BOOL,
|
|
3581
|
+
loc,
|
|
3582
|
+
},
|
|
3583
|
+
update: {
|
|
3584
|
+
kind: "assign",
|
|
3585
|
+
localId: i.id,
|
|
3586
|
+
value: { kind: "bin", op: "+", left: ref(i.id, F64), right: num(1), type: F64, loc },
|
|
3587
|
+
loc,
|
|
3588
|
+
},
|
|
3589
|
+
body: [...binds, ...body],
|
|
3590
|
+
loc,
|
|
3591
|
+
};
|
|
3592
|
+
return {
|
|
3593
|
+
kind: "block",
|
|
3594
|
+
body: [{ kind: "varDecl", localId: arr.id, init: iterable, loc }, loop],
|
|
3595
|
+
loc,
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
finally {
|
|
3599
|
+
L.scopes.pop();
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3439
3602
|
export function lowerForOfMap(L, stmt, iterable, mapT, proj) {
|
|
3440
3603
|
return lowerForOfMapOrSet(L, stmt, iterable, mapT, proj);
|
|
3441
3604
|
}
|
|
@@ -3841,9 +4004,26 @@ export function lowerRegexMethodCall(L, call, access, dynReceiver) {
|
|
|
3841
4004
|
// [whole match, ...captures] or the null arm. The g-flag match returns
|
|
3842
4005
|
// EVERY match (a different shape) and /y is stateful — both fence at
|
|
3843
4006
|
// compile time on literal arguments (values reaching the runtime with
|
|
3844
|
-
// those flags abort, the test() stance). `.index`/`.input
|
|
3845
|
-
//
|
|
3846
|
-
|
|
4007
|
+
// those flags abort, the test() stance). `.index`/`.input` reads on
|
|
4008
|
+
// the result fence per member (array-typed value); `.groups` reads
|
|
4009
|
+
// desugar at their access sites when the regex is statically known
|
|
4010
|
+
// (lowerMatchGroupsRead).
|
|
4011
|
+
// `s.match(re)` also claims a NULLABLE string receiver (string + unit
|
|
4012
|
+
// arms — `process.versions.openssl.match(...)`, the Dict<string>
|
|
4013
|
+
// member the node suite's crypto helper reads): the checked
|
|
4014
|
+
// extraction narrows to the string arm and a unit value throws the
|
|
4015
|
+
// catchable TypeError at the read, where Node's own member read
|
|
4016
|
+
// throws — tsc only admits the spelling in JS sources.
|
|
4017
|
+
const nullableStringRecv = receiverKind === "union" &&
|
|
4018
|
+
name === "match" &&
|
|
4019
|
+
(() => {
|
|
4020
|
+
const t = L.mapTypeOf(L.typeOf(access.expression));
|
|
4021
|
+
if (t?.kind !== "union")
|
|
4022
|
+
return false;
|
|
4023
|
+
const arms = L.unions.get(t.unionId)?.arms ?? [];
|
|
4024
|
+
return arms.some((a) => a.kind === "string") && arms.every((a) => a.kind === "string" || isUnitType(a));
|
|
4025
|
+
})();
|
|
4026
|
+
if ((receiverKind === "string" || nullableStringRecv) && name === "match") {
|
|
3847
4027
|
const arg0 = call.arguments[0];
|
|
3848
4028
|
if (!arg0 || L.mapTypeOf(L.typeOf(arg0))?.kind !== "regex")
|
|
3849
4029
|
return null; // string-pattern match: the SC2020 fence
|
|
@@ -3858,7 +4038,7 @@ export function lowerRegexMethodCall(L, call, access, dynReceiver) {
|
|
|
3858
4038
|
L.unsupported("SC1120", call, "'.match()' with the 'g' or 'y' flag (an every-match array is a different shape — use replaceAll/split, or test() per position)");
|
|
3859
4039
|
}
|
|
3860
4040
|
}
|
|
3861
|
-
const receiver = lowerReceiver();
|
|
4041
|
+
const receiver = nullableStringRecv ? L.lowerExprExpecting(access.expression, STRING) : lowerReceiver();
|
|
3862
4042
|
const re = L.lowerExpr(arg0);
|
|
3863
4043
|
// RegExpMatchArray | null maps to the string[] | null union by
|
|
3864
4044
|
// itself; intern it directly when the checker's spelling doesn't —
|
|
@@ -4232,8 +4412,30 @@ export function lowerBytesMethodCall(L, call, access) {
|
|
|
4232
4412
|
}
|
|
4233
4413
|
const receiver = L.lowerExpr(access.expression);
|
|
4234
4414
|
const args = call.arguments.map((a) => L.lowerExprExpecting(a, F64));
|
|
4235
|
-
// subarray
|
|
4236
|
-
|
|
4415
|
+
// subarray is a VIEW (TypedArray.prototype.subarray aliases), and
|
|
4416
|
+
// Buffer's slice() is subarray's deprecated Node alias — resolved by
|
|
4417
|
+
// where the member is declared, the toString discipline below. Only
|
|
4418
|
+
// the plain typed arrays' slice() copies (JS-exact).
|
|
4419
|
+
const declaredOnBuffer = name === "slice" &&
|
|
4420
|
+
(() => {
|
|
4421
|
+
const nameSym = L.checker.getSymbolAtLocation(access.name);
|
|
4422
|
+
return nameSym !== undefined && L.checker.declarationsOf(nameSym).some((d) => ts.isInterfaceDeclaration(d.parent) && d.parent.name.text === "Buffer");
|
|
4423
|
+
})();
|
|
4424
|
+
const method = name === "subarray" || declaredOnBuffer ? "subarray" : "slice";
|
|
4425
|
+
return { kind: "bytesIntrinsic", method, receiver, args, type: receiverIr, loc };
|
|
4426
|
+
}
|
|
4427
|
+
if (name === "fill" && receiverIr.elem !== "u8") {
|
|
4428
|
+
// TypedArray.prototype.fill on the non-u8 kinds: per-element value
|
|
4429
|
+
// coercion, slice-clamped relative indices, never throws. u8
|
|
4430
|
+
// receivers keep the Buffer fill family (string patterns, throwing
|
|
4431
|
+
// offset validation) — lowerBufferInstanceMethod's surface.
|
|
4432
|
+
if (nArgs < 1 || nArgs > 3) {
|
|
4433
|
+
L.noLowering(`.fill with ${nArgs} arguments on typed arrays`, call);
|
|
4434
|
+
}
|
|
4435
|
+
const receiver = L.lowerExpr(access.expression);
|
|
4436
|
+
const v = L.lowerExprExpecting(call.arguments[0], F64);
|
|
4437
|
+
const idx = call.arguments.slice(1).map((a) => L.lowerExprExpecting(a, F64));
|
|
4438
|
+
return { kind: "bytesIntrinsic", method: "fillElem", receiver, args: [v, ...idx], type: receiverIr, loc };
|
|
4237
4439
|
}
|
|
4238
4440
|
if (name === "set") {
|
|
4239
4441
|
if (nArgs < 1 || nArgs > 2) {
|
|
@@ -4408,6 +4610,12 @@ const BUF_ENCODINGS = {
|
|
|
4408
4610
|
ucs2: "utf16le",
|
|
4409
4611
|
"ucs-2": "utf16le",
|
|
4410
4612
|
};
|
|
4613
|
+
/** A literal encoding's canonical name, or undefined for a spelling Node
|
|
4614
|
+
* does not know — the ladder callers (stream options) turn unknown
|
|
4615
|
+
* literals into Node's runtime ERR_UNKNOWN_ENCODING throw. */
|
|
4616
|
+
export function knownBufEncoding(name) {
|
|
4617
|
+
return own(BUF_ENCODINGS, name);
|
|
4618
|
+
}
|
|
4411
4619
|
/** The literal encoding argument of a Buffer surface, normalized — or a
|
|
4412
4620
|
* fence when it isn't a literal alias Node knows. */
|
|
4413
4621
|
export function bufEncoding(L, what, encNode) {
|
|
@@ -4690,6 +4898,22 @@ export function lowerBufferStaticCall(L, call, access) {
|
|
|
4690
4898
|
const loc = locOf(call);
|
|
4691
4899
|
const args = call.arguments;
|
|
4692
4900
|
if (member === "from") {
|
|
4901
|
+
// Buffer.from(x.buffer[, byteOffset[, length]]): a u8 VIEW sharing
|
|
4902
|
+
// x's storage (Node shares the ArrayBuffer; length is in BYTES).
|
|
4903
|
+
// The first argument must be the SYNTACTIC `.buffer` of a typed
|
|
4904
|
+
// array — the DataView peel — and the construction rides the same
|
|
4905
|
+
// dataViewNew intrinsic (offset/length validation throws Node's
|
|
4906
|
+
// DataView-shaped RangeErrors; valid indices behave exactly).
|
|
4907
|
+
if (args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement) &&
|
|
4908
|
+
ts.isPropertyAccessExpression(args[0]) && args[0].name.text === "buffer") {
|
|
4909
|
+
const srcNode = args[0].expression;
|
|
4910
|
+
const srcIr = L.mapTypeOf(L.typeOf(srcNode));
|
|
4911
|
+
if (srcIr?.kind === "bytes") {
|
|
4912
|
+
const receiver = L.lowerExpr(srcNode);
|
|
4913
|
+
const idxArgs = args.slice(1).map((a) => L.lowerExprExpecting(a, F64));
|
|
4914
|
+
return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4693
4917
|
if (args.length >= 1 && args.length <= 2 && !ts.isSpreadElement(args[0])) {
|
|
4694
4918
|
const argNode = args[0];
|
|
4695
4919
|
if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
|
|
@@ -4719,7 +4943,8 @@ export function lowerBufferStaticCall(L, call, access) {
|
|
|
4719
4943
|
}
|
|
4720
4944
|
}
|
|
4721
4945
|
L.noLowering("Buffer.from with this argument shape", call, "supported: Buffer.from(string, encoding?) with a literal encoding, Buffer.from(u8Array) — a copy — " +
|
|
4722
|
-
"
|
|
4946
|
+
"Buffer.from(number[]), or Buffer.from(x.buffer, byteOffset?, length?) — a view sharing x's " +
|
|
4947
|
+
"storage (no free-standing ArrayBuffer value exists; narrow unions first)");
|
|
4723
4948
|
}
|
|
4724
4949
|
if (member === "alloc" || member === "allocUnsafe") {
|
|
4725
4950
|
const maxArgs = member === "alloc" ? 3 : 1;
|
|
@@ -6305,6 +6530,26 @@ export function lowerDynArrayFlatMapCall(L, call, access, recv) {
|
|
|
6305
6530
|
const { fnArg, arity } = hofCallbackArg(L, argNode, [DYN], DYN);
|
|
6306
6531
|
const ret = fnArg.type.ret;
|
|
6307
6532
|
if (ret.kind !== "array") {
|
|
6533
|
+
// A DYNAMIC-returning callback (`plugins.flatMap((plugin) =>
|
|
6534
|
+
// plugin.languages ?? [])` — the getSupportInfo shape, where the
|
|
6535
|
+
// callback's members ride the DOM): the call dispatches on the
|
|
6536
|
+
// RECEIVER's runtime kind (dynInvoke) with the callback boxed —
|
|
6537
|
+
// a wrapped ISLAND receiver runs the ENGINE's own JS-exact
|
|
6538
|
+
// Array.prototype.flatMap (the routed-ops lane), a native DOM
|
|
6539
|
+
// array runs the runtime's flatMap, and non-arrays throw Node's
|
|
6540
|
+
// TypeError. The result stays dyn, checked per use.
|
|
6541
|
+
if (ret.kind === "dyn" || ret.kind === "jsval") {
|
|
6542
|
+
const boxed = { kind: "dynFrom", value: fnArg, type: DYN, loc };
|
|
6543
|
+
return {
|
|
6544
|
+
kind: "dynInvoke",
|
|
6545
|
+
recv,
|
|
6546
|
+
method: "flatMap",
|
|
6547
|
+
calleeName: access.getText(),
|
|
6548
|
+
args: [boxed],
|
|
6549
|
+
type: DYN,
|
|
6550
|
+
loc,
|
|
6551
|
+
};
|
|
6552
|
+
}
|
|
6308
6553
|
L.unsupported("SC1090", call, `'.flatMap' on 'unknown' receivers whose callback returns '${L.fmt(ret)}' ` +
|
|
6309
6554
|
`(only callbacks returning a typed ARRAY compile — the results concatenate ` +
|
|
6310
6555
|
`without validation; return one-element/empty arrays instead of bare values)`);
|