@nudojs/core 0.4.0 → 1.0.1

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.
@@ -309,11 +309,18 @@ var phiAnd = and;
309
309
  function implies(phi2, pred) {
310
310
  if (pred.op === "true") return true;
311
311
  if (pred.op === "false") return false;
312
+ if (phi2.op === "false") return true;
313
+ if (predEquals(phi2, pred)) return true;
314
+ if (phi2.op === "and" && phi2.args.some((c) => predEquals(c, pred))) return true;
315
+ if (phi2.op === "or") {
316
+ return phi2.args.every((a) => implies(a, pred));
317
+ }
318
+ if (pred.op === "or") {
319
+ return pred.args.some((b) => implies(phi2, b));
320
+ }
312
321
  if (phi2.op === "true") {
313
322
  return decideLiteralPred(pred) === true;
314
323
  }
315
- if (predEquals(phi2, pred)) return true;
316
- if (phi2.op === "and" && phi2.args.some((c) => predEquals(c, pred))) return true;
317
324
  const bounds = extractBounds(phi2);
318
325
  const implied = impliesViaBounds(pred, bounds);
319
326
  if (implied !== void 0) return implied;
@@ -703,6 +710,86 @@ function shapeOnlyFn(paramTypes, returnType, opts) {
703
710
  }
704
711
 
705
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
+ }
706
793
  function isStrLit(a) {
707
794
  return a.shape.k === "prim" && a.shape.type === "string" && a.term?.op === "lit" && typeof a.term.value === "string";
708
795
  }
@@ -712,6 +799,13 @@ function isStrPrim2(a) {
712
799
  function isTemplateAbs(a) {
713
800
  return a.shape.k === "prim" && a.shape.type === "string" && !!a.pred && a.pred.name?.startsWith("`") === true && Array.isArray(a.pred.meta?.templateParts);
714
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
+ }
715
809
  function templatePartsOf(a) {
716
810
  if (isTemplateAbs(a)) {
717
811
  const meta = a.pred.meta;
@@ -719,29 +813,18 @@ function templatePartsOf(a) {
719
813
  }
720
814
  return [a];
721
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
+ }
722
823
  function normalizeParts(parts) {
723
- const out = [];
724
- for (const p of parts) {
725
- const last = out[out.length - 1];
726
- if (last && isStrLit(last) && isStrLit(p)) {
727
- out[out.length - 1] = abs(
728
- { k: "prim", type: "string" },
729
- lit(String(litValue(last)) + String(litValue(p))),
730
- void 0,
731
- "exact"
732
- );
733
- } else {
734
- out.push(p);
735
- }
736
- }
737
- return out;
824
+ return mergeAdjacentFixedViews(absTemplateViews(parts), rebuildAbsFixedView).map((v2) => v2.part);
738
825
  }
739
826
  function formatTemplateName(parts) {
740
- const inner = parts.map((p) => {
741
- if (isStrLit(p)) return String(litValue(p));
742
- return `\${${p.term ? termToString(p.term) : "string"}}`;
743
- }).join("");
744
- return `\`${inner}\``;
827
+ return formatTemplateNameViews(absTemplateViews(parts));
745
828
  }
746
829
  function createTemplateAbs(parts) {
747
830
  const normalized = normalizeParts(parts);
@@ -793,6 +876,324 @@ function coerceToStringParts(a) {
793
876
  return void 0;
794
877
  }
795
878
 
879
+ // src/algebra/derivation.ts
880
+ var collector = null;
881
+ var nextId = 1;
882
+ var byAbs = /* @__PURE__ */ new WeakMap();
883
+ var sessionNodes = null;
884
+ function setDerivationCollector(fn) {
885
+ collector = fn;
886
+ }
887
+ function hasDerivationSession() {
888
+ return sessionNodes !== null;
889
+ }
890
+ function beginDerivationSession() {
891
+ sessionNodes = /* @__PURE__ */ new Map();
892
+ nextId = 1;
893
+ }
894
+ function endDerivationSession() {
895
+ const nodes = sessionNodes ? [...sessionNodes.values()] : [];
896
+ sessionNodes = null;
897
+ collector = null;
898
+ return nodes;
899
+ }
900
+ function abortDerivationSession() {
901
+ sessionNodes = null;
902
+ collector = null;
903
+ }
904
+ function note(node) {
905
+ const full = { ...node, id: nextId++ };
906
+ if (sessionNodes) sessionNodes.set(full.id, full);
907
+ collector?.(full);
908
+ return full;
909
+ }
910
+ function tagDerivationRoot(abs2, meta) {
911
+ const node = note({
912
+ kind: "root",
913
+ expr: meta.expr,
914
+ ...meta.importFrom !== void 0 ? { importFrom: meta.importFrom } : {},
915
+ ...meta.importName !== void 0 ? { importName: meta.importName } : {},
916
+ parents: []
917
+ });
918
+ byAbs.set(abs2, node);
919
+ return node;
920
+ }
921
+ function getDerivation(abs2) {
922
+ return byAbs.get(abs2);
923
+ }
924
+ function setDerivation(abs2, node) {
925
+ byAbs.set(abs2, node);
926
+ }
927
+ function derivationChain(node) {
928
+ const chain = [node];
929
+ const seen = /* @__PURE__ */ new Set([node.id]);
930
+ let cur = node;
931
+ while (cur.kind !== "root" && cur.parents.length > 0) {
932
+ const pid = cur.parents[0];
933
+ if (seen.has(pid) || !sessionNodes) break;
934
+ const parent = sessionNodes.get(pid);
935
+ if (!parent) break;
936
+ seen.add(pid);
937
+ chain.push(parent);
938
+ cur = parent;
939
+ }
940
+ return chain;
941
+ }
942
+ function noteDerivationAdd(a, b, result) {
943
+ if (!sessionNodes) return;
944
+ const vb = litValue(b);
945
+ const va = litValue(a);
946
+ let parent;
947
+ let offset;
948
+ if (typeof vb === "number" && Number.isFinite(vb)) {
949
+ parent = byAbs.get(a);
950
+ offset = vb;
951
+ } else if (typeof va === "number" && Number.isFinite(va)) {
952
+ parent = byAbs.get(b);
953
+ offset = va;
954
+ }
955
+ if (!parent || offset === void 0) return;
956
+ const node = note({
957
+ kind: "shift",
958
+ offset,
959
+ parents: [parent.id]
960
+ });
961
+ byAbs.set(result, node);
962
+ }
963
+ function noteDerivationJoin(inputs, result) {
964
+ if (!sessionNodes) return;
965
+ const parents = [];
966
+ for (const a of inputs) {
967
+ const n = byAbs.get(a);
968
+ if (n && !parents.includes(n.id)) parents.push(n.id);
969
+ }
970
+ if (parents.length === 0) return;
971
+ const node = note({ kind: "join", parents });
972
+ byAbs.set(result, node);
973
+ }
974
+ function projectDerivationDsl(node, localName) {
975
+ const chain = derivationChain(node);
976
+ const root = chain[chain.length - 1];
977
+ if (!root || root.kind !== "root" || root.expr === void 0) return void 0;
978
+ if (chain.some((n) => n.kind === "join" || n.kind === "opaque")) return void 0;
979
+ const shifts = [];
980
+ for (let i = chain.length - 2; i >= 0; i--) {
981
+ const n = chain[i];
982
+ if (n.kind !== "shift" || n.offset === void 0) return void 0;
983
+ shifts.push(n.offset);
984
+ }
985
+ const rootExpr = root.expr;
986
+ const imports = [];
987
+ if (root.importFrom !== void 0) {
988
+ imports.push({
989
+ name: root.importName ?? rootExpr,
990
+ from: root.importFrom
991
+ });
992
+ }
993
+ if (shifts.length === 0) {
994
+ return { prelude: [], expr: rootExpr, imports };
995
+ }
996
+ let current = rootExpr;
997
+ const prelude = [];
998
+ for (let i = 0; i < shifts.length; i++) {
999
+ const step = `${current}.shift(${shifts[i]})`;
1000
+ if (i === shifts.length - 1) {
1001
+ prelude.push(`const ${localName} = ${step};`);
1002
+ return { prelude, expr: localName, imports };
1003
+ }
1004
+ const tmp = `${localName}_${i}`;
1005
+ prelude.push(`const ${tmp} = ${step};`);
1006
+ current = tmp;
1007
+ }
1008
+ return void 0;
1009
+ }
1010
+ function termKey3(t) {
1011
+ return t === void 0 ? "<none>" : termToString(t);
1012
+ }
1013
+
1014
+ // src/algebra/objects.ts
1015
+ function objOf(slots, opts) {
1016
+ const shape = { k: "obj", slots };
1017
+ if (opts?.index) shape.index = opts.index;
1018
+ if (opts?.open) shape.open = true;
1019
+ return { shape, conf: "exact" };
1020
+ }
1021
+ function isObj(a) {
1022
+ return a.shape.k === "obj";
1023
+ }
1024
+ function getSlot(slots, key) {
1025
+ return Object.prototype.hasOwnProperty.call(slots, key) ? slots[key] : void 0;
1026
+ }
1027
+ function spread(base, over) {
1028
+ if (!isObj(base) && !isObj(over)) {
1029
+ if (isObj(over)) return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1030
+ if (isObj(base)) return { shape: { ...base.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1031
+ return unknown;
1032
+ }
1033
+ if (!isObj(over)) {
1034
+ if (!isObj(base)) return unknown;
1035
+ return {
1036
+ shape: { ...base.shape, open: true },
1037
+ conf: confJoin(base.conf, "partial")
1038
+ };
1039
+ }
1040
+ if (!isObj(base)) {
1041
+ return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1042
+ }
1043
+ const slots = { ...base.shape.slots };
1044
+ for (const [k, s] of Object.entries(over.shape.slots)) {
1045
+ slots[k] = s;
1046
+ }
1047
+ const open = base.shape.open || over.shape.open || false;
1048
+ const shape = { k: "obj", slots };
1049
+ if (open) shape.open = true;
1050
+ if (base.shape.index || over.shape.index) {
1051
+ shape.index = over.shape.index ?? base.shape.index;
1052
+ }
1053
+ return { shape, conf: confJoin(base.conf, over.conf) };
1054
+ }
1055
+ function joinObjects(a, b) {
1056
+ if (a.shape.k === "never") return b;
1057
+ if (b.shape.k === "never") return a;
1058
+ if (!isObj(a) || !isObj(b)) {
1059
+ return makeSum(a, b);
1060
+ }
1061
+ const ka = Object.keys(a.shape.slots).sort();
1062
+ const kb = Object.keys(b.shape.slots).sort();
1063
+ const sameKeys = ka.length === kb.length && ka.every((k, i) => k === kb[i]);
1064
+ if (!sameKeys) {
1065
+ return makeSum(a, b);
1066
+ }
1067
+ const slots = {};
1068
+ let conf = confJoin(a.conf, b.conf);
1069
+ for (const k of ka) {
1070
+ const sa = a.shape.slots[k];
1071
+ const sb = b.shape.slots[k];
1072
+ const optional = sa.optional || sb.optional;
1073
+ const jv = joinValues(sa.value, sb.value);
1074
+ conf = confJoin(conf, jv.conf);
1075
+ slots[k] = { value: jv, optional };
1076
+ }
1077
+ return { shape: { k: "obj", slots }, conf };
1078
+ }
1079
+ function joinValues(a, b) {
1080
+ if (a.shape.k === "never") return b;
1081
+ if (b.shape.k === "never") return a;
1082
+ const va = litValue(a);
1083
+ const vb = litValue(b);
1084
+ if (va !== void 0 && Object.is(va, vb)) return a;
1085
+ if (a.shape.k === "prim" && b.shape.k === "prim" && a.shape.type === b.shape.type) {
1086
+ 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
+ );
1093
+ }
1094
+ return abs(a.shape, void 0, void 0, confJoin(confJoin(a.conf, b.conf), "path"));
1095
+ }
1096
+ return makeSum(a, b);
1097
+ }
1098
+ function makeSum(a, b) {
1099
+ const members = flattenSum([a, b]);
1100
+ if (members.length === 1) return members[0];
1101
+ return {
1102
+ shape: { k: "sum", members },
1103
+ conf: confJoin(a.conf, b.conf)
1104
+ };
1105
+ }
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;
1121
+ }
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);
1167
+ }
1168
+ }
1169
+ function fnOf(params, name) {
1170
+ const shape = { k: "fn", params };
1171
+ if (name) shape.name = name;
1172
+ return { shape, conf: "exact" };
1173
+ }
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
+ }
1184
+ }
1185
+ return makeSum(a, b);
1186
+ }
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;
1195
+ }
1196
+
796
1197
  // src/algebra/arithmetic.ts
