@nudojs/core 1.7.0 → 1.7.2

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.
@@ -76,6 +76,7 @@ function simplifyTerm(t) {
76
76
  if (typeof v2 === "boolean") return lit(v2 ? 1 : 0);
77
77
  if (v2 === null) return lit(0);
78
78
  if (typeof v2 === "string") return lit(Number(v2));
79
+ if (typeof v2 === "bigint") return app(fn, args);
79
80
  return lit(NaN);
80
81
  };
81
82
  if (one(b)) return surviveMulOne(a);
@@ -112,6 +113,36 @@ function foldLiterals(fn, xs) {
112
113
  return void 0;
113
114
  }
114
115
 
116
+ // src/algebra/collector-scope.ts
117
+ import { AsyncLocalStorage } from "async_hooks";
118
+ function createScopedSlot(init) {
119
+ const als = new AsyncLocalStorage();
120
+ const fallback = { v: init() };
121
+ const current = () => als.getStore() ?? fallback;
122
+ return {
123
+ get: () => current().v,
124
+ set: (v2) => {
125
+ current().v = v2;
126
+ },
127
+ runScoped: (body) => als.run({ v: current().v }, body)
128
+ };
129
+ }
130
+ var participants = [];
131
+ function registerCollectorScopeParticipant(enter) {
132
+ participants.push(enter);
133
+ }
134
+ var scopeActive = new AsyncLocalStorage();
135
+ function runWithCollectorScope(body) {
136
+ if (scopeActive.getStore() === true) return body();
137
+ let scoped = body;
138
+ for (let i = participants.length - 1; i >= 0; i--) {
139
+ const enter = participants[i];
140
+ const inner = scoped;
141
+ scoped = () => enter(inner);
142
+ }
143
+ return scopeActive.run(true, scoped);
144
+ }
145
+
115
146
  // src/algebra/pred.ts
