@nudojs/core 1.0.1 → 2.0.0

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.
@@ -9,6 +9,8 @@ var runtime_exports = {};
9
9
  __export(runtime_exports, {
10
10
  $add: () => $add,
11
11
  $arr: () => $arr,
12
+ $arrMutContainer: () => $arrMutContainer,
13
+ $arrRest: () => $arrRest,
12
14
  $async: () => $async,
13
15
  $asyncReturn: () => $asyncReturn,
14
16
  $await: () => $await,
@@ -17,6 +19,7 @@ __export(runtime_exports, {
17
19
  $div: () => $div,
18
20
  $elems: () => $elems,
19
21
  $eq: () => $eq,
22
+ $eqLoose: () => $eqLoose,
20
23
  $fnVal: () => $fnVal,
21
24
  $for: () => $for,
22
25
  $forIter: () => $forIter,
@@ -28,38 +31,59 @@ __export(runtime_exports, {
28
31
  $gt: () => $gt,
29
32
  $idx: () => $idx,
30
33
  $idxSet: () => $idxSet,
34
+ $isForkExit: () => $isForkExit,
31
35
  $join: () => $join,
32
36
  $le: () => $le,
33
37
  $len: () => $len,
34
38
  $lit: () => $lit,
39
+ $loopReturn: () => $loopReturn,
35
40
  $lt: () => $lt,
36
41
  $mod: () => $mod,
37
42
  $mul: () => $mul,
38
43
  $ne: () => $ne,
44
+ $neLoose: () => $neLoose,
39
45
  $neg: () => $neg,
40
46
  $not: () => $not,
47
+ $nullishTest: () => $nullishTest,
41
48
  $obj: () => $obj,
49
+ $objRest: () => $objRest,
50
+ $pushLoopExit: () => $pushLoopExit,
42
51
  $regex: () => $regex,
52
+ $rethrowIfNudoReturn: () => $rethrowIfNudoReturn,
43
53
  $set: () => $set,
44
54
  $spread: () => $spread,
45
55
  $sub: () => $sub,
46
56
  $switch: () => $switch,
47
57
  $throw: () => $throw,
58
+ $tryCurrentMark: () => $tryCurrentMark,
59
+ $tryMark: () => $tryMark,
60
+ $tryPopMark: () => $tryPopMark,
61
+ $tryTakeSince: () => $tryTakeSince,
48
62
  $typeof: () => $typeof,
49
63
  $while: () => $while,
50
64
  $whileSeq: () => $whileSeq,
51
65
  $yield: () => $yield,
52
66
  DEFAULT_MAX_LOOP_ITERS: () => DEFAULT_MAX_LOOP_ITERS,
67
+ NudoReturn: () => NudoReturn,
53
68
  NudoThrow: () => NudoThrow,
54
69
  asAbsVal: () => asAbsVal,
70
+ callAtFunctionBoundary: () => callAtFunctionBoundary,
55
71
  currentExecPhi: () => currentExecPhi,
72
+ isArrMutator: () => isArrMutator,
56
73
  isDefinitelyFalse: () => isDefinitelyFalse,
57
74
  isDefinitelyTrue: () => isDefinitelyTrue,
75
+ isNudoReturn: () => isNudoReturn,
58
76
  isNudoThrow: () => isNudoThrow,
59
77
  litTruth: () => litTruth,
60
78
  namespaceNameOf: () => namespaceNameOf,
79
+ pushLoopExit: () => pushLoopExit,
80
+ pushThrowExit: () => pushThrowExit,
81
+ runWithLoopExits: () => runWithLoopExits,
82
+ takeLoopExits: () => takeLoopExits,
83
+ takeThrowExits: () => takeThrowExits,
61
84
  withExecPhi: () => withExecPhi
62
85
  });
86
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
63
87
 
64
88
  // src/algebra/term.ts
65
89
  var lit = (value) => ({
@@ -170,11 +194,16 @@ var ptypeof = (t, type) => ({
170
194
  });
171
195
  function and(...preds) {
172
196
  const flat = [];
197
+ const pushUnique = (p) => {
198
+ if (flat.some((q) => predEquals(q, p))) return;
199
+ flat.push(p);
200
+ };
173
201
  for (const p of preds) {
174
202
  if (p.op === "true") continue;
175
203
  if (p.op === "false") return pFalse;
176
- if (p.op === "and") flat.push(...p.args);
177
- else flat.push(p);
204
+ if (p.op === "and") {
205
+ for (const q of p.args) pushUnique(q);
206
+ } else pushUnique(p);
178
207
  }
179
208
  if (flat.length === 0) return pTrue;
180
209
  if (flat.length === 1) return flat[0];
@@ -182,11 +211,16 @@ function and(...preds) {
182
211
  }
183
212
  function or(...preds) {
184
213
  const flat = [];
214
+ const pushUnique = (p) => {
215
+ if (flat.some((q) => predEquals(q, p))) return;
216
+ flat.push(p);
217
+ };
185
218
  for (const p of preds) {
186
219
  if (p.op === "false") continue;
187
220
  if (p.op === "true") return pTrue;
188
- if (p.op === "or") flat.push(...p.args);
189
- else flat.push(p);
221
+ if (p.op === "or") {
222
+ for (const q of p.args) pushUnique(q);
223
+ } else pushUnique(p);
190
224
  }
191
225
  if (flat.length === 0) return pFalse;
192
226
  if (flat.length === 1) return flat[0];
@@ -380,6 +414,25 @@ function extractBounds(phi2) {
380
414
  return { lo, hi };
381
415
  }
382
416
  function impliesViaBounds(pred, bounds) {
417
+ if (pred.op === "eq") {
418
+ const left2 = pred.a;
419
+ const right2 = pred.b;
420
+ if (right2.op !== "lit" || typeof right2.value !== "number") return void 0;
421
+ const n2 = right2.value;
422
+ if (left2.op === "var") {
423
+ return eqFromBounds(left2.id, n2, bounds);
424
+ }
425
+ if (left2.op === "app" && left2.fn === "+" && left2.args.length === 2) {
426
+ const [a, b] = left2.args;
427
+ if (a.op === "var" && b.op === "lit" && typeof b.value === "number") {
428
+ return eqFromBounds(a.id, n2 - b.value, bounds);
429
+ }
430
+ if (b.op === "var" && a.op === "lit" && typeof a.value === "number") {
431
+ return eqFromBounds(b.id, n2 - a.value, bounds);
432
+ }
433
+ }
434
+ return void 0;
435
+ }
383
436
  if (pred.op !== "gt" && pred.op !== "ge" && pred.op !== "lt" && pred.op !== "le") {
384
437
  return void 0;
385
438
  }
@@ -401,6 +454,20 @@ function impliesViaBounds(pred, bounds) {
401
454
  }
402
455
  return void 0;
403
456
  }
457
+ function eqFromBounds(id, n, bounds) {
458
+ const lo = bounds.lo.get(id);
459
+ const hi = bounds.hi.get(id);
460
+ if (!lo || !hi) return void 0;
461
+ const loCovers = lo.strict ? lo.bound <= n : lo.bound <= n;
462
+ const hiCovers = hi.strict ? hi.bound >= n : hi.bound >= n;
463
+ if (lo.strict && lo.bound >= n) return false;
464
+ if (hi.strict && hi.bound <= n) return false;
465
+ if (!lo.strict && lo.bound > n) return false;
466
+ if (!hi.strict && hi.bound < n) return false;
467
+ if (!loCovers || !hiCovers) return void 0;
468
+ if (!lo.strict && !hi.strict && lo.bound === n && hi.bound === n) return true;
469
+ return void 0;
470
+ }
404
471
  function cmpVar(id, op, n, bounds) {
405
472
  const lo = bounds.lo.get(id);
406
473
  const hi = bounds.hi.get(id);
@@ -709,173 +776,6 @@ function shapeOnlyFn(paramTypes, returnType, opts) {
709
776
  );
710
777
  }
711
778
 
712
- // src/algebra/template.ts
713
- function viewTemplateParts(parts, describe) {
714
- return parts.map((p) => {
715
- const d = describe(p);
716
- return "fixed" in d ? { fixed: d.fixed, render: d.fixed, part: p } : { fixed: void 0, render: d.render, part: p };
717
- });
718
- }
719
- function knownPrefixOfViews(views) {
720
- let s = "";
721
- for (const v2 of views) {
722
- if (v2.fixed !== void 0) s += v2.fixed;
723
- else break;
724
- }
725
- return s;
726
- }
727
- function knownSuffixOfViews(views) {
728
- let s = "";
729
- for (let i = views.length - 1; i >= 0; i--) {
730
- const v2 = views[i];
731
- if (v2.fixed !== void 0) s = v2.fixed + s;
732
- else break;
733
- }
734
- return s;
735
- }
736
- function allFixedTextOfViews(views) {
737
- return views.filter((v2) => v2.fixed !== void 0).map((v2) => v2.fixed).join("");
738
- }
739
- function fixedLengthOfViews(views) {
740
- if (views.some((v2) => v2.fixed === void 0)) return void 0;
741
- return allFixedTextOfViews(views).length;
742
- }
743
- function formatTemplateNameViews(views) {
744
- const inner = views.map((v2) => v2.fixed !== void 0 ? v2.fixed : `\${${v2.render}}`).join("");
745
- return `\`${inner}\``;
746
- }
747
- function mergeAdjacentFixedViews(views, rebuildFixed) {
748
- const out = [];
749
- for (const v2 of views) {
750
- const last = out[out.length - 1];
751
- if (last && last.fixed !== void 0 && v2.fixed !== void 0) {
752
- out[out.length - 1] = rebuildFixed(last.fixed + v2.fixed);
753
- } else {
754
- out.push(v2);
755
- }
756
- }
757
- return out;
758
- }
759
- function templateMatchesValue(value, views) {
760
- let pos = 0;
761
- for (let i = 0; i < views.length; i++) {
762
- const v2 = views[i];
763
- if (v2.fixed !== void 0) {
764
- if (!value.startsWith(v2.fixed, pos)) return false;
765
- pos += v2.fixed.length;
766
- } else {
767
- if (i === views.length - 1) return true;
768
- const next = views[i + 1];
769
- if (next?.fixed !== void 0) {
770
- const idx = value.indexOf(next.fixed, pos);
771
- if (idx === -1) return false;
772
- pos = idx;
773
- } else {
774
- return true;
775
- }
776
- }
777
- }
778
- return pos === value.length;
779
- }
780
- function decideStartsWith(prefix, search) {
781
- if (prefix.length >= search.length) return prefix.startsWith(search);
782
- if (search.startsWith(prefix)) return "unknown";
783
- return false;
784
- }
785
- function decideEndsWith(suffix, search) {
786
- if (suffix.length >= search.length) return suffix.endsWith(search);
787
- if (search.endsWith(suffix)) return "unknown";
788
- return false;
789
- }
790
- function decideIncludes(fixedText, search) {
791
- return fixedText.includes(search) ? true : "unknown";
792
- }
793
- function isStrLit(a) {
794
- return a.shape.k === "prim" && a.shape.type === "string" && a.term?.op === "lit" && typeof a.term.value === "string";
795
- }
796
- function isStrPrim2(a) {
797
- return a.shape.k === "prim" && a.shape.type === "string";
798
- }
799
- function isTemplateAbs(a) {
800
- return a.shape.k === "prim" && a.shape.type === "string" && !!a.pred && a.pred.name?.startsWith("`") === true && Array.isArray(a.pred.meta?.templateParts);
801
- }
802
- function describeAbsPart(p) {
803
- if (isStrLit(p)) return { fixed: String(litValue(p)) };
804
- return { render: p.term ? termToString(p.term) : "string" };
805
- }
806
- function absTemplateViews(parts) {
807
- return viewTemplateParts(parts, describeAbsPart);
808
- }
809
- function templatePartsOf(a) {
810
- if (isTemplateAbs(a)) {
811
- const meta = a.pred.meta;
812
- return meta.templateParts;
813
- }
814
- return [a];
815
- }
816
- function rebuildAbsFixedView(text) {
817
- return {
818
- fixed: text,
819
- render: text,
820
- part: abs({ k: "prim", type: "string" }, lit(text), void 0, "exact")
821
- };
822
- }
823
- function normalizeParts(parts) {
824
- return mergeAdjacentFixedViews(absTemplateViews(parts), rebuildAbsFixedView).map((v2) => v2.part);
825
- }
826
- function formatTemplateName(parts) {
827
- return formatTemplateNameViews(absTemplateViews(parts));
828
- }
829
- function createTemplateAbs(parts) {
830
- const normalized = normalizeParts(parts);
831
- if (normalized.length === 1) {
832
- const only = normalized[0];
833
- if (isStrLit(only)) return only;
834
- if (isStrPrim2(only) && !isTemplateAbs(only)) return only;
835
- }
836
- const name = formatTemplateName(normalized);
837
- const predObj = {
838
- op: "true",
839
- name,
840
- meta: { templateParts: normalized }
841
- };
842
- return {
843
- shape: { k: "prim", type: "string" },
844
- term: void 0,
845
- pred: predObj,
846
- conf: "path"
847
- };
848
- }
849
- function isTemplateLike(a) {
850
- return isTemplateAbs(a);
851
- }
852
- function concatString(a, b) {
853
- if (isStrLit(a) && isStrLit(b)) {
854
- return abs(
855
- { k: "prim", type: "string" },
856
- lit(String(litValue(a)) + String(litValue(b))),
857
- void 0,
858
- "exact"
859
- );
860
- }
861
- const aParts = coerceToStringParts(a);
862
- const bParts = coerceToStringParts(b);
863
- if (!aParts || !bParts) return abs({ k: "unknown" }, void 0, void 0, "partial");
864
- return createTemplateAbs([...aParts, ...bParts]);
865
- }
866
- function coerceToStringParts(a) {
867
- if (isTemplateAbs(a) || isStrPrim2(a)) return templatePartsOf(a);
868
- if (isStrLit(a)) return [a];
869
- const lv = litValue(a);
870
- if (typeof lv === "number" || typeof lv === "boolean") {
871
- return [abs({ k: "prim", type: "string" }, lit(String(lv)), void 0, "exact")];
872
- }
873
- if (a.shape.k === "prim" && a.shape.type === "number") {
874
- return [a];
875
- }
876
- return void 0;
877
- }
878
-
879
779
  // src/algebra/derivation.ts
880
780
  var collector = null;
881
781
  var nextId = 1;
@@ -1084,114 +984,903 @@ function joinValues(a, b) {
1084
984
  if (va !== void 0 && Object.is(va, vb)) return a;
1085
985
  if (a.shape.k === "prim" && b.shape.k === "prim" && a.shape.type === b.shape.type) {
1086
986
  if (va !== void 0 && vb !== void 0) {
1087
- return abs(
1088
- a.shape,
1089
- void 0,
1090
- void 0,
1091
- confJoin(a.conf, "path")
1092
- );
987
+ const nanA = typeof va === "number" && Number.isNaN(va);
988
+ const nanB = typeof vb === "number" && Number.isNaN(vb);
989
+ if (nanA || nanB) {
990
+ return abs(a.shape, void 0, void 0, confJoin(confJoin(a.conf, b.conf), "path"));
991
+ }
992
+ return makeSum(a, b);
1093
993
  }
1094
994
  return abs(a.shape, void 0, void 0, confJoin(confJoin(a.conf, b.conf), "path"));
1095
995
  }
1096
- return makeSum(a, b);
996
+ return makeSum(a, b);
997
+ }
998
+ function makeSum(a, b) {
999
+ const members = flattenSum([a, b]);
1000
+ if (members.length === 1) return members[0];
1001
+ if (members.length > 16) {
1002
+ const first = members[0];
1003
+ const samePrimLit = first.shape.k === "prim" && members.every(
1004
+ (m) => m.shape.k === "prim" && m.shape.type === first.shape.type && litValue(m) !== void 0
1005
+ );
1006
+ if (samePrimLit) {
1007
+ return abs(first.shape, void 0, void 0, "path");
1008
+ }
1009
+ }
1010
+ return {
1011
+ shape: { k: "sum", members },
1012
+ conf: confJoin(a.conf, b.conf)
1013
+ };
1014
+ }
1015
+ function flattenSum(xs) {
1016
+ const out = [];
1017
+ for (const x of xs) {
1018
+ if (x.shape.k === "sum") out.push(...x.shape.members);
1019
+ else out.push(x);
1020
+ }
1021
+ const seen = /* @__PURE__ */ new Set();
1022
+ const deduped = [];
1023
+ for (const x of out) {
1024
+ const key = absShapeKey(x);
1025
+ if (seen.has(key)) continue;
1026
+ seen.add(key);
1027
+ deduped.push(x);
1028
+ }
1029
+ return deduped;
1030
+ }
1031
+ function absShapeKey(a, seen = /* @__PURE__ */ new Set()) {
1032
+ if (seen.has(a)) return "cycle";
1033
+ seen.add(a);
1034
+ try {
1035
+ const s = a.shape;
1036
+ if (s.k === "prim") {
1037
+ const lv = litValue(a);
1038
+ if (lv !== void 0) return `prim:${s.type}:${String(lv)}`;
1039
+ const t = a.term ? termToString(a.term) : "";
1040
+ const p = a.pred && a.pred.op !== "true" ? predToString(a.pred) : "";
1041
+ return `prim:${s.type}:${t}:${p}`;
1042
+ }
1043
+ if (s.k === "never") return "never";
1044
+ if (s.k === "any") return "any";
1045
+ if (s.k === "unknown") {
1046
+ if (a.term?.op === "lit" && a.term.value === void 0) return "unknown:undefined";
1047
+ return "unknown";
1048
+ }
1049
+ if (s.k === "arr") return `arr(${absShapeKey(s.element, seen)})`;
1050
+ if (s.k === "tuple") {
1051
+ const els = s.elements.map((e) => absShapeKey(e, seen)).join(",");
1052
+ const rest = s.rest ? `...${absShapeKey(s.rest, seen)}` : "";
1053
+ return `tuple[${els}${rest}]`;
1054
+ }
1055
+ if (s.k === "brand") return `brand:${s.name}(${absShapeKey(s.shape, seen)})`;
1056
+ if (s.k === "eff") return `eff:${s.eff}<${absShapeKey(s.inner, seen)}>`;
1057
+ if (s.k === "obj") {
1058
+ const slots = Object.keys(s.slots).sort().map((k) => {
1059
+ const slot = s.slots[k];
1060
+ const flags = (slot.optional ? "?" : "") + (slot.readonly ? "r" : "");
1061
+ return `${k}${flags}:${absShapeKey(slot.value, seen)}`;
1062
+ }).join(",");
1063
+ const idx = s.index ? `idx(${absShapeKey(s.index.key, seen)}\u2192${absShapeKey(s.index.value, seen)})` : "";
1064
+ const open = s.open ? "open" : "";
1065
+ return `obj{${slots}}${idx}${open}`;
1066
+ }
1067
+ if (s.k === "fn") {
1068
+ const pts = (s.paramTypes ?? []).map((t) => absShapeKey(t, seen)).join(",");
1069
+ const ret = s.returnType ? absShapeKey(s.returnType, seen) : "?";
1070
+ const name = s.name ? `#${s.name}` : "";
1071
+ return `fn${name}(${s.params.join(",")}|${pts})=>${ret}`;
1072
+ }
1073
+ if (s.k === "sum") {
1074
+ return `sum(${s.members.map((m) => absShapeKey(m, seen)).join("|")})`;
1075
+ }
1076
+ return "other";
1077
+ } finally {
1078
+ seen.delete(a);
1079
+ }
1080
+ }
1081
+ function fnOf(params, name) {
1082
+ const shape = { k: "fn", params };
1083
+ if (name) shape.name = name;
1084
+ return { shape, conf: "exact" };
1085
+ }
1086
+ function joinFunctions(a, b) {
1087
+ const sa = a.shape;
1088
+ const sb = b.shape;
1089
+ if (sa.k !== "fn" || sb.k !== "fn") return makeSum(a, b);
1090
+ const an = sa.name;
1091
+ const bn = sb.name;
1092
+ if (an && an === bn) {
1093
+ if (sa.params.length === sb.params.length && sa.params.every((p, i) => p === sb.params[i])) {
1094
+ return a;
1095
+ }
1096
+ }
1097
+ return makeSum(a, b);
1098
+ }
1099
+ function shapeBrief(a) {
1100
+ const s = a.shape;
1101
+ switch (s.k) {
1102
+ case "never":
1103
+ return "never";
1104
+ case "unknown":
1105
+ case "any":
1106
+ return s.k;
1107
+ case "prim":
1108
+ return s.type;
1109
+ case "arr":
1110
+ return `${shapeBrief(s.element)}[]`;
1111
+ case "obj":
1112
+ return "{\u2026}";
1113
+ case "tuple":
1114
+ return `[${s.elements.length}]`;
1115
+ case "fn":
1116
+ return "fn";
1117
+ case "brand":
1118
+ return s.name;
1119
+ case "eff":
1120
+ return s.eff;
1121
+ case "sum":
1122
+ return s.members.map(shapeBrief).join("|");
1123
+ default:
1124
+ return "\xB7";
1125
+ }
1126
+ }
1127
+ function annotateJoinPath(a, b, result) {
1128
+ if (result === a || result === b) return result;
1129
+ const sa = shapeBrief(a);
1130
+ const sb = shapeBrief(b);
1131
+ if (sa === sb) {
1132
+ const extra = sameShapeJoinNote(a, b);
1133
+ if (!extra) return result;
1134
+ const note3 = `join(${sa}: ${extra})`;
1135
+ if (result.pathNote === note3) return result;
1136
+ return { ...result, pathNote: note3 };
1137
+ }
1138
+ const note2 = `join(${sa} | ${sb})`;
1139
+ if (result.pathNote === note2) return result;
1140
+ return { ...result, pathNote: note2 };
1141
+ }
1142
+ function sameShapeJoinNote(a, b) {
1143
+ if (a.shape.k === "obj" && b.shape.k === "obj") {
1144
+ const ak = Object.keys(a.shape.slots ?? {});
1145
+ const bk = Object.keys(b.shape.slots ?? {});
1146
+ const onlyA = ak.filter((k) => !bk.includes(k));
1147
+ const onlyB = bk.filter((k) => !ak.includes(k));
1148
+ if (onlyA.length === 0 && onlyB.length === 0) return void 0;
1149
+ const parts = [];
1150
+ if (onlyA.length > 0) parts.push(`+${onlyA.join(",")}`);
1151
+ if (onlyB.length > 0) parts.push(`+${onlyB.join(",")}`);
1152
+ return parts.join(" ");
1153
+ }
1154
+ if (a.shape.k === "tuple" && b.shape.k === "tuple") {
1155
+ const la = a.shape.elements.length;
1156
+ const lb = b.shape.elements.length;
1157
+ if (la === lb) return void 0;
1158
+ return `len ${la}|${lb}`;
1159
+ }
1160
+ if (a.shape.k === "brand" && b.shape.k === "brand") {
1161
+ const an = a.shape.name;
1162
+ const bn = b.shape.name;
1163
+ if (an !== bn) return `brand ${an}|${bn}`;
1164
+ const ai = a.shape.shape;
1165
+ const bi = b.shape.shape;
1166
+ return sameShapeJoinNote(ai, bi);
1167
+ }
1168
+ if (a.shape.k === "sum" && b.shape.k === "sum") {
1169
+ const am = a.shape.members.map((m) => shapeBrief(m)).sort().join(",");
1170
+ const bm = b.shape.members.map((m) => shapeBrief(m)).sort().join(",");
1171
+ if (am === bm) return void 0;
1172
+ return `sum ${am}|${bm}`;
1173
+ }
1174
+ return void 0;
1175
+ }
1176
+ function joinAbs(a, b) {
1177
+ if (a.shape.k === "never") return b;
1178
+ if (b.shape.k === "never") return a;
1179
+ if (isObj(a) && isObj(b)) {
1180
+ return annotateJoinPath(a, b, joinObjects(a, b));
1181
+ }
1182
+ if (a.shape.k === "fn" && b.shape.k === "fn") {
1183
+ return annotateJoinPath(a, b, joinFunctions(a, b));
1184
+ }
1185
+ const result = joinValues(a, b);
1186
+ noteDerivationJoin([a, b], result);
1187
+ return annotateJoinPath(a, b, result);
1188
+ }
1189
+
1190
+ // src/algebra/collections.ts
1191
+ var mapTables = /* @__PURE__ */ new WeakMap();
1192
+ var setTables = /* @__PURE__ */ new WeakMap();
1193
+ var armOverlays = [];
1194
+ function pushCollectionArm() {
1195
+ armOverlays.push(/* @__PURE__ */ new WeakMap());
1196
+ }
1197
+ function popCollectionArm() {
1198
+ return armOverlays.pop();
1199
+ }
1200
+ function cloneMapTable(t) {
1201
+ return {
1202
+ byLit: new Map(t.byLit),
1203
+ shadowValues: [...t.shadowValues],
1204
+ maybeAbsent: t.maybeAbsent ? new Set(t.maybeAbsent) : void 0
1205
+ };
1206
+ }
1207
+ function cloneSetTable(t) {
1208
+ return {
1209
+ elements: [...t.elements],
1210
+ maybeAbsent: t.maybeAbsent instanceof Set ? new Set(t.maybeAbsent) : t.maybeAbsent
1211
+ };
1212
+ }
1213
+ function setAbsentKey(t, k) {
1214
+ if (!t) return false;
1215
+ if (t.maybeAbsent === true) return true;
1216
+ return t.maybeAbsent instanceof Set && t.maybeAbsent.has(k);
1217
+ }
1218
+ function setAnyAbsent(t) {
1219
+ if (!t) return false;
1220
+ return t.maybeAbsent === true || t.maybeAbsent instanceof Set && t.maybeAbsent.size > 0;
1221
+ }
1222
+ function mergeCollectionArms(arms) {
1223
+ endCollectionFork(arms);
1224
+ }
1225
+ var forkTouchedStack = [];
1226
+ function beginCollectionFork() {
1227
+ forkTouchedStack.push(/* @__PURE__ */ new Set());
1228
+ }
1229
+ function noteCollectionWrite(id) {
1230
+ const top = forkTouchedStack[forkTouchedStack.length - 1];
1231
+ if (top) top.add(id);
1232
+ }
1233
+ function endCollectionFork(arms) {
1234
+ const touched = forkTouchedStack.pop() ?? /* @__PURE__ */ new Set();
1235
+ const live = arms.filter(Boolean);
1236
+ if (live.length === 0) return;
1237
+ const nested = armOverlays.length > 0;
1238
+ const outerArm = nested ? armOverlays[armOverlays.length - 1] : void 0;
1239
+ const commitMap = (id, merged) => {
1240
+ if (outerArm) {
1241
+ const e = outerArm.get(id) ?? {};
1242
+ outerArm.set(id, { ...e, map: merged });
1243
+ } else {
1244
+ mapTables.set(id, merged);
1245
+ }
1246
+ };
1247
+ const commitSet = (id, merged) => {
1248
+ if (outerArm) {
1249
+ const e = outerArm.get(id) ?? {};
1250
+ outerArm.set(id, { ...e, set: merged });
1251
+ } else {
1252
+ setTables.set(id, merged);
1253
+ }
1254
+ };
1255
+ for (const id of touched) {
1256
+ const armTables = [];
1257
+ const armSetTables = [];
1258
+ let anyMap = false;
1259
+ let anySet = false;
1260
+ for (const arm of live) {
1261
+ const e = arm.get(id);
1262
+ if (e?.map) {
1263
+ anyMap = true;
1264
+ armTables.push(e.map);
1265
+ } else if (anyMap || armTables.length > 0) {
1266
+ armTables.push(void 0);
1267
+ }
1268
+ if (e?.set) {
1269
+ anySet = true;
1270
+ armSetTables.push(e.set);
1271
+ } else if (anySet || armSetTables.length > 0) {
1272
+ armSetTables.push(void 0);
1273
+ }
1274
+ }
1275
+ if (anyMap || armTables.some(Boolean)) {
1276
+ const base = (nested ? mapTableForReadBase(outerArm, id) : mapTables.get(id)) ?? emptyMapTable();
1277
+ const perArm = live.map((arm) => {
1278
+ const e = arm.get(id);
1279
+ return e?.map ?? cloneMapTable(base);
1280
+ });
1281
+ const merged = { byLit: /* @__PURE__ */ new Map(), shadowValues: [], maybeAbsent: /* @__PURE__ */ new Set() };
1282
+ const keyArms = /* @__PURE__ */ new Map();
1283
+ const forcedAbsent = /* @__PURE__ */ new Set();
1284
+ for (const t of perArm) {
1285
+ for (const [k, v2] of t.byLit) {
1286
+ const prev = merged.byLit.get(k);
1287
+ merged.byLit.set(k, prev ? joinAbs(prev, v2) : v2);
1288
+ keyArms.set(k, (keyArms.get(k) ?? 0) + 1);
1289
+ }
1290
+ for (const sv of t.shadowValues) merged.shadowValues.push(sv);
1291
+ if (t.maybeAbsent) {
1292
+ for (const k of t.maybeAbsent) forcedAbsent.add(k);
1293
+ }
1294
+ }
1295
+ for (const [k, count] of keyArms) {
1296
+ if (count < perArm.length) merged.maybeAbsent.add(k);
1297
+ }
1298
+ for (const k of forcedAbsent) merged.maybeAbsent.add(k);
1299
+ if (merged.maybeAbsent.size === 0) delete merged.maybeAbsent;
1300
+ commitMap(id, merged);
1301
+ }
1302
+ if (anySet || armSetTables.some(Boolean)) {
1303
+ const base = (nested ? setTableForReadBase(outerArm, id) : setTables.get(id)) ?? emptySetTable();
1304
+ const perArm = live.map((arm) => {
1305
+ const e = arm.get(id);
1306
+ return e?.set ?? cloneSetTable(base);
1307
+ });
1308
+ const seen = /* @__PURE__ */ new Set();
1309
+ const mergedEls = [];
1310
+ const litArmCount = /* @__PURE__ */ new Map();
1311
+ const forcedAbsent = /* @__PURE__ */ new Set();
1312
+ let wholeUncertain = false;
1313
+ let hasNonLit = false;
1314
+ for (const t of perArm) {
1315
+ if (t.maybeAbsent === true) wholeUncertain = true;
1316
+ if (t.maybeAbsent instanceof Set) {
1317
+ for (const k of t.maybeAbsent) forcedAbsent.add(k);
1318
+ }
1319
+ const armLits = /* @__PURE__ */ new Set();
1320
+ for (const el of t.elements) {
1321
+ const lk = litKeyOf(el);
1322
+ if (lk !== void 0) {
1323
+ if (!seen.has(lk)) {
1324
+ seen.add(lk);
1325
+ mergedEls.push(el);
1326
+ }
1327
+ armLits.add(lk);
1328
+ } else {
1329
+ hasNonLit = true;
1330
+ mergedEls.push(el);
1331
+ }
1332
+ }
1333
+ for (const k of armLits) {
1334
+ litArmCount.set(k, (litArmCount.get(k) ?? 0) + 1);
1335
+ }
1336
+ }
1337
+ const maybeKeys = /* @__PURE__ */ new Set();
1338
+ if (wholeUncertain || hasNonLit) {
1339
+ wholeUncertain = true;
1340
+ } else {
1341
+ for (const [k, count] of litArmCount) {
1342
+ if (count < perArm.length) maybeKeys.add(k);
1343
+ }
1344
+ for (const k of forcedAbsent) maybeKeys.add(k);
1345
+ }
1346
+ commitSet(id, {
1347
+ elements: mergedEls,
1348
+ maybeAbsent: wholeUncertain ? true : maybeKeys.size > 0 ? maybeKeys : void 0
1349
+ });
1350
+ }
1351
+ }
1352
+ }
1353
+ function mapTableForReadBase(arm, id) {
1354
+ return arm.get(id)?.map ?? mapTables.get(id);
1355
+ }
1356
+ function setTableForReadBase(arm, id) {
1357
+ return arm.get(id)?.set ?? setTables.get(id);
1358
+ }
1359
+ function emptyMapTable() {
1360
+ return { byLit: /* @__PURE__ */ new Map(), shadowValues: [] };
1361
+ }
1362
+ function emptySetTable() {
1363
+ return { elements: [] };
1364
+ }
1365
+ function brandOf(name) {
1366
+ return abs(
1367
+ { k: "brand", name, shape: objOf({}) },
1368
+ void 0,
1369
+ void 0,
1370
+ "path"
1371
+ );
1372
+ }
1373
+ function litKeyOf(a) {
1374
+ if (!a) return void 0;
1375
+ if (a.term?.op === "lit") return a.term.value;
1376
+ const v2 = litValue(a);
1377
+ if (v2 === void 0 && a.term === void 0) return void 0;
1378
+ return v2;
1379
+ }
1380
+ function isMapAbs(a) {
1381
+ return !!a && a.shape.k === "brand" && a.shape.name === "Map";
1382
+ }
1383
+ function isSetAbs(a) {
1384
+ return !!a && a.shape.k === "brand" && a.shape.name === "Set";
1385
+ }
1386
+ function elementsFrom(iterable) {
1387
+ if (!iterable) return [];
1388
+ if (iterable.shape.k === "tuple") return [...iterable.shape.elements];
1389
+ if (iterable.shape.k === "arr") {
1390
+ return [iterable.shape.element];
1391
+ }
1392
+ if (iterable.shape.k === "sum") {
1393
+ return iterable.shape.members.flatMap(elementsFrom);
1394
+ }
1395
+ return [];
1396
+ }
1397
+ function makeMapAbs(iterable) {
1398
+ const m = brandOf("Map");
1399
+ const table = emptyMapTable();
1400
+ for (const el of elementsFrom(iterable)) {
1401
+ if (el.shape.k === "tuple" && el.shape.elements.length >= 2) {
1402
+ const k = litKeyOf(el.shape.elements[0]);
1403
+ const v2 = el.shape.elements[1];
1404
+ if (k !== void 0) table.byLit.set(k, v2);
1405
+ else table.shadowValues.push(v2);
1406
+ }
1407
+ }
1408
+ mapTables.set(m, table);
1409
+ return m;
1410
+ }
1411
+ function makeSetAbs(iterable) {
1412
+ const s = brandOf("Set");
1413
+ const table = emptySetTable();
1414
+ const seen = /* @__PURE__ */ new Set();
1415
+ for (const el of elementsFrom(iterable)) {
1416
+ const lk = litKeyOf(el);
1417
+ if (lk !== void 0) {
1418
+ if (seen.has(lk)) continue;
1419
+ seen.add(lk);
1420
+ }
1421
+ table.elements.push(el);
1422
+ }
1423
+ setTables.set(s, table);
1424
+ return s;
1425
+ }
1426
+ function mapTableOf(a) {
1427
+ const existing = mapTables.get(a);
1428
+ if (existing) return existing;
1429
+ const t = emptyMapTable();
1430
+ mapTables.set(a, t);
1431
+ return t;
1432
+ }
1433
+ function setTableOf(a) {
1434
+ const existing = setTables.get(a);
1435
+ if (existing) return existing;
1436
+ const t = emptySetTable();
1437
+ setTables.set(a, t);
1438
+ return t;
1439
+ }
1440
+ function mapTableForWrite(a) {
1441
+ noteCollectionWrite(a);
1442
+ if (armOverlays.length > 0) {
1443
+ let base;
1444
+ for (let i = 0; i < armOverlays.length; i++) {
1445
+ const e = armOverlays[i].get(a);
1446
+ if (e?.map) base = e.map;
1447
+ }
1448
+ if (!base) base = mapTables.get(a);
1449
+ const top = armOverlays[armOverlays.length - 1];
1450
+ let entry = top.get(a);
1451
+ if (!entry?.map) {
1452
+ const cloned = cloneMapTable(base ?? emptyMapTable());
1453
+ entry = { ...entry ?? {}, map: cloned };
1454
+ top.set(a, entry);
1455
+ return cloned;
1456
+ }
1457
+ return entry.map;
1458
+ }
1459
+ return mapTableOf(a);
1460
+ }
1461
+ function mapTableForRead(a) {
1462
+ for (let i = armOverlays.length - 1; i >= 0; i--) {
1463
+ const entry = armOverlays[i].get(a);
1464
+ if (entry?.map) return entry.map;
1465
+ }
1466
+ return mapTables.get(a);
1467
+ }
1468
+ function setTableForWrite(a) {
1469
+ noteCollectionWrite(a);
1470
+ if (armOverlays.length > 0) {
1471
+ let base;
1472
+ for (let i = 0; i < armOverlays.length; i++) {
1473
+ const e = armOverlays[i].get(a);
1474
+ if (e?.set) base = e.set;
1475
+ }
1476
+ if (!base) base = setTables.get(a);
1477
+ const top = armOverlays[armOverlays.length - 1];
1478
+ let entry = top.get(a);
1479
+ if (!entry?.set) {
1480
+ const cloned = cloneSetTable(base ?? emptySetTable());
1481
+ entry = { ...entry ?? {}, set: cloned };
1482
+ top.set(a, entry);
1483
+ return cloned;
1484
+ }
1485
+ return entry.set;
1486
+ }
1487
+ return setTableOf(a);
1488
+ }
1489
+ function setTableForRead(a) {
1490
+ for (let i = armOverlays.length - 1; i >= 0; i--) {
1491
+ const entry = armOverlays[i].get(a);
1492
+ if (entry?.set) return entry.set;
1493
+ }
1494
+ return setTables.get(a);
1495
+ }
1496
+ function mapSetEntry(mapAbs, key, value) {
1497
+ const t = mapTableForWrite(mapAbs);
1498
+ const k = litKeyOf(key);
1499
+ if (k !== void 0) t.byLit.set(k, value);
1500
+ else if (value) t.shadowValues.push(value);
1501
+ return mapAbs;
1502
+ }
1503
+ function mapDeleteEntry(mapAbs, key) {
1504
+ const t = mapTableForWrite(mapAbs);
1505
+ const k = litKeyOf(key);
1506
+ if (k !== void 0) {
1507
+ t.byLit.delete(k);
1508
+ t.maybeAbsent?.delete(k);
1509
+ } else if (t.shadowValues.length === 0 && t.byLit.size > 0) {
1510
+ t.maybeAbsent = new Set(t.byLit.keys());
1511
+ }
1512
+ return abs(
1513
+ { k: "prim", type: "boolean" },
1514
+ void 0,
1515
+ void 0,
1516
+ "path"
1517
+ );
1518
+ }
1519
+ function mapClearEntries(mapAbs) {
1520
+ const t = mapTableForWrite(mapAbs);
1521
+ t.byLit.clear();
1522
+ t.shadowValues.length = 0;
1523
+ delete t.maybeAbsent;
1524
+ return undefAbs();
1525
+ }
1526
+ function undefAbs() {
1527
+ return abs({ k: "unknown" }, { op: "lit", value: void 0 }, void 0, "exact");
1528
+ }
1529
+ function joinAll(els) {
1530
+ if (els.length === 0) return void 0;
1531
+ return els.reduce((a, b) => joinAbs(a, b));
1532
+ }
1533
+ function mapGetEntry(mapAbs, key) {
1534
+ const t = mapTableForRead(mapAbs);
1535
+ if (!t) return unknown;
1536
+ const k = litKeyOf(key);
1537
+ if (k !== void 0) {
1538
+ const v2 = t.byLit.get(k);
1539
+ const absent = t.maybeAbsent?.has(k) === true;
1540
+ if (v2 !== void 0 && !absent && t.shadowValues.length === 0) return v2;
1541
+ if (v2 !== void 0) {
1542
+ return joinAll([v2, ...t.shadowValues, undefAbs()]) ?? undefAbs();
1543
+ }
1544
+ if (t.shadowValues.length === 0) return undefAbs();
1545
+ }
1546
+ const known = [...t.byLit.values(), ...t.shadowValues];
1547
+ const joined = joinAll(known);
1548
+ if (k !== void 0 && t.shadowValues.length === 0) {
1549
+ return undefAbs();
1550
+ }
1551
+ if (joined === void 0) {
1552
+ return k !== void 0 ? undefAbs() : unknown;
1553
+ }
1554
+ return joinAbs(joined, undefAbs());
1555
+ }
1556
+ function mapHasEntry(mapAbs, key) {
1557
+ const t = mapTableForRead(mapAbs);
1558
+ if (!t) return unknown;
1559
+ const k = litKeyOf(key);
1560
+ if (k === void 0) {
1561
+ return t.byLit.size > 0 || t.shadowValues.length > 0 ? abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial") : unknown;
1562
+ }
1563
+ const hit = t.byLit.has(k);
1564
+ const maybeAbsent = t.maybeAbsent?.has(k) === true;
1565
+ if (t.shadowValues.length > 0 || maybeAbsent) {
1566
+ return abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial");
1567
+ }
1568
+ return abs(
1569
+ { k: "prim", type: "boolean" },
1570
+ { op: "lit", value: hit },
1571
+ void 0,
1572
+ "exact"
1573
+ );
1574
+ }
1575
+ function mapSizeAbs(mapAbs) {
1576
+ const t = mapTableForRead(mapAbs);
1577
+ if (!t || t.shadowValues.length > 0 || t.maybeAbsent && t.maybeAbsent.size > 0) {
1578
+ return abs({ k: "prim", type: "number" }, void 0, void 0, "path");
1579
+ }
1580
+ return abs(
1581
+ { k: "prim", type: "number" },
1582
+ { op: "lit", value: t.byLit.size },
1583
+ void 0,
1584
+ "exact"
1585
+ );
1586
+ }
1587
+ function mapValuesAbs(mapAbs) {
1588
+ const t = mapTableForRead(mapAbs);
1589
+ if (!t) return [];
1590
+ return [...t.byLit.values(), ...t.shadowValues];
1591
+ }
1592
+ function keyAbsFromLitKey(k) {
1593
+ if (k === null) {
1594
+ return abs({ k: "unknown" }, { op: "lit", value: null }, void 0, "exact");
1595
+ }
1596
+ if (k === void 0) {
1597
+ return abs({ k: "unknown" }, { op: "lit", value: void 0 }, void 0, "exact");
1598
+ }
1599
+ if (typeof k === "string") return abs({ k: "prim", type: "string" }, { op: "lit", value: k }, void 0, "exact");
1600
+ if (typeof k === "number") return abs({ k: "prim", type: "number" }, { op: "lit", value: k }, void 0, "exact");
1601
+ return abs({ k: "prim", type: "boolean" }, { op: "lit", value: k }, void 0, "exact");
1602
+ }
1603
+ function mapEntriesAbs(mapAbs) {
1604
+ const t = mapTableForRead(mapAbs);
1605
+ if (!t) return [];
1606
+ const entries = [];
1607
+ for (const [k, v2] of t.byLit) {
1608
+ entries.push(
1609
+ abs(
1610
+ { k: "tuple", elements: [keyAbsFromLitKey(k), v2] },
1611
+ void 0,
1612
+ void 0,
1613
+ confJoin(v2.conf, "exact")
1614
+ )
1615
+ );
1616
+ }
1617
+ const unkKey = abs({ k: "unknown" }, void 0, void 0, "partial");
1618
+ for (const v2 of t.shadowValues) {
1619
+ entries.push(
1620
+ abs(
1621
+ { k: "tuple", elements: [unkKey, v2] },
1622
+ void 0,
1623
+ void 0,
1624
+ "partial"
1625
+ )
1626
+ );
1627
+ }
1628
+ return entries;
1629
+ }
1630
+ function setAddEntry(setAbs, value) {
1631
+ const t = setTableForWrite(setAbs);
1632
+ const lk = litKeyOf(value);
1633
+ if (lk !== void 0 && t.elements.some((el) => litKeyOf(el) === lk)) {
1634
+ return setAbs;
1635
+ }
1636
+ t.elements.push(value);
1637
+ return setAbs;
1638
+ }
1639
+ function setDeleteEntry(setAbs, value) {
1640
+ const t = setTableForWrite(setAbs);
1641
+ const lk = litKeyOf(value);
1642
+ if (lk !== void 0) {
1643
+ t.elements = t.elements.filter((el) => litKeyOf(el) !== lk);
1644
+ const hasUnknown = t.elements.some((el) => litKeyOf(el) === void 0);
1645
+ if (hasUnknown) t.maybeAbsent = true;
1646
+ else delete t.maybeAbsent;
1647
+ } else {
1648
+ t.maybeAbsent = true;
1649
+ }
1650
+ return abs({ k: "prim", type: "boolean" }, void 0, void 0, "path");
1651
+ }
1652
+ function setClearEntries(setAbs) {
1653
+ const t = setTableForWrite(setAbs);
1654
+ t.elements = [];
1655
+ delete t.maybeAbsent;
1656
+ return undefAbs();
1657
+ }
1658
+ function setHasEntry(setAbs, value) {
1659
+ const t = setTableForRead(setAbs);
1660
+ if (!t) return unknown;
1661
+ const k = litKeyOf(value);
1662
+ if (k !== void 0) {
1663
+ const hit = t.elements.some((el) => litKeyOf(el) === k);
1664
+ if (setAbsentKey(t, k)) {
1665
+ return abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial");
1666
+ }
1667
+ return abs(
1668
+ { k: "prim", type: "boolean" },
1669
+ { op: "lit", value: hit },
1670
+ void 0,
1671
+ "exact"
1672
+ );
1673
+ }
1674
+ return abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial");
1675
+ }
1676
+ function setSizeAbs(setAbs) {
1677
+ const t = setTableForRead(setAbs);
1678
+ if (!t || setAnyAbsent(t)) {
1679
+ return abs({ k: "prim", type: "number" }, void 0, void 0, "path");
1680
+ }
1681
+ return abs(
1682
+ { k: "prim", type: "number" },
1683
+ { op: "lit", value: t.elements.length },
1684
+ void 0,
1685
+ "exact"
1686
+ );
1687
+ }
1688
+ function setElementsAbs(setAbs) {
1689
+ const t = setTableForRead(setAbs);
1690
+ return t ? [...t.elements] : [];
1691
+ }
1692
+ function collectionExactLen(c) {
1693
+ if (isSetAbs(c)) {
1694
+ const t = setTableForRead(c);
1695
+ if (!t) return void 0;
1696
+ if (t.maybeAbsent === true || t.maybeAbsent instanceof Set && t.maybeAbsent.size > 0) {
1697
+ return void 0;
1698
+ }
1699
+ return t.elements.length;
1700
+ }
1701
+ if (isMapAbs(c)) {
1702
+ const t = mapTableForRead(c);
1703
+ if (!t) return void 0;
1704
+ if (t.shadowValues.length > 0 || t.maybeAbsent && t.maybeAbsent.size > 0) {
1705
+ return void 0;
1706
+ }
1707
+ return t.byLit.size;
1708
+ }
1709
+ return void 0;
1710
+ }
1711
+ function collectionElementJoin(c) {
1712
+ const els = isSetAbs(c) ? setElementsAbs(c) : isMapAbs(c) ? mapEntriesAbs(c) : [];
1713
+ if (els.length === 0) return unknown;
1714
+ return els.reduce((a, b) => joinAbs(a, b));
1715
+ }
1716
+ function clearCollectionTables() {
1717
+ }
1718
+
1719
+ // src/algebra/template.ts
1720
+ function viewTemplateParts(parts, describe) {
1721
+ return parts.map((p) => {
1722
+ const d = describe(p);
1723
+ return "fixed" in d ? { fixed: d.fixed, render: d.fixed, part: p } : { fixed: void 0, render: d.render, part: p };
1724
+ });
1725
+ }
1726
+ function knownPrefixOfViews(views) {
1727
+ let s = "";
1728
+ for (const v2 of views) {
1729
+ if (v2.fixed !== void 0) s += v2.fixed;
1730
+ else break;
1731
+ }
1732
+ return s;
1733
+ }
1734
+ function knownSuffixOfViews(views) {
1735
+ let s = "";
1736
+ for (let i = views.length - 1; i >= 0; i--) {
1737
+ const v2 = views[i];
1738
+ if (v2.fixed !== void 0) s = v2.fixed + s;
1739
+ else break;
1740
+ }
1741
+ return s;
1742
+ }
1743
+ function allFixedTextOfViews(views) {
1744
+ return views.filter((v2) => v2.fixed !== void 0).map((v2) => v2.fixed).join("");
1745
+ }
1746
+ function fixedLengthOfViews(views) {
1747
+ if (views.some((v2) => v2.fixed === void 0)) return void 0;
1748
+ return allFixedTextOfViews(views).length;
1749
+ }
1750
+ function formatTemplateNameViews(views) {
1751
+ const inner = views.map((v2) => v2.fixed !== void 0 ? v2.fixed : `\${${v2.render}}`).join("");
1752
+ return `\`${inner}\``;
1753
+ }
1754
+ function mergeAdjacentFixedViews(views, rebuildFixed) {
1755
+ const out = [];
1756
+ for (const v2 of views) {
1757
+ const last = out[out.length - 1];
1758
+ if (last && last.fixed !== void 0 && v2.fixed !== void 0) {
1759
+ out[out.length - 1] = rebuildFixed(last.fixed + v2.fixed);
1760
+ } else {
1761
+ out.push(v2);
1762
+ }
1763
+ }
1764
+ return out;
1765
+ }
1766
+ function templateMatchesValue(value, views) {
1767
+ let pos = 0;
1768
+ for (let i = 0; i < views.length; i++) {
1769
+ const v2 = views[i];
1770
+ if (v2.fixed !== void 0) {
1771
+ if (!value.startsWith(v2.fixed, pos)) return false;
1772
+ pos += v2.fixed.length;
1773
+ } else {
1774
+ if (i === views.length - 1) return true;
1775
+ const next = views[i + 1];
1776
+ if (next?.fixed !== void 0) {
1777
+ const idx = value.indexOf(next.fixed, pos);
1778
+ if (idx === -1) return false;
1779
+ pos = idx;
1780
+ } else {
1781
+ return true;
1782
+ }
1783
+ }
1784
+ }
1785
+ return pos === value.length;
1786
+ }
1787
+ function decideStartsWith(prefix, search) {
1788
+ if (prefix.length >= search.length) return prefix.startsWith(search);
1789
+ if (search.startsWith(prefix)) return "unknown";
1790
+ return false;
1791
+ }
1792
+ function decideEndsWith(suffix, search) {
1793
+ if (suffix.length >= search.length) return suffix.endsWith(search);
1794
+ if (search.endsWith(suffix)) return "unknown";
1795
+ return false;
1796
+ }
1797
+ function decideIncludes(fixedText, search) {
1798
+ return fixedText.includes(search) ? true : "unknown";
1799
+ }
1800
+ function isStrLit(a) {
1801
+ return a.shape.k === "prim" && a.shape.type === "string" && a.term?.op === "lit" && typeof a.term.value === "string";
1802
+ }
1803
+ function isStrPrim2(a) {
1804
+ return a.shape.k === "prim" && a.shape.type === "string";
1805
+ }
1806
+ function isTemplateAbs(a) {
1807
+ return a.shape.k === "prim" && a.shape.type === "string" && !!a.pred && a.pred.name?.startsWith("`") === true && Array.isArray(a.pred.meta?.templateParts);
1808
+ }
1809
+ function describeAbsPart(p) {
1810
+ if (isStrLit(p)) return { fixed: String(litValue(p)) };
1811
+ return { render: p.term ? termToString(p.term) : "string" };
1812
+ }
1813
+ function absTemplateViews(parts) {
1814
+ return viewTemplateParts(parts, describeAbsPart);
1815
+ }
1816
+ function templatePartsOf(a) {
1817
+ if (isTemplateAbs(a)) {
1818
+ const meta = a.pred.meta;
1819
+ return meta.templateParts;
1820
+ }
1821
+ return [a];
1097
1822
  }
1098
- function makeSum(a, b) {
1099
- const members = flattenSum([a, b]);
1100
- if (members.length === 1) return members[0];
1823
+ function rebuildAbsFixedView(text) {
1101
1824
  return {
1102
- shape: { k: "sum", members },
1103
- conf: confJoin(a.conf, b.conf)
1825
+ fixed: text,
1826
+ render: text,
1827
+ part: abs({ k: "prim", type: "string" }, lit(text), void 0, "exact")
1104
1828
  };
1105
1829
  }
1106
- function flattenSum(xs) {
1107
- const out = [];
1108
- for (const x of xs) {
1109
- if (x.shape.k === "sum") out.push(...x.shape.members);
1110
- else out.push(x);
1111
- }
1112
- const seen = /* @__PURE__ */ new Set();
1113
- const deduped = [];
1114
- for (const x of out) {
1115
- const key = absShapeKey(x);
1116
- if (seen.has(key)) continue;
1117
- seen.add(key);
1118
- deduped.push(x);
1119
- }
1120
- return deduped;
1830
+ function normalizeParts(parts) {
1831
+ return mergeAdjacentFixedViews(absTemplateViews(parts), rebuildAbsFixedView).map((v2) => v2.part);
1121
1832
  }
1122
- function absShapeKey(a, seen = /* @__PURE__ */ new Set()) {
1123
- if (seen.has(a)) return "cycle";
1124
- seen.add(a);
1125
- try {
1126
- const s = a.shape;
1127
- if (s.k === "prim") {
1128
- const lv = litValue(a);
1129
- if (lv !== void 0) return `prim:${s.type}:${String(lv)}`;
1130
- const t = a.term ? termToString(a.term) : "";
1131
- const p = a.pred && a.pred.op !== "true" ? predToString(a.pred) : "";
1132
- return `prim:${s.type}:${t}:${p}`;
1133
- }
1134
- if (s.k === "never") return "never";
1135
- if (s.k === "any") return "any";
1136
- if (s.k === "unknown") return "unknown";
1137
- if (s.k === "arr") return `arr(${absShapeKey(s.element, seen)})`;
1138
- if (s.k === "tuple") {
1139
- const els = s.elements.map((e) => absShapeKey(e, seen)).join(",");
1140
- const rest = s.rest ? `...${absShapeKey(s.rest, seen)}` : "";
1141
- return `tuple[${els}${rest}]`;
1142
- }
1143
- if (s.k === "brand") return `brand:${s.name}(${absShapeKey(s.shape, seen)})`;
1144
- if (s.k === "eff") return `eff:${s.eff}<${absShapeKey(s.inner, seen)}>`;
1145
- if (s.k === "obj") {
1146
- const slots = Object.keys(s.slots).sort().map((k) => {
1147
- const slot = s.slots[k];
1148
- const flags = (slot.optional ? "?" : "") + (slot.readonly ? "r" : "");
1149
- return `${k}${flags}:${absShapeKey(slot.value, seen)}`;
1150
- }).join(",");
1151
- const idx = s.index ? `idx(${absShapeKey(s.index.key, seen)}\u2192${absShapeKey(s.index.value, seen)})` : "";
1152
- const open = s.open ? "open" : "";
1153
- return `obj{${slots}}${idx}${open}`;
1154
- }
1155
- if (s.k === "fn") {
1156
- const pts = (s.paramTypes ?? []).map((t) => absShapeKey(t, seen)).join(",");
1157
- const ret = s.returnType ? absShapeKey(s.returnType, seen) : "?";
1158
- const name = s.name ? `#${s.name}` : "";
1159
- return `fn${name}(${s.params.join(",")}|${pts})=>${ret}`;
1160
- }
1161
- if (s.k === "sum") {
1162
- return `sum(${s.members.map((m) => absShapeKey(m, seen)).join("|")})`;
1163
- }
1164
- return "other";
1165
- } finally {
1166
- seen.delete(a);
1833
+ function formatTemplateName(parts) {
1834
+ return formatTemplateNameViews(absTemplateViews(parts));
1835
+ }
1836
+ function createTemplateAbs(parts) {
1837
+ const normalized = normalizeParts(parts);
1838
+ if (normalized.length === 1) {
1839
+ const only = normalized[0];
1840
+ if (isStrLit(only)) return only;
1841
+ if (isStrPrim2(only) && !isTemplateAbs(only)) return only;
1167
1842
  }
1843
+ const name = formatTemplateName(normalized);
1844
+ const predObj = {
1845
+ op: "true",
1846
+ name,
1847
+ meta: { templateParts: normalized }
1848
+ };
1849
+ return {
1850
+ shape: { k: "prim", type: "string" },
1851
+ term: void 0,
1852
+ pred: predObj,
1853
+ conf: "path"
1854
+ };
1168
1855
  }
1169
- function fnOf(params, name) {
1170
- const shape = { k: "fn", params };
1171
- if (name) shape.name = name;
1172
- return { shape, conf: "exact" };
1856
+ function isTemplateLike(a) {
1857
+ return isTemplateAbs(a);
1173
1858
  }
1174
- function joinFunctions(a, b) {
1175
- const sa = a.shape;
1176
- const sb = b.shape;
1177
- if (sa.k !== "fn" || sb.k !== "fn") return makeSum(a, b);
1178
- const an = sa.name;
1179
- const bn = sb.name;
1180
- if (an && an === bn) {
1181
- if (sa.params.length === sb.params.length && sa.params.every((p, i) => p === sb.params[i])) {
1182
- return a;
1183
- }
1859
+ function concatString(a, b) {
1860
+ if (isStrLit(a) && isStrLit(b)) {
1861
+ return abs(
1862
+ { k: "prim", type: "string" },
1863
+ lit(String(litValue(a)) + String(litValue(b))),
1864
+ void 0,
1865
+ "exact"
1866
+ );
1184
1867
  }
1185
- return makeSum(a, b);
1868
+ const aParts = coerceToStringParts(a);
1869
+ const bParts = coerceToStringParts(b);
1870
+ if (!aParts || !bParts) return abs({ k: "unknown" }, void 0, void 0, "partial");
1871
+ return createTemplateAbs([...aParts, ...bParts]);
1186
1872
  }
1187
- function joinAbs(a, b) {
1188
- if (a.shape.k === "never") return b;
1189
- if (b.shape.k === "never") return a;
1190
- if (isObj(a) && isObj(b)) return joinObjects(a, b);
1191
- if (a.shape.k === "fn" && b.shape.k === "fn") return joinFunctions(a, b);
1192
- const result = joinValues(a, b);
1193
- noteDerivationJoin([a, b], result);
1194
- return result;
1873
+ function coerceToStringParts(a) {
1874
+ if (isTemplateAbs(a) || isStrPrim2(a)) return templatePartsOf(a);
1875
+ if (isStrLit(a)) return [a];
1876
+ const lv = litValue(a);
1877
+ if (typeof lv === "number" || typeof lv === "boolean") {
1878
+ return [abs({ k: "prim", type: "string" }, lit(String(lv)), void 0, "exact")];
1879
+ }
1880
+ if (a.shape.k === "prim" && a.shape.type === "number") {
1881
+ return [a];
1882
+ }
1883
+ return void 0;
1195
1884
  }
1196
1885
 
1197
1886
  // src/algebra/arithmetic.ts
@@ -1877,9 +2566,9 @@ function definitelyNotNullishShape(s) {
1877
2566
  }
1878
2567
  }
1879
2568
  function isNullishLitAbs(a) {
1880
- const v2 = litValue(a);
1881
- if (v2 === null || v2 === void 0) return true;
1882
- return false;
2569
+ const t = a.term;
2570
+ if (!t || t.op !== "lit") return false;
2571
+ return t.value === null || t.value === void 0;
1883
2572
  }
1884
2573
  function strictEqAbs(a, b) {
1885
2574
  const va = litValue(a);
@@ -1894,6 +2583,26 @@ function strictEqAbs(a, b) {
1894
2583
  }
1895
2584
  return void 0;
1896
2585
  }
2586
+ function abstractEq(x, y) {
2587
+ if (x === y) return true;
2588
+ if (x === null && y === void 0) return true;
2589
+ if (x === void 0 && y === null) return true;
2590
+ if (typeof x === "number" && Number.isNaN(x)) return false;
2591
+ if (typeof y === "number" && Number.isNaN(y)) return false;
2592
+ if (typeof x === "boolean") return abstractEq(x ? 1 : 0, y);
2593
+ if (typeof y === "boolean") return abstractEq(x, y ? 1 : 0);
2594
+ if (typeof x === "number" && typeof y === "string") return x === Number(y);
2595
+ if (typeof x === "string" && typeof y === "number") return Number(x) === y;
2596
+ return false;
2597
+ }
2598
+ function looseEqAbs(a, b) {
2599
+ const ta = a.term;
2600
+ const tb = b.term;
2601
+ if (ta?.op === "lit" && tb?.op === "lit") {
2602
+ return abstractEq(ta.value, tb.value);
2603
+ }
2604
+ return strictEqAbs(a, b);
2605
+ }
1897
2606
 
1898
2607
  // src/algebra/containers.ts
1899
2608
  var TUPLE_LITERAL_CAP = 8;
@@ -2115,6 +2824,13 @@ function leqWithPred(src, tgt, phi2, env, depth) {
2115
2824
  const tv = litValue(tgt);
2116
2825
  if (sv !== void 0 && tv !== void 0) {
2117
2826
  if (sv === tv) return ok();
2827
+ if (tgt.shape.k === "prim") {
2828
+ return fail(`lit ${String(sv)} \u22AD lit ${String(tv)}`);
2829
+ }
2830
+ } else if (tv !== void 0 && sv === void 0) {
2831
+ if (tgt.shape.k === "prim") {
2832
+ return fail(`non-lit prim \u22AD lit ${String(tv)}`);
2833
+ }
2118
2834
  }
2119
2835
  const shapeR = leqShape(src, tgt, phi2, env, depth);
2120
2836
  if (!shapeR.ok) return shapeR;
@@ -2215,6 +2931,11 @@ function leqShape(src, tgt, phi2, env, depth) {
2215
2931
  if (srcSlot.optional && !slot.optional) {
2216
2932
  return fail(`slot ${key}: optional \u22AD required`);
2217
2933
  }
2934
+ const ssv = litValue(srcSlot.value);
2935
+ const stv = litValue(slot.value);
2936
+ if (ssv !== void 0 && stv !== void 0 && primOf(srcSlot.value) !== void 0 && primOf(srcSlot.value) === primOf(slot.value)) {
2937
+ continue;
2938
+ }
2218
2939
  const r = leqWithPred(srcSlot.value, slot.value, phi2, env, depth + 1);
2219
2940
  if (!r.ok) return fail(`slot ${key}: ${r.reason}`);
2220
2941
  }
@@ -2481,6 +3202,10 @@ function evalArrayStatic(name, args) {
2481
3202
  return abs({ k: "arr", element: a0 ?? unknown }, void 0, void 0, "path");
2482
3203
  case "from": {
2483
3204
  if (!a0) return unknown;
3205
+ if (isSetAbs(a0) || isMapAbs(a0)) {
3206
+ const el = collectionElementJoin(a0);
3207
+ return abs({ k: "arr", element: el }, void 0, void 0, "path");
3208
+ }
2484
3209
  const k = a0.shape.k;
2485
3210
  if (k === "arr") return a0;
2486
3211
  if (k === "tuple") {
@@ -2599,6 +3324,35 @@ function evalNamespaceCall(ns, method, args) {
2599
3324
  return void 0;
2600
3325
  }
2601
3326
  }
3327
+ var ERROR_CTOR_NAMES = /* @__PURE__ */ new Set([
3328
+ "Error",
3329
+ "TypeError",
3330
+ "RangeError",
3331
+ "SyntaxError",
3332
+ "ReferenceError",
3333
+ "URIError",
3334
+ "EvalError",
3335
+ "AggregateError"
3336
+ ]);
3337
+ function isErrorCtorName(name) {
3338
+ return !!name && ERROR_CTOR_NAMES.has(name);
3339
+ }
3340
+ function errorBrandAbs(name, messageArg) {
3341
+ const message = messageArg ?? strPrim();
3342
+ return abs(
3343
+ {
3344
+ k: "brand",
3345
+ name,
3346
+ shape: objOf({
3347
+ name: { value: strLit(name) },
3348
+ message: { value: message }
3349
+ })
3350
+ },
3351
+ void 0,
3352
+ void 0,
3353
+ "path"
3354
+ );
3355
+ }
2602
3356
  function evalBuiltinNew(className, args) {
2603
3357
  switch (className) {
2604
3358
  case "Date":
@@ -2608,20 +3362,13 @@ function evalBuiltinNew(className, args) {
2608
3362
  case "Promise":
2609
3363
  return evalPromiseCtor(args);
2610
3364
  case "Map":
2611
- return abs(
2612
- { k: "brand", name: "Map", shape: abs({ k: "obj", slots: {} }, void 0, void 0, "exact") },
2613
- void 0,
2614
- void 0,
2615
- "path"
2616
- );
3365
+ return makeMapAbs(args[0]);
2617
3366
  case "Set":
2618
- return abs(
2619
- { k: "brand", name: "Set", shape: abs({ k: "obj", slots: {} }, void 0, void 0, "exact") },
2620
- void 0,
2621
- void 0,
2622
- "path"
2623
- );
3367
+ return makeSetAbs(args[0]);
2624
3368
  default:
3369
+ if (isErrorCtorName(className)) {
3370
+ return errorBrandAbs(className, args[0]);
3371
+ }
2625
3372
  return void 0;
2626
3373
  }
2627
3374
  }
@@ -2631,13 +3378,17 @@ function evalBuiltinInstanceMethod(brandName, method, recv, args) {
2631
3378
  if (brandName === "Map") {
2632
3379
  switch (method) {
2633
3380
  case "get":
2634
- return unknown;
3381
+ return mapGetEntry(recv, args[0]);
2635
3382
  case "has":
2636
- return boolPrim();
3383
+ return mapHasEntry(recv, args[0]);
2637
3384
  case "set":
2638
- return recv;
3385
+ return mapSetEntry(recv, args[0], args[1] ?? unknown);
3386
+ case "delete":
3387
+ return mapDeleteEntry(recv, args[0]);
3388
+ case "clear":
3389
+ return mapClearEntries(recv);
2639
3390
  case "size":
2640
- return numPrim("path");
3391
+ return mapSizeAbs(recv);
2641
3392
  default:
2642
3393
  return void 0;
2643
3394
  }
@@ -2645,11 +3396,15 @@ function evalBuiltinInstanceMethod(brandName, method, recv, args) {
2645
3396
  if (brandName === "Set") {
2646
3397
  switch (method) {
2647
3398
  case "has":
2648
- return boolPrim();
3399
+ return setHasEntry(recv, args[0]);
2649
3400
  case "add":
2650
- return recv;
3401
+ return setAddEntry(recv, args[0] ?? unknown);
3402
+ case "delete":
3403
+ return setDeleteEntry(recv, args[0]);
3404
+ case "clear":
3405
+ return setClearEntries(recv);
2651
3406
  case "size":
2652
- return numPrim("path");
3407
+ return setSizeAbs(recv);
2653
3408
  default:
2654
3409
  return void 0;
2655
3410
  }
@@ -2663,11 +3418,15 @@ __export(calls_exports, {
2663
3418
  $callNamed: () => $callNamed,
2664
3419
  getAbsOrigin: () => getAbsOrigin,
2665
3420
  getBCallCollector: () => getBCallCollector,
3421
+ isEvalMissingSlotEnabled: () => isEvalMissingSlotEnabled,
2666
3422
  noteMemberDispatchMiss: () => noteMemberDispatchMiss,
3423
+ noteObjSlotMissing: () => noteObjSlotMissing,
2667
3424
  notePrimMemberMissing: () => notePrimMemberMissing,
2668
3425
  noteUnknownMemberMissing: () => noteUnknownMemberMissing,
2669
3426
  recordMemberDiag: () => recordMemberDiag,
3427
+ runWithEvalMissingSlot: () => runWithEvalMissingSlot,
2670
3428
  setBCallCollector: () => setBCallCollector,
3429
+ setEvalMissingSlotEnabled: () => setEvalMissingSlotEnabled,
2671
3430
  setMemberDiagCollector: () => setMemberDiagCollector,
2672
3431
  tagAbsOrigin: () => tagAbsOrigin
2673
3432
  });
@@ -3394,6 +4153,19 @@ function setApplyCallbackHost(fn) {
3394
4153
  applyCallbackHost = fn;
3395
4154
  }
3396
4155
  function applyCallbackAbs(cb, args, env, phi2, budget) {
4156
+ const sumIdx = args.findIndex(
4157
+ (a) => a && typeof a === "object" && "shape" in a && a.shape.k === "sum"
4158
+ );
4159
+ if (sumIdx >= 0) {
4160
+ const members = args[sumIdx].shape.members;
4161
+ let acc;
4162
+ for (const m of members) {
4163
+ const nextArgs = args.map((a, i) => i === sumIdx ? m : a);
4164
+ const r = applyCallbackAbs(cb, nextArgs, env, phi2, budget);
4165
+ acc = acc === void 0 ? r : joinAbs(acc, r);
4166
+ }
4167
+ return acc ?? unknown;
4168
+ }
3397
4169
  if (!applyCallbackHost) {
3398
4170
  if (cb && typeof cb === "object" && "shape" in cb) {
3399
4171
  const a = cb;
@@ -3405,7 +4177,7 @@ function applyCallbackAbs(cb, args, env, phi2, budget) {
3405
4177
  }
3406
4178
  return applyCallbackHost(cb, args, env, phi2, budget);
3407
4179
  }
3408
- function undefAbs() {
4180
+ function undefAbs2() {
3409
4181
  return abs(
3410
4182
  { k: "unknown" },
3411
4183
  { op: "lit", value: void 0 },
@@ -3585,6 +4357,7 @@ function getAbsProperty(recv, name) {
3585
4357
  }
3586
4358
 
3587
4359
  // src/algebra/exec/member-diag.ts
4360
+ import { AsyncLocalStorage } from "async_hooks";
3588
4361
  var memberDiagCollector = null;
3589
4362
  var callLocStack = [];
3590
4363
  var absOrigins = /* @__PURE__ */ new WeakMap();
@@ -3684,7 +4457,41 @@ function noteUnknownMemberMissing(recv, name, kind, loc) {
3684
4457
  }
3685
4458
  function noteMemberDispatchMiss(recv, name, kind, loc) {
3686
4459
  if (notePrimMemberMissing(recv, name, kind, loc)) return;
3687
- noteUnknownMemberMissing(recv, name, kind, loc);
4460
+ if (noteUnknownMemberMissing(recv, name, kind, loc)) return;
4461
+ noteObjSlotMissing(recv, name, loc);
4462
+ }
4463
+ var evalMissingSlotAls = new AsyncLocalStorage();
4464
+ var evalMissingSlotFallback = false;
4465
+ function setEvalMissingSlotEnabled(enabled) {
4466
+ evalMissingSlotFallback = enabled;
4467
+ evalMissingSlotAls.enterWith(enabled);
4468
+ }
4469
+ function isEvalMissingSlotEnabled() {
4470
+ return evalMissingSlotAls.getStore() ?? evalMissingSlotFallback;
4471
+ }
4472
+ function runWithEvalMissingSlot(enabled, body) {
4473
+ return evalMissingSlotAls.run(enabled, body);
4474
+ }
4475
+ function noteObjSlotMissing(recv, name, loc) {
4476
+ if (!isEvalMissingSlotEnabled()) return false;
4477
+ const shape = recv?.shape;
4478
+ if (!shape || shape.k !== "obj") return false;
4479
+ const obj2 = shape;
4480
+ if (obj2.open) return false;
4481
+ if (obj2.slots && name in obj2.slots) return false;
4482
+ const conf = recv?.conf;
4483
+ if (conf === "opaque" || conf === "widened") return false;
4484
+ const origin = getAbsOrigin(recv);
4485
+ recordMemberDiag({
4486
+ kind: "property",
4487
+ name,
4488
+ receiver: "object",
4489
+ code: "nudo:missing-slot",
4490
+ line: loc?.[0],
4491
+ column: loc?.[1],
4492
+ ...origin ? { origin } : {}
4493
+ });
4494
+ return true;
3688
4495
  }
3689
4496
 
3690
4497
  // src/algebra/exec/class-registry.ts
@@ -3809,6 +4616,28 @@ function withVar(env, name, value) {
3809
4616
  vars.set(name, value);
3810
4617
  return { vars, fns: env.fns, classes: env.classes, hofCollect: env.hofCollect };
3811
4618
  }
4619
+ function joinEnvs(a, b, base) {
4620
+ const vars = new Map(base.vars);
4621
+ const keys = /* @__PURE__ */ new Set([...a.vars.keys(), ...b.vars.keys()]);
4622
+ for (const k of keys) {
4623
+ const va = a.vars.get(k);
4624
+ const vb = b.vars.get(k);
4625
+ const baseV = base.vars.get(k);
4626
+ if (va !== void 0 && vb !== void 0) {
4627
+ vars.set(k, va === vb ? va : joinAbs(va, vb));
4628
+ } else if (va !== void 0) {
4629
+ vars.set(k, baseV !== void 0 ? joinAbs(baseV, va) : va);
4630
+ } else if (vb !== void 0) {
4631
+ vars.set(k, baseV !== void 0 ? joinAbs(baseV, vb) : vb);
4632
+ }
4633
+ }
4634
+ return {
4635
+ vars,
4636
+ fns: a.fns ?? b.fns,
4637
+ classes: a.classes ?? b.classes,
4638
+ hofCollect: a.hofCollect ?? b.hofCollect
4639
+ };
4640
+ }
3812
4641
  var MAX_CALL_DEPTH = 64;
3813
4642
  var MAX_TOTAL_CALLS = 2e5;
3814
4643
  var _absCallDepth = 0;
@@ -4169,8 +4998,66 @@ function evalNodeInner(node, env, phi2, budget) {
4169
4998
  }
4170
4999
  case "AssignmentExpression": {
4171
5000
  const ae = node;
4172
- if (ae.operator !== "=") return ok2(unknown, phi2, env);
4173
- const rhs = evalNode(ae.right, env, phi2, budget).value;
5001
+ const op = ae.operator;
5002
+ const applyBin = (binOp, lhs, rhsAbs) => {
5003
+ switch (binOp) {
5004
+ case "+":
5005
+ return leakIfNeeded(add(lhs, rhsAbs, phi2), budget, "add");
5006
+ case "-":
5007
+ return leakIfNeeded(sub(lhs, rhsAbs, phi2), budget, "sub");
5008
+ case "*":
5009
+ return leakIfNeeded(mul(lhs, rhsAbs, phi2), budget, "mul");
5010
+ case "/":
5011
+ return leakIfNeeded(div(lhs, rhsAbs, phi2), budget, "div");
5012
+ case "%":
5013
+ return leakIfNeeded(mod(lhs, rhsAbs, phi2), budget, "mod");
5014
+ default:
5015
+ return unknown;
5016
+ }
5017
+ };
5018
+ let rhs;
5019
+ if (op === "=") {
5020
+ rhs = evalNode(ae.right, env, phi2, budget).value;
5021
+ } else if (op === "||=" || op === "&&=" || op === "??=") {
5022
+ const lhs = evalNode(ae.left, env, phi2, budget).value;
5023
+ const lv = litValue(lhs);
5024
+ const nullishLit = isNullishLitAbs(lhs);
5025
+ const definitelyNotNullish = definitelyNotNullishShape(lhs.shape) && !nullishLit;
5026
+ const falsy = lv === false || nullishLit || lv === null || lv === void 0 && lhs.term?.op === "lit" && lhs.term.value === void 0;
5027
+ const truthy = lv !== void 0 && !falsy && !nullishLit;
5028
+ let assignRhs = null;
5029
+ if (op === "||=") {
5030
+ if (truthy) return ok2(lhs, phi2, env);
5031
+ if (falsy || nullishLit) {
5032
+ assignRhs = evalNode(ae.right, env, phi2, budget).value;
5033
+ }
5034
+ } else if (op === "&&=") {
5035
+ if (falsy) return ok2(lhs, phi2, env);
5036
+ if (truthy) {
5037
+ assignRhs = evalNode(ae.right, env, phi2, budget).value;
5038
+ }
5039
+ } else {
5040
+ if (definitelyNotNullish || lv !== void 0 && lv !== null && !nullishLit) {
5041
+ return ok2(lhs, phi2, env);
5042
+ }
5043
+ if (nullishLit || lv === null || lv === void 0 && lhs.term?.op === "lit") {
5044
+ assignRhs = evalNode(ae.right, env, phi2, budget).value;
5045
+ }
5046
+ }
5047
+ if (assignRhs === null) {
5048
+ const r = evalNode(ae.right, env, phi2, budget).value;
5049
+ rhs = joinAbs(lhs, r);
5050
+ } else {
5051
+ rhs = assignRhs;
5052
+ }
5053
+ } else if (op.endsWith("=")) {
5054
+ const binOp = op.slice(0, -1);
5055
+ const lhs = evalNode(ae.left, env, phi2, budget).value;
5056
+ const rhsVal = evalNode(ae.right, env, phi2, budget).value;
5057
+ rhs = applyBin(binOp, lhs, rhsVal);
5058
+ } else {
5059
+ return ok2(unknown, phi2, env);
5060
+ }
4174
5061
  if (ae.left.type === "MemberExpression" && ae.left.object.type === "ThisExpression") {
4175
5062
  const prop = ae.left.property;
4176
5063
  const key = !ae.left.computed && prop.type === "Identifier" ? prop.name : prop.type === "StringLiteral" ? prop.value : void 0;
@@ -4204,6 +5091,25 @@ function evalNodeInner(node, env, phi2, budget) {
4204
5091
  recordAbsAssign(name, prev, rhs, loc);
4205
5092
  return { value: rhs, phi: phi2, env: withVar(env, name, rhs) };
4206
5093
  }
5094
+ if (ae.left.type === "MemberExpression") {
5095
+ const m = ae.left;
5096
+ if (m.object.type === "Identifier") {
5097
+ const root = m.object.name;
5098
+ const prev = env.vars.get(root);
5099
+ const key = !m.computed ? m.property.type === "Identifier" ? m.property.name : m.property.type === "StringLiteral" ? m.property.value : void 0 : void 0;
5100
+ if (prev && key && prev.shape.k === "obj") {
5101
+ const slots = { ...prev.shape.slots };
5102
+ slots[key] = { value: rhs };
5103
+ const updated = abs(
5104
+ { k: "obj", slots },
5105
+ void 0,
5106
+ void 0,
5107
+ prev.conf === "exact" ? "path" : prev.conf
5108
+ );
5109
+ return { value: rhs, phi: phi2, env: withVar(env, root, updated) };
5110
+ }
5111
+ }
5112
+ }
4207
5113
  return ok2(rhs, phi2, env);
4208
5114
  }
4209
5115
  case "AwaitExpression": {
@@ -4233,7 +5139,7 @@ function evalNodeInner(node, env, phi2, budget) {
4233
5139
  if (tv === false) return evalNode(cond.alternate, env, phi2, budget);
4234
5140
  const a = evalNode(cond.consequent, env, phi2, budget);
4235
5141
  const b = evalNode(cond.alternate, env, phi2, budget);
4236
- return { value: joinAbs(a.value, b.value), phi: phi2, env };
5142
+ return { value: joinAbs(a.value, b.value), phi: phi2, env: joinEnvs(a.env, b.env, env) };
4237
5143
  }
4238
5144
  case "ForStatement":
4239
5145
  return evalFor(node, env, phi2, budget);
@@ -4264,6 +5170,8 @@ function evalNodeInner(node, env, phi2, budget) {
4264
5170
  }
4265
5171
  case "IfStatement":
4266
5172
  return evalIf(node, env, phi2, budget);
5173
+ case "SwitchStatement":
5174
+ return evalSwitch(node, env, phi2, budget);
4267
5175
  case "ExpressionStatement":
4268
5176
  return evalNode(node.expression, env, phi2, budget);
4269
5177
  case "VariableDeclaration":
@@ -4285,8 +5193,10 @@ function evalNodeInner(node, env, phi2, budget) {
4285
5193
  const le3 = node;
4286
5194
  const l = evalNode(le3.left, env, phi2, budget);
4287
5195
  const lv = litValue(l.value);
4288
- const falsy = lv === false || lv === null || lv === void 0;
4289
- const truthy = lv !== void 0 && !falsy;
5196
+ const nullishLit = isNullishLitAbs(l.value);
5197
+ const definitelyNotNullish = definitelyNotNullishShape(l.value.shape) && !nullishLit;
5198
+ const falsy = lv === false || nullishLit || lv === void 0 && l.value.term?.op === "lit" && l.value.term.value === void 0 || lv === null;
5199
+ const truthy = lv !== void 0 && !falsy && !nullishLit;
4290
5200
  if (le3.operator === "&&") {
4291
5201
  if (falsy) return ok2(l.value, phi2, env);
4292
5202
  if (truthy) return evalNode(le3.right, env, phi2, budget);
@@ -4299,6 +5209,14 @@ function evalNodeInner(node, env, phi2, budget) {
4299
5209
  const r = evalNode(le3.right, env, phi2, budget);
4300
5210
  return ok2(joinAbs(l.value, r.value), phi2, env);
4301
5211
  }
5212
+ if (le3.operator === "??") {
5213
+ if (nullishLit || lv === null) return evalNode(le3.right, env, phi2, budget);
5214
+ if (definitelyNotNullish || lv !== void 0 && lv !== null) {
5215
+ return ok2(l.value, phi2, env);
5216
+ }
5217
+ const r = evalNode(le3.right, env, phi2, budget);
5218
+ return ok2(joinAbs(l.value, r.value), phi2, env);
5219
+ }
4302
5220
  return ok2(unknown, phi2, env);
4303
5221
  }
4304
5222
  case "TemplateLiteral": {
@@ -4388,12 +5306,39 @@ function evalNodeInner(node, env, phi2, budget) {
4388
5306
  acc = spread(acc, sp);
4389
5307
  continue;
4390
5308
  }
4391
- const keyNode = p.key;
5309
+ if (p.type === "ObjectMethod") {
5310
+ const om = p;
5311
+ const keyNode2 = om.key;
5312
+ let key2;
5313
+ if (keyNode2 && keyNode2.type === "Identifier") key2 = keyNode2.name;
5314
+ if (keyNode2 && keyNode2.type === "StringLiteral") key2 = keyNode2.value;
5315
+ if (!key2 || !om.body) continue;
5316
+ const paramNames = (om.params ?? []).map(
5317
+ (pp, i) => pp.type === "Identifier" ? pp.name : `_a${i}`
5318
+ );
5319
+ const methodBody = om.body;
5320
+ const fnAbs = absFunction(paramNames, {
5321
+ body: methodBody,
5322
+ apply: (args) => {
5323
+ let e2 = env;
5324
+ for (let i = 0; i < paramNames.length; i++) {
5325
+ e2 = withVar(e2, paramNames[i], args[i] ?? unknown);
5326
+ }
5327
+ const r = evalNode(methodBody, e2, phi2, budget);
5328
+ return r.value;
5329
+ }
5330
+ });
5331
+ pending[key2] = { value: fnAbs };
5332
+ continue;
5333
+ }
5334
+ if (p.type !== "ObjectProperty") continue;
5335
+ const op = p;
5336
+ const keyNode = op.key;
4392
5337
  let key;
4393
5338
  if (keyNode && keyNode.type === "Identifier") key = keyNode.name;
4394
5339
  if (keyNode && keyNode.type === "StringLiteral") key = keyNode.value;
4395
- if (!key || !p.value) continue;
4396
- pending[key] = { value: evalNode(p.value, env, phi2, budget).value };
5340
+ if (!key || !op.value) continue;
5341
+ pending[key] = { value: evalNode(op.value, env, phi2, budget).value };
4397
5342
  }
4398
5343
  acc = flushPending(acc);
4399
5344
  return ok2(acc, phi2, env);
@@ -4446,6 +5391,16 @@ function evalBinary(node, env, phi2, budget) {
4446
5391
  if (eq2 !== void 0) return ok2(boolLit(!eq2), phi2, env);
4447
5392
  return ok2(cmp("ne", l, r, phi2), phi2, env);
4448
5393
  }
5394
+ case "==": {
5395
+ const eq2 = looseEqAbs(l, r);
5396
+ if (eq2 !== void 0) return ok2(boolLit(eq2), phi2, env);
5397
+ return ok2(unknown, phi2, env);
5398
+ }
5399
+ case "!=": {
5400
+ const eq2 = looseEqAbs(l, r);
5401
+ if (eq2 !== void 0) return ok2(boolLit(!eq2), phi2, env);
5402
+ return ok2(unknown, phi2, env);
5403
+ }
4449
5404
  case "/":
4450
5405
  return ok2(leakIfNeeded(div(l, r, phi2), budget, "div"), phi2, env);
4451
5406
  case "%":
@@ -4737,7 +5692,7 @@ function evalCall(node, env, phi2, budget) {
4737
5692
  } else if (obj2.shape.k === "arr") {
4738
5693
  applyUnaryCallback(fnNode, obj2.shape.element, env, phi2, budget);
4739
5694
  }
4740
- return ok2(undefAbs(), phi2, env);
5695
+ return ok2(undefAbs2(), phi2, env);
4741
5696
  }
4742
5697
  if ((method === "some" || method === "every") && rawArgs.length >= 1) {
4743
5698
  const fnNode = rawArgs[0];
@@ -4754,7 +5709,7 @@ function evalCall(node, env, phi2, budget) {
4754
5709
  const fnNode = rawArgs[0];
4755
5710
  const elem = obj2.shape.k === "arr" ? obj2.shape.element : obj2.shape.k === "tuple" ? obj2.shape.elements[0] ?? unknown : unknown;
4756
5711
  applyUnaryCallback(fnNode, elem, env, phi2, budget);
4757
- return ok2(joinAbs(elem, undefAbs()), phi2, env);
5712
+ return ok2(joinAbs(elem, undefAbs2()), phi2, env);
4758
5713
  }
4759
5714
  {
4760
5715
  const loc = node.loc ? [node.loc.start.line, node.loc.start.column] : void 0;
@@ -4819,7 +5774,16 @@ function applyAbsFn(fnVal, args, env, phi2, budget) {
4819
5774
  const label = fnVal.shape.name ?? "anonymous";
4820
5775
  if (!enterCall(key, label)) return truncatedAbs();
4821
5776
  try {
4822
- if (impl.apply) return impl.apply(args);
5777
+ if (impl.apply) {
5778
+ try {
5779
+ return impl.apply(args);
5780
+ } catch (e) {
5781
+ if (e && typeof e === "object" && e.name === "NudoReturn") {
5782
+ return e.absValue;
5783
+ }
5784
+ throw e;
5785
+ }
5786
+ }
4823
5787
  const base = impl.env ?? env;
4824
5788
  let local = { vars: new Map(base.vars), fns: base.fns, hofCollect: env.hofCollect };
4825
5789
  if (base.classes) {
@@ -4939,18 +5903,29 @@ function evalFor(node, env, phi2, budget) {
4939
5903
  const r = evalNode(node.init, local, phi2, budget);
4940
5904
  local = r.env;
4941
5905
  }
5906
+ const entry = local;
4942
5907
  let acc = unknown;
5908
+ let exitEnv;
5909
+ let sawAbstractTest = false;
4943
5910
  for (let i = 0; i < MAX_LOOP_ITERS; i++) {
4944
5911
  if (node.test) {
4945
5912
  const t = evalNode(node.test, local, phi2, budget);
4946
5913
  const lv = litValue(t.value);
4947
- if (lv === false || lv === null || lv === void 0) break;
5914
+ if (lv === false || lv === null || lv === void 0) {
5915
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5916
+ break;
5917
+ }
5918
+ if (lv !== true) {
5919
+ sawAbstractTest = true;
5920
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5921
+ }
4948
5922
  }
4949
5923
  const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4950
5924
  if (bodyR.returned) return bodyR;
4951
5925
  if (bodyR.threw) return bodyR;
4952
5926
  if (bodyR.brk) {
4953
5927
  local = bodyR.env;
5928
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
4954
5929
  break;
4955
5930
  }
4956
5931
  local = bodyR.env;
@@ -4960,25 +5935,42 @@ function evalFor(node, env, phi2, budget) {
4960
5935
  local = u.env;
4961
5936
  }
4962
5937
  }
4963
- return ok2(acc, phi2, local);
5938
+ if (sawAbstractTest) {
5939
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5940
+ }
5941
+ return ok2(acc, phi2, exitEnv ?? local);
4964
5942
  }
4965
5943
  function evalWhile(node, env, phi2, budget) {
4966
5944
  let local = env;
5945
+ const entry = local;
4967
5946
  let acc = unknown;
5947
+ let exitEnv;
5948
+ let sawAbstractTest = false;
4968
5949
  for (let i = 0; i < MAX_LOOP_ITERS; i++) {
4969
5950
  const t = evalNode(node.test, local, phi2, budget);
4970
5951
  const lv = litValue(t.value);
4971
- if (lv === false || lv === null || lv === void 0) break;
5952
+ if (lv === false || lv === null || lv === void 0) {
5953
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5954
+ break;
5955
+ }
5956
+ if (lv !== true) {
5957
+ sawAbstractTest = true;
5958
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5959
+ }
4972
5960
  const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4973
5961
  if (bodyR.returned || bodyR.threw) return bodyR;
4974
5962
  if (bodyR.brk) {
4975
5963
  local = bodyR.env;
5964
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
4976
5965
  break;
4977
5966
  }
4978
5967
  local = bodyR.env;
4979
5968
  acc = joinAbs(acc, bodyR.value);
4980
5969
  }
4981
- return ok2(acc, phi2, local);
5970
+ if (sawAbstractTest) {
5971
+ exitEnv = exitEnv ? joinEnvs(exitEnv, local, entry) : local;
5972
+ }
5973
+ return ok2(acc, phi2, exitEnv ?? local);
4982
5974
  }
4983
5975
  function evalDoWhile(node, env, phi2, budget) {
4984
5976
  let local = env;
@@ -5009,13 +6001,50 @@ function evalForOf(node, env, phi2, budget) {
5009
6001
  );
5010
6002
  if (promoted) iterVal = promoted;
5011
6003
  }
5012
- const elements = iterVal.shape.k === "arr" ? [iterVal.shape.element] : iterVal.shape.k === "tuple" ? iterVal.shape.elements : iterVal.shape.k === "sum" ? iterVal.shape.members.flatMap(
5013
- (m) => m.shape.k === "arr" ? [m.shape.element] : m.shape.k === "tuple" ? m.shape.elements : []
5014
- ) : [unknown];
5015
- if (elements.length === 0) elements.push(unknown);
6004
+ const shape = iterVal.shape;
6005
+ const isTuple = shape.k === "tuple";
6006
+ const isArr = shape.k === "arr";
6007
+ let elements = [];
6008
+ if (isArr) {
6009
+ elements = [shape.element];
6010
+ } else if (isTuple) {
6011
+ elements = [...shape.elements];
6012
+ } else if (shape.k === "sum") {
6013
+ elements = shape.members.flatMap(
6014
+ (m) => m.shape.k === "arr" ? [m.shape.element] : m.shape.k === "tuple" ? [...m.shape.elements] : []
6015
+ );
6016
+ } else {
6017
+ elements = [unknown];
6018
+ }
5016
6019
  const left = node.left;
5017
6020
  const bindName = left.type === "Identifier" ? left.name : left.type === "VariableDeclaration" ? left.declarations[0]?.id?.name : void 0;
5018
6021
  if (!bindName) return ok2(unknown, phi2, env);
6022
+ if (isTuple && elements.length === 0) {
6023
+ return ok2(unknown, phi2, env);
6024
+ }
6025
+ const unbounded = !isTuple;
6026
+ if (unbounded) {
6027
+ let cur = env;
6028
+ let joinedEnv = env;
6029
+ let joinedVal = unknown;
6030
+ const el = elements.length > 0 ? elements[0] : unknown;
6031
+ const n2 = elements.length > 0 || isArr || shape.k === "sum" ? MAX_LOOP_ITERS : 0;
6032
+ for (let i = 0; i < n2; i++) {
6033
+ cur = withVar(cur, bindName, el);
6034
+ const bodyR = evalInConditionalFlow(() => evalNode(node.body, cur, phi2, budget));
6035
+ if (bodyR.returned || bodyR.threw) return bodyR;
6036
+ if (bodyR.brk) {
6037
+ cur = bodyR.env;
6038
+ joinedEnv = joinEnvs(joinedEnv, cur, env);
6039
+ break;
6040
+ }
6041
+ cur = bodyR.env;
6042
+ joinedEnv = joinEnvs(joinedEnv, cur, env);
6043
+ joinedVal = joinAbs(joinedVal, bodyR.value);
6044
+ }
6045
+ joinedEnv = joinEnvs(joinedEnv, cur, env);
6046
+ return ok2(joinedVal, phi2, joinedEnv);
6047
+ }
5019
6048
  let local = env;
5020
6049
  let acc = unknown;
5021
6050
  const n = Math.min(elements.length, MAX_LOOP_ITERS);
@@ -5053,6 +6082,20 @@ function evalTry(node, env, phi2, budget) {
5053
6082
  if (node.finalizer) evalNode(node.finalizer, local, curPhi, budget);
5054
6083
  return { value: catchR.value, phi: curPhi, env: local, threw: true };
5055
6084
  }
6085
+ } else if (tryR.partialThrow && node.handler) {
6086
+ const param = node.handler.param && node.handler.param.type === "Identifier" ? node.handler.param.name : void 0;
6087
+ let catchEnv = env;
6088
+ if (param) catchEnv = withVar(env, param, tryR.throwValue ?? tryR.value);
6089
+ const catchR = evalNode(node.handler.body, catchEnv, phi2, budget);
6090
+ value = joinAbs(tryR.value, catchR.value);
6091
+ local = joinEnvs(tryR.env, catchR.env, env);
6092
+ curPhi = catchR.phi;
6093
+ if (catchR.returned && tryR.returned) {
6094
+ return { value, phi: curPhi, env: local, returned: true };
6095
+ }
6096
+ if (catchR.threw && tryR.threw) {
6097
+ return { value, phi: curPhi, env: local, threw: true };
6098
+ }
5056
6099
  } else if (tryR.returned) {
5057
6100
  if (node.finalizer) evalNode(node.finalizer, local, curPhi, budget);
5058
6101
  return tryR;
@@ -5065,7 +6108,13 @@ function evalTry(node, env, phi2, budget) {
5065
6108
  if (fR.returned || fR.threw) return fR;
5066
6109
  local = fR.env;
5067
6110
  }
5068
- return { value, phi: curPhi, env: local, returned: tryR.returned };
6111
+ return {
6112
+ value,
6113
+ phi: curPhi,
6114
+ env: local,
6115
+ returned: tryR.returned,
6116
+ ...tryR.partialReturn || tryR.partialThrow ? { partialReturn: tryR.partialReturn } : {}
6117
+ };
5069
6118
  }
5070
6119
  function evalVarDecl(node, env, phi2, budget) {
5071
6120
  let local = env;
@@ -5105,12 +6154,157 @@ function evalIf(node, env, phi2, budget) {
5105
6154
  const b = evalInConditionalFlow(
5106
6155
  () => evalNode(alt, env, fCons ? and(phi2, fCons) : phi2, budget)
5107
6156
  );
5108
- return { value: joinAbs(a.value, b.value), phi: phi2, env, returned: a.returned || b.returned };
6157
+ const bothRet = !!a.returned && !!b.returned;
6158
+ const eitherRet = !!a.returned || !!b.returned;
6159
+ const contEnv = a.returned && !b.returned ? b.env : b.returned && !a.returned ? a.env : a.threw && !b.threw ? b.env : b.threw && !a.threw ? a.env : joinEnvs(a.env, b.env, env);
6160
+ return {
6161
+ value: joinAbs(a.value, b.value),
6162
+ phi: phi2,
6163
+ env: contEnv,
6164
+ ...bothRet ? { returned: true } : eitherRet ? { partialReturn: true } : {},
6165
+ ...a.threw && b.threw ? { threw: true, throwValue: joinAbs(a.value, b.value) } : {},
6166
+ ...(a.threw || b.threw) && !(a.threw && b.threw) ? { partialThrow: true, throwValue: a.threw ? a.value : b.value } : {}
6167
+ };
5109
6168
  }
5110
- if (a.returned || a.threw) {
6169
+ if (a.returned && a.threw) {
5111
6170
  return { value: a.value, phi: phi2, env, partialReturn: true };
5112
6171
  }
5113
- return { value: unknown, phi: phi2, env };
6172
+ if (a.returned || a.threw) {
6173
+ return {
6174
+ value: a.value,
6175
+ phi: phi2,
6176
+ env,
6177
+ ...a.returned ? { partialReturn: true } : {},
6178
+ ...a.threw ? { partialThrow: true, throwValue: a.value } : {}
6179
+ };
6180
+ }
6181
+ return { value: unknown, phi: phi2, env: joinEnvs(a.env, env, env) };
6182
+ }
6183
+ function evalSwitch(node, env, phi2, budget) {
6184
+ const stmtCompletes = (s) => {
6185
+ if (!s) return false;
6186
+ switch (s.type) {
6187
+ case "BreakStatement":
6188
+ case "ReturnStatement":
6189
+ case "ThrowStatement":
6190
+ case "ContinueStatement":
6191
+ return true;
6192
+ case "BlockStatement":
6193
+ return stmtCompletes(s.body[s.body.length - 1]);
6194
+ case "IfStatement": {
6195
+ const ifs = s;
6196
+ return ifs.alternate != null && stmtCompletes(ifs.consequent) && stmtCompletes(ifs.alternate);
6197
+ }
6198
+ default:
6199
+ return false;
6200
+ }
6201
+ };
6202
+ const pre = [];
6203
+ let pending = [];
6204
+ for (const c of node.cases) {
6205
+ if (c.test == null) {
6206
+ if (pending.length > 0 && c.consequent.length > 0) {
6207
+ pre.push({ tests: pending, body: [...c.consequent], isDefault: false });
6208
+ pending = [];
6209
+ }
6210
+ pre.push({ tests: [], body: [...c.consequent], isDefault: true });
6211
+ continue;
6212
+ }
6213
+ if (c.consequent.length === 0) {
6214
+ pending.push(c.test);
6215
+ continue;
6216
+ }
6217
+ pre.push({ tests: [...pending, c.test], body: [...c.consequent], isDefault: false });
6218
+ pending = [];
6219
+ }
6220
+ if (pending.length > 0) pre.push({ tests: pending, body: [], isDefault: false });
6221
+ const arms = pre.map((a) => ({ ...a, tests: [...a.tests], body: [...a.body] }));
6222
+ for (let i = 0; i < arms.length; i++) {
6223
+ const arm = arms[i];
6224
+ const body = [...arm.body];
6225
+ let j = i + 1;
6226
+ while (j < arms.length && !stmtCompletes(body[body.length - 1])) {
6227
+ body.push(...arms[j].body);
6228
+ if (stmtCompletes(body[body.length - 1])) break;
6229
+ j++;
6230
+ }
6231
+ arm.body = body;
6232
+ }
6233
+ const runBody = (body, e) => {
6234
+ let local = e;
6235
+ let value2 = unknown;
6236
+ for (const s of body) {
6237
+ const r = evalInConditionalFlow(() => evalNode(s, local, phi2, budget));
6238
+ local = r.env;
6239
+ value2 = r.value;
6240
+ if (r.returned || r.threw || r.brk) return { ...r, env: local, value: value2 };
6241
+ }
6242
+ return { value: value2, phi: phi2, env: local };
6243
+ };
6244
+ const disc = evalNode(node.discriminant, env, phi2, budget).value;
6245
+ const dlv = litValue(disc);
6246
+ const hasDefault = arms.some((a) => a.isDefault);
6247
+ const testLit = (t) => {
6248
+ if (t == null) return null;
6249
+ return litValue(evalNode(t, env, phi2, budget).value);
6250
+ };
6251
+ if (dlv !== void 0) {
6252
+ let matched = null;
6253
+ let sawAbstractTest = false;
6254
+ for (const arm of arms) {
6255
+ if (arm.isDefault) continue;
6256
+ let hit = false;
6257
+ for (const t of arm.tests) {
6258
+ const tv = testLit(t);
6259
+ if (tv === null) continue;
6260
+ if (tv === void 0) {
6261
+ sawAbstractTest = true;
6262
+ continue;
6263
+ }
6264
+ if (tv === dlv) {
6265
+ hit = true;
6266
+ break;
6267
+ }
6268
+ }
6269
+ if (hit) {
6270
+ matched = arm;
6271
+ break;
6272
+ }
6273
+ }
6274
+ if (!sawAbstractTest) {
6275
+ if (matched) return runBody(matched.body, env);
6276
+ const dflt = arms.find((a) => a.isDefault);
6277
+ if (dflt) return runBody(dflt.body, env);
6278
+ return ok2(unknown, phi2, env);
6279
+ }
6280
+ }
6281
+ const results = [];
6282
+ if (!hasDefault) results.push(ok2(unknown, phi2, env));
6283
+ for (const arm of arms) {
6284
+ if (arm.body.length === 0 && !arm.isDefault) continue;
6285
+ results.push(runBody(arm.body, env));
6286
+ }
6287
+ if (results.length === 0) return ok2(unknown, phi2, env);
6288
+ let value = results[0].value;
6289
+ let envOut = results[0].env;
6290
+ let allRet = !!results[0].returned;
6291
+ let anyRet = !!results[0].returned;
6292
+ let anyThrew = !!results[0].threw;
6293
+ for (let i = 1; i < results.length; i++) {
6294
+ const r = results[i];
6295
+ value = joinAbs(value, r.value);
6296
+ envOut = joinEnvs(envOut, r.env, env);
6297
+ allRet = allRet && !!r.returned;
6298
+ anyRet = anyRet || !!r.returned;
6299
+ anyThrew = anyThrew || !!r.threw;
6300
+ }
6301
+ return {
6302
+ value,
6303
+ phi: phi2,
6304
+ env: envOut,
6305
+ ...allRet ? { returned: true } : anyRet ? { partialReturn: true } : {},
6306
+ ...anyThrew ? { partialThrow: true } : {}
6307
+ };
5114
6308
  }
5115
6309
  function analyzeFn(source, fnName, args, phi2 = pTrue, budget, file, modules) {
5116
6310
  return evalSource(source, { fn: fnName, args }, { phi: phi2, budget, file, modules }).value;
@@ -5281,7 +6475,7 @@ function $callNamed(name, fn, args, loc, argLocs) {
5281
6475
  try {
5282
6476
  if (typeof fn === "function") {
5283
6477
  const g = GLOBAL_FNS.has(name) && fn === globalThis[name] ? evalGlobalFn(name, args) : void 0;
5284
- result = g ?? fn(...args);
6478
+ result = g ?? callAtFunctionBoundary(() => fn(...args));
5285
6479
  } else if (fn && typeof fn === "object" && "shape" in fn) {
5286
6480
  result = $call(fn, args);
5287
6481
  }
@@ -5352,6 +6546,14 @@ function $ne(a, b) {
5352
6546
  const r = strictEqAbs(a, b);
5353
6547
  return r === void 0 ? bool() : boolLit(!r);
5354
6548
  }
6549
+ function $eqLoose(a, b) {
6550
+ const r = looseEqAbs(a, b);
6551
+ return r === void 0 ? bool() : boolLit(r);
6552
+ }
6553
+ function $neLoose(a, b) {
6554
+ const r = looseEqAbs(a, b);
6555
+ return r === void 0 ? bool() : boolLit(!r);
6556
+ }
5355
6557
  function $lt(a, b) {
5356
6558
  return cmp("lt", a, b, phi);
5357
6559
  }
@@ -5375,13 +6577,28 @@ function asAbsVal(v2) {
5375
6577
  const params = Array.from({ length: n }, (_, i) => `arg${i}`);
5376
6578
  return absFunction(params, {
5377
6579
  body: noBody,
5378
- apply: (args) => v2(...args)
6580
+ // 与 $fnVal / $callNamed 同边界:callee 的 NudoReturn 不得冒泡成 caller
6581
+ apply: (args) => callAtFunctionBoundary(() => v2(...args))
5379
6582
  });
5380
6583
  }
5381
6584
  return $lit(v2);
5382
6585
  }
5383
- function $fnVal(params, impl) {
5384
- return absFunction(params, { body: noBody, apply: (args) => impl(...args) });
6586
+ function callAtFunctionBoundary(body) {
6587
+ return runWithLoopExits(() => {
6588
+ try {
6589
+ return body();
6590
+ } catch (e) {
6591
+ if (isNudoReturn(e)) return e.absValue;
6592
+ throw e;
6593
+ }
6594
+ });
6595
+ }
6596
+ function $fnVal(params, impl, opts) {
6597
+ return absFunction(params, {
6598
+ body: noBody,
6599
+ apply: (args) => callAtFunctionBoundary(() => impl(...args)),
6600
+ ...opts?.bindThis ? { bindThis: true } : {}
6601
+ });
5385
6602
  }
5386
6603
  function $lit(v2) {
5387
6604
  if (v2 && typeof v2 === "object" && "shape" in v2 && "conf" in v2) {
@@ -5436,12 +6653,163 @@ function isDefinitelyFalse(a) {
5436
6653
  function undef() {
5437
6654
  return abs({ k: "unknown" }, { op: "lit", value: void 0 }, pTrue, "exact");
5438
6655
  }
6656
+ var loopExitsAls = new AsyncLocalStorage2();
6657
+ var throwExitsAls = new AsyncLocalStorage2();
6658
+ var tryMarksAls = new AsyncLocalStorage2();
6659
+ function runWithLoopExits(body) {
6660
+ return loopExitsAls.run(
6661
+ [],
6662
+ () => throwExitsAls.run([], () => tryMarksAls.run([], body))
6663
+ );
6664
+ }
6665
+ function takeLoopExits() {
6666
+ return loopExitsAls.getStore() ?? [];
6667
+ }
6668
+ function takeThrowExits() {
6669
+ return throwExitsAls.getStore() ?? [];
6670
+ }
6671
+ function pushLoopExit(v2) {
6672
+ loopExitsAls.getStore()?.push(v2);
6673
+ }
6674
+ function pushThrowExit(v2) {
6675
+ throwExitsAls.getStore()?.push(v2);
6676
+ }
6677
+ function $pushLoopExit(v2) {
6678
+ pushLoopExit(v2);
6679
+ }
6680
+ function $tryMark() {
6681
+ const store = throwExitsAls.getStore();
6682
+ const m = store?.length ?? 0;
6683
+ tryMarksAls.getStore()?.push(m);
6684
+ return m;
6685
+ }
6686
+ function $tryCurrentMark() {
6687
+ const stack = tryMarksAls.getStore();
6688
+ return stack && stack.length > 0 ? stack[stack.length - 1] : 0;
6689
+ }
6690
+ function $tryPopMark() {
6691
+ tryMarksAls.getStore()?.pop();
6692
+ }
6693
+ function $tryTakeSince(mark) {
6694
+ const store = throwExitsAls.getStore();
6695
+ if (!store) return [];
6696
+ return store.splice(Math.min(mark, store.length));
6697
+ }
6698
+ var yieldStack = [];
6699
+ var genPathSensitive = 0;
6700
+ var genJoinOverride = null;
6701
+ function withIsolatedYields(fn) {
6702
+ const top = yieldStack[yieldStack.length - 1];
6703
+ if (!top) return { v: fn(), ys: null };
6704
+ const armYs = [];
6705
+ yieldStack[yieldStack.length - 1] = armYs;
6706
+ try {
6707
+ return { v: fn(), ys: armYs };
6708
+ } finally {
6709
+ yieldStack[yieldStack.length - 1] = top;
6710
+ }
6711
+ }
6712
+ function mergeArmYields(armYsList) {
6713
+ const top = yieldStack[yieldStack.length - 1];
6714
+ if (!top || armYsList.length === 0) return;
6715
+ const concrete = armYsList.filter((x) => x !== null);
6716
+ if (concrete.length === 0) return;
6717
+ if (concrete.length === 1) {
6718
+ top.push(...concrete[0]);
6719
+ return;
6720
+ }
6721
+ let joined = null;
6722
+ for (const ys of concrete) {
6723
+ joined = joined ? joinAbs(joined, $arr(ys)) : $arr(ys);
6724
+ }
6725
+ genPathSensitive++;
6726
+ if (joined) genJoinOverride = joined;
6727
+ for (const ys of concrete) top.push(...ys);
6728
+ }
6729
+ function runForkArm(arm, exits) {
6730
+ try {
6731
+ return { kind: "val", v: asAbsVal(arm()) };
6732
+ } catch (e) {
6733
+ if (isNudoReturn(e)) {
6734
+ exits?.push(e.absValue);
6735
+ return { kind: "ret", v: e.absValue };
6736
+ }
6737
+ if (isNudoThrow(e)) {
6738
+ pushThrowExit(e.absValue);
6739
+ return { kind: "throw", v: e.absValue };
6740
+ }
6741
+ throw e;
6742
+ }
6743
+ }
6744
+ function settleForkArms(a, b, exits) {
6745
+ const throws = [a, b].filter((r) => r.kind === "throw");
6746
+ const nonThrow = [a, b].filter((r) => r.kind !== "throw");
6747
+ if (nonThrow.length === 0) {
6748
+ throw new NudoThrow(throws.map((t) => t.v).reduce((x, y) => joinAbs(x, y)));
6749
+ }
6750
+ const first = nonThrow[0];
6751
+ const second = nonThrow[1] ?? first;
6752
+ if (first.kind === "ret" && second.kind === "ret") {
6753
+ throw new NudoReturn(joinAbs(first.v, second.v));
6754
+ }
6755
+ if (nonThrow.length === 1) {
6756
+ if (first.kind === "ret") {
6757
+ if (!exits) throw new NudoReturn(first.v);
6758
+ return undef();
6759
+ }
6760
+ return first.v;
6761
+ }
6762
+ if (first.kind === "ret") {
6763
+ if (!exits) throw new NudoReturn(first.v);
6764
+ return second.kind === "val" ? second.v : undef();
6765
+ }
6766
+ if (second.kind === "ret") {
6767
+ if (!exits) throw new NudoReturn(second.v);
6768
+ return first.v;
6769
+ }
6770
+ return joinAbs(first.v, second.v);
6771
+ }
5439
6772
  function $fork(test, consequent, alternate) {
5440
6773
  if (isDefinitelyTrue(test)) return asAbsVal(consequent());
5441
6774
  if (isDefinitelyFalse(test)) return alternate ? asAbsVal(alternate()) : undef();
5442
- const a = asAbsVal(consequent());
5443
- const b = alternate ? asAbsVal(alternate()) : undef();
5444
- return joinAbs(a, b);
6775
+ const exits = loopExitsAls.getStore();
6776
+ beginCollectionFork();
6777
+ const arms = [];
6778
+ const armYsList = [];
6779
+ let a;
6780
+ let b;
6781
+ try {
6782
+ pushCollectionArm();
6783
+ try {
6784
+ const r = withIsolatedYields(() => runForkArm(consequent, exits));
6785
+ a = r.v;
6786
+ armYsList.push(r.ys);
6787
+ } finally {
6788
+ arms.push(popCollectionArm());
6789
+ }
6790
+ if (alternate) {
6791
+ pushCollectionArm();
6792
+ try {
6793
+ const r = withIsolatedYields(() => runForkArm(alternate, exits));
6794
+ b = r.v;
6795
+ armYsList.push(r.ys);
6796
+ } finally {
6797
+ arms.push(popCollectionArm());
6798
+ }
6799
+ } else {
6800
+ pushCollectionArm();
6801
+ try {
6802
+ b = { kind: "val", v: undef() };
6803
+ armYsList.push(null);
6804
+ } finally {
6805
+ arms.push(popCollectionArm());
6806
+ }
6807
+ }
6808
+ } finally {
6809
+ endCollectionFork(arms);
6810
+ if (yieldStack.length > 0) mergeArmYields(armYsList);
6811
+ }
6812
+ return settleForkArms(a, b, exits);
5445
6813
  }
5446
6814
  var DEFAULT_MAX_LOOP_ITERS = 8;
5447
6815
  function* $forIter(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
@@ -5457,30 +6825,67 @@ function* $forIter(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
5457
6825
  s = step(afterBody);
5458
6826
  }
5459
6827
  }
5460
- function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
6828
+ function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
5461
6829
  let state = init;
5462
6830
  let exitJoin;
6831
+ let extJoin;
6832
+ const pack = opts?.pack;
6833
+ const unpack = opts?.unpack;
6834
+ const snapCounter = () => {
6835
+ exitJoin = exitJoin ? joinAbs(exitJoin, state) : state;
6836
+ };
6837
+ const snapExt = () => {
6838
+ if (!pack) return;
6839
+ const p = pack();
6840
+ extJoin = extJoin ? joinAbs(extJoin, p) : p;
6841
+ };
6842
+ const applyExtJoin = () => {
6843
+ if (!extJoin || !pack || !unpack) return;
6844
+ unpack(joinAbs(extJoin, pack()));
6845
+ };
5463
6846
  for (let i = 0; i < maxIters; i++) {
5464
6847
  const t = test(state);
5465
6848
  if (isDefinitelyFalse(t)) {
5466
- return exitJoin ? joinAbs(exitJoin, state) : state;
6849
+ snapCounter();
6850
+ snapExt();
6851
+ applyExtJoin();
6852
+ return exitJoin ?? state;
5467
6853
  }
5468
- if (!isDefinitelyTrue(t)) {
5469
- exitJoin = exitJoin ? joinAbs(exitJoin, state) : state;
6854
+ const abstractTest = !isDefinitelyTrue(t);
6855
+ if (abstractTest) {
6856
+ snapCounter();
6857
+ snapExt();
6858
+ }
6859
+ let afterBody;
6860
+ try {
6861
+ afterBody = body(state);
6862
+ } catch (e) {
6863
+ if (isNudoReturn(e) || isNudoThrow(e)) throw e;
6864
+ throw e;
5470
6865
  }
5471
- const afterBody = body(state);
5472
6866
  const next = step(afterBody);
6867
+ if (abstractTest) {
6868
+ state = afterBody;
6869
+ snapExt();
6870
+ }
5473
6871
  if (i > 0) {
5474
6872
  const nv = litValue(next);
5475
6873
  const sv = litValue(state);
5476
6874
  const stuck = nv !== void 0 && sv !== void 0 && nv === sv || nv === void 0 && sv === void 0 && leqAbs(next, state).ok;
5477
6875
  if (stuck) {
5478
- return exitJoin ? joinAbs(exitJoin, next) : next;
6876
+ state = next;
6877
+ snapCounter();
6878
+ snapExt();
6879
+ applyExtJoin();
6880
+ return exitJoin ?? next;
5479
6881
  }
5480
6882
  }
5481
6883
  state = next;
5482
6884
  }
5483
- return exitJoin ? joinAbs(exitJoin, state) : state;
6885
+ snapCounter();
6886
+ snapExt();
6887
+ applyExtJoin();
6888
+ return exitJoin ?? state;
5484
6889
  }
5485
6890
  function tupleOrWiden(els, conf) {
5486
6891
  if (shouldWidenArrayLiteral(els.length)) {
@@ -5496,6 +6901,99 @@ function tupleOrWiden(els, conf) {
5496
6901
  function $arr(items) {
5497
6902
  return tupleOrWiden(items.map(asAbsVal), "exact");
5498
6903
  }
6904
+ var ARR_MUTATORS = /* @__PURE__ */ new Set([
6905
+ "push",
6906
+ "unshift",
6907
+ "pop",
6908
+ "shift",
6909
+ "splice",
6910
+ "reverse",
6911
+ "sort"
6912
+ ]);
6913
+ function isArrMutator(name) {
6914
+ return ARR_MUTATORS.has(name);
6915
+ }
6916
+ function $arrMutContainer(arr, method, args) {
6917
+ const shape = arr.shape;
6918
+ if (shape.k !== "tuple" && shape.k !== "arr") return arr;
6919
+ const vals = args.map((a) => asAbsVal(a));
6920
+ const asArrEl = (els) => els.length > 0 ? els.reduce((x, y) => joinAbs(x, y)) : unknown;
6921
+ if (method === "push" || method === "unshift") {
6922
+ if (shape.k === "tuple") {
6923
+ const els = method === "push" ? [...shape.elements, ...vals] : [...vals, ...shape.elements];
6924
+ const conf = vals.reduce(
6925
+ (acc, v2) => confJoin(acc, v2.conf),
6926
+ arr.conf
6927
+ );
6928
+ return abs(
6929
+ { k: "tuple", elements: els },
6930
+ void 0,
6931
+ void 0,
6932
+ conf
6933
+ );
6934
+ }
6935
+ const el = vals.reduce((acc, v2) => joinAbs(acc, v2), shape.element);
6936
+ return abs({ k: "arr", element: el }, void 0, void 0, confJoin(arr.conf, "path"));
6937
+ }
6938
+ if (method === "pop") {
6939
+ if (shape.k === "tuple") {
6940
+ if (shape.elements.length === 0) return arr;
6941
+ return abs(
6942
+ { k: "tuple", elements: shape.elements.slice(0, -1) },
6943
+ void 0,
6944
+ void 0,
6945
+ arr.conf
6946
+ );
6947
+ }
6948
+ return arr;
6949
+ }
6950
+ if (method === "shift") {
6951
+ if (shape.k === "tuple") {
6952
+ if (shape.elements.length === 0) return arr;
6953
+ return abs(
6954
+ { k: "tuple", elements: shape.elements.slice(1) },
6955
+ void 0,
6956
+ void 0,
6957
+ arr.conf
6958
+ );
6959
+ }
6960
+ return arr;
6961
+ }
6962
+ if (method === "splice") {
6963
+ if (shape.k === "tuple") {
6964
+ return abs(
6965
+ { k: "arr", element: asArrEl(shape.elements) },
6966
+ void 0,
6967
+ void 0,
6968
+ confJoin(arr.conf, "path")
6969
+ );
6970
+ }
6971
+ return arr;
6972
+ }
6973
+ if (method === "reverse") {
6974
+ if (shape.k === "tuple") {
6975
+ return abs(
6976
+ { k: "tuple", elements: [...shape.elements].reverse() },
6977
+ void 0,
6978
+ void 0,
6979
+ arr.conf
6980
+ );
6981
+ }
6982
+ return arr;
6983
+ }
6984
+ if (method === "sort") {
6985
+ if (shape.k === "tuple") {
6986
+ return abs(
6987
+ { k: "arr", element: asArrEl(shape.elements) },
6988
+ void 0,
6989
+ void 0,
6990
+ confJoin(arr.conf, "path")
6991
+ );
6992
+ }
6993
+ return arr;
6994
+ }
6995
+ return arr;
6996
+ }
5499
6997
  function $idx(a, i) {
5500
6998
  const iv = litValue(i);
5501
6999
  if (a.shape.k === "tuple") {
@@ -5511,6 +7009,22 @@ function $idx(a, i) {
5511
7009
  if (a.shape.k === "sum") {
5512
7010
  return a.shape.members.map((m) => $idx(m, i)).reduce((x, y) => joinAbs(x, y));
5513
7011
  }
7012
+ if (a.shape.k === "obj" || a.shape.k === "brand" && a.shape.shape.shape.k === "obj") {
7013
+ const objShape = a.shape.k === "obj" ? a.shape : a.shape.shape.shape;
7014
+ const slots = Object.values(objShape.slots).map((s) => s.value);
7015
+ if (slots.length === 0) return objShape.open ? unknown : undef();
7016
+ const joinSlotsWithUndef = () => joinAbs(slots.reduce((x, y) => joinAbs(x, y)), undef());
7017
+ if (typeof iv === "string" || typeof iv === "number" || typeof iv === "boolean") {
7018
+ const slot = objShape.slots[String(iv)];
7019
+ if (slot) return slot.value;
7020
+ if (objShape.open) return unknown;
7021
+ return undef();
7022
+ }
7023
+ if (objShape.open && slots.length > 0) {
7024
+ return joinAbs(slots.reduce((x, y) => joinAbs(x, y)), unknown);
7025
+ }
7026
+ return joinSlotsWithUndef();
7027
+ }
5514
7028
  const sv = litValue(a);
5515
7029
  if (typeof sv === "string") {
5516
7030
  if (typeof iv === "number" && Number.isInteger(iv)) {
@@ -5570,6 +7084,35 @@ function $obj(slots) {
5570
7084
  function $spread(a, b) {
5571
7085
  return spread(asAbsVal(a), asAbsVal(b));
5572
7086
  }
7087
+ function $objRest(o, keys) {
7088
+ o = asAbsVal(o);
7089
+ if (o.shape.k === "sum") {
7090
+ return o.shape.members.map((m) => $objRest(m, keys)).reduce((a, b) => joinAbs(a, b));
7091
+ }
7092
+ if (!isObj(o)) return unknown;
7093
+ const drop = new Set(keys);
7094
+ const slots = {};
7095
+ let openRest = o.shape.open === true;
7096
+ for (const [k, s] of Object.entries(o.shape.slots)) {
7097
+ if (drop.has(k)) continue;
7098
+ slots[k] = s;
7099
+ }
7100
+ if (o.shape.open) openRest = true;
7101
+ const shape = { k: "obj", slots };
7102
+ if (openRest) shape.open = true;
7103
+ return { shape, conf: o.conf === "exact" ? "exact" : confJoin(o.conf, "partial") };
7104
+ }
7105
+ function $arrRest(a, start) {
7106
+ a = asAbsVal(a);
7107
+ if (a.shape.k === "sum") {
7108
+ return a.shape.members.map((m) => $arrRest(m, start)).reduce((x, y) => joinAbs(x, y));
7109
+ }
7110
+ if (a.shape.k === "tuple") {
7111
+ return tupleOrWiden(a.shape.elements.slice(start), a.conf);
7112
+ }
7113
+ if (a.shape.k === "arr") return a;
7114
+ return unknown;
7115
+ }
5573
7116
  function $concat(a, b) {
5574
7117
  a = asAbsVal(a);
5575
7118
  b = asAbsVal(b);
@@ -5604,20 +7147,49 @@ function $concat(a, b) {
5604
7147
  function $elems(a) {
5605
7148
  if (a.shape.k === "tuple") return [...a.shape.elements];
5606
7149
  if (a.shape.k === "arr") return [a.shape.element];
7150
+ if (isSetAbs(a)) return setElementsAbs(a);
7151
+ if (isMapAbs(a)) return mapEntriesAbs(a);
5607
7152
  return [unknown];
5608
7153
  }
5609
- function $forOf(iterable, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
7154
+ function $forOf(iterable, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
7155
+ const pack = opts?.pack;
7156
+ const unpack = opts?.unpack;
7157
+ let exitJoin;
7158
+ const snapExit = () => {
7159
+ if (!pack) return;
7160
+ const s = pack();
7161
+ exitJoin = exitJoin ? joinAbs(exitJoin, s) : s;
7162
+ };
7163
+ const applyExitJoin = () => {
7164
+ if (!exitJoin || !pack || !unpack) return;
7165
+ unpack(joinAbs(exitJoin, pack()));
7166
+ };
7167
+ const shape = iterable.shape;
5610
7168
  const items = $elems(iterable);
5611
- const n = Math.min(items.length || maxIters, maxIters);
7169
+ const knownLen = shape.k === "tuple" ? shape.elements.length : collectionExactLen(iterable);
7170
+ const unbounded = knownLen === void 0;
7171
+ if (unbounded) snapExit();
7172
+ const n = knownLen !== void 0 ? Math.min(knownLen, maxIters) : items.length > 0 ? maxIters : 0;
5612
7173
  for (let i = 0; i < n; i++) {
5613
7174
  const item = items.length > 0 ? items[Math.min(i, items.length - 1)] : unknown;
5614
- body(item, abs(
5615
- { k: "prim", type: "number" },
5616
- { op: "lit", value: i },
5617
- pTrue,
5618
- "exact"
5619
- ));
7175
+ try {
7176
+ body(
7177
+ item,
7178
+ abs(
7179
+ { k: "prim", type: "number" },
7180
+ { op: "lit", value: i },
7181
+ pTrue,
7182
+ "exact"
7183
+ )
7184
+ );
7185
+ } catch (e) {
7186
+ if (isNudoReturn(e) || isNudoThrow(e)) throw e;
7187
+ throw e;
7188
+ }
7189
+ if (unbounded) snapExit();
5620
7190
  }
7191
+ if (unbounded && n === 0) snapExit();
7192
+ applyExitJoin();
5621
7193
  }
5622
7194
  function namespaceNameOf(v2) {
5623
7195
  if (typeof v2 !== "object" && typeof v2 !== "function") return void 0;
@@ -5665,11 +7237,19 @@ function $get(o, key, opts) {
5665
7237
  }
5666
7238
  return unknown;
5667
7239
  }
5668
- if (o.shape.k === "brand") return $get(o.shape.shape, key, opts);
7240
+ if (o.shape.k === "brand") {
7241
+ if (key === "size" && o.shape.name === "Map") return mapSizeAbs(o);
7242
+ if (key === "size" && o.shape.name === "Set") return setSizeAbs(o);
7243
+ return $get(o.shape.shape, key, opts);
7244
+ }
5669
7245
  if (isObj(o)) {
5670
7246
  const slot = o.shape.slots[key];
5671
- if (slot) return slot.value;
7247
+ if (slot) {
7248
+ if (slot.optional) return joinAbs(slot.value, undef());
7249
+ return slot.value;
7250
+ }
5672
7251
  if (o.shape.open) return unknown;
7252
+ noteObjSlotMissing(o, key);
5673
7253
  return undef();
5674
7254
  }
5675
7255
  if (o.shape.k === "sum") {
@@ -5678,6 +7258,7 @@ function $get(o, key, opts) {
5678
7258
  }
5679
7259
  if (!opts?.silent) {
5680
7260
  noteUnknownMemberMissing(o, key, "property");
7261
+ noteObjSlotMissing(o, key);
5681
7262
  }
5682
7263
  return unknown;
5683
7264
  }
@@ -5725,12 +7306,52 @@ function $while(init, test, step, maxIters = DEFAULT_MAX_LOOP_ITERS) {
5725
7306
  }
5726
7307
  return exitJoin ? joinAbs(exitJoin, state) : state;
5727
7308
  }
5728
- function $whileSeq(test, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
7309
+ function $whileSeq(test, body, maxIters = DEFAULT_MAX_LOOP_ITERS, opts) {
7310
+ const pack = opts?.pack;
7311
+ const unpack = opts?.unpack;
7312
+ let exitJoin;
7313
+ const snapExit = () => {
7314
+ if (!pack) return;
7315
+ const s = pack();
7316
+ exitJoin = exitJoin ? joinAbs(exitJoin, s) : s;
7317
+ };
7318
+ const applyExitJoin = () => {
7319
+ if (!exitJoin || !pack || !unpack) return;
7320
+ unpack(joinAbs(exitJoin, pack()));
7321
+ };
5729
7322
  for (let i = 0; i < maxIters; i++) {
5730
7323
  const t = test();
5731
- if (isDefinitelyFalse(t)) return;
5732
- body();
7324
+ if (isDefinitelyFalse(t)) {
7325
+ applyExitJoin();
7326
+ return;
7327
+ }
7328
+ if (!isDefinitelyTrue(t)) snapExit();
7329
+ try {
7330
+ body();
7331
+ } catch (e) {
7332
+ if (isNudoReturn(e) || isNudoThrow(e)) throw e;
7333
+ throw e;
7334
+ }
7335
+ }
7336
+ snapExit();
7337
+ applyExitJoin();
7338
+ }
7339
+ var NudoReturn = class extends Error {
7340
+ absValue;
7341
+ constructor(absValue) {
7342
+ super("nudo:return");
7343
+ this.name = "NudoReturn";
7344
+ this.absValue = absValue;
5733
7345
  }
7346
+ };
7347
+ function $loopReturn(v2) {
7348
+ throw new NudoReturn(v2);
7349
+ }
7350
+ function isNudoReturn(e) {
7351
+ return e instanceof NudoReturn;
7352
+ }
7353
+ function $rethrowIfNudoReturn(e) {
7354
+ if (isNudoReturn(e)) throw e;
5734
7355
  }
5735
7356
  var NudoThrow = class extends Error {
5736
7357
  absValue;
@@ -5746,11 +7367,35 @@ function $throw(v2) {
5746
7367
  function isNudoThrow(e) {
5747
7368
  return e instanceof NudoThrow;
5748
7369
  }
7370
+ function $isForkExit(e) {
7371
+ return isNudoReturn(e) || isNudoThrow(e);
7372
+ }
5749
7373
  function $catchVal(e) {
5750
7374
  if (isNudoThrow(e)) return e.absValue;
5751
7375
  if (e instanceof Error) {
7376
+ const name = e.name || "Error";
7377
+ const msgAbs = typeof e.message === "string" ? abs(
7378
+ { k: "prim", type: "string" },
7379
+ { op: "lit", value: e.message },
7380
+ pTrue,
7381
+ "exact"
7382
+ ) : abs({ k: "prim", type: "string" }, void 0, void 0, "path");
5752
7383
  return abs(
5753
- { k: "brand", name: e.name || "Error", shape: objOf({}) },
7384
+ {
7385
+ k: "brand",
7386
+ name,
7387
+ shape: objOf({
7388
+ name: {
7389
+ value: abs(
7390
+ { k: "prim", type: "string" },
7391
+ { op: "lit", value: name },
7392
+ pTrue,
7393
+ "exact"
7394
+ )
7395
+ },
7396
+ message: { value: msgAbs }
7397
+ })
7398
+ },
5754
7399
  void 0,
5755
7400
  void 0,
5756
7401
  "path"
@@ -5781,16 +7426,28 @@ function $asyncReturn(v2) {
5781
7426
  if (v2.shape.k === "eff") return v2;
5782
7427
  return wrapPromiseAbs(v2);
5783
7428
  }
5784
- var yieldStack = [];
5785
7429
  function $gen(body) {
5786
7430
  const ys = [];
7431
+ const marker = genPathSensitive;
7432
+ const prevOverride = genJoinOverride;
7433
+ genJoinOverride = null;
5787
7434
  yieldStack.push(ys);
5788
7435
  try {
5789
7436
  body();
5790
7437
  } finally {
5791
7438
  yieldStack.pop();
5792
7439
  }
5793
- return $arr(ys);
7440
+ if (genJoinOverride) {
7441
+ const joined = genJoinOverride;
7442
+ genJoinOverride = prevOverride;
7443
+ return { ...joined, conf: joined.conf === "exact" ? "path" : joined.conf };
7444
+ }
7445
+ genJoinOverride = prevOverride;
7446
+ const arr = $arr(ys);
7447
+ if (genPathSensitive > marker) {
7448
+ return { ...arr, conf: arr.conf === "exact" ? "path" : arr.conf };
7449
+ }
7450
+ return arr;
5794
7451
  }
5795
7452
  function $yield(v2) {
5796
7453
  const top = yieldStack[yieldStack.length - 1];
@@ -5806,10 +7463,63 @@ function $switch(disc, cases, dflt) {
5806
7463
  }
5807
7464
  return dflt ? asAbsVal(dflt()) : undef();
5808
7465
  }
5809
- const parts = cases.map((c) => asAbsVal(c.run()));
5810
- if (dflt) parts.push(asAbsVal(dflt()));
5811
- if (parts.length === 0) return undef();
5812
- return parts.reduce((a, b) => joinAbs(a, b));
7466
+ const exits = loopExitsAls.getStore();
7467
+ beginCollectionFork();
7468
+ const armOverlays2 = [];
7469
+ const armYsList = [];
7470
+ const runArm = (fn) => {
7471
+ pushCollectionArm();
7472
+ try {
7473
+ const r = withIsolatedYields(() => runForkArm(fn, exits));
7474
+ armYsList.push(r.ys);
7475
+ return r.v;
7476
+ } finally {
7477
+ armOverlays2.push(popCollectionArm());
7478
+ }
7479
+ };
7480
+ const results = [];
7481
+ try {
7482
+ const seenRuns = /* @__PURE__ */ new Set();
7483
+ for (const c of cases) {
7484
+ if (seenRuns.has(c.run)) continue;
7485
+ seenRuns.add(c.run);
7486
+ results.push(runArm(c.run));
7487
+ }
7488
+ if (dflt) {
7489
+ if (!seenRuns.has(dflt)) results.push(runArm(dflt));
7490
+ } else {
7491
+ pushCollectionArm();
7492
+ try {
7493
+ results.push({ kind: "val", v: undef() });
7494
+ armYsList.push(null);
7495
+ } finally {
7496
+ armOverlays2.push(popCollectionArm());
7497
+ }
7498
+ }
7499
+ } finally {
7500
+ endCollectionFork(armOverlays2);
7501
+ if (yieldStack.length > 0) mergeArmYields(armYsList);
7502
+ }
7503
+ if (results.length === 0) return undef();
7504
+ const throws = results.filter((r) => r.kind === "throw");
7505
+ const nonThrow = results.filter((r) => r.kind !== "throw");
7506
+ if (nonThrow.length === 0) {
7507
+ throw new NudoThrow(throws.map((t) => t.v).reduce((x, y) => joinAbs(x, y)));
7508
+ }
7509
+ const allRet = nonThrow.every((r) => r.kind === "ret");
7510
+ if (allRet) {
7511
+ throw new NudoReturn(nonThrow.map((r) => r.v).reduce((a, b) => joinAbs(a, b)));
7512
+ }
7513
+ const valParts = nonThrow.filter((r) => r.kind === "val").map((r) => r.v);
7514
+ if (valParts.length === 0) return undef();
7515
+ return valParts.reduce((a, b) => joinAbs(a, b));
7516
+ }
7517
+ function $nullishTest(v2) {
7518
+ if (definitelyNotNullishShape(v2.shape)) return boolLit(false);
7519
+ if (isNullishLitAbs(v2)) return boolLit(true);
7520
+ const t = v2.term;
7521
+ if (t?.op === "lit" && t.value !== null && t.value !== void 0) return boolLit(false);
7522
+ return bool();
5813
7523
  }
5814
7524
 
5815
7525
  // src/algebra/exec/transpile.ts
@@ -5824,6 +7534,7 @@ function matchAsOverride(stmt, opts) {
5824
7534
  function normWs(s) {
5825
7535
  return s.replace(/\s+/g, "");
5826
7536
  }
7537
+ var switchBodySeq = 0;
5827
7538
  function matchReplacement(node, opts) {
5828
7539
  if (!opts.source || !opts.replacements?.length) return null;
5829
7540
  if (node.start == null || node.end == null || !node.loc) return null;
@@ -5848,7 +7559,9 @@ var BIN_OPS = {
5848
7559
  ">": "$gt",
5849
7560
  ">=": "$ge",
5850
7561
  "===": "$eq",
5851
- "!==": "$ne"
7562
+ "!==": "$ne",
7563
+ "==": "$eqLoose",
7564
+ "!=": "$neLoose"
5852
7565
  };
5853
7566
  var COMPOUND_OPS = {
5854
7567
  "+=": "$add",
@@ -5921,6 +7634,65 @@ function setPathSrc(p, valSrc) {
5921
7634
  function readPrefix(p, j) {
5922
7635
  return p.layers.slice(0, j + 1).reduce((acc, l) => l.get(acc), p.rootSrc);
5923
7636
  }
7637
+ var ARR_MUTATOR_NAMES = /* @__PURE__ */ new Set([
7638
+ "push",
7639
+ "unshift",
7640
+ "splice",
7641
+ "pop",
7642
+ "shift",
7643
+ "reverse",
7644
+ "sort"
7645
+ ]);
7646
+ function emitArrMutatorRebinds(expr, opts, pad) {
7647
+ const lines = [];
7648
+ if (!expr || typeof expr !== "object") return lines;
7649
+ const visit = (n) => {
7650
+ if (!n || typeof n !== "object") return;
7651
+ const node = n;
7652
+ if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "ObjectMethod" || node.type === "ClassMethod") {
7653
+ return;
7654
+ }
7655
+ if (node.type === "LogicalExpression" || node.type === "ConditionalExpression") {
7656
+ return;
7657
+ }
7658
+ if (node.type === "AssignmentExpression" && (node.operator === "||=" || node.operator === "&&=" || node.operator === "??=")) {
7659
+ visit(node.left);
7660
+ return;
7661
+ }
7662
+ if (node.type === "CallExpression" && node.callee?.type === "MemberExpression" && node.callee.computed !== true && node.callee.property?.type === "Identifier" && ARR_MUTATOR_NAMES.has(node.callee.property.name)) {
7663
+ const methodName = node.callee.property.name;
7664
+ const argSrcs = (node.arguments ?? []).map(
7665
+ (a) => a.type === "SpreadElement" ? "$lit(undefined)" : isExpression(a) ? transpileExpression(a, opts) : "$lit(undefined)"
7666
+ ).join(", ");
7667
+ const objNode = node.callee.object;
7668
+ if (objNode.type === "Identifier") {
7669
+ const name = objNode.name;
7670
+ lines.push(
7671
+ `${pad}${name} = $arrMutContainer(${name}, ${JSON.stringify(methodName)}, [${argSrcs}]);`
7672
+ );
7673
+ } else if (objNode.type === "MemberExpression" || objNode.type === "ThisExpression") {
7674
+ const path = objNode.type === "MemberExpression" ? memberPathOf(
7675
+ objNode,
7676
+ opts
7677
+ ) : null;
7678
+ if (path) {
7679
+ const recvSrc = readPathSrc(path);
7680
+ const mutSrc = `$arrMutContainer(${recvSrc}, ${JSON.stringify(methodName)}, [${argSrcs}])`;
7681
+ lines.push(`${pad}${path.rootSrc} = ${setPathSrc(path, mutSrc)};`);
7682
+ }
7683
+ }
7684
+ }
7685
+ for (const key of Object.keys(node)) {
7686
+ if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
7687
+ if (key === "callee" || key === "property") continue;
7688
+ const child = node[key];
7689
+ if (Array.isArray(child)) child.forEach(visit);
7690
+ else if (child && typeof child === "object") visit(child);
7691
+ }
7692
+ };
7693
+ visit(expr);
7694
+ return lines;
7695
+ }
5924
7696
  function transpileSource(source, opts = {}) {
5925
7697
  const file = parseSource(source);
5926
7698
  return transpileFile(file, { ...opts, source: opts.source ?? source });
@@ -5929,7 +7701,7 @@ function transpileFile(file, opts = {}) {
5929
7701
  const runtime = opts.runtimeImport ?? "@nudojs/core/exec";
5930
7702
  const lines = [
5931
7703
  `// nudo B-path transpile \u2014 values are Abs; operators are overloaded calls`,
5932
- `import { $add, $sub, $mul, $div, $mod, $neg, $typeof, $not, $eq, $ne, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $while, $whileSeq, $arr, $idx, $idxSet, $len, $call, $throw, $class, $new, $invoke, $invokeSuper, $super, $async, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex } from ${JSON.stringify(runtime)};`,
7704
+ `import { $add, $sub, $mul, $div, $mod, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $while, $whileSeq, $arr, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $class, $new, $invoke, $invokeSuper, $super, $async, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $rethrowIfNudoReturn, $nullishTest, $tryMark, $tryTakeSince, $tryCurrentMark, $tryPopMark, $pushLoopExit, $objRest, $arrRest, $isForkExit } from ${JSON.stringify(runtime)};`,
5933
7705
  ``
5934
7706
  ];
5935
7707
  for (const stmt of file.program.body) {
@@ -5940,12 +7712,226 @@ function transpileFile(file, opts = {}) {
5940
7712
  function indent(n) {
5941
7713
  return " ".repeat(n);
5942
7714
  }
7715
+ function collectAssignedIds(node, acc) {
7716
+ if (!node || typeof node !== "object") return;
7717
+ const n = node;
7718
+ if (n.type === "AssignmentExpression" && n.left?.type === "Identifier" && n.left.name) {
7719
+ acc.add(n.left.name);
7720
+ }
7721
+ if (n.type === "AssignmentExpression" && n.left?.type === "MemberExpression") {
7722
+ let cur = n.left;
7723
+ while (cur?.type === "MemberExpression") cur = cur.object;
7724
+ if (cur?.type === "Identifier" && cur.name) acc.add(cur.name);
7725
+ }
7726
+ if (n.type === "UpdateExpression" && n.argument?.type === "Identifier" && n.argument.name) {
7727
+ acc.add(n.argument.name);
7728
+ }
7729
+ for (const key of Object.keys(n)) {
7730
+ if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
7731
+ const child = n[key];
7732
+ if (Array.isArray(child)) child.forEach((c) => collectAssignedIds(c, acc));
7733
+ else if (child && typeof child === "object") collectAssignedIds(child, acc);
7734
+ }
7735
+ }
7736
+ var FUNCTION_SCOPE_TYPES = /* @__PURE__ */ new Set([
7737
+ "FunctionDeclaration",
7738
+ "FunctionExpression",
7739
+ "ArrowFunctionExpression",
7740
+ "ObjectMethod",
7741
+ "ClassMethod",
7742
+ "ClassPrivateMethod"
7743
+ ]);
7744
+ var BINDING_SCOPE_TYPES = /* @__PURE__ */ new Set([
7745
+ ...FUNCTION_SCOPE_TYPES,
7746
+ "CatchClause",
7747
+ "ForOfStatement",
7748
+ "ForInStatement"
7749
+ ]);
7750
+ function collectPatternNames(id, acc) {
7751
+ if (!id || typeof id !== "object") return;
7752
+ const n = id;
7753
+ if (n.type === "Identifier" && n.name) acc.add(n.name);
7754
+ else if (n.type === "RestElement") collectPatternNames(n.argument, acc);
7755
+ else if (n.type === "AssignmentPattern") collectPatternNames(n.left, acc);
7756
+ else if (n.type === "ObjectPattern") {
7757
+ for (const p of n.properties ?? []) {
7758
+ const prop = p;
7759
+ if (prop?.type === "RestElement") collectPatternNames(prop.argument, acc);
7760
+ else collectPatternNames(prop?.value, acc);
7761
+ }
7762
+ } else if (n.type === "ArrayPattern") {
7763
+ for (const el of n.elements ?? []) collectPatternNames(el, acc);
7764
+ }
7765
+ }
7766
+ var freeAssignedCache = /* @__PURE__ */ new WeakMap();
7767
+ var mutatorRecvCache = /* @__PURE__ */ new WeakMap();
7768
+ function collectFreeAssignedNames(...nodes) {
7769
+ const cachedParts = [];
7770
+ const pending = [];
7771
+ for (const node of nodes) {
7772
+ if (node && typeof node === "object") {
7773
+ const hit = freeAssignedCache.get(node);
7774
+ if (hit) {
7775
+ cachedParts.push(hit);
7776
+ continue;
7777
+ }
7778
+ pending.push(node);
7779
+ }
7780
+ }
7781
+ if (pending.length === 0) {
7782
+ const merged2 = /* @__PURE__ */ new Set();
7783
+ for (const p of cachedParts) for (const n of p) merged2.add(n);
7784
+ return [...merged2];
7785
+ }
7786
+ const free = /* @__PURE__ */ new Set();
7787
+ const markFree = (name, shadowed) => {
7788
+ if (name && name !== "undefined" && !shadowed.has(name)) free.add(name);
7789
+ };
7790
+ const walk = (node, shadowed) => {
7791
+ if (!node || typeof node !== "object") return;
7792
+ const n = node;
7793
+ let nextShadowed = shadowed;
7794
+ const pushShadow = (names) => {
7795
+ const add2 = [];
7796
+ for (const name of names) {
7797
+ if (name && !nextShadowed.has(name)) add2.push(name);
7798
+ }
7799
+ if (add2.length === 0) return;
7800
+ nextShadowed = new Set(nextShadowed);
7801
+ for (const name of add2) nextShadowed.add(name);
7802
+ };
7803
+ if (FUNCTION_SCOPE_TYPES.has(n.type)) {
7804
+ const bound = /* @__PURE__ */ new Set();
7805
+ collectPatternNames(n.id, bound);
7806
+ for (const p of n.params ?? []) collectPatternNames(p, bound);
7807
+ pushShadow(bound);
7808
+ } else if (n.type === "CatchClause") {
7809
+ const bound = /* @__PURE__ */ new Set();
7810
+ collectPatternNames(n.param, bound);
7811
+ pushShadow(bound);
7812
+ } else if (n.type === "ForOfStatement" || n.type === "ForInStatement") {
7813
+ const bound = /* @__PURE__ */ new Set();
7814
+ const left = n.left;
7815
+ if (left?.type === "VariableDeclaration") {
7816
+ for (const d of left.declarations ?? []) collectPatternNames(d.id, bound);
7817
+ } else {
7818
+ collectPatternNames(left, bound);
7819
+ }
7820
+ pushShadow(bound);
7821
+ }
7822
+ if (n.type === "AssignmentExpression") {
7823
+ const left = n.left;
7824
+ if (left?.type === "Identifier") markFree(left.name, nextShadowed);
7825
+ else if (left?.type === "MemberExpression") {
7826
+ let cur = left;
7827
+ while (cur?.type === "MemberExpression") {
7828
+ cur = cur.object;
7829
+ }
7830
+ if (cur?.type === "Identifier") markFree(cur.name, nextShadowed);
7831
+ }
7832
+ }
7833
+ if (n.type === "UpdateExpression") {
7834
+ const arg = n.argument;
7835
+ if (arg?.type === "Identifier") markFree(arg.name, nextShadowed);
7836
+ }
7837
+ if (n.type === "CallExpression" && n.callee?.type === "MemberExpression" && n.callee.computed !== true && n.callee.property?.type === "Identifier" && ARR_MUTATOR_NAMES.has(n.callee.property.name)) {
7838
+ const obj2 = n.callee.object;
7839
+ if (obj2?.type === "Identifier") markFree(obj2.name, nextShadowed);
7840
+ else if (obj2?.type === "MemberExpression" || obj2?.type === "ThisExpression") {
7841
+ let cur = obj2;
7842
+ while (cur?.type === "MemberExpression") {
7843
+ cur = cur.object;
7844
+ }
7845
+ if (cur?.type === "Identifier") markFree(cur.name, nextShadowed);
7846
+ }
7847
+ }
7848
+ for (const key of Object.keys(n)) {
7849
+ if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
7850
+ if (key === "callee" || key === "property" || key === "param" || key === "params") continue;
7851
+ const child = n[key];
7852
+ if (Array.isArray(child)) {
7853
+ if (n.type === "BlockStatement" || n.type === "Program" || n.type === "StaticBlock" || n.type === "SwitchCase") {
7854
+ let blockShadow = nextShadowed;
7855
+ for (const stmt of child) {
7856
+ walk(stmt, blockShadow);
7857
+ const stmtNode = stmt;
7858
+ if (!stmtNode) continue;
7859
+ const declared = /* @__PURE__ */ new Set();
7860
+ if (stmtNode.type === "VariableDeclaration") {
7861
+ for (const d of stmtNode.declarations ?? []) collectPatternNames(d.id, declared);
7862
+ } else if (stmtNode.type === "FunctionDeclaration" || stmtNode.type === "ClassDeclaration") {
7863
+ collectPatternNames(stmtNode.id, declared);
7864
+ }
7865
+ if (declared.size > 0) {
7866
+ if (blockShadow === nextShadowed) blockShadow = new Set(blockShadow);
7867
+ for (const name of declared) blockShadow.add(name);
7868
+ }
7869
+ }
7870
+ continue;
7871
+ }
7872
+ for (const item of child) walk(item, nextShadowed);
7873
+ } else if (child && typeof child === "object") {
7874
+ walk(child, nextShadowed);
7875
+ }
7876
+ }
7877
+ if (FUNCTION_SCOPE_TYPES.has(n.type) && n.body) {
7878
+ walk(n.body, nextShadowed);
7879
+ }
7880
+ };
7881
+ for (const node of pending) {
7882
+ walk(node, /* @__PURE__ */ new Set());
7883
+ }
7884
+ const computed = [...free];
7885
+ for (const node of pending) freeAssignedCache.set(node, computed);
7886
+ const merged = new Set(computed);
7887
+ for (const p of cachedParts) for (const n of p) merged.add(n);
7888
+ return [...merged];
7889
+ }
7890
+ function collectForkBindingNames(...nodes) {
7891
+ return collectFreeAssignedNames(...nodes);
7892
+ }
7893
+ function stmtCompletesControl(stmt) {
7894
+ if (!stmt) return false;
7895
+ switch (stmt.type) {
7896
+ case "BreakStatement":
7897
+ case "ReturnStatement":
7898
+ case "ThrowStatement":
7899
+ case "ContinueStatement":
7900
+ return true;
7901
+ case "BlockStatement":
7902
+ return stmtCompletesControl(stmt.body[stmt.body.length - 1]);
7903
+ case "IfStatement":
7904
+ return stmt.alternate != null && stmtCompletesControl(stmt.consequent) && stmtCompletesControl(stmt.alternate);
7905
+ default:
7906
+ return false;
7907
+ }
7908
+ }
5943
7909
  function stmtReturns(stmt) {
5944
7910
  if (stmt.type === "ReturnStatement" || stmt.type === "ThrowStatement") return true;
5945
7911
  if (stmt.type === "BlockStatement") return stmt.body.some(stmtReturns);
5946
7912
  if (stmt.type === "IfStatement") {
5947
7913
  return stmtReturns(stmt.consequent) && stmt.alternate != null && stmtReturns(stmt.alternate);
5948
7914
  }
7915
+ if (stmt.type === "SwitchStatement") {
7916
+ const arms = [];
7917
+ for (const c of stmt.cases) {
7918
+ const testIsDefault = c.test === null || c.test === void 0;
7919
+ const last = arms[arms.length - 1];
7920
+ if (last && !last.isDefault && last.stmts.length === 0 && !testIsDefault) {
7921
+ last.stmts = c.consequent;
7922
+ continue;
7923
+ }
7924
+ if (last && !last.isDefault && !testIsDefault && last.stmts.length > 0 && c.consequent.length === 0) {
7925
+ continue;
7926
+ }
7927
+ arms.push({ stmts: c.consequent, isDefault: testIsDefault });
7928
+ }
7929
+ const armOk = (a) => a.stmts.length > 0 && a.stmts.every(stmtReturns);
7930
+ const nonDefault = arms.filter((a) => !a.isDefault);
7931
+ const dflt = arms.find((a) => a.isDefault);
7932
+ if (dflt === void 0) return false;
7933
+ return nonDefault.length > 0 && nonDefault.every(armOk) && armOk(dflt);
7934
+ }
5949
7935
  return false;
5950
7936
  }
5951
7937
  function transpileFnBodyStmts(stmts, depth, opts) {
@@ -5957,11 +7943,61 @@ function transpileFnBodyStmts(stmts, depth, opts) {
5957
7943
  if (rest.length === 0) continue;
5958
7944
  const head = stmts.slice(0, i).map((s) => transpileStatement(s, depth, opts)).join("\n");
5959
7945
  const test = transpileExpression(stmt.test, opts);
5960
- const cons = transpileBlockAsThunk(stmt.consequent, depth, opts);
5961
- const altBody = transpileFnBodyStmts(rest, depth + 1, opts);
5962
- const promoted = `${indent(depth)}return $fork(${test}, ${cons}, () => {
7946
+ const recvSet = /* @__PURE__ */ new Set([
7947
+ ...collectForkBindingNames(stmt.consequent),
7948
+ ...collectForkBindingNames(stmt.test),
7949
+ ...rest.flatMap((r) => collectForkBindingNames(r))
7950
+ ]);
7951
+ const names = [...recvSet];
7952
+ const pad = indent(depth);
7953
+ const padIn = indent(depth + 1);
7954
+ const wrapArm = (thunk, outPrefix) => {
7955
+ if (names.length === 0) return thunk;
7956
+ return [
7957
+ `() => {`,
7958
+ ...names.map((n) => `${padIn}${n} = __fk0_${n};`),
7959
+ `${padIn}let __cont = true;`,
7960
+ `${padIn}try {`,
7961
+ `${padIn} return (${thunk})();`,
7962
+ `${padIn}} catch (e) {`,
7963
+ `${padIn} if ($isForkExit(e)) __cont = false;`,
7964
+ `${padIn} throw e;`,
7965
+ `${padIn}} finally {`,
7966
+ `${padIn} if (__cont) {`,
7967
+ ...names.map((n) => `${padIn} __${outPrefix}${n} = ${n};`),
7968
+ ...names.map((n) => `${padIn} __${outPrefix}set_${n} = true;`),
7969
+ `${padIn} }`,
7970
+ `${padIn}}`,
7971
+ `}`
7972
+ ].join("\n");
7973
+ };
7974
+ const testRecvs = collectArrMutatorReceivers(stmt.test);
7975
+ const testRebinds = testRecvs.size ? emitArrMutatorRebinds(stmt.test, opts, pad) : [];
7976
+ const cons = wrapArm(transpileBlockAsThunk(stmt.consequent, depth, opts), "fk1_");
7977
+ const altBody = transpileFnBodyStmts(rest, depth + 1, { ...opts, inLoop: opts.inLoop });
7978
+ const altThunk = `() => {
5963
7979
  ${altBody}
5964
- ${indent(depth)}});`;
7980
+ ${pad}}`;
7981
+ const alt = wrapArm(altThunk, "fk2_");
7982
+ const inCtrl = (opts.inLoop ?? 0) > 0 || (opts.inTry ?? 0) > 0;
7983
+ const applyJoin = names.length ? forkJoinBindings(names, pad).join("\n") : "";
7984
+ if (names.length === 0) {
7985
+ const promoted2 = [
7986
+ ...testRebinds,
7987
+ inCtrl ? `${pad}$loopReturn($fork(${test}, ${cons}, ${alt}));` : `${pad}return $fork(${test}, ${cons}, ${alt});`
7988
+ ].join("\n");
7989
+ return head ? `${head}
7990
+ ${promoted2}` : promoted2;
7991
+ }
7992
+ const promoted = [
7993
+ `${pad}{`,
7994
+ ...testRebinds,
7995
+ ...forkBindingDecls(names, padIn),
7996
+ `${padIn}const __fkR = $fork(${test}, ${cons}, ${alt});`,
7997
+ applyJoin.split("\n").map((l) => l.replace(/^\s*/, padIn)).join("\n"),
7998
+ inCtrl ? `${padIn}$loopReturn(__fkR);` : `${padIn}return __fkR;`,
7999
+ `${pad}}`
8000
+ ].join("\n");
5965
8001
  return head ? `${head}
5966
8002
  ${promoted}` : promoted;
5967
8003
  }
@@ -5973,11 +8009,18 @@ function emitDestructure(pattern, fromSrc, kw, pad, opts, out, tmpSeq) {
5973
8009
  return;
5974
8010
  }
5975
8011
  if (pattern.type === "ObjectPattern") {
8012
+ const namedKeys = [];
8013
+ let restName;
5976
8014
  for (const prop of pattern.properties) {
8015
+ if (prop.type === "RestElement") {
8016
+ if (prop.argument.type === "Identifier") restName = prop.argument.name;
8017
+ continue;
8018
+ }
5977
8019
  if (prop.type !== "ObjectProperty") continue;
5978
8020
  if (prop.key.type !== "Identifier" && prop.key.type !== "StringLiteral") continue;
5979
8021
  const key = prop.key.type === "Identifier" ? prop.key.name : String(prop.key.value);
5980
8022
  const keyLit = JSON.stringify(key);
8023
+ namedKeys.push(key);
5981
8024
  if (prop.value.type === "AssignmentPattern") {
5982
8025
  const def = transpileExpression(prop.value.right, opts);
5983
8026
  const left = prop.value.left;
@@ -6002,11 +8045,25 @@ function emitDestructure(pattern, fromSrc, kw, pad, opts, out, tmpSeq) {
6002
8045
  out.push(`${pad}${kw} ${prop.value.name} = $get(${fromSrc}, ${keyLit});`);
6003
8046
  }
6004
8047
  }
8048
+ if (restName) {
8049
+ out.push(
8050
+ `${pad}${kw} ${restName} = $objRest(${fromSrc}, ${JSON.stringify(namedKeys)});`
8051
+ );
8052
+ }
6005
8053
  return;
6006
8054
  }
6007
8055
  if (pattern.type === "ArrayPattern") {
8056
+ let restName;
8057
+ let restAt = 0;
6008
8058
  pattern.elements.forEach((el, i) => {
6009
8059
  if (!el) return;
8060
+ if (el.type === "RestElement") {
8061
+ if (el.argument.type === "Identifier") {
8062
+ restName = el.argument.name;
8063
+ restAt = i;
8064
+ }
8065
+ return;
8066
+ }
6010
8067
  if (el.type === "AssignmentPattern") {
6011
8068
  const def = transpileExpression(el.right, opts);
6012
8069
  const idx = `$idx(${fromSrc}, $lit(${i}))`;
@@ -6029,6 +8086,9 @@ function emitDestructure(pattern, fromSrc, kw, pad, opts, out, tmpSeq) {
6029
8086
  out.push(`${pad}${kw} ${el.name} = $idx(${fromSrc}, $lit(${i}));`);
6030
8087
  }
6031
8088
  });
8089
+ if (restName) {
8090
+ out.push(`${pad}${kw} ${restName} = $arrRest(${fromSrc}, ${restAt});`);
8091
+ }
6032
8092
  }
6033
8093
  }
6034
8094
  function emitParamBinding(params, pad, opts) {
@@ -6069,6 +8129,122 @@ function emitParamBinding(params, pad, opts) {
6069
8129
  });
6070
8130
  return { sig, rest, prologue };
6071
8131
  }
8132
+ function collectArrMutatorReceivers(node, acc = /* @__PURE__ */ new Set()) {
8133
+ if (!node || typeof node !== "object") return acc;
8134
+ const hit = mutatorRecvCache.get(node);
8135
+ if (hit) {
8136
+ for (const n of hit) acc.add(n);
8137
+ return acc;
8138
+ }
8139
+ const local = /* @__PURE__ */ new Set();
8140
+ collectArrMutatorReceiversUncached(node, local);
8141
+ mutatorRecvCache.set(node, local);
8142
+ for (const n of local) acc.add(n);
8143
+ return acc;
8144
+ }
8145
+ function collectArrMutatorReceiversUncached(node, acc = /* @__PURE__ */ new Set()) {
8146
+ if (!node || typeof node !== "object") return acc;
8147
+ const n = node;
8148
+ if (n.type === "FunctionExpression" || n.type === "ArrowFunctionExpression" || n.type === "ObjectMethod" || n.type === "ClassMethod" || n.type === "FunctionDeclaration") {
8149
+ return acc;
8150
+ }
8151
+ if (n.type === "CallExpression" && n.callee?.type === "MemberExpression") {
8152
+ const callee = n.callee;
8153
+ const propName = !callee.computed && callee.property?.type === "Identifier" ? callee.property.name : void 0;
8154
+ if (propName && ARR_MUTATOR_NAMES.has(propName)) {
8155
+ const obj2 = callee.object;
8156
+ if (obj2?.type === "Identifier") {
8157
+ acc.add(obj2.name);
8158
+ } else if (obj2?.type === "MemberExpression") {
8159
+ let cur = obj2;
8160
+ while (cur?.type === "MemberExpression") {
8161
+ cur = cur.object;
8162
+ }
8163
+ if (cur?.type === "Identifier") {
8164
+ acc.add(cur.name);
8165
+ }
8166
+ }
8167
+ }
8168
+ }
8169
+ for (const key of Object.keys(n)) {
8170
+ if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
8171
+ const child = n[key];
8172
+ if (Array.isArray(child)) child.forEach((c) => collectArrMutatorReceiversUncached(c, acc));
8173
+ else if (child && typeof child === "object") collectArrMutatorReceiversUncached(child, acc);
8174
+ }
8175
+ return acc;
8176
+ }
8177
+ function forkArmThunk(bodyLines, outPrefix, names) {
8178
+ return [
8179
+ `() => {`,
8180
+ ...names.map((n) => ` ${n} = __fk0_${n};`),
8181
+ ` let __cont = true;`,
8182
+ ` try {`,
8183
+ ...bodyLines.map((l) => ` ${l}`),
8184
+ ` } catch (e) {`,
8185
+ ` if ($isForkExit(e)) __cont = false;`,
8186
+ ` throw e;`,
8187
+ ` } finally {`,
8188
+ ` if (__cont) {`,
8189
+ ...names.map((n) => ` __${outPrefix}${n} = ${n};`),
8190
+ ...names.map((n) => ` __${outPrefix}set_${n} = true;`),
8191
+ ` }`,
8192
+ ` }`,
8193
+ `}`
8194
+ ].join("\n");
8195
+ }
8196
+ function forkBindingDecls(names, pad = "") {
8197
+ return names.flatMap((n) => [
8198
+ `${pad}const __fk0_${n} = ${n};`,
8199
+ `${pad}let __fk1_${n}; let __fk2_${n};`,
8200
+ `${pad}let __fk1_set_${n} = false; let __fk2_set_${n} = false;`
8201
+ ]);
8202
+ }
8203
+ function forkJoinBindings(names, pad = "") {
8204
+ return names.map(
8205
+ (n) => `${pad}${n} = (__fk1_set_${n} && __fk2_set_${n}) ? $join(__fk1_${n}, __fk2_${n}) : (__fk1_set_${n} ? __fk1_${n} : (__fk2_set_${n} ? __fk2_${n} : ${n}));`
8206
+ );
8207
+ }
8208
+ function transpileShortCircuitExpr(opts, parts) {
8209
+ const alwaysNames = new Set(collectForkBindingNames(...parts.alwaysNodes));
8210
+ const branchNames = new Set(alwaysNames);
8211
+ for (const n of parts.consNodes) for (const id of collectForkBindingNames(n)) branchNames.add(id);
8212
+ for (const n of parts.altNodes) for (const id of collectForkBindingNames(n)) branchNames.add(id);
8213
+ const names = [...branchNames];
8214
+ const alwaysRebinds = [];
8215
+ for (const n of parts.alwaysNodes) {
8216
+ alwaysRebinds.push(...emitArrMutatorRebinds(n, opts, ""));
8217
+ }
8218
+ const consRebinds = [];
8219
+ for (const n of parts.consNodes) {
8220
+ if (parts.alwaysNodes.includes(n)) continue;
8221
+ consRebinds.push(...emitArrMutatorRebinds(n, opts, ""));
8222
+ }
8223
+ const altRebinds = [];
8224
+ for (const n of parts.altNodes) {
8225
+ if (parts.alwaysNodes.includes(n)) continue;
8226
+ altRebinds.push(...emitArrMutatorRebinds(n, opts, ""));
8227
+ }
8228
+ if (alwaysNames.size === 0 && branchNames.size === 0) {
8229
+ const forkTest2 = parts.testSrc ?? parts.alwaysSrc;
8230
+ const consExpr = parts.consSrc === "__test" ? parts.alwaysSrc : parts.consSrc;
8231
+ const altExpr = parts.altSrc === "__test" ? parts.alwaysSrc : parts.altSrc;
8232
+ return `$fork(${forkTest2}, () => ${consExpr}, () => ${altExpr})`;
8233
+ }
8234
+ const consLines = parts.consSrc === "__test" ? [`return __test;`] : consRebinds.length === 0 ? [`return (${parts.consSrc});`] : [`const __v = (${parts.consSrc});`, ...consRebinds, `return __v;`];
8235
+ const altLines = parts.altSrc === "__test" ? [`return __test;`] : altRebinds.length === 0 ? [`return (${parts.altSrc});`] : [`const __v = (${parts.altSrc});`, ...altRebinds, `return __v;`];
8236
+ const forkTest = parts.testSrc ?? "__test";
8237
+ return [
8238
+ `(() => {`,
8239
+ ` const __test = (${parts.alwaysSrc});`,
8240
+ ...alwaysRebinds.map((l) => ` ${l}`),
8241
+ ...names.length ? forkBindingDecls(names, " ") : [],
8242
+ ` const __r = $fork(${forkTest}, ${forkArmThunk(consLines, "fk1_", names)}, ${forkArmThunk(altLines, "fk2_", names)});`,
8243
+ ...forkJoinBindings(names, " "),
8244
+ ` return __r;`,
8245
+ `})()`
8246
+ ].join("\n");
8247
+ }
6072
8248
  function transpileStatement(stmt, depth, opts) {
6073
8249
  const pad = indent(depth);
6074
8250
  switch (stmt.type) {
@@ -6106,20 +8282,22 @@ function transpileStatement(stmt, depth, opts) {
6106
8282
  }
6107
8283
  case "FunctionDeclaration": {
6108
8284
  if (!stmt.id) return `${pad}// <anonymous fn skipped>`;
8285
+ const exportKw = depth === 0 ? "export " : "";
8286
+ const fnOpts = { ...opts, inLoop: 0 };
6109
8287
  const { sig, rest, prologue } = emitParamBinding(
6110
8288
  stmt.params,
6111
8289
  indent(depth + 2),
6112
- opts
8290
+ fnOpts
6113
8291
  );
6114
8292
  const named = sig;
6115
8293
  const paramsSig = rest ? [...named, `...${rest}`] : named;
6116
8294
  const params = paramsSig.join(", ");
6117
- const bodyStmts = stmt.body.type === "BlockStatement" ? [...prologue, transpileFnBodyStmts(stmt.body.body, depth + 2, opts)].join("\n") : `${indent(depth + 2)}return ${transpileExpression(stmt.body, opts)};`;
8295
+ const bodyStmts = stmt.body.type === "BlockStatement" ? [...prologue, transpileFnBodyStmts(stmt.body.body, depth + 2, fnOpts)].join("\n") : `${indent(depth + 2)}return ${transpileExpression(stmt.body, fnOpts)};`;
6118
8296
  const restBind = rest ? `${indent(depth + 1)}const ${rest} = arguments.length > ${named.length} ? $arr(Array.from(arguments).slice(${named.length})) : $arr([]);
6119
8297
  ` : "";
6120
8298
  if (stmt.generator) {
6121
8299
  return [
6122
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
8300
+ `${pad}${exportKw}function ${stmt.id.name}(${named.join(", ")}) {`,
6123
8301
  restBind,
6124
8302
  `${indent(depth + 1)}return $gen(() => {`,
6125
8303
  bodyStmts,
@@ -6129,7 +8307,7 @@ function transpileStatement(stmt, depth, opts) {
6129
8307
  }
6130
8308
  if (stmt.async) {
6131
8309
  return [
6132
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
8310
+ `${pad}${exportKw}function ${stmt.id.name}(${named.join(", ")}) {`,
6133
8311
  restBind,
6134
8312
  `${indent(depth + 1)}return $async(() => {`,
6135
8313
  bodyStmts,
@@ -6138,7 +8316,7 @@ function transpileStatement(stmt, depth, opts) {
6138
8316
  ].join("\n");
6139
8317
  }
6140
8318
  return [
6141
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
8319
+ `${pad}${exportKw}function ${stmt.id.name}(${named.join(", ")}) {`,
6142
8320
  restBind,
6143
8321
  bodyStmts,
6144
8322
  `${pad}}`
@@ -6146,16 +8324,73 @@ function transpileStatement(stmt, depth, opts) {
6146
8324
  }
6147
8325
  case "ReturnStatement": {
6148
8326
  const asVar = matchAsOverride(stmt, opts);
6149
- if (asVar) return `${pad}return ${asVar};`;
6150
- if (!stmt.argument) return `${pad}return $lit(undefined);`;
6151
- return `${pad}return ${transpileExpression(stmt.argument, opts)};`;
8327
+ const prefix = (opts.inLoop ?? 0) > 0 ? "$loopReturn" : "return";
8328
+ const markExpr = opts.tryMarkName ?? "$tryCurrentMark()";
8329
+ const emitRet = (src, mutNodes) => {
8330
+ const retRebinds = mutNodes ? emitArrMutatorRebinds(mutNodes, opts, pad) : [];
8331
+ if ((opts.inTry ?? 0) > 0) {
8332
+ return [
8333
+ `${pad}const __nudoRet = ${src};`,
8334
+ ...retRebinds,
8335
+ `${pad}{`,
8336
+ `${indent(depth + 1)}const __xs = $tryTakeSince(${markExpr});`,
8337
+ `${indent(depth + 1)}if (__xs.length) {`,
8338
+ `${indent(depth + 2)}$pushLoopExit(__nudoRet);`,
8339
+ `${indent(depth + 2)}$throw(__xs.reduce((a, b) => $join(a, b)));`,
8340
+ `${indent(depth + 1)}}`,
8341
+ `${pad}}`,
8342
+ `${pad}${prefix}(__nudoRet);`
8343
+ ].join("\n");
8344
+ }
8345
+ if (retRebinds.length === 0) return `${pad}${prefix}(${src});`;
8346
+ return [
8347
+ `${pad}let __mutRet = ${src};`,
8348
+ ...retRebinds,
8349
+ `${pad}${prefix}(__mutRet);`
8350
+ ].join("\n");
8351
+ };
8352
+ if (asVar) return emitRet(asVar);
8353
+ if (!stmt.argument) return emitRet(`$lit(undefined)`);
8354
+ const retSrc = transpileExpression(stmt.argument, opts);
8355
+ return emitRet(retSrc, stmt.argument);
6152
8356
  }
6153
8357
  case "ThrowStatement": {
6154
8358
  const arg = stmt.argument ? transpileExpression(stmt.argument, opts) : "$lit(undefined)";
6155
8359
  return `${pad}$throw(${arg});`;
6156
8360
  }
6157
- case "ExpressionStatement":
8361
+ case "ExpressionStatement": {
8362
+ const expr = stmt.expression;
8363
+ const exprRebinds = emitArrMutatorRebinds(expr, opts, pad);
8364
+ if (expr.type === "CallExpression" && expr.callee.type === "MemberExpression" && !expr.callee.computed && expr.callee.property.type === "Identifier") {
8365
+ const methodName = expr.callee.property.name;
8366
+ if (["push", "unshift", "splice", "pop", "shift", "reverse", "sort"].includes(methodName)) {
8367
+ const argSrcs = expr.arguments.map(
8368
+ (a) => a.type === "SpreadElement" ? "$lit(undefined)" : transpileExpression(a, opts)
8369
+ ).join(", ");
8370
+ const objNode = expr.callee.object;
8371
+ if (objNode.type === "Identifier") {
8372
+ const name = objNode.name;
8373
+ return `${pad}${name} = $arrMutContainer(${name}, ${JSON.stringify(methodName)}, [${argSrcs}]);`;
8374
+ }
8375
+ if (objNode.type === "MemberExpression" || objNode.type === "ThisExpression") {
8376
+ const path = objNode.type === "MemberExpression" ? memberPathOf(objNode, opts) : null;
8377
+ if (path) {
8378
+ const recvSrc = readPathSrc(path);
8379
+ const mutSrc = `$arrMutContainer(${recvSrc}, ${JSON.stringify(methodName)}, [${argSrcs}])`;
8380
+ return `${pad}${path.rootSrc} = ${setPathSrc(path, mutSrc)};`;
8381
+ }
8382
+ return `${pad}${transpileExpression(stmt.expression, opts)};`;
8383
+ }
8384
+ }
8385
+ }
8386
+ if (exprRebinds.length > 0) {
8387
+ return [
8388
+ `${pad}${transpileExpression(expr, opts)};`,
8389
+ ...exprRebinds
8390
+ ].join("\n");
8391
+ }
6158
8392
  return `${pad}${transpileExpression(stmt.expression, opts)};`;
8393
+ }
6159
8394
  case "VariableDeclaration": {
6160
8395
  const kw = "let";
6161
8396
  const asVar = matchAsOverride(stmt, opts);
@@ -6165,6 +8400,9 @@ function transpileStatement(stmt, depth, opts) {
6165
8400
  if (d.id.type === "Identifier") {
6166
8401
  const init = asVar ? asVar : d.init ? transpileExpression(d.init, opts) : "$lit(undefined)";
6167
8402
  lines.push(`${pad}${kw} ${d.id.name} = ${init};`);
8403
+ if (d.init && !asVar) {
8404
+ lines.push(...emitArrMutatorRebinds(d.init, opts, pad));
8405
+ }
6168
8406
  continue;
6169
8407
  }
6170
8408
  if (!d.init) {
@@ -6174,18 +8412,74 @@ function transpileStatement(stmt, depth, opts) {
6174
8412
  const initSrc = transpileExpression(d.init, opts);
6175
8413
  const tmp = `_d${tmpSeq++}_${stmt.loc?.start.line ?? 0}`;
6176
8414
  lines.push(`${pad}const ${tmp} = ${initSrc};`);
8415
+ lines.push(...emitArrMutatorRebinds(d.init, opts, pad));
6177
8416
  emitDestructure(d.id, tmp, kw, pad, opts, lines, { n: 0 });
6178
8417
  }
6179
8418
  return lines.join("\n");
6180
8419
  }
6181
8420
  case "IfStatement": {
6182
8421
  const test = transpileExpression(stmt.test, opts);
6183
- const cons = transpileBlockAsThunk(stmt.consequent, depth, opts);
6184
- const alt = stmt.alternate ? transpileBlockAsThunk(stmt.alternate, depth, opts) : "undefined";
8422
+ const recvSet = /* @__PURE__ */ new Set([
8423
+ ...collectForkBindingNames(stmt.consequent),
8424
+ ...collectForkBindingNames(stmt.alternate)
8425
+ ]);
8426
+ const testRecvs = collectArrMutatorReceivers(stmt.test);
8427
+ const testRebinds = testRecvs.size ? emitArrMutatorRebinds(stmt.test, opts, pad) : [];
8428
+ const names = [...recvSet];
8429
+ const padIn = indent(depth + 1);
8430
+ const padDecl = names.length > 0 ? padIn : pad;
8431
+ const wrapArm = (thunk, outPrefix) => {
8432
+ if (names.length === 0) return thunk;
8433
+ return [
8434
+ `() => {`,
8435
+ ...names.map((n) => `${padIn}${n} = __fk0_${n};`),
8436
+ `${padIn}let __cont = true;`,
8437
+ `${padIn}try {`,
8438
+ `${padIn} return (${thunk})();`,
8439
+ `${padIn}} catch (e) {`,
8440
+ `${padIn} if ($isForkExit(e)) __cont = false;`,
8441
+ `${padIn} throw e;`,
8442
+ `${padIn}} finally {`,
8443
+ `${padIn} if (__cont) {`,
8444
+ ...names.map((n) => `${padIn} __${outPrefix}${n} = ${n};`),
8445
+ ...names.map((n) => `${padIn} __${outPrefix}set_${n} = true;`),
8446
+ `${padIn} }`,
8447
+ `${padIn}}`,
8448
+ `}`
8449
+ ].join("\n");
8450
+ };
8451
+ const consRaw = transpileBlockAsThunk(stmt.consequent, depth, opts);
8452
+ const altRaw = stmt.alternate ? transpileBlockAsThunk(stmt.alternate, depth, opts) : "undefined";
8453
+ const cons = wrapArm(consRaw, "fk1_");
8454
+ const alt = names.length ? wrapArm(altRaw === "undefined" ? "() => $lit(undefined)" : altRaw, "fk2_") : altRaw;
8455
+ const joinLines = names.length ? [...testRebinds, ...forkBindingDecls(names, padDecl)] : testRebinds;
8456
+ const applyJoin = names.length ? forkJoinBindings(names, padDecl).join("\n") : "";
8457
+ const inCtrl = (opts.inLoop ?? 0) > 0;
8458
+ const openBlock = names.length > 0 ? `${pad}{` : null;
8459
+ const closeBlock = names.length > 0 ? `${pad}}` : null;
6185
8460
  if (stmtReturns(stmt.consequent) && stmt.alternate !== void 0 && stmt.alternate !== null && stmtReturns(stmt.alternate)) {
6186
- return `${pad}return $fork(${test}, ${cons}, ${alt});`;
8461
+ if (names.length === 0) {
8462
+ return [
8463
+ ...joinLines,
8464
+ inCtrl ? `${pad}$loopReturn($fork(${test}, ${cons}, ${alt}));` : `${pad}return $fork(${test}, ${cons}, ${alt});`
8465
+ ].join("\n");
8466
+ }
8467
+ return [
8468
+ openBlock,
8469
+ ...joinLines,
8470
+ `${padDecl}const __fkR = $fork(${test}, ${cons}, ${alt});`,
8471
+ applyJoin,
8472
+ inCtrl ? `${padDecl}$loopReturn(__fkR);` : `${padDecl}return __fkR;`,
8473
+ closeBlock
8474
+ ].join("\n");
6187
8475
  }
6188
- return `${pad}$fork(${test}, ${cons}, ${alt});`;
8476
+ return [
8477
+ openBlock,
8478
+ ...joinLines,
8479
+ `${padDecl}$fork(${test}, ${cons}, ${alt});`,
8480
+ applyJoin,
8481
+ closeBlock
8482
+ ].filter((l) => l !== null && l !== "").join("\n");
6189
8483
  }
6190
8484
  case "ForStatement": {
6191
8485
  const initName = extractForInitName(stmt.init);
@@ -6193,8 +8487,21 @@ function transpileStatement(stmt, depth, opts) {
6193
8487
  const initExpr = stmt.init && stmt.init.type === "VariableDeclaration" && stmt.init.declarations[0]?.init ? transpileExpression(stmt.init.declarations[0].init, opts) : "$lit(undefined)";
6194
8488
  const testSrc = stmt.test ? transpileExpression(stmt.test, opts) : "$lit(true)";
6195
8489
  const updateSrc = stmt.update ? transpileExpression(stmt.update, opts) : `$lit(undefined)`;
6196
- const bodyStmts = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, opts)).join("\n") : transpileStatement(stmt.body, depth + 2, opts);
8490
+ const forBodyOpts = {
8491
+ ...opts,
8492
+ inLoop: (opts.inLoop ?? 0) + 1
8493
+ };
8494
+ const bodyStmts = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, forBodyOpts)).join("\n") : transpileStatement(stmt.body, depth + 2, forBodyOpts);
6197
8495
  const max = opts.maxLoopIters ?? 8;
8496
+ const assigned = /* @__PURE__ */ new Set();
8497
+ collectAssignedIds(stmt.body, assigned);
8498
+ collectAssignedIds(stmt.test, assigned);
8499
+ collectAssignedIds(stmt.update, assigned);
8500
+ collectArrMutatorReceivers(stmt.body, assigned);
8501
+ const names = [...assigned].filter((n) => n !== initName && n !== "undefined");
8502
+ const packSrc = names.length === 0 ? null : `$obj({ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(", ")} })`;
8503
+ const unpackSrc = names.length === 0 ? null : `(__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
8504
+ const optsSrc = packSrc && unpackSrc ? `, { pack: () => ${packSrc}, unpack: ${unpackSrc} }` : "";
6198
8505
  return [
6199
8506
  `${pad}// for \u2192 $for (bounded unroll, max=${max})`,
6200
8507
  `${pad}$for(`,
@@ -6205,7 +8512,7 @@ function transpileStatement(stmt, depth, opts) {
6205
8512
  bodyStmts,
6206
8513
  `${indent(depth + 1)} return ${initName};`,
6207
8514
  `${indent(depth + 1)}},`,
6208
- `${indent(depth + 1)}${max}`,
8515
+ `${indent(depth + 1)}${max}${optsSrc}`,
6209
8516
  `${pad});`
6210
8517
  ].join("\n");
6211
8518
  }
@@ -6213,58 +8520,172 @@ function transpileStatement(stmt, depth, opts) {
6213
8520
  return transpileFnBodyStmts(stmt.body, depth, opts);
6214
8521
  case "SwitchStatement": {
6215
8522
  const disc = transpileExpression(stmt.discriminant, opts);
6216
- const arms = [];
8523
+ const pre = [];
8524
+ let pendingTests = [];
6217
8525
  for (const c of stmt.cases) {
6218
8526
  const testSrc = c.test ? transpileExpression(c.test, opts) : null;
6219
8527
  if (testSrc === null) {
6220
- arms.push({ tests: [], stmts: c.consequent, isDefault: true });
6221
- } else if (arms.length > 0 && !arms[arms.length - 1].isDefault && arms[arms.length - 1].stmts.length === 0) {
6222
- const last = arms[arms.length - 1];
6223
- last.tests.push(testSrc);
6224
- last.stmts = c.consequent;
6225
- } else {
6226
- arms.push({ tests: [testSrc], stmts: c.consequent, isDefault: false });
8528
+ if (pendingTests.length > 0 && c.consequent.length > 0) {
8529
+ pre.push({ tests: pendingTests, stmts: c.consequent, isDefault: false });
8530
+ pendingTests = [];
8531
+ }
8532
+ pre.push({ tests: [], stmts: c.consequent, isDefault: true });
8533
+ continue;
6227
8534
  }
6228
- }
6229
- const merged = [];
6230
- for (const arm of arms) {
6231
- if (merged.length > 0 && merged[merged.length - 1].stmts === arm.stmts && !arm.isDefault) {
6232
- merged[merged.length - 1].tests.push(...arm.tests);
6233
- } else {
6234
- merged.push({ ...arm, tests: [...arm.tests] });
8535
+ if (c.consequent.length === 0) {
8536
+ pendingTests.push(testSrc);
8537
+ continue;
6235
8538
  }
8539
+ pre.push({ tests: [...pendingTests, testSrc], stmts: c.consequent, isDefault: false });
8540
+ pendingTests = [];
8541
+ }
8542
+ if (pendingTests.length > 0) {
8543
+ pre.push({ tests: pendingTests, stmts: [], isDefault: false });
8544
+ }
8545
+ const merged = pre.map((arm) => ({ ...arm, tests: [...arm.tests], stmts: [...arm.stmts] }));
8546
+ for (let i = 0; i < merged.length; i++) {
8547
+ const arm = merged[i];
8548
+ const body = [...arm.stmts];
8549
+ let j = i + 1;
8550
+ while (j < merged.length && !stmtCompletesControl(body[body.length - 1])) {
8551
+ body.push(...merged[j].stmts);
8552
+ if (stmtCompletesControl(body[body.length - 1])) break;
8553
+ j++;
8554
+ }
8555
+ arm.stmts = body;
6236
8556
  }
8557
+ const armReturns = (arm) => arm.stmts.length > 0 && arm.stmts.every(stmtReturns);
8558
+ const nonDefaultArms = merged.filter((a) => !a.isDefault);
8559
+ const defaultArm = merged.find((a) => a.isDefault);
8560
+ const allReturn = defaultArm !== void 0 && nonDefaultArms.length > 0 && nonDefaultArms.every(armReturns) && armReturns(defaultArm);
6237
8561
  const caseLines = [];
8562
+ const sharedBodyDecls = [];
6238
8563
  let defaultSrc = null;
8564
+ const bodyIdxBase = switchBodySeq;
8565
+ let bodyIdx = 0;
8566
+ const armOpts = {
8567
+ ...opts,
8568
+ inLoop: (opts.inLoop ?? 0) + 1
8569
+ };
8570
+ const recvSet = /* @__PURE__ */ new Set([
8571
+ ...merged.flatMap((a) => collectForkBindingNames(...a.stmts)),
8572
+ ...collectForkBindingNames(stmt.discriminant)
8573
+ ]);
8574
+ const names = [...recvSet];
8575
+ const nArms = merged.filter((a) => !a.isDefault).length + (defaultArm ? 1 : 0) + (defaultArm ? 0 : 1);
8576
+ const wrapArmThunk = (thunk, outIdx) => {
8577
+ if (names.length === 0) return thunk;
8578
+ return [
8579
+ `() => {`,
8580
+ ...names.map((n) => `${indent(depth + 1)}${n} = __sw0_${n};`),
8581
+ `${indent(depth + 1)}let __cont = true;`,
8582
+ `${indent(depth + 1)}try {`,
8583
+ `${indent(depth + 2)}return (${thunk})();`,
8584
+ `${indent(depth + 1)}} catch (e) {`,
8585
+ `${indent(depth + 2)}if ($isForkExit(e)) __cont = false;`,
8586
+ `${indent(depth + 2)}throw e;`,
8587
+ `${indent(depth + 1)}} finally {`,
8588
+ `${indent(depth + 2)}if (__cont) {`,
8589
+ ...names.map((n) => `${indent(depth + 3)}__sw${outIdx + 1}_${n} = ${n};`),
8590
+ ...names.map((n) => `${indent(depth + 3)}__sw${outIdx + 1}set_${n} = true;`),
8591
+ `${indent(depth + 2)}}`,
8592
+ `${indent(depth + 1)}}`,
8593
+ `}`
8594
+ ].join("\n");
8595
+ };
8596
+ let armSeq = 0;
6239
8597
  for (const arm of merged) {
6240
- const body = arm.stmts.map((s) => transpileStatement(s, depth + 2, opts)).join("\n") || `${indent(depth + 2)}return $lit(undefined);`;
6241
- const thunk = `() => {
8598
+ const body = arm.stmts.length === 0 ? "" : arm.stmts.map((s) => transpileStatement(s, depth + 2, armOpts)).join("\n");
8599
+ const rawThunk = `() => {
6242
8600
  ${body}
6243
8601
  ${indent(depth + 1)}}`;
8602
+ const thunk = wrapArmThunk(rawThunk, armSeq);
8603
+ armSeq++;
8604
+ const shared = arm.tests.length > 1 && !arm.isDefault;
8605
+ const runRef = shared ? `__swBody${bodyIdxBase + bodyIdx++}` : thunk;
8606
+ if (shared) {
8607
+ sharedBodyDecls.push(`${pad}const ${runRef} = ${thunk};`);
8608
+ }
6244
8609
  if (arm.isDefault) {
6245
8610
  defaultSrc = thunk;
6246
8611
  } else {
6247
8612
  for (const t of arm.tests) {
6248
- caseLines.push(`{ test: ${t}, run: ${thunk} },`);
8613
+ caseLines.push(`{ test: ${t}, run: ${runRef} },`);
6249
8614
  }
6250
8615
  }
6251
8616
  }
8617
+ if (!defaultArm && names.length > 0) {
8618
+ defaultSrc = wrapArmThunk(`() => {
8619
+ ${indent(depth + 2)}return $lit(undefined);
8620
+ ${indent(depth + 1)}}`, armSeq);
8621
+ }
8622
+ switchBodySeq += Math.max(bodyIdx, 1);
6252
8623
  const dflt = defaultSrc ? `, ${defaultSrc}` : "";
8624
+ const discRebinds = collectArrMutatorReceivers(stmt.discriminant).size ? emitArrMutatorRebinds(stmt.discriminant, opts, pad) : [];
8625
+ const switchCall = `$switch(${disc}, [
8626
+ ${caseLines.map((l) => indent(depth + 1) + l).join("\n")}
8627
+ ${indent(depth + 1)}]${dflt})`;
8628
+ if (names.length === 0) {
8629
+ return [
8630
+ ...discRebinds,
8631
+ ...sharedBodyDecls,
8632
+ allReturn ? `${pad}return ${switchCall};` : `${pad}${switchCall};`
8633
+ ].join("\n");
8634
+ }
8635
+ const decls = names.flatMap((n) => [
8636
+ `${pad}const __sw0_${n} = ${n};`,
8637
+ ...Array.from(
8638
+ { length: Math.max(nArms, armSeq + (defaultArm ? 0 : 1)) },
8639
+ (_, i) => `${pad}let __sw${i + 1}_${n}; let __sw${i + 1}set_${n} = false;`
8640
+ )
8641
+ ]);
8642
+ const slotCount = Math.max(nArms, armSeq + (defaultArm ? 0 : 1));
8643
+ const joins = names.map((n) => {
8644
+ const slots = Array.from(
8645
+ { length: slotCount },
8646
+ (_, i) => `(__sw${i + 1}set_${n} ? __sw${i + 1}_${n} : null)`
8647
+ );
8648
+ return `${pad}${n} = (() => { const __p = [${slots.join(",")}].filter((x) => x !== null); return __p.length === 0 ? ${n} : __p.reduce((a, b) => $join(a, b)); })();`;
8649
+ });
6253
8650
  return [
6254
- `${pad}return $switch(${disc}, [`,
6255
- ...caseLines.map((l) => indent(depth + 1) + l),
6256
- `${indent(depth + 1)}]${dflt});`
6257
- ].join("\n");
8651
+ ...discRebinds,
8652
+ `${pad}{`,
8653
+ ...decls.map((l) => l.replace(new RegExp(`^${pad}`), `${pad}`)),
8654
+ ...sharedBodyDecls.map(
8655
+ (l) => l.startsWith(pad) ? `${pad}${l.slice(pad.length)}` : `${pad}${l}`
8656
+ ),
8657
+ `${pad}const __swR = ${switchCall};`,
8658
+ ...joins,
8659
+ allReturn ? `${pad}return __swR;` : null,
8660
+ `${pad}}`
8661
+ ].filter((l) => l !== null).join("\n");
6258
8662
  }
6259
8663
  case "TryStatement": {
6260
- const tryBody = stmt.block.type === "BlockStatement" ? stmt.block.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n") : transpileStatement(stmt.block, depth + 1, opts);
6261
- const lines = [`${pad}try {`, tryBody, `${pad}}`];
8664
+ const markName = `__nudoTm_${stmt.loc?.start.line ?? 0}`;
8665
+ const tryOpts = {
8666
+ ...opts,
8667
+ inTry: (opts.inTry ?? 0) + 1,
8668
+ tryMarkName: markName
8669
+ };
8670
+ const tryBody = stmt.block.type === "BlockStatement" ? stmt.block.body.map((s) => transpileStatement(s, depth + 1, tryOpts)).join("\n") : transpileStatement(stmt.block, depth + 1, tryOpts);
8671
+ const lines = [
8672
+ `${pad}const ${markName} = $tryMark();`,
8673
+ `${pad}try {`,
8674
+ tryBody,
8675
+ `${pad}}`
8676
+ ];
8677
+ const catchParam = stmt.handler?.param?.type === "Identifier" ? stmt.handler.param.name : "e";
8678
+ const catchTmp = `__nudoE_${stmt.loc?.start.line ?? 0}`;
8679
+ const transpileCatchBody = (d, o) => !stmt.handler ? "" : stmt.handler.body.type === "BlockStatement" ? stmt.handler.body.body.map((s) => transpileStatement(s, d, o)).join("\n") : transpileStatement(stmt.handler.body, d, o);
6262
8680
  if (stmt.handler) {
6263
- const param = stmt.handler.param?.type === "Identifier" ? stmt.handler.param.name : "e";
6264
- const catchTmp = `__nudoE_${stmt.loc?.start.line ?? 0}`;
6265
- const catchBody = stmt.handler.body.type === "BlockStatement" ? stmt.handler.body.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n") : transpileStatement(stmt.handler.body, depth + 1, opts);
8681
+ const catchBody = transpileCatchBody(depth + 1, opts);
6266
8682
  lines.push(`${pad}catch (${catchTmp}) {`);
6267
- lines.push(`${indent(depth + 1)}const ${param} = $catchVal(${catchTmp});`);
8683
+ lines.push(`${indent(depth + 1)}$rethrowIfNudoReturn(${catchTmp});`);
8684
+ lines.push(`${indent(depth + 1)}const __xs_${markName} = $tryTakeSince(${markName});`);
8685
+ lines.push(`${indent(depth + 1)}__xs_${markName}.push($catchVal(${catchTmp}));`);
8686
+ lines.push(
8687
+ `${indent(depth + 1)}const ${catchParam} = __xs_${markName}.reduce((a, b) => $join(a, b));`
8688
+ );
6268
8689
  lines.push(catchBody);
6269
8690
  lines.push(`${pad}}`);
6270
8691
  }
@@ -6272,6 +8693,30 @@ ${indent(depth + 1)}}`;
6272
8693
  const finBody = stmt.finalizer.type === "BlockStatement" ? stmt.finalizer.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n") : transpileStatement(stmt.finalizer, depth + 1, opts);
6273
8694
  lines.push(`${pad}finally {`);
6274
8695
  lines.push(finBody);
8696
+ lines.push(`${pad}$tryPopMark();`);
8697
+ lines.push(`${pad}}`);
8698
+ } else {
8699
+ lines.push(`${pad}$tryPopMark();`);
8700
+ }
8701
+ if (stmt.handler) {
8702
+ const catchBody = transpileCatchBody(depth + 2, opts);
8703
+ lines.push(`${pad}{`);
8704
+ lines.push(`${indent(depth + 1)}const __post_${markName} = $tryTakeSince(${markName});`);
8705
+ lines.push(`${indent(depth + 1)}if (__post_${markName}.length) {`);
8706
+ lines.push(
8707
+ `${indent(depth + 2)}const ${catchParam} = __post_${markName}.reduce((a, b) => $join(a, b));`
8708
+ );
8709
+ lines.push(
8710
+ catchBody.split("\n").map((l) => l ? `${indent(depth + 2)}${l.trimStart()}` : l).join("\n")
8711
+ );
8712
+ lines.push(`${indent(depth + 1)}}`);
8713
+ lines.push(`${pad}}`);
8714
+ } else {
8715
+ lines.push(`${pad}{`);
8716
+ lines.push(`${indent(depth + 1)}const __post_${markName} = $tryTakeSince(${markName});`);
8717
+ lines.push(`${indent(depth + 1)}if (__post_${markName}.length) {`);
8718
+ lines.push(`${indent(depth + 2)}$throw(__post_${markName}.reduce((a, b) => $join(a, b)));`);
8719
+ lines.push(`${indent(depth + 1)}}`);
6275
8720
  lines.push(`${pad}}`);
6276
8721
  }
6277
8722
  return lines.join("\n");
@@ -6300,24 +8745,77 @@ ${indent(depth + 1)}}`;
6300
8745
  { n: 0 }
6301
8746
  );
6302
8747
  }
6303
- const bodyStmts = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, opts)).join("\n") : transpileStatement(stmt.body, depth + 2, opts);
8748
+ const bodyOpts = {
8749
+ ...opts,
8750
+ inLoop: (opts.inLoop ?? 0) + 1
8751
+ };
8752
+ const bodyStmts = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, bodyOpts)).join("\n") : transpileStatement(stmt.body, depth + 2, bodyOpts);
6304
8753
  const max = opts.maxLoopIters ?? 8;
8754
+ const assigned = /* @__PURE__ */ new Set();
8755
+ collectAssignedIds(stmt.body, assigned);
8756
+ collectArrMutatorReceivers(stmt.body, assigned);
8757
+ const names = [...assigned].filter((n) => n !== bindName && n !== "undefined");
8758
+ const optsSrc = names.length === 0 ? "" : `, { pack: () => $obj({ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(", ")} }), unpack: (__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} } }`;
6305
8759
  return [
6306
8760
  `${pad}$forOf(${iter}, (${bindName}, _i) => {`,
6307
8761
  ...bodyLines,
6308
8762
  bodyStmts,
6309
- `${pad}}, ${max});`
8763
+ `${pad}}, ${max}${optsSrc});`
6310
8764
  ].join("\n");
6311
8765
  }
6312
8766
  case "WhileStatement": {
6313
8767
  const test = transpileExpression(stmt.test, opts);
6314
- const body = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n") : transpileStatement(stmt.body, depth + 1, opts);
8768
+ const bodyOpts = {
8769
+ ...opts,
8770
+ inLoop: (opts.inLoop ?? 0) + 1
8771
+ };
8772
+ const body = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 1, bodyOpts)).join("\n") : transpileStatement(stmt.body, depth + 1, bodyOpts);
6315
8773
  const max = opts.maxLoopIters ?? 8;
8774
+ const assigned = /* @__PURE__ */ new Set();
8775
+ collectAssignedIds(stmt.body, assigned);
8776
+ collectAssignedIds(stmt.test, assigned);
8777
+ const names = [...assigned].filter((n) => n !== "undefined");
8778
+ if (names.length === 0) {
8779
+ return [
8780
+ `${pad}// while \u2192 $whileSeq (bounded, max=${max})`,
8781
+ `${pad}$whileSeq(() => ${test}, () => {`,
8782
+ body,
8783
+ `${pad}}, ${max});`
8784
+ ].join("\n");
8785
+ }
8786
+ const packSrc = `$obj({ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(", ")} })`;
8787
+ const unpackSrc = `(__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
6316
8788
  return [
6317
- `${pad}// while \u2192 $whileSeq (bounded, max=${max})`,
8789
+ `${pad}// while \u2192 $whileSeq (instrumented bindings: ${names.join(", ")})`,
6318
8790
  `${pad}$whileSeq(() => ${test}, () => {`,
6319
8791
  body,
6320
- `${pad}}, ${max});`
8792
+ `${pad}}, ${max}, { pack: () => ${packSrc}, unpack: ${unpackSrc} });`
8793
+ ].join("\n");
8794
+ }
8795
+ case "DoWhileStatement": {
8796
+ const test = transpileExpression(stmt.test, opts);
8797
+ const bodyOpts = {
8798
+ ...opts,
8799
+ inLoop: (opts.inLoop ?? 0) + 1
8800
+ };
8801
+ const bodyStmts = stmt.body.type === "BlockStatement" ? stmt.body.body.map((s) => transpileStatement(s, depth + 1, bodyOpts)).join("\n") : transpileStatement(stmt.body, depth + 1, bodyOpts);
8802
+ const max = opts.maxLoopIters ?? 8;
8803
+ const assigned = /* @__PURE__ */ new Set();
8804
+ collectAssignedIds(stmt.body, assigned);
8805
+ collectAssignedIds(stmt.test, assigned);
8806
+ collectArrMutatorReceivers(stmt.body, assigned);
8807
+ const names = [...assigned].filter((n) => n !== "undefined");
8808
+ const packSrc = names.length === 0 ? null : `$obj({ ${names.map((n) => `${JSON.stringify(n)}: ${n}`).join(", ")} })`;
8809
+ const unpackSrc = names.length === 0 ? null : `(__lp) => { ${names.map((n) => `${n} = $get(__lp, ${JSON.stringify(n)});`).join(" ")} }`;
8810
+ const optsSrc = packSrc && unpackSrc ? `, { pack: () => ${packSrc}, unpack: ${unpackSrc} }` : "";
8811
+ return [
8812
+ `${pad}// do-while \u2192 body + $whileSeq (bounded, max=${max})`,
8813
+ `{`,
8814
+ bodyStmts,
8815
+ `${indent(depth + 1)}$whileSeq(() => ${test}, () => {`,
8816
+ bodyStmts,
8817
+ `${indent(depth + 1)}}, ${max}${optsSrc});`,
8818
+ `${pad}}`
6321
8819
  ].join("\n");
6322
8820
  }
6323
8821
  case "ClassDeclaration": {
@@ -6342,6 +8840,8 @@ function transpileClass(stmt, depth, opts) {
6342
8840
  });
6343
8841
  const methodOpts = {
6344
8842
  ...opts,
8843
+ inLoop: 0,
8844
+ inTry: 0,
6345
8845
  thisParam: "__this",
6346
8846
  className: name
6347
8847
  };
@@ -6425,6 +8925,9 @@ ${indent(depth)}}`;
6425
8925
  }
6426
8926
  if (stmt.type === "ReturnStatement") {
6427
8927
  const v2 = stmt.argument ? transpileExpression(stmt.argument, opts) : "$lit(undefined)";
8928
+ if ((opts.inLoop ?? 0) > 0) {
8929
+ return `() => { $loopReturn(${v2}); }`;
8930
+ }
6428
8931
  return `() => ${v2}`;
6429
8932
  }
6430
8933
  const one = transpileStatement(stmt, depth + 1, opts);
@@ -6466,15 +8969,53 @@ function transpileExpression(expr, opts = {}) {
6466
8969
  }
6467
8970
  case "LogicalExpression": {
6468
8971
  const op = expr.operator;
8972
+ const lNode = expr.left;
8973
+ const rNode = expr.right;
6469
8974
  const l = transpileExpression(expr.left, opts);
6470
8975
  const r = transpileExpression(expr.right, opts);
6471
- return op === "&&" ? `$fork(${l}, () => ${r}, () => ${l})` : `$fork(${l}, () => ${l}, () => ${r})`;
8976
+ if (op === "??") {
8977
+ return transpileShortCircuitExpr(opts, {
8978
+ alwaysNodes: [lNode],
8979
+ alwaysSrc: l,
8980
+ // 测试用 nullish;返回侧:nullish → right,否则 → left
8981
+ consSrc: r,
8982
+ consNodes: [rNode],
8983
+ altSrc: l,
8984
+ altNodes: [lNode],
8985
+ testSrc: `$nullishTest(${l})`
8986
+ });
8987
+ }
8988
+ return op === "&&" ? transpileShortCircuitExpr(opts, {
8989
+ alwaysNodes: [lNode],
8990
+ alwaysSrc: l,
8991
+ consSrc: r,
8992
+ consNodes: [rNode],
8993
+ altSrc: "__test",
8994
+ altNodes: []
8995
+ }) : transpileShortCircuitExpr(opts, {
8996
+ alwaysNodes: [lNode],
8997
+ alwaysSrc: l,
8998
+ consSrc: "__test",
8999
+ consNodes: [],
9000
+ altSrc: r,
9001
+ altNodes: [rNode]
9002
+ });
6472
9003
  }
6473
9004
  case "ConditionalExpression": {
9005
+ const testNode = expr.test;
9006
+ const consNode = expr.consequent;
9007
+ const altNode = expr.alternate;
6474
9008
  const test = transpileExpression(expr.test, opts);
6475
9009
  const c = transpileExpression(expr.consequent, opts);
6476
9010
  const a = transpileExpression(expr.alternate, opts);
6477
- return `$fork(${test}, () => ${c}, () => ${a})`;
9011
+ return transpileShortCircuitExpr(opts, {
9012
+ alwaysNodes: [testNode],
9013
+ alwaysSrc: test,
9014
+ consSrc: c,
9015
+ consNodes: [consNode],
9016
+ altSrc: a,
9017
+ altNodes: [altNode]
9018
+ });
6478
9019
  }
6479
9020
  case "RegExpLiteral": {
6480
9021
  return `$regex(${JSON.stringify(expr.pattern)}${expr.flags ? `, ${JSON.stringify(expr.flags)}` : ""})`;
@@ -6543,6 +9084,22 @@ function transpileExpression(expr, opts = {}) {
6543
9084
  acc = acc === null ? arg : `$spread(${acc}, ${arg})`;
6544
9085
  continue;
6545
9086
  }
9087
+ if (prop.type === "ObjectMethod") {
9088
+ flushProps();
9089
+ const mkey = prop.key.type === "Identifier" ? JSON.stringify(prop.key.name) : prop.key.type === "StringLiteral" ? JSON.stringify(prop.key.value) : null;
9090
+ if (mkey === null) continue;
9091
+ const paramNames = prop.params.map(
9092
+ (p) => p.type === "Identifier" && p.name ? p.name : "_a"
9093
+ );
9094
+ const methodOpts = { ...opts, inLoop: 0, inTry: 0, thisParam: "__this" };
9095
+ const bodySrc = prop.body.type === "BlockStatement" ? `{
9096
+ ${prop.body.body.map((s) => transpileStatement(s, 1, methodOpts)).join("\n")}
9097
+ }` : transpileExpression(prop.body, methodOpts);
9098
+ const bindParams = ["__this", ...paramNames];
9099
+ const fnValSrc = `$fnVal([${paramNames.map((p) => JSON.stringify(p)).join(", ")}], (${bindParams.join(", ")}) => ${bodySrc}, { bindThis: true })`;
9100
+ props.push(`${mkey}: ${fnValSrc}`);
9101
+ continue;
9102
+ }
6546
9103
  if (prop.type !== "ObjectProperty") continue;
6547
9104
  if (prop.computed) {
6548
9105
  flushProps();
@@ -6554,6 +9111,23 @@ function transpileExpression(expr, opts = {}) {
6554
9111
  }
6555
9112
  const key = prop.key.type === "Identifier" ? JSON.stringify(prop.key.name) : prop.key.type === "StringLiteral" ? JSON.stringify(prop.key.value) : null;
6556
9113
  if (key === null) continue;
9114
+ if (prop.value.type === "FunctionExpression" && !prop.value.async) {
9115
+ const fn = prop.value;
9116
+ if (!fn.generator) {
9117
+ const paramNames = fn.params.map(
9118
+ (p) => p.type === "Identifier" && p.name ? p.name : "_a"
9119
+ );
9120
+ const methodOpts = { ...opts, inLoop: 0, thisParam: "__this" };
9121
+ const bodySrc = fn.body.type === "BlockStatement" ? `{
9122
+ ${fn.body.body.map((s) => transpileStatement(s, 1, methodOpts)).join("\n")}
9123
+ }` : transpileExpression(fn.body, methodOpts);
9124
+ const bindParams = ["__this", ...paramNames];
9125
+ props.push(
9126
+ `${key}: $fnVal([${paramNames.map((p) => JSON.stringify(p)).join(", ")}], (${bindParams.join(", ")}) => ${bodySrc}, { bindThis: true })`
9127
+ );
9128
+ continue;
9129
+ }
9130
+ }
6557
9131
  const valSrc = transpileExpression(prop.value, opts);
6558
9132
  props.push(`${key}: ${valSrc}`);
6559
9133
  }
@@ -6605,6 +9179,58 @@ function transpileExpression(expr, opts = {}) {
6605
9179
  case "AssignmentExpression": {
6606
9180
  const compoundFn = COMPOUND_OPS[expr.operator];
6607
9181
  const right = transpileExpression(expr.right, opts);
9182
+ const op = expr.operator;
9183
+ if (op === "||=" || op === "&&=" || op === "??=") {
9184
+ const rNode = expr.right;
9185
+ const emitLogicalAssign = (targetSrc, setSrc) => {
9186
+ if (op === "||=") {
9187
+ const sc2 = transpileShortCircuitExpr(opts, {
9188
+ alwaysNodes: [],
9189
+ alwaysSrc: targetSrc,
9190
+ consSrc: "__test",
9191
+ consNodes: [],
9192
+ altSrc: right,
9193
+ altNodes: [rNode]
9194
+ });
9195
+ return setSrc(sc2);
9196
+ }
9197
+ if (op === "&&=") {
9198
+ const sc2 = transpileShortCircuitExpr(opts, {
9199
+ alwaysNodes: [],
9200
+ alwaysSrc: targetSrc,
9201
+ consSrc: right,
9202
+ consNodes: [rNode],
9203
+ altSrc: "__test",
9204
+ altNodes: []
9205
+ });
9206
+ return setSrc(sc2);
9207
+ }
9208
+ const sc = transpileShortCircuitExpr(opts, {
9209
+ alwaysNodes: [],
9210
+ alwaysSrc: targetSrc,
9211
+ consSrc: right,
9212
+ consNodes: [rNode],
9213
+ altSrc: targetSrc,
9214
+ altNodes: [],
9215
+ testSrc: `$nullishTest(${targetSrc})`
9216
+ });
9217
+ return setSrc(sc);
9218
+ };
9219
+ if (expr.left.type === "Identifier") {
9220
+ return emitLogicalAssign(expr.left.name, (val) => `${expr.left.type === "Identifier" ? expr.left.name : ""} = ${val}`);
9221
+ }
9222
+ if (expr.left.type === "MemberExpression") {
9223
+ const m = expr.left;
9224
+ const path = memberPathOf(m, opts);
9225
+ if (path) {
9226
+ return emitLogicalAssign(readPathSrc(path), (val) => {
9227
+ const writeSrc = setPathSrc(path, val);
9228
+ return `${path.rootSrc} = ${writeSrc}`;
9229
+ });
9230
+ }
9231
+ }
9232
+ return `/* assign ${op} */ $lit(undefined)`;
9233
+ }
6608
9234
  if (expr.left.type === "MemberExpression") {
6609
9235
  const m = expr.left;
6610
9236
  const path = memberPathOf(m, opts);
@@ -6694,10 +9320,11 @@ function transpileExpression(expr, opts = {}) {
6694
9320
  case "FunctionExpression": {
6695
9321
  const fn = expr;
6696
9322
  const { sig, rest, prologue } = emitParamBinding(fn.params, indent(1), opts);
9323
+ const fnBodyOpts = { ...opts, inLoop: 0 };
6697
9324
  const paramParts = rest ? [...sig, `...${rest}`] : sig;
6698
9325
  const nameList = `[${sig.map((p) => JSON.stringify(p)).join(", ")}]`;
6699
9326
  if (fn.body.type === "BlockStatement") {
6700
- const inner = [...prologue, transpileFnBodyStmts(fn.body.body, 1, opts)].join("\n");
9327
+ const inner = [...prologue, transpileFnBodyStmts(fn.body.body, 1, fnBodyOpts)].join("\n");
6701
9328
  if (fn.async) {
6702
9329
  return `$fnVal(${nameList}, (${paramParts.join(", ")}) => $async(() => {
6703
9330
  ${inner}
@@ -6707,7 +9334,7 @@ ${inner}
6707
9334
  ${inner}
6708
9335
  })`;
6709
9336
  }
6710
- const bodySrc = transpileExpression(fn.body, opts);
9337
+ const bodySrc = transpileExpression(fn.body, fnBodyOpts);
6711
9338
  if (prologue.length > 0) {
6712
9339
  const thunk = fn.async ? `$async(() => ${bodySrc})` : bodySrc;
6713
9340
  return `$fnVal(${nameList}, (${paramParts.join(", ")}) => {
@@ -6807,7 +9434,7 @@ function $new(cls, args) {
6807
9434
  if (args.length === 1) {
6808
9435
  const n = litValue(args[0]);
6809
9436
  if (typeof n === "number" && Number.isInteger(n) && n >= 0 && n <= 4096) {
6810
- const els = Array.from({ length: n }, () => undefAbs());
9437
+ const els = Array.from({ length: n }, () => undefAbs2());
6811
9438
  return abs({ k: "tuple", elements: els }, void 0, void 0, "exact");
6812
9439
  }
6813
9440
  return abs({ k: "arr", element: unknown }, void 0, void 0, "partial");
@@ -6818,9 +9445,14 @@ function $new(cls, args) {
6818
9445
  const p = args[0] ? litValue(args[0]) : void 0;
6819
9446
  if (typeof p === "string") return $regex(p, args[1] ? String(litValue(args[1]) ?? "") : "");
6820
9447
  }
6821
- const name = cls.name || "Object";
9448
+ const clsName = cls.name || "Object";
9449
+ if (isErrorCtorName(clsName)) {
9450
+ return errorBrandAbs(clsName, args[0]);
9451
+ }
9452
+ if (clsName === "Map") return makeMapAbs(args[0]);
9453
+ if (clsName === "Set") return makeSetAbs(args[0]);
6822
9454
  const shape = objOf({});
6823
- return abs({ k: "brand", name, shape }, void 0, void 0, "path");
9455
+ return abs({ k: "brand", name: clsName, shape }, void 0, void 0, "path");
6824
9456
  }
6825
9457
  const spec = specOf(cls);
6826
9458
  if (!spec) {
@@ -6884,7 +9516,7 @@ function execRegexBrand(re, method, args) {
6884
9516
  if (!m) {
6885
9517
  return abs({ k: "unknown" }, { op: "lit", value: null }, void 0, "exact");
6886
9518
  }
6887
- const els = m.map((g) => g === void 0 ? undefAbs() : strLit(g));
9519
+ const els = m.map((g) => g === void 0 ? undefAbs2() : strLit(g));
6888
9520
  return abs({ k: "tuple", elements: els }, void 0, void 0, "exact");
6889
9521
  }
6890
9522
  function stringRegexMethod(recv, method, args) {
@@ -6917,10 +9549,69 @@ function stringRegexMethod(recv, method, args) {
6917
9549
  if (!m) {
6918
9550
  return abs({ k: "unknown" }, { op: "lit", value: null }, void 0, "exact");
6919
9551
  }
6920
- const els = m.map((g) => g === void 0 ? undefAbs() : strLit(g));
9552
+ const els = m.map((g) => g === void 0 ? undefAbs2() : strLit(g));
6921
9553
  return abs({ k: "tuple", elements: els }, void 0, void 0, "exact");
6922
9554
  }
6923
9555
  function $invoke(thisVal, method, args, loc) {
9556
+ if (method === "call" || method === "apply" || method === "bind") {
9557
+ const expandApplyArgs = (list) => {
9558
+ if (list === null || list === void 0) return [];
9559
+ if (Array.isArray(list)) {
9560
+ return list.map(
9561
+ (x) => x && typeof x === "object" && "shape" in x ? x : unknown
9562
+ );
9563
+ }
9564
+ if (typeof list === "object" && "shape" in list) {
9565
+ const s = list.shape;
9566
+ if (s.k === "tuple") return [...s.elements];
9567
+ if (s.k === "arr") return [s.element];
9568
+ }
9569
+ return [unknown];
9570
+ };
9571
+ const boundFnParams = (fnVal, boundCount) => {
9572
+ if (fnVal && typeof fnVal === "object" && "shape" in fnVal) {
9573
+ const s = fnVal.shape;
9574
+ if (s.k === "fn" && Array.isArray(s.params)) {
9575
+ return s.params.slice(boundCount);
9576
+ }
9577
+ }
9578
+ if (typeof fnVal === "function") {
9579
+ const arity = fnVal.length ?? 0;
9580
+ const rem = Math.max(0, arity - boundCount);
9581
+ return Array.from({ length: rem }, (_, i) => `_a${boundCount + i}`);
9582
+ }
9583
+ return ["_rest"];
9584
+ };
9585
+ if (typeof thisVal === "function") {
9586
+ const fn = thisVal;
9587
+ if (method === "call") {
9588
+ return callAtFunctionBoundary(() => fn(...args.slice(1)));
9589
+ }
9590
+ if (method === "apply") {
9591
+ return callAtFunctionBoundary(() => fn(...expandApplyArgs(args[1])));
9592
+ }
9593
+ const bound = args.slice(1);
9594
+ return absFunction(boundFnParams(thisVal, bound.length), {
9595
+ apply: (callArgs) => callAtFunctionBoundary(() => fn(...bound, ...callArgs))
9596
+ });
9597
+ }
9598
+ if (thisVal && typeof thisVal === "object" && "shape" in thisVal) {
9599
+ const fnImpl = getFnImpl(thisVal);
9600
+ const isCallable = thisVal.shape.k === "fn" || fnImpl !== void 0;
9601
+ if (isCallable) {
9602
+ if (method === "call") {
9603
+ return $call(thisVal, args.slice(1));
9604
+ }
9605
+ if (method === "apply") {
9606
+ return $call(thisVal, expandApplyArgs(args[1]));
9607
+ }
9608
+ const bound = args.slice(1);
9609
+ return absFunction(boundFnParams(thisVal, bound.length), {
9610
+ apply: (callArgs) => callAtFunctionBoundary(() => $call(thisVal, [...bound, ...callArgs]))
9611
+ });
9612
+ }
9613
+ }
9614
+ }
6924
9615
  if (!thisVal || typeof thisVal !== "object" || !("shape" in thisVal)) {
6925
9616
  const ns = namespaceNameOf(thisVal);
6926
9617
  return (ns ? evalNamespaceCall(ns, method, args) : void 0) ?? unknown;
@@ -6936,6 +9627,10 @@ function $invoke(thisVal, method, args, loc) {
6936
9627
  }
6937
9628
  const brandName = thisVal.shape.k === "brand" ? thisVal.shape.name : void 0;
6938
9629
  if (brandName) {
9630
+ if (brandName === "Map" || brandName === "Set") {
9631
+ const viaCol = evalBuiltinInstanceMethod(brandName, method, thisVal, args);
9632
+ if (viaCol !== void 0) return viaCol;
9633
+ }
6939
9634
  const m = findMethod(brandName, method);
6940
9635
  if (m) return m(thisVal, ...args);
6941
9636
  const spec = getBClass(brandName);
@@ -6957,6 +9652,7 @@ function $invoke(thisVal, method, args, loc) {
6957
9652
  const prop = $get(thisVal, method, { silent: true });
6958
9653
  const impl = prop && typeof prop === "object" && "shape" in prop ? getFnImpl(prop) : void 0;
6959
9654
  if (impl) {
9655
+ if (impl.bindThis) return $call(prop, [thisVal, ...args]);
6960
9656
  return $call(prop, args);
6961
9657
  }
6962
9658
  if (notePrimMemberMissing(thisVal, method, "method", loc)) return unknown;
@@ -6974,8 +9670,21 @@ function memberLikelyHasMethod(m, method) {
6974
9670
  function invokeArrMethod(arr, method, args) {
6975
9671
  const shape = arr.shape;
6976
9672
  const callFn = (fn, ...fnArgs) => {
9673
+ const sumIdx = fnArgs.findIndex(
9674
+ (a) => a && typeof a === "object" && "shape" in a && a.shape.k === "sum"
9675
+ );
9676
+ if (sumIdx >= 0) {
9677
+ const members = fnArgs[sumIdx].shape.members;
9678
+ let acc;
9679
+ for (const m of members) {
9680
+ const next = fnArgs.map((a, i) => i === sumIdx ? m : a);
9681
+ const r = callFn(fn, ...next);
9682
+ acc = acc === void 0 ? r : joinAbs(acc, r);
9683
+ }
9684
+ return acc ?? unknown;
9685
+ }
6977
9686
  if (typeof fn === "function") {
6978
- const r = fn(...fnArgs);
9687
+ const r = callAtFunctionBoundary(() => fn(...fnArgs));
6979
9688
  if (r && typeof r === "object" && "shape" in r) return r;
6980
9689
  return unknown;
6981
9690
  }
@@ -7033,7 +9742,7 @@ function invokeArrMethod(arr, method, args) {
7033
9742
  if (method === "forEach" && args[0]) {
7034
9743
  const list = shape.k === "tuple" ? shape.elements : [shape.element];
7035
9744
  for (const el of list) callFn(args[0], el);
7036
- return undefAbs();
9745
+ return undefAbs2();
7037
9746
  }
7038
9747
  if ((method === "some" || method === "every") && args[0]) {
7039
9748
  const list = shape.k === "tuple" ? shape.elements : [shape.element];
@@ -7043,7 +9752,7 @@ function invokeArrMethod(arr, method, args) {
7043
9752
  if (method === "find" && args[0]) {
7044
9753
  const el = shape.k === "tuple" ? shape.elements[0] ?? unknown : shape.element;
7045
9754
  callFn(args[0], el);
7046
- return joinAbs(el, undefAbs());
9755
+ return joinAbs(el, undefAbs2());
7047
9756
  }
7048
9757
  if (method === "join") {
7049
9758
  return abs({ k: "prim", type: "string" }, void 0, void 0, "path");
@@ -7063,11 +9772,35 @@ function invokeArrMethod(arr, method, args) {
7063
9772
  if (method === "includes") {
7064
9773
  return abs({ k: "prim", type: "boolean" }, void 0, void 0, "partial");
7065
9774
  }
7066
- if (method === "at" || method === "pop" || method === "shift") {
9775
+ if (method === "push" || method === "unshift") {
9776
+ return abs({ k: "prim", type: "number" }, void 0, void 0, "path");
9777
+ }
9778
+ if (method === "pop") {
9779
+ if (shape.k === "tuple") {
9780
+ return shape.elements.length > 0 ? shape.elements[shape.elements.length - 1] ?? unknown : undefAbs2();
9781
+ }
9782
+ if (shape.k === "arr") return joinAbs(shape.element, undefAbs2());
9783
+ }
9784
+ if (method === "shift") {
7067
9785
  if (shape.k === "tuple" && shape.elements.length > 0) {
7068
9786
  return shape.elements[0] ?? unknown;
7069
9787
  }
7070
- if (shape.k === "arr") return shape.element;
9788
+ if (shape.k === "arr") return joinAbs(shape.element, undefAbs2());
9789
+ }
9790
+ if (method === "at") {
9791
+ const raw = args[0] !== void 0 ? litValue(args[0]) : void 0;
9792
+ const iv = typeof raw === "number" && Number.isInteger(raw) ? raw : void 0;
9793
+ if (shape.k === "tuple") {
9794
+ const els = shape.elements;
9795
+ if (iv === void 0) {
9796
+ if (els.length === 0) return undefAbs2();
9797
+ return joinAbs(els.reduce((a, b) => joinAbs(a, b)), undefAbs2());
9798
+ }
9799
+ const idx = iv < 0 ? els.length + iv : iv;
9800
+ if (idx >= 0 && idx < els.length) return els[idx] ?? unknown;
9801
+ return undefAbs2();
9802
+ }
9803
+ if (shape.k === "arr") return joinAbs(shape.element, undefAbs2());
7071
9804
  }
7072
9805
  return void 0;
7073
9806
  }
@@ -7109,13 +9842,32 @@ function $thisSet(thisVal, key, value) {
7109
9842
  }
7110
9843
  function $orDefault(v2, dflt) {
7111
9844
  if (v2 === void 0) return asAbsVal(dflt());
7112
- if (litValue(v2) === void 0 && v2.shape.k !== "never") {
7113
- if (v2.term?.op === "lit" && v2.term.value === void 0) return asAbsVal(dflt());
7114
- if (v2.shape.k === "unknown" && v2.term?.op === "lit") return asAbsVal(dflt());
9845
+ if (isDefinitelyUndefinedAbs(v2)) return asAbsVal(dflt());
9846
+ if (v2.shape.k === "sum") {
9847
+ const d = asAbsVal(dflt());
9848
+ const parts = [];
9849
+ let sawUndef = false;
9850
+ for (const m of v2.shape.members) {
9851
+ if (isDefinitelyUndefinedAbs(m)) {
9852
+ sawUndef = true;
9853
+ continue;
9854
+ }
9855
+ parts.push(m);
9856
+ }
9857
+ if (!sawUndef) return v2;
9858
+ if (parts.length === 0) return d;
9859
+ let joined = parts[0];
9860
+ for (let i = 1; i < parts.length; i++) joined = joinAbs(joined, parts[i]);
9861
+ return joinAbs(joined, d);
7115
9862
  }
7116
- if (v2.term?.op === "lit" && v2.term.value === void 0) return asAbsVal(dflt());
7117
9863
  return v2;
7118
9864
  }
9865
+ function isDefinitelyUndefinedAbs(v2) {
9866
+ if (!v2) return false;
9867
+ if (v2.term?.op === "lit" && v2.term.value === void 0) return true;
9868
+ if (v2.shape.k === "unknown" && v2.term?.op === "lit" && litValue(v2) === void 0) return true;
9869
+ return false;
9870
+ }
7119
9871
  function isNullishAbs(v2) {
7120
9872
  if (!v2 || v2.term?.op !== "lit") return false;
7121
9873
  const lv = v2.term.value;
@@ -7154,11 +9906,47 @@ function $setKey(o, key, value) {
7154
9906
  if (typeof k === "string" || typeof k === "number") {
7155
9907
  return $set(o, String(k), value);
7156
9908
  }
7157
- return $set(o, "?", value);
9909
+ const val = asAbsVal(value);
9910
+ if (o.shape.k === "brand") {
9911
+ const inner = $setKey(o.shape.shape, key, value);
9912
+ return abs(
9913
+ { k: "brand", name: o.shape.name, shape: inner },
9914
+ o.term,
9915
+ o.pred,
9916
+ confJoin(o.conf, value.conf)
9917
+ );
9918
+ }
9919
+ if (o.shape.k !== "obj") {
9920
+ return abs(
9921
+ {
9922
+ k: "obj",
9923
+ slots: {},
9924
+ index: { key: unknown, value: val },
9925
+ open: true
9926
+ },
9927
+ void 0,
9928
+ void 0,
9929
+ confJoin("path", value.conf)
9930
+ );
9931
+ }
9932
+ const shape = o.shape;
9933
+ const prevIndex = shape.index?.value;
9934
+ const indexVal = prevIndex ? joinAbs(prevIndex, val) : val;
9935
+ const next = objOf({ ...shape.slots }, {
9936
+ index: { key: shape.index?.key ?? unknown, value: indexVal },
9937
+ open: true
9938
+ });
9939
+ next.conf = confJoin(o.conf, value.conf);
9940
+ return next;
7158
9941
  }
7159
9942
 
7160
9943
  // src/algebra/exec/run.ts
7161
9944
  var rtAll = { ...runtime_exports, ...class_exports, ...calls_exports };
9945
+ rtAll.isNudoReturn = isNudoReturn;
9946
+ rtAll.isNudoThrow = isNudoThrow;
9947
+ rtAll.$isForkExit = $isForkExit;
9948
+ rtAll.runWithLoopExits = runWithLoopExits;
9949
+ rtAll.takeLoopExits = takeLoopExits;
7162
9950
  var RUNTIME_IMPORT_RE = /^import\s*\{[^}]+\}\s*from\s*"[^"]+";\s*$/m;
7163
9951
  function rewriteUserImports(js) {
7164
9952
  js = js.replace(
@@ -7364,33 +10152,59 @@ function isAbsVal(v2) {
7364
10152
  function callTranspiledExportFull(exports, name, args) {
7365
10153
  const fn = exports[name];
7366
10154
  if (typeof fn === "function") {
7367
- try {
7368
- const r = fn(...args);
7369
- if (!isAbsVal(r)) return { result: unknown, throws: never };
7370
- return { result: r, throws: never };
7371
- } catch (e) {
7372
- if (isNudoThrow(e)) {
7373
- return { result: never, throws: e.absValue };
7374
- }
7375
- return { result: unknown, throws: never };
7376
- }
7377
- }
7378
- if (isAbsVal(fn)) {
7379
- if (fn.shape.k === "fn") {
10155
+ return runWithLoopExits(() => {
7380
10156
  try {
7381
- const r = $call(fn, args);
7382
- return { result: r, throws: never };
10157
+ const r = fn(...args);
10158
+ if (!isAbsVal(r)) return joinControlExits(unknown);
10159
+ return joinControlExits(r);
7383
10160
  } catch (e) {
10161
+ if (isNudoReturn(e)) {
10162
+ return joinControlExits(e.absValue);
10163
+ }
7384
10164
  if (isNudoThrow(e)) {
7385
- return { result: never, throws: e.absValue };
10165
+ const result = joinLoopExits(never);
10166
+ const throws = joinThrowExits(e.absValue);
10167
+ return { result, throws };
7386
10168
  }
7387
- return { result: unknown, throws: never };
10169
+ return joinControlExits(unknown);
7388
10170
  }
10171
+ });
10172
+ }
10173
+ if (isAbsVal(fn)) {
10174
+ if (fn.shape.k === "fn") {
10175
+ return runWithLoopExits(() => {
10176
+ try {
10177
+ const r = $call(fn, args);
10178
+ return joinControlExits(r);
10179
+ } catch (e) {
10180
+ if (isNudoReturn(e)) {
10181
+ return joinControlExits(e.absValue);
10182
+ }
10183
+ if (isNudoThrow(e)) {
10184
+ return { result: joinLoopExits(never), throws: joinThrowExits(e.absValue) };
10185
+ }
10186
+ return joinControlExits(unknown);
10187
+ }
10188
+ });
7389
10189
  }
7390
10190
  return { result: fn, throws: never };
7391
10191
  }
7392
10192
  return { result: unknown, throws: never };
7393
10193
  }
10194
+ function joinLoopExits(normal) {
10195
+ const exits = takeLoopExits();
10196
+ if (exits.length === 0) return normal;
10197
+ return exits.reduce((acc, x) => joinAbs(acc, x), normal);
10198
+ }
10199
+ function joinThrowExits(base) {
10200
+ const exits = takeThrowExits();
10201
+ let t = base;
10202
+ for (const x of exits) t = t ? joinAbs(t, x) : x;
10203
+ return t ?? never;
10204
+ }
10205
+ function joinControlExits(normal) {
10206
+ return { result: joinLoopExits(normal), throws: joinThrowExits(void 0) };
10207
+ }
7394
10208
  function callTranspiledExport(exports, name, args) {
7395
10209
  return callTranspiledExportFull(exports, name, args).result;
7396
10210
  }
@@ -7494,7 +10308,7 @@ export {
7494
10308
  instantiateReturn,
7495
10309
  setApplyCallbackHost,
7496
10310
  applyCallbackAbs,
7497
- undefAbs,
10311
+ undefAbs2 as undefAbs,
7498
10312
  mapElementFallback,
7499
10313
  projectFlatMapResult,
7500
10314
  asAbs,
@@ -7530,6 +10344,34 @@ export {
7530
10344
  definitelyNotNullishShape,
7531
10345
  isNullishLitAbs,
7532
10346
  strictEqAbs,
10347
+ looseEqAbs,
10348
+ pushCollectionArm,
10349
+ popCollectionArm,
10350
+ mergeCollectionArms,
10351
+ beginCollectionFork,
10352
+ noteCollectionWrite,
10353
+ endCollectionFork,
10354
+ isMapAbs,
10355
+ isSetAbs,
10356
+ makeMapAbs,
10357
+ makeSetAbs,
10358
+ mapSetEntry,
10359
+ mapDeleteEntry,
10360
+ mapClearEntries,
10361
+ mapGetEntry,
10362
+ mapHasEntry,
10363
+ mapSizeAbs,
10364
+ mapValuesAbs,
10365
+ mapEntriesAbs,
10366
+ setAddEntry,
10367
+ setDeleteEntry,
10368
+ setClearEntries,
10369
+ setHasEntry,
10370
+ setSizeAbs,
10371
+ setElementsAbs,
10372
+ collectionExactLen,
10373
+ collectionElementJoin,
10374
+ clearCollectionTables,
7533
10375
  evalMathMethod,
7534
10376
  evalObjectMethod,
7535
10377
  evalJsonMethod,
@@ -7544,6 +10386,8 @@ export {
7544
10386
  evalPromiseCtor,
7545
10387
  evalPromiseStatic,
7546
10388
  evalNamespaceCall,
10389
+ isErrorCtorName,
10390
+ errorBrandAbs,
7547
10391
  evalBuiltinNew,
7548
10392
  evalBuiltinInstanceMethod,
7549
10393
  callAbsMethod,
@@ -7577,6 +10421,10 @@ export {
7577
10421
  notePrimMemberMissing,
7578
10422
  noteUnknownMemberMissing,
7579
10423
  noteMemberDispatchMiss,
10424
+ setEvalMissingSlotEnabled,
10425
+ isEvalMissingSlotEnabled,
10426
+ runWithEvalMissingSlot,
10427
+ noteObjSlotMissing,
7580
10428
  registerBClass,
7581
10429
  getBClass,
7582
10430
  clearBClasses,
@@ -7618,27 +10466,44 @@ export {
7618
10466
  $not,
7619
10467
  $eq,
7620
10468
  $ne,
10469
+ $eqLoose,
10470
+ $neLoose,
7621
10471
  $lt,
7622
10472
  $le,
7623
10473
  $gt,
7624
10474
  $ge,
7625
10475
  $join,
7626
10476
  asAbsVal,
10477
+ callAtFunctionBoundary,
7627
10478
  $fnVal,
7628
10479
  $lit,
7629
10480
  litTruth,
7630
10481
  isDefinitelyTrue,
7631
10482
  isDefinitelyFalse,
10483
+ runWithLoopExits,
10484
+ takeLoopExits,
10485
+ takeThrowExits,
10486
+ pushLoopExit,
10487
+ pushThrowExit,
10488
+ $pushLoopExit,
10489
+ $tryMark,
10490
+ $tryCurrentMark,
10491
+ $tryPopMark,
10492
+ $tryTakeSince,
7632
10493
  $fork,
7633
10494
  DEFAULT_MAX_LOOP_ITERS,
7634
10495
  $forIter,
7635
10496
  $for,
7636
10497
  $arr,
10498
+ isArrMutator,
10499
+ $arrMutContainer,
7637
10500
  $idx,
7638
10501
  $idxSet,
7639
10502
  $len,
7640
10503
  $obj,
7641
10504
  $spread,
10505
+ $objRest,
10506
+ $arrRest,
7642
10507
  $concat,
7643
10508
  $elems,
7644
10509
  $forOf,
@@ -7648,9 +10513,14 @@ export {
7648
10513
  $set,
7649
10514
  $while,
7650
10515
  $whileSeq,
10516
+ NudoReturn,
10517
+ $loopReturn,
10518
+ isNudoReturn,
10519
+ $rethrowIfNudoReturn,
7651
10520
  NudoThrow,
7652
10521
  $throw,
7653
10522
  isNudoThrow,
10523
+ $isForkExit,
7654
10524
  $catchVal,
7655
10525
  $async,
7656
10526
  $await,
@@ -7658,6 +10528,7 @@ export {
7658
10528
  $gen,
7659
10529
  $yield,
7660
10530
  $switch,
10531
+ $nullishTest,
7661
10532
  transpileSource,
7662
10533
  transpileFile,
7663
10534
  transpileExpression,