797
1198
  function add(a, b, phi2 = pTrue) {
798
1199
  const va = litValue(a);
@@ -815,7 +1216,9 @@ function add(a, b, phi2 = pTrue) {
815
1216
  const term = simplifyTerm(app("+", [a.term, b.term]));
816
1217
  const pred = addPred(a, b, term, phi2);
817
1218
  const conf = term.op === "lit" ? "exact" : confJoin(confJoin(a.conf, b.conf), "path");
818
- return abs({ k: "prim", type: "number" }, term, pred, conf);
1219
+ const result = abs({ k: "prim", type: "number" }, term, pred, conf);
1220
+ noteDerivationAdd(a, b, result);
1221
+ return result;
819
1222
  }
820
1223
  if (isAnyLike(a) || isAnyLike(b)) {
821
1224
  const term = a.term && b.term ? simplifyTerm(app("+", [a.term, b.term])) : void 0;
@@ -854,7 +1257,7 @@ function dedupAbsMembers(ms) {
854
1257
  const seen = /* @__PURE__ */ new Set();
855
1258
  const out = [];
856
1259
  for (const m of ms) {
857
- const key = m.shape.k === "prim" ? `prim:${m.shape.type}` : m.shape.k === "sum" ? `sum:${m.shape.members.length}` : m.shape.k;
1260
+ const key = absShapeKey(m);
858
1261
  if (seen.has(key)) continue;
859
1262
  seen.add(key);
860
1263
  out.push(m);
@@ -934,7 +1337,7 @@ function collectBoundsFromPred(pred, term, acc) {
934
1337
  }
935
1338
  if (p.op === "gt" && match(p.a) && p.b.op === "lit" && typeof p.b.value === "number") {
936
1339
  const n = p.b.value;
937
- if (acc.lo === void 0 || n > acc.lo.value || n === acc.lo.value && p.op === "gt") {
1340
+ if (acc.lo === void 0 || n > acc.lo.value || n === acc.lo.value && !acc.lo.strict) {
938
1341
  acc.lo = { value: n, strict: true };
939
1342
  }
940
1343
  return;
@@ -948,7 +1351,7 @@ function collectBoundsFromPred(pred, term, acc) {
948
1351
  }
949
1352
  if (p.op === "lt" && match(p.a) && p.b.op === "lit" && typeof p.b.value === "number") {
950
1353
  const n = p.b.value;
951
- if (acc.hi === void 0 || n < acc.hi.value) {
1354
+ if (acc.hi === void 0 || n < acc.hi.value || n === acc.hi.value && !acc.hi.strict) {
952
1355
  acc.hi = { value: n, strict: true };
953
1356
  }
954
1357
  return;
@@ -967,7 +1370,7 @@ function collectBoundsFromPhi(phi2, id, acc) {
967
1370
  for (const p of conjs) {
968
1371
  if (p.op === "gt" && p.a.op === "var" && p.a.id === id && p.b.op === "lit" && typeof p.b.value === "number") {
969
1372
  const n = p.b.value;
970
- if (acc.lo === void 0 || n > acc.lo.value) {
1373
+ if (acc.lo === void 0 || n > acc.lo.value || n === acc.lo.value && !acc.lo.strict) {
971
1374
  acc.lo = { value: n, strict: true };
972
1375
  }
973
1376
  }
@@ -979,7 +1382,7 @@ function collectBoundsFromPhi(phi2, id, acc) {
979
1382
  }
980
1383
  if (p.op === "lt" && p.a.op === "var" && p.a.id === id && p.b.op === "lit" && typeof p.b.value === "number") {
981
1384
  const n = p.b.value;
982
- if (acc.hi === void 0 || n < acc.hi.value) {
1385
+ if (acc.hi === void 0 || n < acc.hi.value || n === acc.hi.value && !acc.hi.strict) {
983
1386
  acc.hi = { value: n, strict: true };
984
1387
  }
985
1388
  }
@@ -1220,6 +1623,20 @@ function compareLits(op, a, b) {
1220
1623
  return a >= b;
1221
1624
  }
1222
1625
  }
1626
+ if (op === "lt" || op === "le" || op === "gt" || op === "ge") {
1627
+ const x = a;
1628
+ const y = b;
1629
+ switch (op) {
1630
+ case "lt":
1631
+ return x < y;
1632
+ case "le":
1633
+ return x <= y;
1634
+ case "gt":
1635
+ return x > y;
1636
+ case "ge":
1637
+ return x >= y;
1638
+ }
1639
+ }
1223
1640
  return void 0;
1224
1641
  }
1225
1642
  function decideByBounds(op, a, b, phi2) {
@@ -1258,6 +1675,34 @@ function trueConstraint(c) {
1258
1675
  if (c.term?.op === "lit" && c.term.value === false) return void 0;
1259
1676
  return c.pred;
1260
1677
  }
1678
+ function refineAbsForRelTrue(a, op, k) {
1679
+ const bound = (t) => op === "gt" ? gt(t, lit(k)) : op === "ge" ? ge(t, lit(k)) : op === "lt" ? lt(t, lit(k)) : le(t, lit(k));
1680
+ if (isNumPrim(a) && a.term) {
1681
+ const pred = a.pred && a.pred.op !== "true" ? and(a.pred, bound(a.term)) : bound(a.term);
1682
+ return abs(a.shape, a.term, pred, a.conf);
1683
+ }
1684
+ if (isStrPrim(a)) return a;
1685
+ if ((a.shape.k === "any" || a.shape.k === "unknown") && a.term) {
1686
+ const numArm = abs({ k: "prim", type: "number" }, a.term, bound(a.term), "path");
1687
+ const strArm = abs({ k: "prim", type: "string" }, a.term, void 0, "path");
1688
+ return makeSum(numArm, strArm);
1689
+ }
1690
+ return a;
1691
+ }
1692
+ function matchRelIdentLit(test) {
1693
+ const t = test;
1694
+ if (t?.type !== "BinaryExpression") return void 0;
1695
+ const rel = t.operator === ">" ? "gt" : t.operator === ">=" ? "ge" : t.operator === "<" ? "lt" : t.operator === "<=" ? "le" : void 0;
1696
+ if (!rel) return void 0;
1697
+ if (t.left?.type === "Identifier" && t.left.name && t.right?.type === "NumericLiteral" && typeof t.right.value === "number") {
1698
+ return { name: t.left.name, op: rel, k: t.right.value };
1699
+ }
1700
+ if (t.right?.type === "Identifier" && t.right.name && t.left?.type === "NumericLiteral" && typeof t.left.value === "number") {
1701
+ const flipped = rel === "gt" ? "lt" : rel === "ge" ? "le" : rel === "lt" ? "gt" : "ge";
1702
+ return { name: t.right.name, op: flipped, k: t.left.value };
1703
+ }
1704
+ return void 0;
1705
+ }
1261
1706
  function falseConstraint(c) {
1262
1707
  if (c.term?.op === "lit" && c.term.value === true) return void 0;
1263
1708
  if (c.term?.op === "lit" && c.term.value === false) return pTrue;
@@ -1371,7 +1816,7 @@ function flipBounds(pred, src, dst, out) {
1371
1816
  if (p.op !== "gt" && p.op !== "ge" && p.op !== "lt" && p.op !== "le") {
1372
1817
  return;
1373
1818
  }
1374
- if (termKey3(p.a) !== termKey3(src)) return;
1819
+ if (termKey4(p.a) !== termKey4(src)) return;
1375
1820
  if (p.b.op !== "lit" || typeof p.b.value !== "number") return;
1376
1821
  const n = p.b.value;
1377
1822
  if (p.op === "gt") out.push(lt(dst, lit(-n)));
@@ -1381,7 +1826,7 @@ function flipBounds(pred, src, dst, out) {
1381
1826
  };
1382
1827
  apply(pred);
1383
1828
  }
1384
- function termKey3(t) {
1829
+ function termKey4(t) {
1385
1830
  if (t.op === "lit") return `lit:${JSON.stringify(t.value)}`;
1386
1831
  if (t.op === "var") return `var:${t.id}`;
1387
1832
  return `app:${t.fn}`;
@@ -1450,169 +1895,13 @@ function strictEqAbs(a, b) {
1450
1895
  return void 0;
1451
1896
  }
1452
1897
 
1453
- // src/algebra/objects.ts
1454
- function objOf(slots, opts) {
1455
- const shape = { k: "obj", slots };
1456
- if (opts?.index) shape.index = opts.index;
1457
- if (opts?.open) shape.open = true;
1458
- return { shape, conf: "exact" };
1459
- }
1460
- function isObj(a) {
1461
- return a.shape.k === "obj";
1462
- }
1463
- function spread(base, over) {
1464
- if (!isObj(base) && !isObj(over)) {
1465
- if (isObj(over)) return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1466
- if (isObj(base)) return { shape: { ...base.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1467
- return unknown;
1468
- }
1469
- if (!isObj(over)) {
1470
- if (!isObj(base)) return unknown;
1471
- return {
1472
- shape: { ...base.shape, open: true },
1473
- conf: confJoin(base.conf, "partial")
1474
- };
1475
- }
1476
- if (!isObj(base)) {
1477
- return { shape: { ...over.shape, open: true }, conf: confJoin(base.conf, over.conf) };
1478
- }
1479
- const slots = { ...base.shape.slots };
1480
- for (const [k, s] of Object.entries(over.shape.slots)) {
1481
- slots[k] = s;
1482
- }
1483
- const open = base.shape.open || over.shape.open || false;
1484
- const shape = { k: "obj", slots };
1485
- if (open) shape.open = true;
1486
- if (base.shape.index || over.shape.index) {
1487
- shape.index = over.shape.index ?? base.shape.index;
1488
- }
1489
- return { shape, conf: confJoin(base.conf, over.conf) };
1490
- }
1491
- function joinObjects(a, b) {
1492
- if (a.shape.k === "never") return b;
1493
- if (b.shape.k === "never") return a;
1494
- if (!isObj(a) || !isObj(b)) {
1495
- return makeSum(a, b);
1496
- }
1497
- const ka = Object.keys(a.shape.slots).sort();
1498
- const kb = Object.keys(b.shape.slots).sort();
1499
- const sameKeys = ka.length === kb.length && ka.every((k, i) => k === kb[i]);
1500
- if (!sameKeys) {
1501
- return makeSum(a, b);
1502
- }
1503
- const slots = {};
1504
- let conf = confJoin(a.conf, b.conf);
1505
- for (const k of ka) {
1506
- const sa = a.shape.slots[k];
1507
- const sb = b.shape.slots[k];
1508
- const optional = sa.optional || sb.optional;
1509
- const jv = joinValues(sa.value, sb.value);
1510
- conf = confJoin(conf, jv.conf);
1511
- slots[k] = { value: jv, optional };
1512
- }
1513
- return { shape: { k: "obj", slots }, conf };
1514
- }
1515
- function joinValues(a, b) {
1516
- if (a.shape.k === "never") return b;
1517
- if (b.shape.k === "never") return a;
1518
- const va = litValue(a);
1519
- const vb = litValue(b);
1520
- if (va !== void 0 && va === vb) return a;
1521
- if (a.shape.k === "prim" && b.shape.k === "prim" && a.shape.type === b.shape.type) {
1522
- if (va !== void 0 && vb !== void 0) {
1523
- return abs(
1524
- a.shape,
1525
- void 0,
1526
- void 0,
1527
- confJoin(a.conf, "path")
1528
- );
1529
- }
1530
- return abs(a.shape, void 0, void 0, confJoin(confJoin(a.conf, b.conf), "path"));
1531
- }
1532
- return makeSum(a, b);
1533
- }
1534
- function makeSum(a, b) {
1535
- const members = flattenSum([a, b]);
1536
- if (members.length === 1) return members[0];
1537
- return {
1538
- shape: { k: "sum", members },
1539
- conf: confJoin(a.conf, b.conf)
1540
- };
1541
- }
1542
- function flattenSum(xs) {
1543
- const out = [];
1544
- for (const x of xs) {
1545
- if (x.shape.k === "sum") out.push(...x.shape.members);
1546
- else out.push(x);
1547
- }
1548
- const seen = /* @__PURE__ */ new Set();
1549
- const deduped = [];
1550
- for (const x of out) {
1551
- const key = shapeKey(x);
1552
- if (seen.has(key)) continue;
1553
- seen.add(key);
1554
- deduped.push(x);
1555
- }
1556
- return deduped;
1898
+ // src/algebra/containers.ts
1899
+ var TUPLE_LITERAL_CAP = 8;
1900
+ function shouldWidenArrayLiteral(n) {
1901
+ return n > TUPLE_LITERAL_CAP;
1557
1902
  }
1558
- function shapeKey(a) {
1559
- const s = a.shape;
1560
- if (s.k === "prim") return `prim:${s.type}`;
1561
- if (s.k === "never") return "never";
1562
- if (s.k === "any") return "any";
1563
- if (s.k === "unknown") return "unknown";
1564
- if (s.k === "obj") return `obj:${Object.keys(s.slots).sort().join(",")}`;
1565
- if (s.k === "fn") return `fn:${s.params.length}`;
1566
- if (s.k === "sum") return `sum:${s.members.length}`;
1567
- return "other";
1568
- }
1569
- function collapseToOptional(sum) {
1570
- if (sum.shape.k !== "sum") {
1571
- if (isObj(sum)) return { ...sum, conf: confJoin(sum.conf, "widened") };
1572
- return sum;
1573
- }
1574
- const objs = sum.shape.members.filter(isObj);
1575
- if (objs.length === 0) {
1576
- return abs({ k: "unknown" }, void 0, void 0, "widened");
1577
- }
1578
- const allKeys = /* @__PURE__ */ new Set();
1579
- for (const o of objs) {
1580
- for (const k of Object.keys(o.shape.slots)) allKeys.add(k);
1581
- }
1582
- const slots = {};
1583
- for (const k of allKeys) {
1584
- const present = objs.filter((o) => k in o.shape.slots);
1585
- const values = present.map((o) => o.shape.slots[k].value);
1586
- const joined = values.reduce((acc, v2) => joinValues(acc, v2));
1587
- const optional = present.length < objs.length;
1588
- slots[k] = { value: joined, optional };
1589
- }
1590
- return { shape: { k: "obj", slots }, conf: "widened" };
1591
- }
1592
- function fnOf(params, name) {
1593
- const shape = { k: "fn", params };
1594
- if (name) shape.name = name;
1595
- return { shape, conf: "exact" };
1596
- }
1597
- function joinFunctions(a, b) {
1598
- const sa = a.shape;
1599
- const sb = b.shape;
1600
- if (sa.k !== "fn" || sb.k !== "fn") return makeSum(a, b);
1601
- const an = sa.name;
1602
- const bn = sb.name;
1603
- if (an && an === bn) {
1604
- if (sa.params.length === sb.params.length && sa.params.every((p, i) => p === sb.params[i])) {
1605
- return a;
1606
- }
1607
- }
1608
- return makeSum(a, b);
1609
- }
1610
- function joinAbs(a, b) {
1611
- if (a.shape.k === "never") return b;
1612
- if (b.shape.k === "never") return a;
1613
- if (isObj(a) && isObj(b)) return joinObjects(a, b);
1614
- if (a.shape.k === "fn" && b.shape.k === "fn") return joinFunctions(a, b);
1615
- return joinValues(a, b);
1903
+ function widenedArrayConf() {
1904
+ return "path";
1616
1905
  }
1617
1906
 
1618
1907
  // src/algebra/language.ts
@@ -1728,8 +2017,8 @@ function litFalse() {
1728
2017
  function projectBrand(self, key) {
1729
2018
  if (self.shape.k !== "brand") return unknown;
1730
2019
  const inner = self.shape.shape;
1731
- if (inner.shape.k === "obj") {
1732
- const slot = inner.shape.slots[key];
2020
+ if (inner && inner.shape.k === "obj") {
2021
+ const slot = getSlot(inner.shape.slots, key);
1733
2022
  if (slot) return slot.value;
1734
2023
  }
1735
2024
  return unknown;
@@ -1918,7 +2207,7 @@ function leqShape(src, tgt, phi2, env, depth) {
1918
2207
  const srcObj = s.k === "obj" ? s : s.k === "brand" ? s.shape.shape.k === "obj" ? s.shape.shape : null : null;
1919
2208
  if (!srcObj || srcObj.k !== "obj") return fail(`shape ${s.k} \u22AD obj`);
1920
2209
  for (const [key, slot] of Object.entries(t.slots)) {
1921
- const srcSlot = srcObj.slots[key];
2210
+ const srcSlot = getSlot(srcObj.slots, key);
1922
2211
  if (!srcSlot) {
1923
2212
  if (slot.optional) continue;
1924
2213
  return fail(`missing slot ${key}`);
@@ -2025,6 +2314,8 @@ function evalMathMethod(name, args) {
2025
2314
  case "round":
2026
2315
  if (typeof a0 === "number") return numLit(Math.round(a0));
2027
2316
  return numPrim();
2317
+ case "random":
2318
+ return numPrim("path");
2028
2319
  case "sqrt":
2029
2320
  if (typeof a0 === "number") return numLit(Math.sqrt(a0));
2030
2321
  return numPrim();
@@ -2104,6 +2395,12 @@ function evalJsonMethod(name, args) {
2104
2395
  if (name === "parse") return unknown;
2105
2396
  return void 0;
2106
2397
  }
2398
+ function foldParseInt(s, radix) {
2399
+ const str2 = String(s);
2400
+ if (radix === void 0) return numLit(parseInt(str2));
2401
+ if (!Number.isInteger(radix) || radix < 2 || radix > 36) return numLit(NaN);
2402
+ return numLit(parseInt(str2, radix));
2403
+ }
2107
2404
  function evalNumberStatic(name, args) {
2108
2405
  const a0 = args[0] ? litValue(args[0]) : void 0;
2109
2406
  switch (name) {
@@ -2117,12 +2414,16 @@ function evalNumberStatic(name, args) {
2117
2414
  if (typeof a0 === "number") return boolLit(Number.isFinite(a0));
2118
2415
  return boolPrim();
2119
2416
  case "parseInt":
2120
- case "parseFloat":
2121
2417
  if (typeof a0 === "string" || typeof a0 === "number") {
2122
- const n = name === "parseInt" ? parseInt(String(a0), 10) : parseFloat(String(a0));
2123
- return numLit(n);
2418
+ const radix = args[1] ? litValue(args[1]) : void 0;
2419
+ if (radix === void 0) return foldParseInt(a0, void 0);
2420
+ if (typeof radix === "number") return foldParseInt(a0, radix);
2421
+ return numPrim();
2124
2422
  }
2125
2423
  return numPrim();
2424
+ case "parseFloat":
2425
+ if (typeof a0 === "string" || typeof a0 === "number") return numLit(parseFloat(String(a0)));
2426
+ return numPrim();
2126
2427
  case "MAX_SAFE_INTEGER":
2127
2428
  return numLit(Number.MAX_SAFE_INTEGER);
2128
2429
  default:
@@ -2133,7 +2434,12 @@ function evalGlobalFn(name, args) {
2133
2434
  const a0 = args[0] ? litValue(args[0]) : void 0;
2134
2435
  switch (name) {
2135
2436
  case "parseInt":
2136
- if (typeof a0 === "string" || typeof a0 === "number") return numLit(parseInt(String(a0), 10));
2437
+ if (typeof a0 === "string" || typeof a0 === "number") {
2438
+ const radix = args[1] ? litValue(args[1]) : void 0;
2439
+ if (radix === void 0) return foldParseInt(a0, void 0);
2440
+ if (typeof radix === "number") return foldParseInt(a0, radix);
2441
+ return numPrim();
2442
+ }
2137
2443
  return numPrim();
2138
2444
  case "parseFloat":
2139
2445
  if (typeof a0 === "string" || typeof a0 === "number") return numLit(parseFloat(String(a0)));
@@ -2156,17 +2462,44 @@ function evalGlobalFn(name, args) {
2156
2462
  return void 0;
2157
2463
  }
2158
2464
  }
2465
+ function peelBrand(shape) {
2466
+ let s = shape;
2467
+ while (s.k === "brand") s = s.shape.shape;
2468
+ return s;
2469
+ }
2159
2470
  function evalArrayStatic(name, args) {
2160
2471
  const a0 = args[0];
2161
2472
  switch (name) {
2162
2473
  case "isArray": {
2163
2474
  if (!a0) return boolLit(false);
2164
- const k = a0.shape.k;
2165
- return boolLit(k === "arr" || k === "tuple");
2475
+ const s = peelBrand(a0.shape);
2476
+ if (s.k === "arr" || s.k === "tuple") return boolLit(true);
2477
+ if (s.k === "any" || s.k === "unknown" || s.k === "sum") return boolPrim();
2478
+ return boolLit(false);
2166
2479
  }
2167
- case "from":
2168
2480
  case "of":
2169
2481
  return abs({ k: "arr", element: a0 ?? unknown }, void 0, void 0, "path");
2482
+ case "from": {
2483
+ if (!a0) return unknown;
2484
+ const k = a0.shape.k;
2485
+ if (k === "arr") return a0;
2486
+ if (k === "tuple") {
2487
+ const els = a0.shape.elements;
2488
+ if (els.length === 0) return abs({ k: "arr", element: unknown }, void 0, void 0, "path");
2489
+ let el = els[0];
2490
+ for (let i = 1; i < els.length; i++) el = joinAbs(el, els[i]);
2491
+ return abs({ k: "arr", element: el }, void 0, void 0, "path");
2492
+ }
2493
+ if (k === "prim" && a0.shape.type === "string") {
2494
+ return abs(
2495
+ { k: "arr", element: abs({ k: "prim", type: "string" }, void 0, void 0, "path") },
2496
+ void 0,
2497
+ void 0,
2498
+ "path"
2499
+ );
2500
+ }
2501
+ return unknown;
2502
+ }
2170
2503
  default:
2171
2504
  return void 0;
2172
2505
  }
@@ -2180,7 +2513,7 @@ function evalDateCtor(args) {
2180
2513
  );
2181
2514
  }
2182
2515
  function evalDateStatic(name, _args) {
2183
- if (name === "now") return numLit(Date.now());
2516
+ if (name === "now") return numPrim("path");
2184
2517
  return void 0;
2185
2518
  }
2186
2519
  function evalDateMethod(name, _recv, _args) {
@@ -2518,10 +2851,10 @@ function parseUncached(source, opts) {
2518
2851
  attachComment: true,
2519
2852
  errorRecovery: opts?.errorRecovery === true
2520
2853
  });
2521
- return stripTypes(ast);
2854
+ return opts?.keepTs === true ? ast : stripTypes(ast);
2522
2855
  }
2523
2856
  function parseSource(source, opts) {
2524
- if (opts?.errorRecovery === true) {
2857
+ if (opts?.keepTs === true || opts?.errorRecovery === true) {
2525
2858
  return parseUncached(source, opts);
2526
2859
  }
2527
2860
  if (source.length > MAX_AST_SOURCE_CHARS) {
@@ -3127,29 +3460,6 @@ function numPrim2(conf = "path") {
3127
3460
  function strArr(conf = "path") {
3128
3461
  return abs({ k: "arr", element: strPrim2("path") }, void 0, void 0, conf);
3129
3462
  }
3130
- function knownPrefix(parts) {
3131
- let s = "";
3132
- for (const p of parts) {
3133
- if (p.term?.op === "lit" && typeof p.term.value === "string") s += p.term.value;
3134
- else break;
3135
- }
3136
- return s;
3137
- }
3138
- function knownSuffix(parts) {
3139
- let s = "";
3140
- for (let i = parts.length - 1; i >= 0; i--) {
3141
- const p = parts[i];
3142
- if (p.term?.op === "lit" && typeof p.term.value === "string") s = p.term.value + s;
3143
- else break;
3144
- }
3145
- return s;
3146
- }
3147
- function fixedLength(parts) {
3148
- if (parts.some((p) => !(p.term?.op === "lit" && typeof p.term.value === "string"))) {
3149
- return void 0;
3150
- }
3151
- return parts.reduce((n, p) => n + String(p.term && p.term.op === "lit" ? p.term.value : "").length, 0);
3152
- }
3153
3463
  function isStrRecv(recv) {
3154
3464
  return isTemplateLike(recv) || recv.shape.k === "prim" && recv.shape.type === "string" || recv.term?.op === "lit" && typeof recv.term.value === "string";
3155
3465
  }
@@ -3158,27 +3468,24 @@ function callAbsMethod(recv, name, args) {
3158
3468
  const a0 = args[0] ? litValue(args[0]) : void 0;
3159
3469
  const lit3 = recv.term?.op === "lit" && typeof recv.term.value === "string" ? recv.term.value : void 0;
3160
3470
  if (isTemplateLike(recv)) {
3161
- const parts = templatePartsOf(recv);
3162
- const prefix = knownPrefix(parts);
3163
- const suffix = knownSuffix(parts);
3471
+ const views = absTemplateViews(templatePartsOf(recv));
3472
+ const prefix = knownPrefixOfViews(views);
3473
+ const suffix = knownSuffixOfViews(views);
3164
3474
  switch (name) {
3165
3475
  case "startsWith": {
3166
3476
  if (typeof a0 !== "string") return boolPrim2();
3167
- if (prefix.length >= a0.length) return boolLit(prefix.startsWith(a0));
3168
- if (a0.startsWith(prefix)) return boolPrim2();
3169
- return boolLit(false);
3477
+ const d = decideStartsWith(prefix, a0);
3478
+ return d === "unknown" ? boolPrim2() : boolLit(d);
3170
3479
  }
3171
3480
  case "endsWith": {
3172
3481
  if (typeof a0 !== "string") return boolPrim2();
3173
- if (suffix.length >= a0.length) return boolLit(suffix.endsWith(a0));
3174
- if (a0.startsWith(prefix)) return boolPrim2();
3175
- return boolLit(false);
3482
+ const d = decideEndsWith(suffix, a0);
3483
+ return d === "unknown" ? boolPrim2() : boolLit(d);
3176
3484
  }
3177
3485
  case "includes": {
3178
3486
  if (typeof a0 !== "string") return boolPrim2();
3179
- const fixed = parts.filter((p) => p.term?.op === "lit" && typeof p.term.value === "string").map((p) => String(p.term && p.term.op === "lit" ? p.term.value : "")).join("");
3180
- if (fixed.includes(a0)) return boolLit(true);
3181
- return boolPrim2();
3487
+ const d = decideIncludes(allFixedTextOfViews(views), a0);
3488
+ return d === "unknown" ? boolPrim2() : boolLit(d);
3182
3489
  }
3183
3490
  case "toUpperCase":
3184
3491
  case "toLowerCase":
@@ -3248,7 +3555,7 @@ function callAbsMethod(recv, name, args) {
3248
3555
  const parts = lit3.split(sep).map((s) => strLit(s));
3249
3556
  return abs({ k: "tuple", elements: parts }, void 0, void 0, "exact");
3250
3557
  }
3251
- return abs({ k: "tuple", elements: [strLit(lit3)] }, void 0, void 0, "path");
3558
+ return strArr("path");
3252
3559
  }
3253
3560
  return strArr("path");
3254
3561
  }
@@ -3264,8 +3571,7 @@ function callAbsMethod(recv, name, args) {
3264
3571
  function getAbsProperty(recv, name) {
3265
3572
  if (name === "length") {
3266
3573
  if (isTemplateLike(recv)) {
3267
- const parts = templatePartsOf(recv);
3268
- const n = fixedLength(parts);
3574
+ const n = fixedLengthOfViews(absTemplateViews(templatePartsOf(recv)));
3269
3575
  if (n !== void 0) return numLit(n);
3270
3576
  return numPrim2("path");
3271
3577
  }
@@ -3534,8 +3840,8 @@ function callBudgetKey(kind, id, args) {
3534
3840
  return `${kind}|${id}|${parts.join(",")}`;
3535
3841
  }
3536
3842
  var absTruncCollector = null;
3537
- function setAbsTruncationCollector(collector) {
3538
- absTruncCollector = collector;
3843
+ function setAbsTruncationCollector(collector2) {
3844
+ absTruncCollector = collector2;
3539
3845
  }
3540
3846
  function noteTruncation(label) {
3541
3847
  if (!absTruncCollector) return;
@@ -3559,8 +3865,10 @@ function exitCall() {
3559
3865
  _activeCallKeys.pop();
3560
3866
  }
3561
3867
  var absCallCollector = null;
3562
- function setAbsCallCollector(collector) {
3563
- absCallCollector = collector;
3868
+ function setAbsCallCollector(collector2) {
3869
+ const prev = absCallCollector;
3870
+ absCallCollector = collector2;
3871
+ return prev;
3564
3872
  }
3565
3873
  function recordAbsCall(fnName, args, result, callLoc, threw) {
3566
3874
  if (!absCallCollector) return;
@@ -3570,8 +3878,8 @@ function recordAbsCall(fnName, args, result, callLoc, threw) {
3570
3878
  }
3571
3879
  }
3572
3880
  var absNodeCollector = null;
3573
- function setAbsNodeCollector(collector) {
3574
- absNodeCollector = collector;
3881
+ function setAbsNodeCollector(collector2) {
3882
+ absNodeCollector = collector2;
3575
3883
  }
3576
3884
  function recordAbsNode(node, value) {
3577
3885
  if (!absNodeCollector || !value) return;
@@ -3581,8 +3889,17 @@ function recordAbsNode(node, value) {
3581
3889
  }
3582
3890
  }
3583
3891
  var absAssignCollector = null;
3584
- function setAbsAssignCollector(collector) {
3585
- absAssignCollector = collector;
3892
+ var assignFlowDepth = 0;
3893
+ function setAbsAssignCollector(collector2) {
3894
+ absAssignCollector = collector2;
3895
+ }
3896
+ function evalInConditionalFlow(body) {
3897
+ assignFlowDepth++;
3898
+ try {
3899
+ return body();
3900
+ } finally {
3901
+ assignFlowDepth--;
3902
+ }
3586
3903
  }
3587
3904
  function recordAbsAssign(name, prev, next, loc) {
3588
3905
  if (!absAssignCollector) return;
@@ -3592,7 +3909,8 @@ function recordAbsAssign(name, prev, next, loc) {
3592
3909
  prev,
3593
3910
  next,
3594
3911
  line: loc?.start.line,
3595
- column: loc?.start.column
3912
+ column: loc?.start.column,
3913
+ conditional: assignFlowDepth > 0
3596
3914
  });
3597
3915
  } catch {
3598
3916
  }
@@ -3602,6 +3920,16 @@ function evalSource(source, entry, opts = {}) {
3602
3920
  const file = opts.file ?? parseSource(source);
3603
3921
  const env = emptyEnv();
3604
3922
  let phi2 = opts.phi ?? pTrue;
3923
+ if (opts.seedVars) {
3924
+ for (const [k, v2] of Object.entries(opts.seedVars)) {
3925
+ env.vars.set(k, v2);
3926
+ }
3927
+ }
3928
+ if (opts.seedFns) {
3929
+ for (const [k, fn] of Object.entries(opts.seedFns)) {
3930
+ env.fns.set(k, fn);
3931
+ }
3932
+ }
3605
3933
  if (opts.modules) {
3606
3934
  for (const stmt of file.program.body) {
3607
3935
  if (stmt.type === "ImportDeclaration") {
@@ -3635,8 +3963,13 @@ function evalSource(source, entry, opts = {}) {
3635
3963
  }
3636
3964
  }
3637
3965
  }
3638
- const value = callFunction(env, entry.fn, entry.args, phi2, opts.budget);
3639
- return { value, phi: phi2, env };
3966
+ const full = callFunctionFull(env, entry.fn, entry.args, phi2, opts.budget);
3967
+ return {
3968
+ value: full.result,
3969
+ phi: phi2,
3970
+ env,
3971
+ ...full.throws.shape.k !== "never" ? { threw: true, ...full.throwLoc ? { throwLoc: full.throwLoc } : {} } : {}
3972
+ };
3640
3973
  }
3641
3974
  function registerClassDecl(env, node) {
3642
3975
  const cls = node;
@@ -3692,6 +4025,37 @@ function registerFunction(env, decl) {
3692
4025
  async: decl.async === true
3693
4026
  });
3694
4027
  }
4028
+ function callFunctionFull(env, name, args, phi2 = pTrue, budget = defaultLeakBudget) {
4029
+ const fn = env.fns.get(name);
4030
+ const neverAbs = abs({ k: "never" }, void 0, void 0, "exact");
4031
+ if (!fn) return { result: unknown, throws: neverAbs };
4032
+ const key = callBudgetKey("fn", name, args);
4033
+ if (!enterCall(key, name)) {
4034
+ return { result: truncatedAbs(), throws: neverAbs };
4035
+ }
4036
+ try {
4037
+ let local = { vars: new Map(env.vars), fns: env.fns, hofCollect: env.hofCollect };
4038
+ const cls = env.classes;
4039
+ if (cls) local.classes = cls;
4040
+ fn.params.forEach((p, i) => {
4041
+ local.vars.set(p, args[i] ?? unknown);
4042
+ });
4043
+ const result = evalNode(fn.body, local, phi2, budget);
4044
+ if (result.threw) {
4045
+ return {
4046
+ result: neverAbs,
4047
+ throws: result.value,
4048
+ ...result.throwLoc ? { throwLoc: result.throwLoc } : {}
4049
+ };
4050
+ }
4051
+ if (fn.async) {
4052
+ return { result: coerceAsyncReturn(result.value), throws: neverAbs };
4053
+ }
4054
+ return { result: result.value, throws: neverAbs };
4055
+ } finally {
4056
+ exitCall();
4057
+ }
4058
+ }
3695
4059
  function callFunction(env, name, args, phi2 = pTrue, budget = defaultLeakBudget) {
3696
4060
  const fn = env.fns.get(name);
3697
4061
  if (!fn) return unknown;
@@ -3858,7 +4222,18 @@ function evalNodeInner(node, env, phi2, budget) {
3858
4222
  case "ThrowStatement": {
3859
4223
  const arg = node.argument;
3860
4224
  const v2 = arg ? evalNode(arg, env, phi2, budget).value : unknown;
3861
- return { value: v2, phi: phi2, env, threw: true };
4225
+ const loc = node.loc ? { line: node.loc.start.line, column: node.loc.start.column } : void 0;
4226
+ return { value: v2, phi: phi2, env, threw: true, ...loc ? { throwLoc: loc } : {} };
4227
+ }
4228
+ case "ConditionalExpression": {
4229
+ const cond = node;
4230
+ const t = evalNode(cond.test, env, phi2, budget).value;
4231
+ const tv = litValue(t);
4232
+ if (tv === true) return evalNode(cond.consequent, env, phi2, budget);
4233
+ if (tv === false) return evalNode(cond.alternate, env, phi2, budget);
4234
+ const a = evalNode(cond.consequent, env, phi2, budget);
4235
+ const b = evalNode(cond.alternate, env, phi2, budget);
4236
+ return { value: joinAbs(a.value, b.value), phi: phi2, env };
3862
4237
  }
3863
4238
  case "ForStatement":
3864
4239
  return evalFor(node, env, phi2, budget);
@@ -3970,14 +4345,14 @@ function evalNodeInner(node, env, phi2, budget) {
3970
4345
  }
3971
4346
  if (!m.computed && m.property.type === "Identifier" && obj2.shape.k === "obj") {
3972
4347
  const key = m.property.name;
3973
- const slot = obj2.shape.slots[key];
4348
+ const slot = getSlot(obj2.shape.slots, key);
3974
4349
  if (slot) return ok2(slot.value, phi2, env);
3975
4350
  }
3976
4351
  if (m.computed) {
3977
4352
  const key = evalNode(m.property, env, phi2, budget).value;
3978
4353
  const kl = litValue(key);
3979
4354
  if (typeof kl === "string" && obj2.shape.k === "obj") {
3980
- const slot = obj2.shape.slots[kl];
4355
+ const slot = getSlot(obj2.shape.slots, kl);
3981
4356
  if (slot) return ok2(slot.value, phi2, env);
3982
4357
  }
3983
4358
  if (typeof kl === "number") {
@@ -4029,11 +4404,11 @@ function evalNodeInner(node, env, phi2, budget) {
4029
4404
  if (els.length === 0) {
4030
4405
  return ok2(abs({ k: "arr", element: unknown }, void 0, void 0, "exact"), phi2, env);
4031
4406
  }
4032
- if (els.length <= 8) {
4407
+ if (!shouldWidenArrayLiteral(els.length)) {
4033
4408
  return ok2(abs({ k: "tuple", elements: els }, void 0, void 0, "exact"), phi2, env);
4034
4409
  }
4035
4410
  const elem = els.reduce((x, y) => joinAbs(x, y));
4036
- return ok2(abs({ k: "arr", element: elem }, void 0, void 0, "path"), phi2, env);
4411
+ return ok2(abs({ k: "arr", element: elem }, void 0, void 0, widenedArrayConf()), phi2, env);
4037
4412
  }
4038
4413
  default:
4039
4414
  return ok2(unknown, phi2, env);
@@ -4309,18 +4684,27 @@ function evalCall(node, env, phi2, budget) {
4309
4684
  }
4310
4685
  if (obj2.shape.k === "tuple") {
4311
4686
  const kept = [];
4312
- for (const el of obj2.shape.elements) {
4313
- const p = applyUnaryCallback(fnNode, el, env, phi2, budget);
4687
+ let anyUncertain = false;
4688
+ for (const el2 of obj2.shape.elements) {
4689
+ const p = applyUnaryCallback(fnNode, el2, env, phi2, budget);
4314
4690
  const lv = litValue(p);
4315
4691
  if (lv === false) continue;
4316
- kept.push(el);
4692
+ if (lv !== true) anyUncertain = true;
4693
+ kept.push(el2);
4317
4694
  }
4318
4695
  if (kept.length === 0) {
4319
4696
  return ok2(abs({ k: "arr", element: unknown }, void 0, void 0, "path"), phi2, env);
4320
4697
  }
4321
- if (kept.length === 1) return ok2(kept[0], phi2, env);
4698
+ if (!anyUncertain) {
4699
+ return ok2(
4700
+ abs({ k: "tuple", elements: kept }, void 0, void 0, confJoin(obj2.conf, "path")),
4701
+ phi2,
4702
+ env
4703
+ );
4704
+ }
4705
+ const el = kept.reduce((a, b) => joinAbs(a, b));
4322
4706
  return ok2(
4323
- abs({ k: "tuple", elements: kept }, void 0, void 0, confJoin(obj2.conf, "path")),
4707
+ abs({ k: "arr", element: el }, void 0, void 0, confJoin(obj2.conf, "path")),
4324
4708
  phi2,
4325
4709
  env
4326
4710
  );
@@ -4531,7 +4915,16 @@ function evalBlock(node, env, phi2, budget) {
4531
4915
  pendingPartial = void 0;
4532
4916
  }
4533
4917
  if (r.returned || r.brk || r.cont || r.threw) {
4534
- return { value: last, phi: curPhi, env: local, returned: r.returned, brk: r.brk, cont: r.cont, threw: r.threw };
4918
+ return {
4919
+ value: last,
4920
+ phi: curPhi,
4921
+ env: local,
4922
+ returned: r.returned,
4923
+ brk: r.brk,
4924
+ cont: r.cont,
4925
+ threw: r.threw,
4926
+ ...r.throwLoc ? { throwLoc: r.throwLoc } : {}
4927
+ };
4535
4928
  }
4536
4929
  }
4537
4930
  if (pendingPartial !== void 0) {
@@ -4553,7 +4946,7 @@ function evalFor(node, env, phi2, budget) {
4553
4946
  const lv = litValue(t.value);
4554
4947
  if (lv === false || lv === null || lv === void 0) break;
4555
4948
  }
4556
- const bodyR = evalNode(node.body, local, phi2, budget);
4949
+ const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4557
4950
  if (bodyR.returned) return bodyR;
4558
4951
  if (bodyR.threw) return bodyR;
4559
4952
  if (bodyR.brk) {
@@ -4576,7 +4969,7 @@ function evalWhile(node, env, phi2, budget) {
4576
4969
  const t = evalNode(node.test, local, phi2, budget);
4577
4970
  const lv = litValue(t.value);
4578
4971
  if (lv === false || lv === null || lv === void 0) break;
4579
- const bodyR = evalNode(node.body, local, phi2, budget);
4972
+ const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4580
4973
  if (bodyR.returned || bodyR.threw) return bodyR;
4581
4974
  if (bodyR.brk) {
4582
4975
  local = bodyR.env;
@@ -4591,7 +4984,7 @@ function evalDoWhile(node, env, phi2, budget) {
4591
4984
  let local = env;
4592
4985
  let acc = unknown;
4593
4986
  for (let i = 0; i < MAX_LOOP_ITERS; i++) {
4594
- const bodyR = evalNode(node.body, local, phi2, budget);
4987
+ const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4595
4988
  if (bodyR.returned || bodyR.threw) return bodyR;
4596
4989
  if (bodyR.brk) {
4597
4990
  local = bodyR.env;
@@ -4628,7 +5021,7 @@ function evalForOf(node, env, phi2, budget) {
4628
5021
  const n = Math.min(elements.length, MAX_LOOP_ITERS);
4629
5022
  for (let i = 0; i < n; i++) {
4630
5023
  local = withVar(local, bindName, elements[i]);
4631
- const bodyR = evalNode(node.body, local, phi2, budget);
5024
+ const bodyR = evalInConditionalFlow(() => evalNode(node.body, local, phi2, budget));
4632
5025
  if (bodyR.returned || bodyR.threw) return bodyR;
4633
5026
  if (bodyR.brk) {
4634
5027
  local = bodyR.env;
@@ -4687,8 +5080,15 @@ function evalVarDecl(node, env, phi2, budget) {
4687
5080
  function evalIf(node, env, phi2, budget) {
4688
5081
  const t = evalNode(node.test, env, phi2, budget).value;
4689
5082
  const tv = litValue(t);
5083
+ const refineEnv = (branch) => {
5084
+ const m = matchRelIdentLit(node.test);
5085
+ if (!m || branch !== "true") return env;
5086
+ const cur = env.vars.get(m.name);
5087
+ if (!cur) return env;
5088
+ return withVar(env, m.name, refineAbsForRelTrue(cur, m.op, m.k));
5089
+ };
4690
5090
  if (tv === true) {
4691
- return evalNode(node.consequent, env, phi2, budget);
5091
+ return evalNode(node.consequent, refineEnv("true"), phi2, budget);
4692
5092
  }
4693
5093
  if (tv === false) {
4694
5094
  if (node.alternate) return evalNode(node.alternate, env, phi2, budget);
@@ -4696,9 +5096,15 @@ function evalIf(node, env, phi2, budget) {
4696
5096
  }
4697
5097
  const tCons = trueConstraint(t);
4698
5098
  const fCons = falseConstraint(t);
4699
- const a = evalNode(node.consequent, env, tCons ? and(phi2, tCons) : phi2, budget);
4700
- if (node.alternate) {
4701
- const b = evalNode(node.alternate, env, fCons ? and(phi2, fCons) : phi2, budget);
5099
+ const envT = refineEnv("true");
5100
+ const a = evalInConditionalFlow(
5101
+ () => evalNode(node.consequent, envT, tCons ? and(phi2, tCons) : phi2, budget)
5102
+ );
5103
+ const alt = node.alternate;
5104
+ if (alt) {
5105
+ const b = evalInConditionalFlow(
5106
+ () => evalNode(alt, env, fCons ? and(phi2, fCons) : phi2, budget)
5107
+ );
4702
5108
  return { value: joinAbs(a.value, b.value), phi: phi2, env, returned: a.returned || b.returned };
4703
5109
  }
4704
5110
  if (a.returned || a.threw) {
@@ -4709,6 +5115,20 @@ function evalIf(node, env, phi2, budget) {
4709
5115
  function analyzeFn(source, fnName, args, phi2 = pTrue, budget, file, modules) {
4710
5116
  return evalSource(source, { fn: fnName, args }, { phi: phi2, budget, file, modules }).value;
4711
5117
  }
5118
+ function analyzeFnFull(source, fnName, args, opts = {}) {
5119
+ const r = evalSource(source, { fn: fnName, args }, opts);
5120
+ if (r.threw) {
5121
+ return {
5122
+ result: abs({ k: "never" }, void 0, void 0, "exact"),
5123
+ throws: r.value,
5124
+ ...r.throwLoc ? { throwLoc: r.throwLoc } : {}
5125
+ };
5126
+ }
5127
+ return {
5128
+ result: r.value,
5129
+ throws: abs({ k: "never" }, void 0, void 0, "exact")
5130
+ };
5131
+ }
4712
5132
  function evalProgramAbs(source, opts = {}) {
4713
5133
  resetAbsCallBudget();
4714
5134
  const file = opts.file ?? parseSource(source);
@@ -4842,8 +5262,8 @@ var GLOBAL_FNS = /* @__PURE__ */ new Set([
4842
5262
  "String",
4843
5263
  "Boolean"
4844
5264
  ]);
4845
- function setBCallCollector(collector) {
4846
- bCallCollector = collector;
5265
+ function setBCallCollector(collector2) {
5266
+ bCallCollector = collector2;
4847
5267
  }
4848
5268
  function getBCallCollector() {
4849
5269
  return bCallCollector;
@@ -5062,8 +5482,19 @@ function $for(init, test, step, body, maxIters = DEFAULT_MAX_LOOP_ITERS) {
5062
5482
  }
5063
5483
  return exitJoin ? joinAbs(exitJoin, state) : state;
5064
5484
  }
5485
+ function tupleOrWiden(els, conf) {
5486
+ if (shouldWidenArrayLiteral(els.length)) {
5487
+ return abs(
5488
+ { k: "arr", element: els.reduce((x, y) => joinAbs(x, y)) },
5489
+ void 0,
5490
+ void 0,
5491
+ widenedArrayConf()
5492
+ );
5493
+ }
5494
+ return abs({ k: "tuple", elements: els }, void 0, void 0, conf);
5495
+ }
5065
5496
  function $arr(items) {
5066
- return abs({ k: "tuple", elements: items.map(asAbsVal) }, void 0, void 0, "exact");
5497
+ return tupleOrWiden(items.map(asAbsVal), "exact");
5067
5498
  }
5068
5499
  function $idx(a, i) {
5069
5500
  const iv = litValue(i);
@@ -5142,33 +5573,33 @@ function $spread(a, b) {
5142
5573
  function $concat(a, b) {
5143
5574
  a = asAbsVal(a);
5144
5575
  b = asAbsVal(b);
5145
- if (a.shape.k === "tuple" && b.shape.k === "tuple") {
5146
- return abs(
5147
- { k: "tuple", elements: [...a.shape.elements, ...b.shape.elements] },
5148
- void 0,
5149
- void 0,
5150
- confJoin(a.conf, b.conf)
5151
- );
5576
+ const as = a.shape;
5577
+ const bs = b.shape;
5578
+ if (as.k === "tuple" && bs.k === "tuple") {
5579
+ return tupleOrWiden([...as.elements, ...bs.elements], confJoin(a.conf, b.conf));
5580
+ }
5581
+ if (as.k === "arr" || bs.k === "arr") {
5582
+ const ea = as.k === "tuple" ? as.elements.reduce((x, y) => joinAbs(x, y)) : as.k === "arr" ? as.element : a;
5583
+ const eb = bs.k === "tuple" ? bs.elements.reduce((x, y) => joinAbs(x, y)) : bs.k === "arr" ? bs.element : b;
5584
+ return abs({ k: "arr", element: joinAbs(ea, eb) }, void 0, void 0, "path");
5152
5585
  }
5153
- if (a.shape.k === "tuple" && b.shape.k !== "tuple") {
5586
+ if (as.k === "tuple") {
5154
5587
  return abs(
5155
- { k: "tuple", elements: [...a.shape.elements, b] },
5588
+ { k: "tuple", elements: [...as.elements, b] },
5156
5589
  void 0,
5157
5590
  void 0,
5158
5591
  confJoin(a.conf, b.conf)
5159
5592
  );
5160
5593
  }
5161
- if (a.shape.k !== "tuple" && b.shape.k === "tuple") {
5594
+ if (bs.k === "tuple") {
5162
5595
  return abs(
5163
- { k: "tuple", elements: [a, ...b.shape.elements] },
5596
+ { k: "tuple", elements: [a, ...bs.elements] },
5164
5597
  void 0,
5165
5598
  void 0,
5166
5599
  confJoin(a.conf, b.conf)
5167
5600
  );
5168
5601
  }
5169
- const ea = a.shape.k === "arr" ? a.shape.element : a;
5170
- const eb = b.shape.k === "arr" ? b.shape.element : b;
5171
- return abs({ k: "arr", element: joinAbs(ea, eb) }, void 0, void 0, "path");
5602
+ return abs({ k: "arr", element: joinAbs(a, b) }, void 0, void 0, "path");
5172
5603
  }
5173
5604
  function $elems(a) {
5174
5605
  if (a.shape.k === "tuple") return [...a.shape.elements];
@@ -6585,6 +7016,10 @@ function invokeArrMethod(arr, method, args) {
6585
7016
  return acc;
6586
7017
  }
6587
7018
  if (method === "filter" && args[0]) {
7019
+ if (shape.k === "tuple") {
7020
+ const el = shape.elements.length > 0 ? shape.elements.reduce((a, b) => joinAbs(a, b)) : unknown;
7021
+ return abs({ k: "arr", element: el }, void 0, void 0, confJoin(arr.conf, "path"));
7022
+ }
6588
7023
  return arr;
6589
7024
  }
6590
7025
  if (method === "flatMap" && args[0]) {
@@ -6961,10 +7396,6 @@ function callTranspiledExport(exports, name, args) {
6961
7396
  }
6962
7397
 
6963
7398
  export {
6964
- stripTypes,
6965
- resetParseSourceCache,
6966
- getParseSourceCacheSize,
6967
- parseSource,
6968
7399
  lit,
6969
7400
  v,
6970
7401
  app,
@@ -7014,19 +7445,37 @@ export {
7014
7445
  isStrPrim,
7015
7446
  isExactLit,
7016
7447
  litValue,
7448
+ stripTypes,
7449
+ resetParseSourceCache,
7450
+ getParseSourceCacheSize,
7451
+ parseSource,
7017
7452
  attachFnImpl,
7018
7453
  getFnImpl,
7019
7454
  absFunction,
7020
7455
  relationFingerprint,
7021
7456
  relationFn,
7022
7457
  shapeOnlyFn,
7458
+ setDerivationCollector,
7459
+ hasDerivationSession,
7460
+ beginDerivationSession,
7461
+ endDerivationSession,
7462
+ abortDerivationSession,
7463
+ tagDerivationRoot,
7464
+ getDerivation,
7465
+ setDerivation,
7466
+ derivationChain,
7467
+ noteDerivationAdd,
7468
+ noteDerivationJoin,
7469
+ projectDerivationDsl,
7470
+ termKey3 as termKey,
7023
7471
  objOf,
7024
7472
  isObj,
7473
+ getSlot,
7025
7474
  spread,
7026
7475
  joinObjects,
7027
7476
  joinValues,
7028
7477
  makeSum,
7029
- collapseToOptional,
7478
+ absShapeKey,
7030
7479
  fnOf,
7031
7480
  joinFunctions,
7032
7481
  joinAbs,
@@ -7049,18 +7498,31 @@ export {
7049
7498
  mapElementFallback,
7050
7499
  projectFlatMapResult,
7051
7500
  asAbs,
7501
+ viewTemplateParts,
7502
+ knownPrefixOfViews,
7503
+ knownSuffixOfViews,
7504
+ allFixedTextOfViews,
7505
+ fixedLengthOfViews,
7506
+ formatTemplateNameViews,
7507
+ mergeAdjacentFixedViews,
7508
+ templateMatchesValue,
7509
+ decideStartsWith,
7510
+ decideEndsWith,
7511
+ decideIncludes,
7512
+ absTemplateViews,
7052
7513
  templatePartsOf,
7053
7514
  createTemplateAbs,
7054
7515
  isTemplateLike,
7055
7516
  concatString,
7056
7517
  add,
7057
- numericBounds,
7058
7518
  sub,
7059
7519
  mul,
7060
7520
  div,
7061
7521
  mod,
7062
7522
  cmp,
7063
7523
  trueConstraint,
7524
+ refineAbsForRelTrue,
7525
+ matchRelIdentLit,
7064
7526
  falseConstraint,
7065
7527
  typeofAbs,
7066
7528
  negAbs,
@@ -7130,11 +7592,13 @@ export {
7130
7592
  setAbsNodeCollector,
7131
7593
  setAbsAssignCollector,
7132
7594
  evalSource,
7595
+ callFunctionFull,
7133
7596
  callFunction,
7134
7597
  evalMethodBody,
7135
7598
  evalNode,
7136
7599
  applyAbsFn,
7137
7600
  analyzeFn,
7601
+ analyzeFnFull,
7138
7602
  evalProgramAbs,
7139
7603
  collectAbsNodeTypes,
7140
7604
  findAbsAtPosition,