116
147
  var TYPEOF_NAMES = [
117
148
  "undefined",
@@ -343,12 +374,15 @@ function predVars(p) {
343
374
  }
344
375
  var emptyPhi = pTrue;
345
376
  var phiAnd = and;
346
- var implicationOracle;
377
+ var implicationOracleSlot = createScopedSlot(
378
+ () => void 0
379
+ );
380
+ registerCollectorScopeParticipant((body) => implicationOracleSlot.runScoped(body));
347
381
  function setImplicationOracle(fn) {
348
- implicationOracle = fn;
382
+ implicationOracleSlot.set(fn);
349
383
  }
350
384
  function getImplicationOracle() {
351
- return implicationOracle;
385
+ return implicationOracleSlot.get();
352
386
  }
353
387
  function implies(phi2, pred) {
354
388
  if (pred.op === "true") return true;
@@ -391,6 +425,7 @@ function implies(phi2, pred) {
391
425
  const ctx2 = buildCtx(phi2);
392
426
  if (proveInCtx(ctx2, pred)) return true;
393
427
  if (decideLiteralPred(pred) === true) return true;
428
+ const implicationOracle = implicationOracleSlot.get();
394
429
  if (implicationOracle && implicationOracle(phi2, pred) === true) return true;
395
430
  return false;
396
431
  }
@@ -1160,6 +1195,35 @@ function isExactLit(a) {
1160
1195
  function litValue(a) {
1161
1196
  return a?.term?.op === "lit" ? { ok: true, value: a.term.value } : { ok: false };
1162
1197
  }
1198
+ function absNumLit(a) {
1199
+ if (!a) return void 0;
1200
+ const vR = litValue(a);
1201
+ const v2 = vR.ok ? vR.value : void 0;
1202
+ return typeof v2 === "number" ? v2 : void 0;
1203
+ }
1204
+ function absStrLit(a) {
1205
+ if (!a) return void 0;
1206
+ const vR = litValue(a);
1207
+ const v2 = vR.ok ? vR.value : void 0;
1208
+ return typeof v2 === "string" ? v2 : void 0;
1209
+ }
1210
+ function allAbsStr(args) {
1211
+ const result = [];
1212
+ for (const a of args) {
1213
+ const s = absStrLit(a);
1214
+ if (s === void 0) return void 0;
1215
+ result.push(s);
1216
+ }
1217
+ return result;
1218
+ }
1219
+ function absLit(value) {
1220
+ if (typeof value === "number") return numLit(value);
1221
+ if (typeof value === "string") return strLit(value);
1222
+ if (typeof value === "boolean") return boolLit(value);
1223
+ if (typeof value === "bigint") return abs({ k: "prim", type: "bigint" }, void 0, void 0, "exact");
1224
+ if (value === null) return abs({ k: "unknown" }, lit(null), void 0, "exact");
1225
+ return abs({ k: "unknown" }, lit(void 0), void 0, "exact");
1226
+ }
1163
1227
 
1164
1228
  // src/strip-types.ts
1165
1229
  var REMOVE = /* @__PURE__ */ Symbol("nudo.strip.remove");
@@ -1526,34 +1590,41 @@ function shapeOnlyFn(paramTypes, returnType, opts) {
1526
1590
  }
1527
1591
 
1528
1592
  // src/algebra/derivation.ts
1529
- var collector = null;
1530
- var nextId = 1;
1593
+ var derivationSlot = createScopedSlot(() => ({
1594
+ collector: null,
1595
+ nextId: 1,
1596
+ sessionNodes: null
1597
+ }));
1598
+ registerCollectorScopeParticipant((body) => derivationSlot.runScoped(body));
1531
1599
  var byAbs = /* @__PURE__ */ new WeakMap();
1532
- var sessionNodes = null;
1533
1600
  function setDerivationCollector(fn) {
1534
- collector = fn;
1601
+ derivationSlot.get().collector = fn;
1535
1602
  }
1536
1603
  function hasDerivationSession() {
1537
- return sessionNodes !== null;
1604
+ return derivationSlot.get().sessionNodes !== null;
1538
1605
  }
1539
1606
  function beginDerivationSession() {
1540
- sessionNodes = /* @__PURE__ */ new Map();
1541
- nextId = 1;
1607
+ const s = derivationSlot.get();
1608
+ s.sessionNodes = /* @__PURE__ */ new Map();
1609
+ s.nextId = 1;
1542
1610
  }
1543
1611
  function endDerivationSession() {
1544
- const nodes = sessionNodes ? [...sessionNodes.values()] : [];
1545
- sessionNodes = null;
1546
- collector = null;
1612
+ const s = derivationSlot.get();
1613
+ const nodes = s.sessionNodes ? [...s.sessionNodes.values()] : [];
1614
+ s.sessionNodes = null;
1615
+ s.collector = null;
1547
1616
  return nodes;
1548
1617
  }
1549
1618
  function abortDerivationSession() {
1550
- sessionNodes = null;
1551
- collector = null;
1619
+ const s = derivationSlot.get();
1620
+ s.sessionNodes = null;
1621
+ s.collector = null;
1552
1622
  }
1553
1623
  function note(node) {
1554
- const full = { ...node, id: nextId++ };
1555
- if (sessionNodes) sessionNodes.set(full.id, full);
1556
- collector?.(full);
1624
+ const s = derivationSlot.get();
1625
+ const full = { ...node, id: s.nextId++ };
1626
+ if (s.sessionNodes) s.sessionNodes.set(full.id, full);
1627
+ s.collector?.(full);
1557
1628
  return full;
1558
1629
  }
1559
1630
  function tagDerivationRoot(abs2, meta) {
@@ -1579,6 +1650,7 @@ function derivationChain(node) {
1579
1650
  let cur = node;
1580
1651
  while (cur.kind !== "root" && cur.parents.length > 0) {
1581
1652
  const pid = cur.parents[0];
1653
+ const sessionNodes = derivationSlot.get().sessionNodes;
1582
1654
  if (seen.has(pid) || !sessionNodes) break;
1583
1655
  const parent = sessionNodes.get(pid);
1584
1656
  if (!parent) break;
@@ -1589,7 +1661,7 @@ function derivationChain(node) {
1589
1661
  return chain;
1590
1662
  }
1591
1663
  function noteDerivationAdd(a, b, result) {
1592
- if (!sessionNodes) return;
1664
+ if (!derivationSlot.get().sessionNodes) return;
1593
1665
  const vbR = litValue(b);
1594
1666
  const vb = vbR.ok ? vbR.value : void 0;
1595
1667
  const vaR = litValue(a);
@@ -1612,7 +1684,7 @@ function noteDerivationAdd(a, b, result) {
1612
1684
  byAbs.set(result, node);
1613
1685
  }
1614
1686
  function noteDerivationJoin(inputs, result) {
1615
- if (!sessionNodes) return;
1687
+ if (!derivationSlot.get().sessionNodes) return;
1616
1688
  const parents = [];
1617
1689
  for (const a of inputs) {
1618
1690
  const n = byAbs.get(a);
@@ -2944,7 +3016,7 @@ function isSymbolAbs(a) {
2944
3016
  return !!a && a.shape.k === "prim" && a.shape.type === "symbol";
2945
3017
  }
2946
3018
 
2947
- // src/algebra/exec/nudo-throw.ts
3019
+ // src/algebra/nudo-throw.ts
2948
3020
  var NudoThrow = class extends Error {
2949
3021
  absValue;
2950
3022
  constructor(absValue) {
@@ -2957,9 +3029,9 @@ function isNudoThrow(e) {
2957
3029
  return e instanceof NudoThrow;
2958
3030
  }
2959
3031
 
2960
- // src/algebra/exec/may-throw.ts
2961
- import { AsyncLocalStorage } from "async_hooks";
2962
- var mayThrowAls = new AsyncLocalStorage();
3032
+ // src/algebra/may-throw.ts
3033
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3034
+ var mayThrowAls = new AsyncLocalStorage2();
2963
3035
  var syncCtx = { collector: null, tryFrames: [] };
2964
3036
  function ctx() {
2965
3037
  return mayThrowAls.getStore() ?? syncCtx;
@@ -3011,11 +3083,11 @@ function $tryReleaseSoft() {
3011
3083
  return effects;
3012
3084
  }
3013
3085
  function flushMayThrowEffects(effects) {
3014
- const collector2 = ctx().collector;
3015
- if (!collector2 || effects.length === 0) return;
3086
+ const collector = ctx().collector;
3087
+ if (!collector || effects.length === 0) return;
3016
3088
  for (const e of effects) {
3017
3089
  try {
3018
- collector2(e);
3090
+ collector(e);
3019
3091
  } catch {
3020
3092
  }
3021
3093
  }
@@ -3128,6 +3200,29 @@ function filterDeclaredThrows(effects, declared) {
3128
3200
  }
3129
3201
 
3130
3202
  // src/algebra/arithmetic.ts
3203
+ function distributeSumBinOp(op, a, b, phi2, eval2) {
3204
+ if (a.shape.k !== "sum" && b.shape.k !== "sum") return void 0;
3205
+ const parts = [];
3206
+ const as = a.shape.k === "sum" ? a.shape.members : [a];
3207
+ const bs = b.shape.k === "sum" ? b.shape.members : [b];
3208
+ for (const x of as) {
3209
+ for (const y of bs) {
3210
+ const r = eval2(x, y, phi2);
3211
+ if (r.shape.k === "never") continue;
3212
+ if (r.shape.k === "sum") parts.push(...r.shape.members);
3213
+ else parts.push(r);
3214
+ }
3215
+ }
3216
+ const uniq = dedupAbsMembers(parts);
3217
+ const term = a.term && b.term ? simplifyTerm(app(op, [a.term, b.term])) : void 0;
3218
+ if (uniq.length === 0) {
3219
+ return abs({ k: "unknown" }, term, void 0, "partial");
3220
+ }
3221
+ if (uniq.length === 1) {
3222
+ return abs(uniq[0].shape, term, uniq[0].pred, confJoin(a.conf, b.conf));
3223
+ }
3224
+ return abs({ k: "sum", members: uniq }, term, void 0, "partial");
3225
+ }
3131
3226
  function add(a, b, phi2 = pTrue) {
3132
3227
  if (isSymbolAbs(a) || isSymbolAbs(b)) {
3133
3228
  throw new NudoThrow(errorTypeAbs("TypeError"));
@@ -3185,28 +3280,8 @@ function add(a, b, phi2 = pTrue) {
3185
3280
  "partial"
3186
3281
  );
3187
3282
  }
3188
- if (a.shape.k === "sum" || b.shape.k === "sum") {
3189
- const parts = [];
3190
- const as = a.shape.k === "sum" ? a.shape.members : [a];
3191
- const bs = b.shape.k === "sum" ? b.shape.members : [b];
3192
- for (const x of as) {
3193
- for (const y of bs) {
3194
- const r = add(x, y, phi2);
3195
- if (r.shape.k === "never") continue;
3196
- if (r.shape.k === "sum") parts.push(...r.shape.members);
3197
- else parts.push(r);
3198
- }
3199
- }
3200
- const uniq = dedupAbsMembers(parts);
3201
- const term = a.term && b.term ? simplifyTerm(app("+", [a.term, b.term])) : void 0;
3202
- if (uniq.length === 0) {
3203
- return abs({ k: "unknown" }, term, void 0, "partial");
3204
- }
3205
- if (uniq.length === 1) {
3206
- return abs(uniq[0].shape, term, uniq[0].pred, confJoin(a.conf, b.conf));
3207
- }
3208
- return abs({ k: "sum", members: uniq }, term, void 0, "partial");
3209
- }
3283
+ const distributed = distributeSumBinOp("+", a, b, phi2, add);
3284
+ if (distributed) return distributed;
3210
3285
  if (isNumPrim(a) || isNumPrim(b) || isBigPrim(a) || isBigPrim(b) || a.shape.k === "unknown" || b.shape.k === "unknown" || a.shape.k === "obj" || b.shape.k === "obj" || a.shape.k === "fn" || b.shape.k === "fn" || a.shape.k === "brand" || b.shape.k === "brand") {
3211
3286
  return abs({ k: "sum", members: [num(), str()] }, void 0, void 0, "partial");
3212
3287
  }
@@ -3323,6 +3398,35 @@ function addPred(a, b, sumTerm, phi2) {
3323
3398
  return and(...facts);
3324
3399
  }
3325
3400
  function numericBounds(a, phi2 = pTrue) {
3401
+ if (a.shape.k === "sum") {
3402
+ const members = a.shape.members;
3403
+ let lo;
3404
+ let hi;
3405
+ let loOpen = false;
3406
+ let hiOpen = false;
3407
+ for (const m of members) {
3408
+ const mb = numericBounds(m, phi2);
3409
+ if (!mb) return void 0;
3410
+ if (mb.lo === void 0) {
3411
+ loOpen = true;
3412
+ } else if (!loOpen) {
3413
+ if (lo === void 0 || mb.lo.value < lo.value || mb.lo.value === lo.value && !mb.lo.strict && lo.strict) {
3414
+ lo = mb.lo;
3415
+ }
3416
+ }
3417
+ if (mb.hi === void 0) {
3418
+ hiOpen = true;
3419
+ } else if (!hiOpen) {
3420
+ if (hi === void 0 || mb.hi.value > hi.value || mb.hi.value === hi.value && !mb.hi.strict && hi.strict) {
3421
+ hi = mb.hi;
3422
+ }
3423
+ }
3424
+ }
3425
+ if (loOpen) lo = void 0;
3426
+ if (hiOpen) hi = void 0;
3427
+ if (lo === void 0 && hi === void 0) return void 0;
3428
+ return { lo, hi };
3429
+ }
3326
3430
  if (!isNumPrim(a)) return void 0;
3327
3431
  const result = {};
3328
3432
  if (a.pred && a.term) {
@@ -3429,6 +3533,8 @@ function sub(a, b, phi2 = pTrue) {
3429
3533
  if (isAnyLike(a) || isAnyLike(b)) {
3430
3534
  return toNumberResult(a, b, "-");
3431
3535
  }
3536
+ const distributed = distributeSumBinOp("-", a, b, phi2, sub);
3537
+ if (distributed) return distributed;
3432
3538
  return abs({ k: "unknown" }, void 0, void 0, "partial");
3433
3539
  }
3434
3540
  function mul(a, b, phi2 = pTrue) {
@@ -3501,6 +3607,8 @@ function mul(a, b, phi2 = pTrue) {
3501
3607
  if (isAnyLike(a) || isAnyLike(b)) {
3502
3608
  return toNumberResult(a, b, "*");
3503
3609
  }
3610
+ const distributed = distributeSumBinOp("*", a, b, phi2, mul);
3611
+ if (distributed) return distributed;
3504
3612
  return abs({ k: "unknown" }, void 0, void 0, "partial");
3505
3613
  }
3506
3614
  function div(a, b, phi2 = pTrue) {
@@ -3561,6 +3669,8 @@ function div(a, b, phi2 = pTrue) {
3561
3669
  if (isAnyLike(a) || isAnyLike(b)) {
3562
3670
  return toNumberResult(a, b, "/");
3563
3671
  }
3672
+ const distributed = distributeSumBinOp("/", a, b, phi2, div);
3673
+ if (distributed) return distributed;
3564
3674
  return abs({ k: "unknown" }, void 0, void 0, "partial");
3565
3675
  }
3566
3676
  function mod(a, b, phi2 = pTrue) {
@@ -3611,6 +3721,8 @@ function mod(a, b, phi2 = pTrue) {
3611
3721
  if (isAnyLike(a) || isAnyLike(b)) {
3612
3722
  return toNumberResult(a, b, "%");
3613
3723
  }
3724
+ const distributed = distributeSumBinOp("%", a, b, phi2, mod);
3725
+ if (distributed) return distributed;
3614
3726
  return abs({ k: "unknown" }, void 0, void 0, "partial");
3615
3727
  }
3616
3728
  function cmp(op, a, b, phi2 = pTrue) {
@@ -3800,7 +3912,7 @@ function migrateInvariants(from, to) {
3800
3912
  }
3801
3913
 
3802
3914
  // src/algebra/exec/runtime/state.ts
3803
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3915
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
3804
3916
 
3805
3917
  // src/algebra/containers.ts
3806
3918
  var TUPLE_LITERAL_CAP = 8;
@@ -3825,6 +3937,17 @@ function clearStaleTermPred(v2) {
3825
3937
  v2.pred = void 0;
3826
3938
  }
3827
3939
  var phi = pTrue;
3940
+ function confPartial(a) {
3941
+ return a.conf === "exact" || a.conf === "path" ? { ...a, conf: "partial" } : a;
3942
+ }
3943
+ function confPartialPacked(a) {
3944
+ if (a.shape.k !== "obj") return confPartial(a);
3945
+ const slots = {};
3946
+ for (const [k, slot] of Object.entries(a.shape.slots)) {
3947
+ slots[k] = { value: confPartial(slot.value) };
3948
+ }
3949
+ return objOf(slots);
3950
+ }
3828
3951
  function currentExecPhi() {
3829
3952
  return phi;
3830
3953
  }
@@ -3974,10 +4097,10 @@ function isDefinitelyFalse(a) {
3974
4097
  function undef() {
3975
4098
  return abs({ k: "unknown" }, { op: "lit", value: void 0 }, pTrue, "exact");
3976
4099
  }
3977
- var loopExitsAls = new AsyncLocalStorage2();
3978
- var throwExitsAls = new AsyncLocalStorage2();
3979
- var tryMarksAls = new AsyncLocalStorage2();
3980
- var softFrameActiveAls = new AsyncLocalStorage2();
4100
+ var loopExitsAls = new AsyncLocalStorage3();
4101
+ var throwExitsAls = new AsyncLocalStorage3();
4102
+ var tryMarksAls = new AsyncLocalStorage3();
4103
+ var softFrameActiveAls = new AsyncLocalStorage3();
3981
4104
  function runWithLoopExits(body) {
3982
4105
  return loopExitsAls.run(
3983
4106
  [],
@@ -4111,6 +4234,150 @@ function $rethrowIfNudoReturn(e) {
4111
4234
  if (isNudoReturn(e)) throw e;
4112
4235
  }
4113
4236
 
4237
+ // src/algebra/call-budget.ts
4238
+ var MAX_CALL_DEPTH = 64;
4239
+ var MAX_TOTAL_CALLS = 2e4;
4240
+ var _absCallDepth = 0;
4241
+ var _absTotalCalls = 0;
4242
+ var _activeCallKeys = [];
4243
+ var _fnCallIds = /* @__PURE__ */ new WeakMap();
4244
+ var _fnCallIdSeq = 0;
4245
+ var _callTruncated = false;
4246
+ var _callDepthLimit = MAX_CALL_DEPTH;
4247
+ var _totalCallsLimit = MAX_TOTAL_CALLS;
4248
+ function getAbsCallBudgetStats() {
4249
+ return {
4250
+ calls: _absTotalCalls,
4251
+ maxCalls: _totalCallsLimit,
4252
+ forks: _evalForkCount,
4253
+ maxForks: _evalForkBudgetLimit,
4254
+ callTruncated: _callTruncated,
4255
+ forkTruncated: _evalForkTruncNoted,
4256
+ truncated: _callTruncated || _evalForkTruncNoted
4257
+ };
4258
+ }
4259
+ function resetAbsCallBudget() {
4260
+ _absCallDepth = 0;
4261
+ _absTotalCalls = 0;
4262
+ _activeCallKeys = [];
4263
+ _callTruncated = false;
4264
+ _callDepthLimit = MAX_CALL_DEPTH;
4265
+ _totalCallsLimit = MAX_TOTAL_CALLS;
4266
+ resetEvalForkBudget();
4267
+ }
4268
+ function withFnBudgetOverride(budget, run) {
4269
+ const prevDepth = _callDepthLimit;
4270
+ const prevCalls = _totalCallsLimit;
4271
+ const prevForks = _evalForkBudgetLimit;
4272
+ if (typeof budget.depth === "number" && Number.isFinite(budget.depth) && budget.depth >= 1) {
4273
+ _callDepthLimit = Math.floor(budget.depth);
4274
+ }
4275
+ if (typeof budget.calls === "number" && Number.isFinite(budget.calls) && budget.calls >= 1) {
4276
+ _totalCallsLimit = Math.floor(budget.calls);
4277
+ }
4278
+ if (typeof budget.forks === "number" && Number.isFinite(budget.forks) && budget.forks >= 1) {
4279
+ setEvalForkBudgetLimit(Math.floor(budget.forks));
4280
+ }
4281
+ try {
4282
+ run();
4283
+ } finally {
4284
+ _callDepthLimit = prevDepth;
4285
+ _totalCallsLimit = prevCalls;
4286
+ setEvalForkBudgetLimit(prevForks);
4287
+ }
4288
+ }
4289
+ function stableCallId(obj2) {
4290
+ let id = _fnCallIds.get(obj2);
4291
+ if (id === void 0) {
4292
+ id = `#${++_fnCallIdSeq}`;
4293
+ _fnCallIds.set(obj2, id);
4294
+ }
4295
+ return id;
4296
+ }
4297
+ function truncatedAbs() {
4298
+ return abs({ k: "unknown" }, void 0, void 0, "opaque");
4299
+ }
4300
+ function callBudgetKey(kind, id, args) {
4301
+ const parts = args.map((a) => {
4302
+ const sh = a?.shape;
4303
+ if (!sh) return `js:${typeof a}`;
4304
+ const t = a.term ? termToString(a.term) : "";
4305
+ return `${sh.k}:${t}`;
4306
+ });
4307
+ return `${kind}|${id}|${parts.join(",")}`;
4308
+ }
4309
+ var absTruncCollectorSlot = createScopedSlot(() => null);
4310
+ registerCollectorScopeParticipant((body) => absTruncCollectorSlot.runScoped(body));
4311
+ function setAbsTruncationCollector(collector) {
4312
+ const prev = absTruncCollectorSlot.get();
4313
+ absTruncCollectorSlot.set(collector);
4314
+ return prev;
4315
+ }
4316
+ function noteAbsTruncation(label) {
4317
+ const absTruncCollector = absTruncCollectorSlot.get();
4318
+ if (!absTruncCollector) return;
4319
+ try {
4320
+ absTruncCollector(label);
4321
+ } catch {
4322
+ }
4323
+ }
4324
+ function enterCall(key, label) {
4325
+ if (_activeCallKeys.includes(key) || _absCallDepth >= _callDepthLimit || _absTotalCalls >= _totalCallsLimit) {
4326
+ _callTruncated = true;
4327
+ noteAbsTruncation(label);
4328
+ return false;
4329
+ }
4330
+ _activeCallKeys.push(key);
4331
+ _absCallDepth++;
4332
+ _absTotalCalls++;
4333
+ return true;
4334
+ }
4335
+ function exitCall() {
4336
+ if (_absCallDepth > 0) _absCallDepth--;
4337
+ if (_activeCallKeys.length > 0) _activeCallKeys.pop();
4338
+ }
4339
+ var MAX_EVAL_TOTAL_FORKS = 5e3;
4340
+ var _evalForkBudgetLimit = MAX_EVAL_TOTAL_FORKS;
4341
+ var _evalForkCount = 0;
4342
+ var _evalForkTruncNoted = false;
4343
+ var FORK_TRUNCATION_LABEL = "#fork-budget";
4344
+ var HOST_EFFECT_LABEL_PREFIX = "#host-effect:";
4345
+ var PROMISE_MICRO_OVERFLOW_LABEL = "#promise-micro-overflow";
4346
+ var PROMISE_MICRO_ERROR_LABEL = "#promise-micro-error";
4347
+ var MATH_FOLD_ERROR_LABEL = "#math-fold-error";
4348
+ function noteHostEffectBlocked(name) {
4349
+ noteAbsTruncation(`${HOST_EFFECT_LABEL_PREFIX}${name}`);
4350
+ }
4351
+ function noteEvalForkTruncation() {
4352
+ noteAbsTruncation(FORK_TRUNCATION_LABEL);
4353
+ }
4354
+ function setEvalForkBudgetLimit(n) {
4355
+ if (typeof n === "number" && Number.isFinite(n) && n >= 1) {
4356
+ _evalForkBudgetLimit = Math.floor(n);
4357
+ } else {
4358
+ _evalForkBudgetLimit = MAX_EVAL_TOTAL_FORKS;
4359
+ }
4360
+ return _evalForkBudgetLimit;
4361
+ }
4362
+ function getEvalForkBudgetLimit() {
4363
+ return _evalForkBudgetLimit;
4364
+ }
4365
+ function getEvalForkCount() {
4366
+ return _evalForkCount;
4367
+ }
4368
+ function resetEvalForkBudget() {
4369
+ _evalForkCount = 0;
4370
+ _evalForkTruncNoted = false;
4371
+ }
4372
+ function bumpEvalForkBudget() {
4373
+ if (++_evalForkCount <= _evalForkBudgetLimit) return true;
4374
+ if (!_evalForkTruncNoted) {
4375
+ _evalForkTruncNoted = true;
4376
+ noteEvalForkTruncation();
4377
+ }
4378
+ return false;
4379
+ }
4380
+
4114
4381
  // src/algebra/builtins/shared.ts
4115
4382
  var noBody2 = { type: "BlockStatement", body: [], directives: [] };
4116
4383
  function numPrim(conf = "path") {
@@ -4156,6 +4423,11 @@ function isNonNaN(a, phi2) {
4156
4423
  if (a.term?.op === "lit") {
4157
4424
  return typeof a.term.value === "number" && !Number.isNaN(a.term.value);
4158
4425
  }
4426
+ if (a.shape.k === "sum") {
4427
+ return a.shape.members.every(
4428
+ (m) => isNonNaN(m, phi2)
4429
+ );
4430
+ }
4159
4431
  const hasNonNaNFact = (p) => {
4160
4432
  if (!p) return false;
4161
4433
  if (p.op === "and") return p.args.some(hasNonNaNFact);
@@ -4277,7 +4549,9 @@ function roundingAbs(name, arg) {
4277
4549
  const impl = name === "round" ? Math.round : name === "floor" ? Math.floor : name === "ceil" ? Math.ceil : Math.trunc;
4278
4550
  const b = numericBounds(arg, phi2);
4279
4551
  const mayNaN = !isNonNaN(arg, phi2);
4280
- const term = arg.term ? simplifyTerm(app(`Math.${name}`, [arg.term])) : void 0;
4552
+ const term = simplifyTerm(
4553
+ app(`Math.${name}`, [arg.term ?? app("arg0", [])])
4554
+ );
4281
4555
  let out = {};
4282
4556
  if (b) {
4283
4557
  if (b.lo !== void 0) {
@@ -4289,7 +4563,7 @@ function roundingAbs(name, arg) {
4289
4563
  out.hi = Number.isNaN(v2) ? void 0 : { value: v2, strict: false };
4290
4564
  }
4291
4565
  }
4292
- const pred = term ? boundsToPred(term, out) : void 0;
4566
+ const pred = boundsToPred(term, out);
4293
4567
  const bounded = abs({ k: "prim", type: "number" }, term, pred, "path");
4294
4568
  if (!mayNaN) return bounded;
4295
4569
  return makeSum(numLit(NaN), bounded);
@@ -4312,6 +4586,7 @@ function evalMathMethod(name, args) {
4312
4586
  try {
4313
4587
  return numLit((name === "min" ? Math.min : Math.max)(...nums2));
4314
4588
  } catch {
4589
+ noteAbsTruncation(MATH_FOLD_ERROR_LABEL);
4315
4590
  return numPrim();
4316
4591
  }
4317
4592
  }
@@ -4330,6 +4605,7 @@ function evalMathMethod(name, args) {
4330
4605
  name === "round" ? Math.round(n) : name === "floor" ? Math.floor(n) : name === "ceil" ? Math.ceil(n) : Math.trunc(n)
4331
4606
  );
4332
4607
  } catch {
4608
+ noteAbsTruncation(MATH_FOLD_ERROR_LABEL);
4333
4609
  return numPrim();
4334
4610
  }
4335
4611
  }
@@ -4352,6 +4628,7 @@ function evalMathMethod(name, args) {
4352
4628
  try {
4353
4629
  return numLit(impl(...nums));
4354
4630
  } catch {
4631
+ noteAbsTruncation(MATH_FOLD_ERROR_LABEL);
4355
4632
  return numPrim();
4356
4633
  }
4357
4634
  }
@@ -6111,147 +6388,6 @@ function evalRegExpMethod(name, recv, args) {
6111
6388
  return void 0;
6112
6389
  }
6113
6390
 
6114
- // src/algebra/call-budget.ts
6115
- var MAX_CALL_DEPTH = 64;
6116
- var MAX_TOTAL_CALLS = 2e4;
6117
- var _absCallDepth = 0;
6118
- var _absTotalCalls = 0;
6119
- var _activeCallKeys = [];
6120
- var _fnCallIds = /* @__PURE__ */ new WeakMap();
6121
- var _fnCallIdSeq = 0;
6122
- var _callTruncated = false;
6123
- var _callDepthLimit = MAX_CALL_DEPTH;
6124
- var _totalCallsLimit = MAX_TOTAL_CALLS;
6125
- function getAbsCallBudgetStats() {
6126
- return {
6127
- calls: _absTotalCalls,
6128
- maxCalls: _totalCallsLimit,
6129
- forks: _evalForkCount,
6130
- maxForks: _evalForkBudgetLimit,
6131
- callTruncated: _callTruncated,
6132
- forkTruncated: _evalForkTruncNoted,
6133
- truncated: _callTruncated || _evalForkTruncNoted
6134
- };
6135
- }
6136
- function resetAbsCallBudget() {
6137
- _absCallDepth = 0;
6138
- _absTotalCalls = 0;
6139
- _activeCallKeys = [];
6140
- _callTruncated = false;
6141
- _callDepthLimit = MAX_CALL_DEPTH;
6142
- _totalCallsLimit = MAX_TOTAL_CALLS;
6143
- resetEvalForkBudget();
6144
- }
6145
- function withFnBudgetOverride(budget, run) {
6146
- const prevDepth = _callDepthLimit;
6147
- const prevCalls = _totalCallsLimit;
6148
- const prevForks = _evalForkBudgetLimit;
6149
- if (typeof budget.depth === "number" && Number.isFinite(budget.depth) && budget.depth >= 1) {
6150
- _callDepthLimit = Math.floor(budget.depth);
6151
- }
6152
- if (typeof budget.calls === "number" && Number.isFinite(budget.calls) && budget.calls >= 1) {
6153
- _totalCallsLimit = Math.floor(budget.calls);
6154
- }
6155
- if (typeof budget.forks === "number" && Number.isFinite(budget.forks) && budget.forks >= 1) {
6156
- setEvalForkBudgetLimit(Math.floor(budget.forks));
6157
- }
6158
- try {
6159
- run();
6160
- } finally {
6161
- _callDepthLimit = prevDepth;
6162
- _totalCallsLimit = prevCalls;
6163
- setEvalForkBudgetLimit(prevForks);
6164
- }
6165
- }
6166
- function stableCallId(obj2) {
6167
- let id = _fnCallIds.get(obj2);
6168
- if (id === void 0) {
6169
- id = `#${++_fnCallIdSeq}`;
6170
- _fnCallIds.set(obj2, id);
6171
- }
6172
- return id;
6173
- }
6174
- function truncatedAbs() {
6175
- return abs({ k: "unknown" }, void 0, void 0, "opaque");
6176
- }
6177
- function callBudgetKey(kind, id, args) {
6178
- const parts = args.map((a) => {
6179
- const sh = a?.shape;
6180
- if (!sh) return `js:${typeof a}`;
6181
- const t = a.term ? termToString(a.term) : "";
6182
- return `${sh.k}:${t}`;
6183
- });
6184
- return `${kind}|${id}|${parts.join(",")}`;
6185
- }
6186
- var absTruncCollector = null;
6187
- function setAbsTruncationCollector(collector2) {
6188
- const prev = absTruncCollector;
6189
- absTruncCollector = collector2;
6190
- return prev;
6191
- }
6192
- function noteAbsTruncation(label) {
6193
- if (!absTruncCollector) return;
6194
- try {
6195
- absTruncCollector(label);
6196
- } catch {
6197
- }
6198
- }
6199
- function enterCall(key, label) {
6200
- if (_activeCallKeys.includes(key) || _absCallDepth >= _callDepthLimit || _absTotalCalls >= _totalCallsLimit) {
6201
- _callTruncated = true;
6202
- noteAbsTruncation(label);
6203
- return false;
6204
- }
6205
- _activeCallKeys.push(key);
6206
- _absCallDepth++;
6207
- _absTotalCalls++;
6208
- return true;
6209
- }
6210
- function exitCall() {
6211
- if (_absCallDepth > 0) _absCallDepth--;
6212
- if (_activeCallKeys.length > 0) _activeCallKeys.pop();
6213
- }
6214
- var MAX_EVAL_TOTAL_FORKS = 5e3;
6215
- var _evalForkBudgetLimit = MAX_EVAL_TOTAL_FORKS;
6216
- var _evalForkCount = 0;
6217
- var _evalForkTruncNoted = false;
6218
- var FORK_TRUNCATION_LABEL = "#fork-budget";
6219
- var HOST_EFFECT_LABEL_PREFIX = "#host-effect:";
6220
- var PROMISE_MICRO_OVERFLOW_LABEL = "#promise-micro-overflow";
6221
- var PROMISE_MICRO_ERROR_LABEL = "#promise-micro-error";
6222
- function noteHostEffectBlocked(name) {
6223
- noteAbsTruncation(`${HOST_EFFECT_LABEL_PREFIX}${name}`);
6224
- }
6225
- function noteEvalForkTruncation() {
6226
- noteAbsTruncation(FORK_TRUNCATION_LABEL);
6227
- }
6228
- function setEvalForkBudgetLimit(n) {
6229
- if (typeof n === "number" && Number.isFinite(n) && n >= 1) {
6230
- _evalForkBudgetLimit = Math.floor(n);
6231
- } else {
6232
- _evalForkBudgetLimit = MAX_EVAL_TOTAL_FORKS;
6233
- }
6234
- return _evalForkBudgetLimit;
6235
- }
6236
- function getEvalForkBudgetLimit() {
6237
- return _evalForkBudgetLimit;
6238
- }
6239
- function getEvalForkCount() {
6240
- return _evalForkCount;
6241
- }
6242
- function resetEvalForkBudget() {
6243
- _evalForkCount = 0;
6244
- _evalForkTruncNoted = false;
6245
- }
6246
- function bumpEvalForkBudget() {
6247
- if (++_evalForkCount <= _evalForkBudgetLimit) return true;
6248
- if (!_evalForkTruncNoted) {
6249
- _evalForkTruncNoted = true;
6250
- noteEvalForkTruncation();
6251
- }
6252
- return false;
6253
- }
6254
-
6255
6391
  // src/algebra/builtins/promise.ts
6256
6392
  var promiseExecStack = [];
6257
6393
  function enterPromiseExecutorScope() {
@@ -8114,25 +8250,12 @@ function leqPred(src, tgt, phi2, depth) {
8114
8250
  if (!tp) return ok();
8115
8251
  if (!sp) {
8116
8252
  if (implies(phi2, tp)) return ok();
8117
- return fail(`pred \u22AD ${predBrief(tp)}`);
8253
+ return fail(`pred \u22AD ${predToString(tp)}`);
8118
8254
  }
8119
8255
  const combined = phi2.op === "true" ? sp : { op: "and", args: [phi2, sp] };
8120
8256
  if (implies(combined, tp)) return ok();
8121
8257
  if (numericBoundsImply(sp, tp)) return ok();
8122
- return fail(`pred \u22AD ${predBrief(tp)}`);
8123
- }
8124
- function predBrief(p) {
8125
- switch (p.op) {
8126
- case "gt":
8127
- case "ge":
8128
- case "lt":
8129
- case "le":
8130
- case "eq":
8131
- case "ne":
8132
- return p.op;
8133
- default:
8134
- return p.op;
8135
- }
8258
+ return fail(`pred \u22AD ${predToString(tp)}`);
8136
8259
  }
8137
8260
  function numericBoundsImply(src, tgt) {
8138
8261
  const one = (p) => p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le";
@@ -8156,7 +8279,7 @@ function numericBoundsImply(src, tgt) {
8156
8279
  return sb <= tb;
8157
8280
  }
8158
8281
  function sameTermSide(a, b) {
8159
- return a.a.op === b.a.op && termEquals(a.a, b.a);
8282
+ return termEquals(a.a, b.a);
8160
8283
  }
8161
8284
  function litGE(a, b) {
8162
8285
  if (a.op !== "lit" || b.op !== "lit") return false;
@@ -8464,25 +8587,87 @@ function formatShapeInner(a, budget) {
8464
8587
  }
8465
8588
  return parts.join(" | ");
8466
8589
  }
8467
- default:
8468
- return "\xB7";
8590
+ default:
8591
+ return "\xB7";
8592
+ }
8593
+ }
8594
+ function formatAbsMultiline(a, label) {
8595
+ const lines = [];
8596
+ if (label) lines.push(label);
8597
+ lines.push(` ${formatShape(a)}`);
8598
+ if (a.term && a.term.op !== "lit") {
8599
+ lines.push(` term: ${termToString(a.term)}`);
8600
+ }
8601
+ if (a.pred && a.pred.op !== "true") {
8602
+ lines.push(` pred: ${predToString(a.pred)}`);
8603
+ }
8604
+ lines.push(` conf: ${a.conf}`);
8605
+ return lines.join("\n");
8606
+ }
8607
+
8608
+ // src/algebra/lru-map.ts
8609
+ var BoundedLruMap = class {
8610
+ map = /* @__PURE__ */ new Map();
8611
+ max;
8612
+ constructor(max) {
8613
+ this.max = max;
8614
+ }
8615
+ get size() {
8616
+ return this.map.size;
8617
+ }
8618
+ getMax() {
8619
+ return this.max;
8620
+ }
8621
+ setMax(max) {
8622
+ this.max = max;
8623
+ this.trim();
8624
+ }
8625
+ has(key) {
8626
+ return this.map.has(key);
8627
+ }
8628
+ get(key) {
8629
+ const hit = this.map.get(key);
8630
+ if (hit === void 0) return void 0;
8631
+ this.map.delete(key);
8632
+ this.map.set(key, hit);
8633
+ return hit;
8634
+ }
8635
+ set(key, value) {
8636
+ if (this.max <= 0) return;
8637
+ while (this.map.size >= this.max && !this.map.has(key)) {
8638
+ const oldest = this.map.keys().next().value;
8639
+ if (oldest === void 0) break;
8640
+ this.map.delete(oldest);
8641
+ }
8642
+ this.map.delete(key);
8643
+ this.map.set(key, value);
8469
8644
  }
8470
- }
8471
- function formatAbsMultiline(a, label) {
8472
- const lines = [];
8473
- if (label) lines.push(label);
8474
- lines.push(` ${formatShape(a)}`);
8475
- if (a.term && a.term.op !== "lit") {
8476
- lines.push(` term: ${termToString(a.term)}`);
8645
+ delete(key) {
8646
+ return this.map.delete(key);
8477
8647
  }
8478
- if (a.pred && a.pred.op !== "true") {
8479
- lines.push(` pred: ${predToString(a.pred)}`);
8648
+ clear() {
8649
+ this.map.clear();
8480
8650
  }
8481
- lines.push(` conf: ${a.conf}`);
8482
- return lines.join("\n");
8483
- }
8651
+ trim() {
8652
+ while (this.map.size > this.max) {
8653
+ const oldest = this.map.keys().next().value;
8654
+ if (oldest === void 0) break;
8655
+ this.map.delete(oldest);
8656
+ }
8657
+ }
8658
+ };
8484
8659
 
8485
8660
  // src/algebra/code-text.ts
8661
+ var SOURCE_SCAN_CACHE_MAX = 256;
8662
+ var stripCommentsAndStringsCache = new BoundedLruMap(
8663
+ SOURCE_SCAN_CACHE_MAX
8664
+ );
8665
+ var stripStringsKeepCommentsCache = new BoundedLruMap(
8666
+ SOURCE_SCAN_CACHE_MAX
8667
+ );
8668
+ var maskCommentsAndStringsCache = new BoundedLruMap(
8669
+ SOURCE_SCAN_CACHE_MAX
8670
+ );
8486
8671
  var REGEX_KEYWORDS = /* @__PURE__ */ new Set([
8487
8672
  "await",
8488
8673
  "case",
@@ -8719,27 +8904,36 @@ function scanSource(source) {
8719
8904
  return { spans, literals };
8720
8905
  }
8721
8906
  function stripCommentsAndStrings(source) {
8907
+ const hit = stripCommentsAndStringsCache.get(source);
8908
+ if (hit !== void 0) return hit;
8722
8909
  let out = "";
8723
8910
  for (const span of scanSource(source).spans) {
8724
8911
  if (span.kind === "code") out += span.text;
8725
8912
  else if (span.kind === "comment") out += " ";
8726
8913
  else out += '""';
8727
8914
  }
8915
+ stripCommentsAndStringsCache.set(source, out);
8728
8916
  return out;
8729
8917
  }
8730
8918
  function stripStringsKeepComments(source) {
8919
+ const hit = stripStringsKeepCommentsCache.get(source);
8920
+ if (hit !== void 0) return hit;
8731
8921
  let out = "";
8732
8922
  for (const span of scanSource(source).spans) {
8733
8923
  out += span.kind === "string" ? '""' : span.text;
8734
8924
  }
8925
+ stripStringsKeepCommentsCache.set(source, out);
8735
8926
  return out;
8736
8927
  }
8737
8928
  function maskCommentsAndStrings(source) {
8929
+ const hit = maskCommentsAndStringsCache.get(source);
8930
+ if (hit !== void 0) return hit;
8738
8931
  let out = "";
8739
8932
  for (const span of scanSource(source).spans) {
8740
8933
  if (span.kind === "code") out += span.text;
8741
8934
  else out += span.text.replace(/[^\n]/g, " ");
8742
8935
  }
8936
+ maskCommentsAndStringsCache.set(source, out);
8743
8937
  return out;
8744
8938
  }
8745
8939
  function scanStringLiterals(source) {
@@ -9003,6 +9197,18 @@ function isStatefulMethodName(name) {
9003
9197
  // src/algebra/exec/transpile/intrinsics.ts
9004
9198
  var HOST_INTRINSIC_NAMES = ["undefined", "NaN", "Infinity"];
9005
9199
  var HOST_INTRINSIC_SET = new Set(HOST_INTRINSIC_NAMES);
9200
+ var ENV_SHADOW_SKIP_GLOBALS = /* @__PURE__ */ new Set([
9201
+ ...HOST_INTRINSIC_NAMES,
9202
+ "Math",
9203
+ "Number",
9204
+ "JSON",
9205
+ "Object",
9206
+ "Array",
9207
+ "String",
9208
+ "Date",
9209
+ "Promise",
9210
+ "BigInt"
9211
+ ]);
9006
9212
  var UNDEF_LIT = "$lit(void 0)";
9007
9213
  function hostIntrinsicLit(name) {
9008
9214
  switch (name) {
@@ -9276,6 +9482,18 @@ function collectLexicalDeclNames(node, acc) {
9276
9482
  else if (child && typeof child === "object") collectLexicalDeclNames(child, acc);
9277
9483
  }
9278
9484
  }
9485
+ function collectLoopBodyTopLevelDeclNames(body, acc) {
9486
+ const n = body;
9487
+ if (!n || n.type !== "BlockStatement" || !Array.isArray(n.body)) return;
9488
+ for (const s of n.body) {
9489
+ const stmt = s;
9490
+ if (stmt.type === "VariableDeclaration" && stmt.kind !== "var") {
9491
+ for (const d of stmt.declarations ?? []) collectPatternNames2(d.id, acc);
9492
+ } else if (stmt.type === "FunctionDeclaration" || stmt.type === "ClassDeclaration") {
9493
+ collectPatternNames2(stmt.id, acc);
9494
+ }
9495
+ }
9496
+ }
9279
9497
  function computeConstScope(stmts, parentConsts) {
9280
9498
  const consts = /* @__PURE__ */ new Set();
9281
9499
  const mutables = /* @__PURE__ */ new Set();
@@ -10482,7 +10700,9 @@ ${pad}export default ${name};`;
10482
10700
  collectAssignedIds(stmt.test, assigned2);
10483
10701
  collectAssignedIds(stmt.update, assigned2);
10484
10702
  collectArrMutatorReceivers(stmt.body, assigned2);
10485
- const names2 = [...assigned2].filter((n) => !HOST_INTRINSIC_SET.has(n));
10703
+ const bodyLocalDecls2 = /* @__PURE__ */ new Set();
10704
+ collectLoopBodyTopLevelDeclNames(stmt.body, bodyLocalDecls2);
10705
+ const names2 = [...assigned2].filter((n) => !HOST_INTRINSIC_SET.has(n) && !bodyLocalDecls2.has(n));
10486
10706
  const packSrc2 = names2.length === 0 ? null : `$obj({ ${names2.map((n) => `${JSON.stringify(n)}: $copy(${n})`).join(", ")} })`;
10487
10707
  const unpackSrc2 = names2.length === 0 ? null : `(__lp) => { ${names2.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
10488
10708
  const optsSrc2 = (() => {
@@ -10522,7 +10742,9 @@ ${pad}export default ${name};`;
10522
10742
  collectAssignedIds(stmt.test, assigned);
10523
10743
  collectAssignedIds(stmt.update, assigned);
10524
10744
  collectArrMutatorReceivers(stmt.body, assigned);
10525
- const names = [...assigned].filter((n) => n !== initName && !HOST_INTRINSIC_SET.has(n));
10745
+ const bodyLocalDecls = /* @__PURE__ */ new Set();
10746
+ collectLoopBodyTopLevelDeclNames(stmt.body, bodyLocalDecls);
10747
+ const names = [...assigned].filter((n) => n !== initName && !HOST_INTRINSIC_SET.has(n) && !bodyLocalDecls.has(n));
10526
10748
  const packSrc = names.length === 0 ? null : `$obj({ ${names.map((n) => `${JSON.stringify(n)}: $copy(${n})`).join(", ")} })`;
10527
10749
  const unpackSrc = names.length === 0 ? null : `(__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
10528
10750
  const optsSrc = (() => {
@@ -10831,7 +11053,9 @@ ${indent(depth + 1)}]${dflt})`;
10831
11053
  const assigned = /* @__PURE__ */ new Set();
10832
11054
  collectAssignedIds(stmt.body, assigned);
10833
11055
  collectArrMutatorReceivers(stmt.body, assigned);
10834
- const names = [...assigned].filter((n) => n !== bindName && !HOST_INTRINSIC_SET.has(n));
11056
+ const bodyLocalDecls = /* @__PURE__ */ new Set();
11057
+ collectLoopBodyTopLevelDeclNames(stmt.body, bodyLocalDecls);
11058
+ const names = [...assigned].filter((n) => n !== bindName && !HOST_INTRINSIC_SET.has(n) && !bodyLocalDecls.has(n));
10835
11059
  const loopOpts = opts.loopLabel ? `label: ${JSON.stringify(opts.loopLabel)}` : "";
10836
11060
  const optsSrc = names.length === 0 ? loopOpts ? `, { ${loopOpts} }` : "" : `, { pack: () => $obj({ ${names.map((n) => `${JSON.stringify(n)}: $copy(${n})`).join(", ")} }), unpack: (__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }${loopOpts ? `, ${loopOpts}` : ""} }`;
10837
11061
  return [
@@ -10853,7 +11077,9 @@ ${indent(depth + 1)}]${dflt})`;
10853
11077
  const assigned = /* @__PURE__ */ new Set();
10854
11078
  collectAssignedIds(stmt.body, assigned);
10855
11079
  collectAssignedIds(stmt.test, assigned);
10856
- const names = [...assigned].filter((n) => !HOST_INTRINSIC_SET.has(n));
11080
+ const bodyLocalDecls = /* @__PURE__ */ new Set();
11081
+ collectLoopBodyTopLevelDeclNames(stmt.body, bodyLocalDecls);
11082
+ const names = [...assigned].filter((n) => !HOST_INTRINSIC_SET.has(n) && !bodyLocalDecls.has(n));
10857
11083
  const loopOpts = opts.loopLabel ? `label: ${JSON.stringify(opts.loopLabel)}` : "";
10858
11084
  if (names.length === 0) {
10859
11085
  return [
@@ -10885,7 +11111,9 @@ ${indent(depth + 1)}]${dflt})`;
10885
11111
  collectAssignedIds(stmt.body, assigned);
10886
11112
  collectAssignedIds(stmt.test, assigned);
10887
11113
  collectArrMutatorReceivers(stmt.body, assigned);
10888
- const names = [...assigned].filter((n) => !HOST_INTRINSIC_SET.has(n));
11114
+ const bodyLocalDecls = /* @__PURE__ */ new Set();
11115
+ collectLoopBodyTopLevelDeclNames(stmt.body, bodyLocalDecls);
11116
+ const names = [...assigned].filter((n) => !HOST_INTRINSIC_SET.has(n) && !bodyLocalDecls.has(n));
10889
11117
  const packSrc = names.length === 0 ? null : `$obj({ ${names.map((n) => `${JSON.stringify(n)}: $copy(${n})`).join(", ")} })`;
10890
11118
  const unpackSrc = names.length === 0 ? null : `(__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
10891
11119
  const loopOpts = opts.loopLabel ? `label: ${JSON.stringify(opts.loopLabel)}` : "";
@@ -11371,10 +11599,11 @@ function transpileExpression(expr, opts = {}) {
11371
11599
  return transpileShortCircuitExpr(opts, {
11372
11600
  alwaysNodes: [lNode],
11373
11601
  alwaysSrc: l,
11374
- // 测试用 nullish;返回侧:nullish → right,否则 → left
11602
+ // 测试用 nullish;返回侧:nullish → right,否则 → left 的**非 nullish 部分**
11603
+ // (索引访问/可选字段的左值常携带 undefined 臂,不去则 ?? 的 alt 仍含 undefined)
11375
11604
  consSrc: r,
11376
11605
  consNodes: [rNode],
11377
- altSrc: l,
11606
+ altSrc: `$removeNullish(${l})`,
11378
11607
  altNodes: [lNode],
11379
11608
  testSrc: `$nullishTest(${l})`
11380
11609
  });
@@ -11764,7 +11993,7 @@ ${mBodyInner}
11764
11993
  alwaysSrc: targetSrc,
11765
11994
  consSrc: right,
11766
11995
  consNodes: [rNode],
11767
- altSrc: targetSrc,
11996
+ altSrc: `$removeNullish(${targetSrc})`,
11768
11997
  altNodes: [],
11769
11998
  testSrc: `$nullishTest(${targetSrc})`
11770
11999
  });
@@ -12019,13 +12248,13 @@ function transpileSource(source, opts = {}) {
12019
12248
  return transpileFile(file, { ...opts, source: opts.source ?? source });
12020
12249
  }
12021
12250
  function runtimeImportOf(runtime) {
12022
- return `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`;
12251
+ return `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $removeNullish, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`;
12023
12252
  }
12024
12253
  function transpileFile(file, opts = {}) {
12025
12254
  const runtime = opts.runtimeImport ?? "@nudojs/core/exec";
12026
12255
  const lines = [
12027
12256
  `// nudo evaluator transpile \u2014 values are Abs; operators are overloaded calls`,
12028
- `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`,
12257
+ `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $removeNullish, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`,
12029
12258
  ``
12030
12259
  ];
12031
12260
  for (const stmt of file.program.body) {
@@ -12157,8 +12386,9 @@ function $join(a, b) {
12157
12386
  }
12158
12387
 
12159
12388
  // src/algebra/exec/member-diag.ts
12160
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
12161
- var memberDiagCollector = null;
12389
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
12390
+ var memberDiagCollectorSlot = createScopedSlot(() => null);
12391
+ registerCollectorScopeParticipant((body) => memberDiagCollectorSlot.runScoped(body));
12162
12392
  var callLocStack = [];
12163
12393
  var absOrigins = /* @__PURE__ */ new WeakMap();
12164
12394
  function tagAbsOrigin(a, loc) {
@@ -12169,8 +12399,8 @@ function getAbsOrigin(a) {
12169
12399
  return absOrigins.get(a);
12170
12400
  }
12171
12401
  function setMemberDiagCollector(c) {
12172
- const prev = memberDiagCollector;
12173
- memberDiagCollector = c;
12402
+ const prev = memberDiagCollectorSlot.get();
12403
+ memberDiagCollectorSlot.set(c);
12174
12404
  return prev;
12175
12405
  }
12176
12406
  function pushCallLoc(loc) {
@@ -12180,6 +12410,7 @@ function popCallLoc() {
12180
12410
  callLocStack.pop();
12181
12411
  }
12182
12412
  function recordMemberDiag(d) {
12413
+ const memberDiagCollector = memberDiagCollectorSlot.get();
12183
12414
  if (!memberDiagCollector) return;
12184
12415
  const origin = d.origin ?? callLocStack[callLocStack.length - 1];
12185
12416
  try {
@@ -12323,7 +12554,7 @@ function definitelyUncallableMember(recv, name) {
12323
12554
  }
12324
12555
  return false;
12325
12556
  }
12326
- var evalMissingSlotAls = new AsyncLocalStorage3();
12557
+ var evalMissingSlotAls = new AsyncLocalStorage4();
12327
12558
  var evalMissingSlotFallback = false;
12328
12559
  function setEvalMissingSlotEnabled(enabled) {
12329
12560
  evalMissingSlotFallback = enabled;
@@ -12468,6 +12699,7 @@ __export(runtime_exports, {
12468
12699
  $pushLoopExit: () => $pushLoopExit,
12469
12700
  $rawThis: () => $rawThis,
12470
12701
  $regex: () => $regex,
12702
+ $removeNullish: () => $removeNullish,
12471
12703
  $rethrowIfNudoReturn: () => $rethrowIfNudoReturn,
12472
12704
  $set: () => $set,
12473
12705
  $setProto: () => $setProto,
@@ -12499,12 +12731,15 @@ __export(runtime_exports, {
12499
12731
  $whileSeq: () => $whileSeq,
12500
12732
  $yield: () => $yield,
12501
12733
  DEFAULT_MAX_LOOP_ITERS: () => DEFAULT_MAX_LOOP_ITERS,
12734
+ LOOP_TRUNCATION_LABEL: () => LOOP_TRUNCATION_LABEL,
12735
+ MAX_CONCRETE_LOOP_ITERS: () => MAX_CONCRETE_LOOP_ITERS,
12502
12736
  NudoLoopSignal: () => NudoLoopSignal,
12503
12737
  NudoReturn: () => NudoReturn,
12504
12738
  NudoThrow: () => NudoThrow,
12505
12739
  asAbsVal: () => asAbsVal,
12506
12740
  callAtFunctionBoundary: () => callAtFunctionBoundary,
12507
12741
  clearStaleTermPred: () => clearStaleTermPred,
12742
+ confPartial: () => confPartial,
12508
12743
  currentExecPhi: () => currentExecPhi,
12509
12744
  fillTuple: () => fillTuple,
12510
12745
  isArrMutator: () => isArrMutator,
@@ -12527,6 +12762,8 @@ __export(runtime_exports, {
12527
12762
 
12528
12763
  // src/algebra/exec/runtime/loop-budget.ts
12529
12764
  var DEFAULT_MAX_LOOP_ITERS = 8;
12765
+ var MAX_CONCRETE_LOOP_ITERS = 1024;
12766
+ var LOOP_TRUNCATION_LABEL = "#loop-iterations";
12530
12767
 
12531
12768
  // src/algebra/exec/runtime/containers.ts
12532
12769
  function tupleOrWiden(els, conf) {
@@ -13263,7 +13500,9 @@ function $forOf(iterable, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13263
13500
  const knownLen = shape.k === "tuple" ? shape.elements.length : typeof sv === "string" ? [...sv].length : collectionExactLen(iterable);
13264
13501
  const unbounded = knownLen === void 0;
13265
13502
  if (unbounded) snapExit();
13266
- const n = knownLen !== void 0 ? Math.min(knownLen, maxIters) : items.length > 0 ? 1 : 0;
13503
+ const concreteCap = Math.max(maxIters, MAX_CONCRETE_LOOP_ITERS);
13504
+ const n = knownLen !== void 0 ? Math.min(knownLen, concreteCap) : items.length > 0 ? 1 : 0;
13505
+ const concreteOverrun = knownLen !== void 0 && knownLen > concreteCap;
13267
13506
  for (let i = 0; i < n; i++) {
13268
13507
  const item = items.length > 0 ? items[Math.min(i, items.length - 1)] : unknown;
13269
13508
  try {
@@ -13288,19 +13527,29 @@ function $forOf(iterable, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13288
13527
  if (unbounded) snapExit();
13289
13528
  }
13290
13529
  if (unbounded && n === 0) snapExit();
13530
+ if (concreteOverrun) {
13531
+ noteAbsTruncation(LOOP_TRUNCATION_LABEL);
13532
+ if (pack && unpack) unpack(confPartialPacked(pack()));
13533
+ return;
13534
+ }
13291
13535
  applyExitJoin();
13292
13536
  }
13537
+ var NAMESPACE_GLOBALS = [
13538
+ ["Math", Math],
13539
+ ["Number", Number],
13540
+ ["JSON", JSON],
13541
+ ["Object", Object],
13542
+ ["Array", Array],
13543
+ ["String", String],
13544
+ ["Date", Date],
13545
+ ["Promise", Promise],
13546
+ ["BigInt", BigInt]
13547
+ ];
13293
13548
  function namespaceNameOf(v2) {
13294
13549
  if (typeof v2 !== "object" && typeof v2 !== "function") return void 0;
13295
- if (v2 === Math) return "Math";
13296
- if (v2 === Number) return "Number";
13297
- if (v2 === JSON) return "JSON";
13298
- if (v2 === Object) return "Object";
13299
- if (v2 === Array) return "Array";
13300
- if (v2 === String) return "String";
13301
- if (v2 === Date) return "Date";
13302
- if (v2 === Promise) return "Promise";
13303
- if (v2 === BigInt) return "BigInt";
13550
+ for (const [name, host] of NAMESPACE_GLOBALS) {
13551
+ if (v2 === host) return name;
13552
+ }
13304
13553
  return void 0;
13305
13554
  }
13306
13555
  function $regex(pattern, flags = "") {
@@ -13882,7 +14131,10 @@ function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13882
14131
  if (!extJoin || !pack || !unpack) return;
13883
14132
  unpack(joinAbs(extJoin, pack()));
13884
14133
  };
13885
- for (let i = 0; i < maxIters; i++) {
14134
+ let limit = maxIters;
14135
+ let extended = false;
14136
+ let concreteExhausted = false;
14137
+ for (let i = 0; i < limit; i++) {
13886
14138
  const t = test(state);
13887
14139
  if (isDefinitelyFalse(t)) {
13888
14140
  snapCounter();
@@ -13892,6 +14144,7 @@ function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13892
14144
  }
13893
14145
  const abstractTest = !isDefinitelyTrue(t);
13894
14146
  if (abstractTest) {
14147
+ if (extended) break;
13895
14148
  snapCounter();
13896
14149
  snapExt();
13897
14150
  }
@@ -13931,21 +14184,39 @@ function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13931
14184
  }
13932
14185
  }
13933
14186
  state = next;
14187
+ if (i + 1 === limit && isDefinitelyTrue(test(state))) {
14188
+ if (limit < MAX_CONCRETE_LOOP_ITERS) {
14189
+ limit = MAX_CONCRETE_LOOP_ITERS;
14190
+ extended = true;
14191
+ } else {
14192
+ concreteExhausted = true;
14193
+ }
14194
+ }
13934
14195
  }
13935
14196
  snapCounter();
13936
14197
  snapExt();
14198
+ if (concreteExhausted) {
14199
+ noteAbsTruncation(LOOP_TRUNCATION_LABEL);
14200
+ if (extJoin && pack && unpack) unpack(confPartialPacked(joinAbs(extJoin, pack())));
14201
+ return confPartial(exitJoin ?? state);
14202
+ }
13937
14203
  applyExtJoin();
13938
14204
  return exitJoin ?? state;
13939
14205
  }
13940
14206
  function $while(init, test, step, maxIters = DEFAULT_MAX_LOOP_ITERS) {
13941
14207
  let state = init;
13942
14208
  let exitJoin;
13943
- for (let i = 0; i < maxIters; i++) {
14209
+ let limit = maxIters;
14210
+ let extended = false;
14211
+ let concreteExhausted = false;
14212
+ for (let i = 0; i < limit; i++) {
13944
14213
  const t = test(state);
13945
14214
  if (isDefinitelyFalse(t)) {
13946
14215
  return exitJoin ? joinAbs(exitJoin, state) : state;
13947
14216
  }
13948
- if (!isDefinitelyTrue(t)) {
14217
+ const abstractTest = !isDefinitelyTrue(t);
14218
+ if (abstractTest) {
14219
+ if (extended) break;
13949
14220
  exitJoin = exitJoin ? joinAbs(exitJoin, state) : state;
13950
14221
  }
13951
14222
  const next = step(state);
@@ -13958,6 +14229,18 @@ function $while(init, test, step, maxIters = DEFAULT_MAX_LOOP_ITERS) {
13958
14229
  }
13959
14230
  }
13960
14231
  state = next;
14232
+ if (i + 1 === limit && isDefinitelyTrue(test(state))) {
14233
+ if (limit < MAX_CONCRETE_LOOP_ITERS) {
14234
+ limit = MAX_CONCRETE_LOOP_ITERS;
14235
+ extended = true;
14236
+ } else {
14237
+ concreteExhausted = true;
14238
+ }
14239
+ }
14240
+ }
14241
+ if (concreteExhausted) {
14242
+ noteAbsTruncation(LOOP_TRUNCATION_LABEL);
14243
+ return confPartial(exitJoin ? joinAbs(exitJoin, state) : state);
13961
14244
  }
13962
14245
  return exitJoin ? joinAbs(exitJoin, state) : state;
13963
14246
  }
@@ -13974,13 +14257,28 @@ function $whileSeq(test, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13974
14257
  if (!exitJoin || !pack || !unpack) return;
13975
14258
  unpack(joinAbs(exitJoin, pack()));
13976
14259
  };
13977
- for (let i = 0; i < maxIters; i++) {
14260
+ let limit = maxIters;
14261
+ let extended = false;
14262
+ let concreteExhausted = false;
14263
+ const boundaryGate = (i) => {
14264
+ if (i + 1 !== limit || !isDefinitelyTrue(test())) return;
14265
+ if (limit < MAX_CONCRETE_LOOP_ITERS) {
14266
+ limit = MAX_CONCRETE_LOOP_ITERS;
14267
+ extended = true;
14268
+ } else {
14269
+ concreteExhausted = true;
14270
+ }
14271
+ };
14272
+ for (let i = 0; i < limit; i++) {
13978
14273
  const t = test();
13979
14274
  if (isDefinitelyFalse(t)) {
13980
14275
  applyExitJoin();
13981
14276
  return;
13982
14277
  }
13983
- if (!isDefinitelyTrue(t)) snapExit();
14278
+ if (!isDefinitelyTrue(t)) {
14279
+ if (extended) break;
14280
+ snapExit();
14281
+ }
13984
14282
  try {
13985
14283
  body();
13986
14284
  } catch (e) {
@@ -13988,12 +14286,21 @@ function $whileSeq(test, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
13988
14286
  applyExitJoin();
13989
14287
  return;
13990
14288
  }
13991
- if (isNudoContinue(e, opts?.label)) continue;
14289
+ if (isNudoContinue(e, opts?.label)) {
14290
+ boundaryGate(i);
14291
+ continue;
14292
+ }
13992
14293
  if (isNudoReturn(e) || isNudoThrow(e)) throw e;
13993
14294
  throw e;
13994
14295
  }
14296
+ boundaryGate(i);
13995
14297
  }
13996
14298
  snapExit();
14299
+ if (concreteExhausted) {
14300
+ noteAbsTruncation(LOOP_TRUNCATION_LABEL);
14301
+ if (exitJoin && pack && unpack) unpack(confPartialPacked(joinAbs(exitJoin, pack())));
14302
+ return;
14303
+ }
13997
14304
  applyExitJoin();
13998
14305
  }
13999
14306
  function $switch(disc, cases, dflt) {
@@ -14148,6 +14455,19 @@ function $yield(v2) {
14148
14455
  if (top) top.push(v2);
14149
14456
  return unknown;
14150
14457
  }
14458
+ function $removeNullish(a) {
14459
+ if (!a || typeof a !== "object" || !("shape" in a)) return a;
14460
+ if (definitelyNotNullishShape(a.shape)) return a;
14461
+ if (isNullishLitAbs(a)) return a;
14462
+ if (a.shape.k === "sum") {
14463
+ const members = a.shape.members;
14464
+ const kept = members.filter((m) => !isNullishLitAbs(m));
14465
+ if (kept.length === members.length) return a;
14466
+ if (kept.length === 0) return a;
14467
+ return kept.length === 1 ? kept[0] : { ...a, shape: { k: "sum", members: kept } };
14468
+ }
14469
+ return a;
14470
+ }
14151
14471
  function $nullishTest(v2) {
14152
14472
  if (definitelyNotNullishShape(v2.shape)) return boolLit(false);
14153
14473
  if (isNullishLitAbs(v2)) return boolLit(true);
@@ -14203,60 +14523,6 @@ __export(calls_exports, {
14203
14523
  setEvalCallCollector: () => setEvalCallCollector,
14204
14524
  withEvalBudgetOverride: () => withEvalBudgetOverride
14205
14525
  });
14206
-
14207
- // src/algebra/lru-map.ts
14208
- var BoundedLruMap = class {
14209
- map = /* @__PURE__ */ new Map();
14210
- max;
14211
- constructor(max) {
14212
- this.max = max;
14213
- }
14214
- get size() {
14215
- return this.map.size;
14216
- }
14217
- getMax() {
14218
- return this.max;
14219
- }
14220
- setMax(max) {
14221
- this.max = max;
14222
- this.trim();
14223
- }
14224
- has(key) {
14225
- return this.map.has(key);
14226
- }
14227
- get(key) {
14228
- const hit = this.map.get(key);
14229
- if (hit === void 0) return void 0;
14230
- this.map.delete(key);
14231
- this.map.set(key, hit);
14232
- return hit;
14233
- }
14234
- set(key, value) {
14235
- if (this.max <= 0) return;
14236
- while (this.map.size >= this.max && !this.map.has(key)) {
14237
- const oldest = this.map.keys().next().value;
14238
- if (oldest === void 0) break;
14239
- this.map.delete(oldest);
14240
- }
14241
- this.map.delete(key);
14242
- this.map.set(key, value);
14243
- }
14244
- delete(key) {
14245
- return this.map.delete(key);
14246
- }
14247
- clear() {
14248
- this.map.clear();
14249
- }
14250
- trim() {
14251
- while (this.map.size > this.max) {
14252
- const oldest = this.map.keys().next().value;
14253
- if (oldest === void 0) break;
14254
- this.map.delete(oldest);
14255
- }
14256
- }
14257
- };
14258
-
14259
- // src/algebra/exec/calls.ts
14260
14526
  var PURE_CALL_MEMO_MAX = 256;
14261
14527
  var pureCallMemo = /* @__PURE__ */ new WeakMap();
14262
14528
  function clearPureCallMemo() {
@@ -14268,14 +14534,17 @@ function joinThrowsSince(mark) {
14268
14534
  if (items.length === 1) return items[0];
14269
14535
  return items.reduce((a, b) => joinAbs(a, b));
14270
14536
  }
14271
- var evalCallCollector = null;
14272
- var evalAssignCollector = null;
14273
- function setEvalAssignCollector(collector2) {
14274
- const prev = evalAssignCollector;
14275
- evalAssignCollector = collector2;
14537
+ var evalCallCollectorSlot = createScopedSlot(() => null);
14538
+ registerCollectorScopeParticipant((body) => evalCallCollectorSlot.runScoped(body));
14539
+ var evalAssignCollectorSlot = createScopedSlot(() => null);
14540
+ registerCollectorScopeParticipant((body) => evalAssignCollectorSlot.runScoped(body));
14541
+ function setEvalAssignCollector(collector) {
14542
+ const prev = evalAssignCollectorSlot.get();
14543
+ evalAssignCollectorSlot.set(collector);
14276
14544
  return prev;
14277
14545
  }
14278
14546
  function $assignRecord(name, prev, next, line, column, conditional) {
14547
+ const evalAssignCollector = evalAssignCollectorSlot.get();
14279
14548
  if (!evalAssignCollector) return;
14280
14549
  try {
14281
14550
  evalAssignCollector({
@@ -14289,11 +14558,13 @@ function $assignRecord(name, prev, next, line, column, conditional) {
14289
14558
  } catch {
14290
14559
  }
14291
14560
  }
14292
- var bindingSink = null;
14561
+ var bindingSinkSlot = createScopedSlot(() => null);
14562
+ registerCollectorScopeParticipant((body) => bindingSinkSlot.runScoped(body));
14293
14563
  function setEvalBindingSink(sink) {
14294
- bindingSink = sink;
14564
+ bindingSinkSlot.set(sink);
14295
14565
  }
14296
14566
  function $recordBinding(name, value) {
14567
+ const bindingSink = bindingSinkSlot.get();
14297
14568
  if (bindingSink) bindingSink.set(name, value);
14298
14569
  }
14299
14570
  var GLOBAL_FNS = /* @__PURE__ */ new Set([
@@ -14352,19 +14623,20 @@ function blockHostSideEffect(fn) {
14352
14623
  return abs({ k: "unknown" }, void 0, void 0, "opaque");
14353
14624
  }
14354
14625
  function noteEvalCallRecord(r) {
14626
+ const evalCallCollector = evalCallCollectorSlot.get();
14355
14627
  if (!evalCallCollector) return;
14356
14628
  try {
14357
14629
  evalCallCollector(r);
14358
14630
  } catch {
14359
14631
  }
14360
14632
  }
14361
- function setEvalCallCollector(collector2) {
14362
- const prev = evalCallCollector;
14363
- evalCallCollector = collector2;
14633
+ function setEvalCallCollector(collector) {
14634
+ const prev = evalCallCollectorSlot.get();
14635
+ evalCallCollectorSlot.set(collector);
14364
14636
  return prev;
14365
14637
  }
14366
14638
  function getEvalCallCollector() {
14367
- return evalCallCollector;
14639
+ return evalCallCollectorSlot.get();
14368
14640
  }
14369
14641
  var MAX_EVAL_CALL_DEPTH = 64;
14370
14642
  var MAX_EVAL_TOTAL_CALLS = 2e4;
@@ -14528,6 +14800,7 @@ function $callNamed(name, fn, args, loc, argLocs) {
14528
14800
  }
14529
14801
  m.set(pk, makeAbsApplyResult(result, joinThrowsSince(throwMark)));
14530
14802
  }
14803
+ const evalCallCollector = evalCallCollectorSlot.get();
14531
14804
  if (evalCallCollector) {
14532
14805
  try {
14533
14806
  evalCallCollector({
@@ -15364,13 +15637,24 @@ function invokeArrMethod(arr, method, args) {
15364
15637
  kept.push(el2);
15365
15638
  });
15366
15639
  if (kept.length === 0) {
15367
- return abs({ k: "arr", element: unknown }, void 0, void 0, "path");
15640
+ return abs({ k: "tuple", elements: [] }, void 0, void 0, confJoin(arr.conf, "path"));
15368
15641
  }
15369
15642
  if (!anyUncertain) {
15370
15643
  return abs({ k: "tuple", elements: kept }, void 0, void 0, confJoin(arr.conf, "path"));
15371
15644
  }
15645
+ const conf = confJoin(arr.conf, "path");
15646
+ if (kept.length <= 3) {
15647
+ let acc;
15648
+ const total = 1 << kept.length;
15649
+ for (let mask = 0; mask < total; mask++) {
15650
+ const els = kept.filter((_, bit) => (mask & 1 << bit) !== 0);
15651
+ const sub2 = abs({ k: "tuple", elements: els }, void 0, void 0, conf);
15652
+ acc = acc === void 0 ? sub2 : joinAbs(acc, sub2);
15653
+ }
15654
+ return acc;
15655
+ }
15372
15656
  const el = kept.reduce((a, b) => joinAbs(a, b));
15373
- return abs({ k: "arr", element: el }, void 0, void 0, confJoin(arr.conf, "path"));
15657
+ return abs({ k: "arr", element: el }, void 0, void 0, conf);
15374
15658
  }
15375
15659
  return arr;
15376
15660
  }
@@ -15737,6 +16021,9 @@ function rtAllBindings() {
15737
16021
  return cached;
15738
16022
  }
15739
16023
 
16024
+ // src/algebra/exec/run.ts
16025
+ import { parse as babelParse2 } from "@babel/parser";
16026
+
15740
16027
  // src/algebra/abs-modules.ts
15741
16028
  function namespaceAbsOf(mod2) {
15742
16029
  const slots = {};
@@ -15922,76 +16209,87 @@ function rewriteUserImports(js) {
15922
16209
  );
15923
16210
  }
15924
16211
  function stripEffectfulTopLevel(js) {
16212
+ let body;
16213
+ try {
16214
+ body = babelParse2(js, {
16215
+ sourceType: "module",
16216
+ allowReturnOutsideFunction: true,
16217
+ attachComment: false
16218
+ }).program.body;
16219
+ } catch {
16220
+ return js;
16221
+ }
15925
16222
  const declared = /* @__PURE__ */ new Set();
15926
- for (const m of js.matchAll(/^(?:export\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/gm)) {
15927
- declared.add(m[1]);
16223
+ for (const stmt of body) collectTopLevelDeclared(stmt, declared);
16224
+ const cuts = [];
16225
+ for (const stmt of body) {
16226
+ if (isEffectfulTopLevelStmt(stmt, declared)) cuts.push([stmt.start, stmt.end]);
15928
16227
  }
15929
- for (const m of js.matchAll(/^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/gm)) {
15930
- declared.add(m[1]);
16228
+ if (cuts.length === 0) return js;
16229
+ let out = "";
16230
+ let pos = 0;
16231
+ for (const [start, end] of cuts) {
16232
+ out += js.slice(pos, start);
16233
+ pos = end;
16234
+ while (pos < js.length && js[pos] === ";") pos++;
16235
+ const nl = js.indexOf("\n", pos);
16236
+ const lineRest = js.slice(pos, nl === -1 ? js.length : nl);
16237
+ if (/^\s*$/.test(lineRest)) pos = nl === -1 ? js.length : nl + 1;
16238
+ }
16239
+ return out + js.slice(pos);
16240
+ }
16241
+ function collectTopLevelDeclared(stmt, declared) {
16242
+ const decl = stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportDefaultDeclaration" ? stmt.declaration : stmt;
16243
+ if (!decl) return;
16244
+ if ((decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") && decl.id) {
16245
+ declared.add(decl.id.name);
16246
+ return;
15931
16247
  }
15932
- for (const m of js.matchAll(/^import\s*\{([^}]+)\}\s*from/gm)) {
15933
- for (const part of m[1].split(",")) {
15934
- const local = part.split(/\s+as\s+/).pop()?.trim();
15935
- if (local) declared.add(local);
16248
+ if (decl.type === "VariableDeclaration") {
16249
+ for (const d of decl.declarations) {
16250
+ if (d.id.type === "Identifier") declared.add(d.id.name);
15936
16251
  }
16252
+ return;
15937
16253
  }
15938
- for (const m of js.matchAll(/^import\s+\*\s+as\s+([A-Za-z_$][\w$]*)/gm)) {
15939
- declared.add(m[1]);
16254
+ if (decl.type === "ImportDeclaration") {
16255
+ for (const spec of decl.specifiers) declared.add(spec.local.name);
15940
16256
  }
15941
- for (const m of js.matchAll(/^import\s+([A-Za-z_$][\w$]*)\s*,/gm)) {
15942
- declared.add(m[1]);
16257
+ }
16258
+ function isEffectfulTopLevelStmt(stmt, declared) {
16259
+ switch (stmt.type) {
16260
+ case "ExpressionStatement":
16261
+ return isEffectfulTopLevelExpr(stmt.expression, declared);
16262
+ // 源形态控制流(transpile 后不出现,兜底口径与旧正则一致;do-while 旧正则不剥,保持)
16263
+ case "IfStatement":
16264
+ case "ForStatement":
16265
+ case "ForInStatement":
16266
+ case "ForOfStatement":
16267
+ case "WhileStatement":
16268
+ return true;
16269
+ default:
16270
+ return false;
15943
16271
  }
15944
- const lines = js.split("\n");
15945
- const out = [];
15946
- let i = 0;
15947
- while (i < lines.length) {
15948
- const line = lines[i];
15949
- const isTop = /^\S/.test(line) && line.trim().length > 0;
15950
- const t = line.trim();
15951
- if (isTop) {
15952
- if (/^(console\.|fetch\s*\(|setTimeout\s*\(|setInterval\s*\()/.test(t)) {
15953
- while (i < lines.length && !lines[i].trim().endsWith(";") && !lines[i].trim().endsWith("}")) i++;
15954
- i++;
15955
- continue;
15956
- }
15957
- const namedCall = t.match(/^\$callNamed\(\s*"([^"]+)"/);
15958
- if (namedCall && !declared.has(namedCall[1])) {
15959
- while (i < lines.length && !lines[i].trim().endsWith(";") && !lines[i].trim().endsWith("}")) i++;
15960
- i++;
15961
- continue;
15962
- }
15963
- const callMatch = t.match(/^([A-Za-z_$][\w$]*)\s*\(/);
15964
- if (callMatch && !callMatch[1].startsWith("$") && callMatch[1] !== "__nudoExport" && callMatch[1] !== "__nudoExportStar" && callMatch[1] !== "__nudoRecordBinding" && callMatch[1] !== "__nudoRecordAssign" && !declared.has(callMatch[1]) && !/^(const|let|var|function|export|import|return|if|for|while|switch|try|throw|class)\b/.test(t)) {
15965
- while (i < lines.length && !lines[i].trim().endsWith(";") && !lines[i].trim().endsWith("}")) i++;
15966
- i++;
15967
- continue;
15968
- }
15969
- if (/^(if\s*\(|for\s*\(|while\s*\(|\$fork\s*\(|\$for\s*\(|\$while)/.test(t)) {
15970
- i++;
15971
- if (/^\$/.test(t)) {
15972
- let depth = (t.match(/\(/g) || []).length - (t.match(/\)/g) || []).length;
15973
- while (i < lines.length && depth > 0) {
15974
- const l = lines[i];
15975
- depth += (l.match(/\(/g) || []).length;
15976
- depth -= (l.match(/\)/g) || []).length;
15977
- i++;
15978
- }
15979
- } else {
15980
- let depth = t.includes("{") ? 1 : 0;
15981
- while (i < lines.length && depth > 0) {
15982
- const l = lines[i];
15983
- depth += (l.match(/\{/g) || []).length;
15984
- depth -= (l.match(/\}/g) || []).length;
15985
- i++;
15986
- }
15987
- }
15988
- continue;
15989
- }
15990
- }
15991
- out.push(line);
15992
- i++;
16272
+ }
16273
+ function isEffectfulTopLevelExpr(expr, declared) {
16274
+ if (expr.type !== "CallExpression") return false;
16275
+ const callee = expr.callee;
16276
+ if (callee.type === "MemberExpression" && memberChainRoot(callee) === "console") {
16277
+ return true;
15993
16278
  }
15994
- return out.join("\n");
16279
+ if (callee.type !== "Identifier") return false;
16280
+ const name = callee.name;
16281
+ if (name === "fetch" || name === "setTimeout" || name === "setInterval") return true;
16282
+ if (name === "$callNamed") {
16283
+ const first = expr.arguments[0];
16284
+ return first?.type === "StringLiteral" && !declared.has(first.value);
16285
+ }
16286
+ if (name === "$for" || name === "$fork" || name.startsWith("$while")) return true;
16287
+ return !name.startsWith("$") && name !== "__nudoExport" && name !== "__nudoExportStar" && name !== "__nudoRecordBinding" && name !== "__nudoRecordAssign" && !declared.has(name);
16288
+ }
16289
+ function memberChainRoot(member) {
16290
+ let node = member.object;
16291
+ while (node.type === "MemberExpression") node = node.object;
16292
+ return node.type === "Identifier" ? node.name : void 0;
15995
16293
  }
15996
16294
  function runtimeArgNames() {
15997
16295
  return Object.keys(rtAllBindings()).filter((k) => k.startsWith("$"));
@@ -16076,17 +16374,19 @@ function rewriteExportStatements(js) {
16076
16374
  );
16077
16375
  }
16078
16376
  var runBindings = /* @__PURE__ */ new WeakMap();
16079
- var ENV_SHADOW_SKIP = HOST_INTRINSIC_SET;
16377
+ var ENV_SHADOW_SKIP = ENV_SHADOW_SKIP_GLOBALS;
16080
16378
  function bindingsOf(run) {
16081
16379
  return runBindings.get(run);
16082
16380
  }
16083
16381
  function runTranspiled(source, opts = {}) {
16084
- enterEvalCallBudgetSession();
16085
- try {
16086
- return runTranspiledInner(source, opts);
16087
- } finally {
16088
- exitEvalCallBudgetSession();
16089
- }
16382
+ return runWithCollectorScope(() => {
16383
+ enterEvalCallBudgetSession();
16384
+ try {
16385
+ return runTranspiledInner(source, opts);
16386
+ } finally {
16387
+ exitEvalCallBudgetSession();
16388
+ }
16389
+ });
16090
16390
  }
16091
16391
  function runTranspiledInner(source, opts) {
16092
16392
  const modules = opts.modules ?? {};
@@ -16209,9 +16509,10 @@ function noteDrainedClassCollisions() {
16209
16509
  );
16210
16510
  }
16211
16511
  }
16212
- var evalFallbackCollector = null;
16213
- function setEvalFallbackCollector(collector2) {
16214
- evalFallbackCollector = collector2;
16512
+ var evalFallbackCollectorSlot = createScopedSlot(() => null);
16513
+ registerCollectorScopeParticipant((body) => evalFallbackCollectorSlot.runScoped(body));
16514
+ function setEvalFallbackCollector(collector) {
16515
+ evalFallbackCollectorSlot.set(collector);
16215
16516
  }
16216
16517
  function evalExprAbs(expr, bindings = {}) {
16217
16518
  const src = transpileExpression(expr, {});
@@ -16249,6 +16550,7 @@ function noteEvalFallback(e) {
16249
16550
  if (f.reason === "internal") _fbInternal++;
16250
16551
  else if (f.reason === "module-throw") _fbModuleThrow++;
16251
16552
  else if (f.reason.startsWith("unsupported:")) _fbUnsupported++;
16553
+ const evalFallbackCollector = evalFallbackCollectorSlot.get();
16252
16554
  if (!evalFallbackCollector) return;
16253
16555
  try {
16254
16556
  evalFallbackCollector(f);
@@ -16267,20 +16569,22 @@ function isAbsVal(v2) {
16267
16569
  return !!v2 && typeof v2 === "object" && "shape" in v2 && "conf" in v2;
16268
16570
  }
16269
16571
  function callTranspiledExportFull(exports, name, args, opts) {
16270
- enterEvalCallBudgetSession();
16271
- beginClassEpoch();
16272
- try {
16273
- return callTranspiledExportFullInner(exports, name, args, opts);
16274
- } finally {
16275
- exitEvalCallBudgetSession();
16276
- noteDrainedClassCollisions();
16277
- }
16572
+ return runWithCollectorScope(() => {
16573
+ enterEvalCallBudgetSession();
16574
+ beginClassEpoch();
16575
+ try {
16576
+ return callTranspiledExportFullInner(exports, name, args, opts);
16577
+ } finally {
16578
+ exitEvalCallBudgetSession();
16579
+ noteDrainedClassCollisions();
16580
+ }
16581
+ });
16278
16582
  }
16279
16583
  function callTranspiledExportFullInner(exports, name, args, opts) {
16280
16584
  const fn = Object.hasOwn(exports, name) ? exports[name] : void 0;
16281
16585
  if (typeof fn === "function") {
16282
16586
  const callArgs = args.map(
16283
- (a) => a && typeof a === "object" && "shape" in a ? $copy(a) : a
16587
+ (a) => a && typeof a === "object" && "shape" in a ? $copy(a) : asAbsVal(a)
16284
16588
  );
16285
16589
  return runWithLoopExits(() => {
16286
16590
  try {
@@ -16952,6 +17256,9 @@ export {
16952
17256
  litKeyString,
16953
17257
  termToString,
16954
17258
  simplifyTerm,
17259
+ createScopedSlot,
17260
+ registerCollectorScopeParticipant,
17261
+ runWithCollectorScope,
16955
17262
  TYPEOF_NAMES,
16956
17263
  primToTypeof,
16957
17264
  pTrue,
@@ -17006,6 +17313,10 @@ export {
17006
17313
  isBigPrim,
17007
17314
  isExactLit,
17008
17315
  litValue,
17316
+ absNumLit,
17317
+ absStrLit,
17318
+ allAbsStr,
17319
+ absLit,
17009
17320
  stripTypes,
17010
17321
  resetParseSourceCache,
17011
17322
  getParseSourceCacheSize,
@@ -17163,6 +17474,31 @@ export {
17163
17474
  isNudoContinue,
17164
17475
  $isBreakTo,
17165
17476
  $rethrowIfNudoReturn,
17477
+ MAX_CALL_DEPTH,
17478
+ MAX_TOTAL_CALLS,
17479
+ getAbsCallBudgetStats,
17480
+ resetAbsCallBudget,
17481
+ withFnBudgetOverride,
17482
+ stableCallId,
17483
+ truncatedAbs,
17484
+ callBudgetKey,
17485
+ setAbsTruncationCollector,
17486
+ noteAbsTruncation,
17487
+ enterCall,
17488
+ exitCall,
17489
+ MAX_EVAL_TOTAL_FORKS,
17490
+ FORK_TRUNCATION_LABEL,
17491
+ HOST_EFFECT_LABEL_PREFIX,
17492
+ PROMISE_MICRO_OVERFLOW_LABEL,
17493
+ PROMISE_MICRO_ERROR_LABEL,
17494
+ MATH_FOLD_ERROR_LABEL,
17495
+ noteHostEffectBlocked,
17496
+ noteEvalForkTruncation,
17497
+ setEvalForkBudgetLimit,
17498
+ getEvalForkBudgetLimit,
17499
+ getEvalForkCount,
17500
+ resetEvalForkBudget,
17501
+ bumpEvalForkBudget,
17166
17502
  evalMathMethod,
17167
17503
  builtinCtorAbs,
17168
17504
  builtinCtorNameOf,
@@ -17228,30 +17564,6 @@ export {
17228
17564
  regexBrandAbsFrom,
17229
17565
  tryMakeRegexAbs,
17230
17566
  evalRegExpMethod,
17231
- MAX_CALL_DEPTH,
17232
- MAX_TOTAL_CALLS,
17233
- getAbsCallBudgetStats,
17234
- resetAbsCallBudget,
17235
- withFnBudgetOverride,
17236
- stableCallId,
17237
- truncatedAbs,
17238
- callBudgetKey,
17239
- setAbsTruncationCollector,
17240
- noteAbsTruncation,
17241
- enterCall,
17242
- exitCall,
17243
- MAX_EVAL_TOTAL_FORKS,
17244
- FORK_TRUNCATION_LABEL,
17245
- HOST_EFFECT_LABEL_PREFIX,
17246
- PROMISE_MICRO_OVERFLOW_LABEL,
17247
- PROMISE_MICRO_ERROR_LABEL,
17248
- noteHostEffectBlocked,
17249
- noteEvalForkTruncation,
17250
- setEvalForkBudgetLimit,
17251
- getEvalForkBudgetLimit,
17252
- getEvalForkCount,
17253
- resetEvalForkBudget,
17254
- bumpEvalForkBudget,
17255
17567
  enterPromiseExecutorScope,
17256
17568
  leavePromiseExecutorScope,
17257
17569
  notePromiseExecutorFork,
@@ -17432,6 +17744,7 @@ export {
17432
17744
  $asyncReturn,
17433
17745
  $gen,
17434
17746
  $yield,
17747
+ $removeNullish,
17435
17748
  $nullishTest,
17436
17749
  $reStateCall,
17437
17750
  $class,