@nudojs/core 1.7.9 → 1.8.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.
- package/dist/{chunk-YQIRU637.js → chunk-P6O5BXOA.js} +1389 -426
- package/dist/{chunk-5SAMWKI6.js → chunk-WT5J6QTZ.js} +80 -716
- package/dist/exec.d.ts +11 -1
- package/dist/exec.js +3 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +180 -64
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +2 -2
- package/dist/{projection-budget-CtwnzYLG.d.ts → projection-budget-vi5Ssjdr.d.ts} +37 -8
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
$invoke,
|
|
3
3
|
$new,
|
|
4
|
+
CONSTRAINT_BUILDERS,
|
|
4
5
|
abs,
|
|
5
|
-
|
|
6
|
+
andC,
|
|
6
7
|
anyAbs,
|
|
7
|
-
app,
|
|
8
8
|
callTranspiledExportFull,
|
|
9
|
+
constraintToEntryAbs,
|
|
9
10
|
createScopedSlot,
|
|
10
11
|
defaultLeakBudget,
|
|
12
|
+
derefConstraint,
|
|
11
13
|
emptyEnv,
|
|
12
|
-
eq,
|
|
13
14
|
evalExprAbs,
|
|
15
|
+
fnConstraintToEntryReqs,
|
|
14
16
|
foldRequireSpecArg,
|
|
15
17
|
formalParamDisplayNames,
|
|
16
18
|
formalParamsFromNodes,
|
|
@@ -18,37 +20,32 @@ import {
|
|
|
18
20
|
formatShape,
|
|
19
21
|
formatShapeSlot,
|
|
20
22
|
freeIdentifiers,
|
|
21
|
-
ge,
|
|
22
23
|
getFnImpl,
|
|
23
24
|
getSlot,
|
|
24
|
-
gt,
|
|
25
25
|
identBoundaryRegex,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
instantiateConstraint,
|
|
27
|
+
isIntFlag,
|
|
28
|
+
isNudoConstraint,
|
|
29
29
|
litKeyString,
|
|
30
30
|
litValue,
|
|
31
|
+
literalMeetsConstraint,
|
|
31
32
|
locateContractParam,
|
|
32
|
-
lt,
|
|
33
33
|
numLit,
|
|
34
|
-
or,
|
|
35
34
|
pTrue,
|
|
36
35
|
parseSource,
|
|
37
36
|
predToString,
|
|
38
|
-
primToTypeof,
|
|
39
|
-
ptypeof,
|
|
40
37
|
registerCollectorScopeParticipant,
|
|
41
38
|
runTranspiledOptionsMemoKey,
|
|
42
39
|
snapshotAbs,
|
|
43
40
|
stripStringsKeepComments,
|
|
44
41
|
termToString,
|
|
42
|
+
throwConstraintToKinds,
|
|
45
43
|
tryRunTranspiled,
|
|
46
|
-
unknown,
|
|
47
44
|
v,
|
|
48
45
|
withEvalBudgetOverride,
|
|
49
46
|
withExecPhi,
|
|
50
47
|
withFnBudgetOverride
|
|
51
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-P6O5BXOA.js";
|
|
52
49
|
|
|
53
50
|
// src/algebra/directive-scan.ts
|
|
54
51
|
function cleanDirectiveLine(raw, kind) {
|
|
@@ -153,16 +150,16 @@ function listFnDirectiveScopes(file) {
|
|
|
153
150
|
const decl = d;
|
|
154
151
|
const idName = decl.id?.type === "Identifier" ? decl.id.name : void 0;
|
|
155
152
|
if (isFnExpr(decl.init)) {
|
|
156
|
-
const
|
|
153
|
+
const fn = decl.init;
|
|
157
154
|
const scope = buildScope(
|
|
158
155
|
idName ?? "<anonymous>",
|
|
159
|
-
|
|
156
|
+
fn,
|
|
160
157
|
ctx.wrapperNode,
|
|
161
158
|
node.leadingComments,
|
|
162
159
|
ctx.wrapperNode?.leadingComments
|
|
163
160
|
);
|
|
164
161
|
out.push(scope);
|
|
165
|
-
visit2(
|
|
162
|
+
visit2(fn, { owner: idName });
|
|
166
163
|
} else {
|
|
167
164
|
visit2(decl.init, { owner: idName, commentHost: node, wrapperNode: ctx.wrapperNode });
|
|
168
165
|
}
|
|
@@ -360,17 +357,17 @@ function listFnDirectiveScopes(file) {
|
|
|
360
357
|
const vd = raw;
|
|
361
358
|
const idName = vd.id?.type === "Identifier" ? vd.id.name : void 0;
|
|
362
359
|
if (isFnExpr(vd.init)) {
|
|
363
|
-
const
|
|
360
|
+
const fn = vd.init;
|
|
364
361
|
out.push(
|
|
365
362
|
buildScope(
|
|
366
363
|
idName ?? "default",
|
|
367
|
-
|
|
364
|
+
fn,
|
|
368
365
|
wrapper,
|
|
369
366
|
d.leadingComments,
|
|
370
367
|
wrapper.leadingComments
|
|
371
368
|
)
|
|
372
369
|
);
|
|
373
|
-
visit2(
|
|
370
|
+
visit2(fn, { owner: idName });
|
|
374
371
|
} else {
|
|
375
372
|
visit2(vd.init, {
|
|
376
373
|
owner: idName,
|
|
@@ -419,10 +416,10 @@ function parseEnvPayload(payload) {
|
|
|
419
416
|
return payload.split(",").map((e) => e.trim().replace(/^['"]|['"]$/g, "")).filter((e) => e && (/^\w+$/.test(e) || isPathLikeEnv(e)));
|
|
420
417
|
}
|
|
421
418
|
function parseMockModulePayload(payload) {
|
|
422
|
-
const
|
|
423
|
-
if (
|
|
424
|
-
const names =
|
|
425
|
-
return { source:
|
|
419
|
+
const partial = payload.match(/^\s*"([^"]+)"\s*\{([^}]+)\}\s*from\s*"([^"]+)"\s*$/);
|
|
420
|
+
if (partial) {
|
|
421
|
+
const names = partial[2].split(",").map((n) => n.trim()).filter(Boolean);
|
|
422
|
+
return { source: partial[1], names, fromPath: partial[3] };
|
|
426
423
|
}
|
|
427
424
|
const full = payload.match(/^\s*"([^"]+)"\s+from\s*"([^"]+)"\s*$/);
|
|
428
425
|
if (full) {
|
|
@@ -617,15 +614,15 @@ function scanContractSegments(lines) {
|
|
|
617
614
|
}
|
|
618
615
|
function scanThrowsDecl(lines) {
|
|
619
616
|
const kinds = /* @__PURE__ */ new Set();
|
|
620
|
-
let
|
|
617
|
+
let any = false;
|
|
621
618
|
for (const line of lines) {
|
|
622
619
|
const th = line.match(/^@nudo:throws\s+(.+)$/i);
|
|
623
620
|
if (th) {
|
|
624
621
|
const spec = th[1].trim();
|
|
625
|
-
if (spec === "*")
|
|
622
|
+
if (spec === "*") any = true;
|
|
626
623
|
else {
|
|
627
624
|
for (const k of spec.split(/[,\s|]+/).map((s) => s.trim()).filter(Boolean)) {
|
|
628
|
-
if (k === "*")
|
|
625
|
+
if (k === "*") any = true;
|
|
629
626
|
else kinds.add(k);
|
|
630
627
|
}
|
|
631
628
|
}
|
|
@@ -633,16 +630,16 @@ function scanThrowsDecl(lines) {
|
|
|
633
630
|
const cs = line.match(/!!\s*throws(?:\s+([A-Za-z*][\w*|,\s]*))?/i);
|
|
634
631
|
if (cs) {
|
|
635
632
|
const spec = (cs[1] ?? "*").trim();
|
|
636
|
-
if (spec === "" || spec === "*")
|
|
633
|
+
if (spec === "" || spec === "*") any = true;
|
|
637
634
|
else {
|
|
638
635
|
for (const k of spec.split(/[,\s|]+/).map((s) => s.trim()).filter(Boolean)) {
|
|
639
|
-
if (k === "*")
|
|
636
|
+
if (k === "*") any = true;
|
|
640
637
|
else kinds.add(k);
|
|
641
638
|
}
|
|
642
639
|
}
|
|
643
640
|
}
|
|
644
641
|
}
|
|
645
|
-
if (
|
|
642
|
+
if (any) return "*";
|
|
646
643
|
if (kinds.size > 0) return [...kinds].join(",");
|
|
647
644
|
return void 0;
|
|
648
645
|
}
|
|
@@ -753,8 +750,8 @@ function createDiagChannel(cap) {
|
|
|
753
750
|
let seq = 0;
|
|
754
751
|
const buf = [];
|
|
755
752
|
return {
|
|
756
|
-
setCollector(
|
|
757
|
-
collector =
|
|
753
|
+
setCollector(fn) {
|
|
754
|
+
collector = fn;
|
|
758
755
|
},
|
|
759
756
|
getCollector() {
|
|
760
757
|
return collector;
|
|
@@ -789,7 +786,7 @@ function createScopedDiagChannel(cap) {
|
|
|
789
786
|
const fallback = createDiagChannel(cap);
|
|
790
787
|
const chan = () => als.getStore() ?? fallback;
|
|
791
788
|
return {
|
|
792
|
-
setCollector: (
|
|
789
|
+
setCollector: (fn) => chan().setCollector(fn),
|
|
793
790
|
getCollector: () => chan().getCollector(),
|
|
794
791
|
count: () => chan().count(),
|
|
795
792
|
take: () => chan().take(),
|
|
@@ -803,529 +800,6 @@ function createScopedDiagChannel(cap) {
|
|
|
803
800
|
};
|
|
804
801
|
}
|
|
805
802
|
|
|
806
|
-
// src/algebra/constraint.ts
|
|
807
|
-
var SELF = "__nudo_self__";
|
|
808
|
-
function selfTerm() {
|
|
809
|
-
return v(SELF);
|
|
810
|
-
}
|
|
811
|
-
function getTerm(obj, key) {
|
|
812
|
-
return app("get", [obj, lit(key)]);
|
|
813
|
-
}
|
|
814
|
-
function lenTerm(t) {
|
|
815
|
-
return app("length", [t]);
|
|
816
|
-
}
|
|
817
|
-
function isConstraint(x) {
|
|
818
|
-
return !!x && typeof x === "object" && x.__nudoConstraint === true;
|
|
819
|
-
}
|
|
820
|
-
function isNudoConstraint(x) {
|
|
821
|
-
return isConstraint(x);
|
|
822
|
-
}
|
|
823
|
-
var intFlaggedBuilders = /* @__PURE__ */ new WeakSet();
|
|
824
|
-
function isIntFlag(c) {
|
|
825
|
-
return c.int === true || intFlaggedBuilders.has(c);
|
|
826
|
-
}
|
|
827
|
-
function makeBuilder(prim, preds, extra) {
|
|
828
|
-
const fields = extra?.fields;
|
|
829
|
-
const element = extra?.element;
|
|
830
|
-
const isInt = extra?.int;
|
|
831
|
-
const optional = extra?.optional;
|
|
832
|
-
const members = extra?.members;
|
|
833
|
-
const fnSlot = extra?.fn;
|
|
834
|
-
const base = {
|
|
835
|
-
__nudoConstraint: true,
|
|
836
|
-
...prim ? { prim } : {},
|
|
837
|
-
preds: [...preds],
|
|
838
|
-
...fields ? { fields } : {},
|
|
839
|
-
...element ? { element } : {},
|
|
840
|
-
...optional ? { isOptional: true } : {},
|
|
841
|
-
...members ? { members } : {},
|
|
842
|
-
...fnSlot ? { fn: fnSlot } : {}
|
|
843
|
-
};
|
|
844
|
-
const add = (p) => makeBuilder(prim, [...preds, p], extra);
|
|
845
|
-
const builder = Object.assign(
|
|
846
|
-
/* @__PURE__ */ Object.create(null),
|
|
847
|
-
base,
|
|
848
|
-
{
|
|
849
|
-
gt: (n) => add(gt(selfTerm(), lit(n))),
|
|
850
|
-
ge: (n) => add(ge(selfTerm(), lit(n))),
|
|
851
|
-
lt: (n) => add(lt(selfTerm(), lit(n))),
|
|
852
|
-
le: (n) => add(le(selfTerm(), lit(n))),
|
|
853
|
-
int: () => makeBuilder(prim ?? "number", preds, { ...extra, int: true }),
|
|
854
|
-
min: (n) => add(ge(lenTerm(selfTerm()), lit(n))),
|
|
855
|
-
max: (n) => add(le(lenTerm(selfTerm()), lit(n))),
|
|
856
|
-
length: (n) => add(and(ge(lenTerm(selfTerm()), lit(n)), le(lenTerm(selfTerm()), lit(n)))),
|
|
857
|
-
shift: (n) => {
|
|
858
|
-
if (!Number.isFinite(n))
|
|
859
|
-
throw new Error("nudo shift(): offset must be a finite number");
|
|
860
|
-
if (fields || element || members || fnSlot)
|
|
861
|
-
throw new Error("nudo shift(): only numeric scalar constraint chains are allowed (shape/array/union/fn are not supported)");
|
|
862
|
-
if (prim !== void 0 && prim !== "number")
|
|
863
|
-
throw new Error(`nudo shift(): only numeric chains are allowed (prim=${prim})`);
|
|
864
|
-
return makeBuilder(prim, shiftBoundPreds(preds, n), extra);
|
|
865
|
-
},
|
|
866
|
-
optional: () => makeBuilder(prim, preds, { ...extra, optional: true })
|
|
867
|
-
}
|
|
868
|
-
);
|
|
869
|
-
if (isInt) intFlaggedBuilders.add(builder);
|
|
870
|
-
return builder;
|
|
871
|
-
}
|
|
872
|
-
function shiftBoundPreds(preds, n) {
|
|
873
|
-
return preds.map((p) => {
|
|
874
|
-
if (p.op !== "gt" && p.op !== "ge" && p.op !== "lt" && p.op !== "le")
|
|
875
|
-
throw new Error(`nudo shift(): predicate ${p.op} is not supported (only gt/ge/lt/le constant bounds)`);
|
|
876
|
-
const { a, b } = p;
|
|
877
|
-
if (b.op !== "lit" || typeof b.value !== "number")
|
|
878
|
-
throw new Error("nudo shift(): the right-hand side of a constant bound must be a numeric literal");
|
|
879
|
-
if (termHasApp(a, "length") || termHasApp(b, "length"))
|
|
880
|
-
throw new Error("nudo shift(): length(...) bounds are not supported");
|
|
881
|
-
return { op: p.op, a, b: lit(b.value + n) };
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
function termHasApp(t, fn2) {
|
|
885
|
-
if (t.op !== "app") return false;
|
|
886
|
-
if (t.fn === fn2) return true;
|
|
887
|
-
return t.args.some((x) => termHasApp(x, fn2));
|
|
888
|
-
}
|
|
889
|
-
function number() {
|
|
890
|
-
return makeBuilder("number", []);
|
|
891
|
-
}
|
|
892
|
-
function string() {
|
|
893
|
-
return makeBuilder("string", []);
|
|
894
|
-
}
|
|
895
|
-
function boolean() {
|
|
896
|
-
return makeBuilder("boolean", []);
|
|
897
|
-
}
|
|
898
|
-
function any() {
|
|
899
|
-
return makeBuilder(void 0, []);
|
|
900
|
-
}
|
|
901
|
-
function array(item) {
|
|
902
|
-
return makeBuilder(void 0, [], {
|
|
903
|
-
element: asNestedConstraint(item, "array(item)")
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
function shape(fields) {
|
|
907
|
-
const mapped = {};
|
|
908
|
-
for (const [k, v2] of Object.entries(fields)) {
|
|
909
|
-
const constraint = asNestedConstraint(v2, `shape \u5B57\u6BB5 '${k}'`);
|
|
910
|
-
mapped[k] = {
|
|
911
|
-
constraint,
|
|
912
|
-
...constraint.isOptional ? { optional: true } : {}
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
return makeBuilder(void 0, [], { fields: mapped });
|
|
916
|
-
}
|
|
917
|
-
function toPlainConstraint(c) {
|
|
918
|
-
if (!isConstraint(c))
|
|
919
|
-
throw new Error("nudo: expected a constraint value (number()/string()/\u2026 or a combinator)");
|
|
920
|
-
return {
|
|
921
|
-
__nudoConstraint: true,
|
|
922
|
-
...c.prim ? { prim: c.prim } : {},
|
|
923
|
-
preds: [...c.preds],
|
|
924
|
-
...c.fields ? { fields: c.fields } : {},
|
|
925
|
-
...c.element ? { element: c.element } : {},
|
|
926
|
-
// isIntFlag 统一读取:builder(int 是方法)查 WeakSet,纯数据看 === true
|
|
927
|
-
...isIntFlag(c) ? { int: true } : {},
|
|
928
|
-
...c.isOptional ? { isOptional: true } : {},
|
|
929
|
-
...c.members ? { members: c.members } : {},
|
|
930
|
-
...c.fn ? { fn: c.fn } : {}
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
function litC(v2) {
|
|
934
|
-
const prim = typeof v2 === "number" ? "number" : typeof v2 === "string" ? "string" : typeof v2 === "boolean" ? "boolean" : void 0;
|
|
935
|
-
return makeBuilder(prim, [eq(selfTerm(), lit(v2))]);
|
|
936
|
-
}
|
|
937
|
-
function asNestedConstraint(x, ctx) {
|
|
938
|
-
if (isConstraint(x)) return toPlainConstraint(x);
|
|
939
|
-
if (x === null || x === void 0 || typeof x === "number" || typeof x === "string" || typeof x === "boolean") {
|
|
940
|
-
return toPlainConstraint(litC(x));
|
|
941
|
-
}
|
|
942
|
-
throw new Error(
|
|
943
|
-
`nudo: ${ctx} expects a constraint value (number()/string()/\u2026) or a concrete literal; received a non-constraint`
|
|
944
|
-
);
|
|
945
|
-
}
|
|
946
|
-
function union(...cs) {
|
|
947
|
-
if (cs.length === 0)
|
|
948
|
-
throw new Error("nudo union(): at least one member constraint is required");
|
|
949
|
-
return makeBuilder(void 0, [], {
|
|
950
|
-
members: cs.map((c) => asNestedConstraint(c, "union member"))
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
function nullable(c) {
|
|
954
|
-
return makeBuilder(void 0, [], {
|
|
955
|
-
members: [
|
|
956
|
-
asNestedConstraint(c, "nullable()"),
|
|
957
|
-
toPlainConstraint(litC(null)),
|
|
958
|
-
toPlainConstraint(litC(void 0))
|
|
959
|
-
]
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
function constraintAdmitsNullish(c) {
|
|
963
|
-
if (c.members) return c.members.some((m) => constraintAdmitsNullish(m));
|
|
964
|
-
if (!c.prim && c.preds.length === 0 && !c.fields && !c.element && !c.fn) return true;
|
|
965
|
-
for (const p of c.preds) {
|
|
966
|
-
for (const flat of p.op === "and" ? p.args : [p]) {
|
|
967
|
-
if (flat.op !== "eq") continue;
|
|
968
|
-
for (const side of [flat.a, flat.b]) {
|
|
969
|
-
if (side.op === "lit" && (side.value === null || side.value === void 0)) return true;
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return false;
|
|
974
|
-
}
|
|
975
|
-
function fn(params, returns, opts) {
|
|
976
|
-
const normalized = {};
|
|
977
|
-
for (const [k, v2] of Object.entries(params)) {
|
|
978
|
-
normalized[k] = asNestedConstraint(v2, `fn param '${k}'`);
|
|
979
|
-
}
|
|
980
|
-
return makeBuilder(void 0, [], {
|
|
981
|
-
fn: {
|
|
982
|
-
params: normalized,
|
|
983
|
-
...returns !== void 0 ? { returns: asNestedConstraint(returns, "fn return value") } : {},
|
|
984
|
-
...opts?.throws !== void 0 ? { throws: asNestedConstraint(opts.throws, "fn throws") } : {}
|
|
985
|
-
}
|
|
986
|
-
});
|
|
987
|
-
}
|
|
988
|
-
function andC(...cs) {
|
|
989
|
-
if (cs.length === 0)
|
|
990
|
-
throw new Error("nudo and(): at least one constraint is required");
|
|
991
|
-
let prim;
|
|
992
|
-
let isInt = false;
|
|
993
|
-
let allOptional = true;
|
|
994
|
-
const preds = [];
|
|
995
|
-
for (const c of cs) {
|
|
996
|
-
if (!isConstraint(c))
|
|
997
|
-
throw new Error("nudo: expected a constraint value (number()/string()/\u2026 or a combinator)");
|
|
998
|
-
if (c.fields || c.element || c.members || c.fn)
|
|
999
|
-
throw new Error("nudo and(): Phase 1 supports scalar constraint conjunction only (shape/array/union/fn are not supported)");
|
|
1000
|
-
if (c.prim) {
|
|
1001
|
-
if (prim !== void 0 && prim !== c.prim)
|
|
1002
|
-
throw new Error(`nudo and(): inconsistent prim (${prim} vs ${c.prim})`);
|
|
1003
|
-
prim = c.prim;
|
|
1004
|
-
}
|
|
1005
|
-
preds.push(...c.preds);
|
|
1006
|
-
if (isIntFlag(c)) isInt = true;
|
|
1007
|
-
if (!c.isOptional) allOptional = false;
|
|
1008
|
-
}
|
|
1009
|
-
return makeBuilder(prim, preds, {
|
|
1010
|
-
...isInt ? { int: true } : {},
|
|
1011
|
-
...allOptional ? { optional: true } : {}
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
function partial(c) {
|
|
1015
|
-
if (!isConstraint(c) || !c.fields)
|
|
1016
|
-
throw new Error("nudo partial(): only shape(...) constraints are accepted");
|
|
1017
|
-
const fields = {};
|
|
1018
|
-
for (const [k, f] of Object.entries(c.fields)) {
|
|
1019
|
-
fields[k] = {
|
|
1020
|
-
constraint: { ...toPlainConstraint(f.constraint), isOptional: true },
|
|
1021
|
-
optional: true
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
return makeBuilder(c.prim, c.preds, { fields });
|
|
1025
|
-
}
|
|
1026
|
-
function pick(c, keys) {
|
|
1027
|
-
if (!isConstraint(c) || !c.fields)
|
|
1028
|
-
throw new Error("nudo pick(): only shape(...) constraints are accepted");
|
|
1029
|
-
const fields = {};
|
|
1030
|
-
for (const k of keys) {
|
|
1031
|
-
const f = c.fields[k];
|
|
1032
|
-
if (f) fields[k] = f;
|
|
1033
|
-
}
|
|
1034
|
-
return makeBuilder(c.prim, c.preds, { fields });
|
|
1035
|
-
}
|
|
1036
|
-
function omit(c, keys) {
|
|
1037
|
-
if (!isConstraint(c) || !c.fields)
|
|
1038
|
-
throw new Error("nudo omit(): only shape(...) constraints are accepted");
|
|
1039
|
-
const drop = new Set(keys);
|
|
1040
|
-
const fields = {};
|
|
1041
|
-
for (const [k, f] of Object.entries(c.fields)) {
|
|
1042
|
-
if (!drop.has(k)) fields[k] = f;
|
|
1043
|
-
}
|
|
1044
|
-
return makeBuilder(c.prim, c.preds, { fields });
|
|
1045
|
-
}
|
|
1046
|
-
var CONSTRAINT_BUILDERS = {
|
|
1047
|
-
number,
|
|
1048
|
-
string,
|
|
1049
|
-
boolean,
|
|
1050
|
-
any,
|
|
1051
|
-
array,
|
|
1052
|
-
shape,
|
|
1053
|
-
lit: litC,
|
|
1054
|
-
union,
|
|
1055
|
-
nullable,
|
|
1056
|
-
fn,
|
|
1057
|
-
and: andC,
|
|
1058
|
-
partial,
|
|
1059
|
-
pick,
|
|
1060
|
-
omit
|
|
1061
|
-
};
|
|
1062
|
-
var CONSTRAINT_BUILDER_NAMES = Object.keys(
|
|
1063
|
-
CONSTRAINT_BUILDERS
|
|
1064
|
-
);
|
|
1065
|
-
var CONSTRAINT_EXPR_RE = new RegExp(
|
|
1066
|
-
`^(${CONSTRAINT_BUILDER_NAMES.join("|")})\\s*\\(`
|
|
1067
|
-
);
|
|
1068
|
-
function substTerm(t, paramName) {
|
|
1069
|
-
if (t.op === "var" && t.id === SELF) return v(paramName);
|
|
1070
|
-
if (t.op === "app" && t.fn === "get" && t.args.length === 2) {
|
|
1071
|
-
return getTerm(substTerm(t.args[0], paramName), String(
|
|
1072
|
-
t.args[1].op === "lit" ? t.args[1].value : ""
|
|
1073
|
-
));
|
|
1074
|
-
}
|
|
1075
|
-
return t;
|
|
1076
|
-
}
|
|
1077
|
-
function substPred(p, paramName) {
|
|
1078
|
-
switch (p.op) {
|
|
1079
|
-
case "gt":
|
|
1080
|
-
case "ge":
|
|
1081
|
-
case "lt":
|
|
1082
|
-
case "le":
|
|
1083
|
-
case "eq":
|
|
1084
|
-
case "ne": {
|
|
1085
|
-
return { op: p.op, a: substTerm(p.a, paramName), b: substTerm(p.b, paramName) };
|
|
1086
|
-
}
|
|
1087
|
-
case "typeof": {
|
|
1088
|
-
return { op: "typeof", t: substTerm(p.t, paramName), type: p.type };
|
|
1089
|
-
}
|
|
1090
|
-
case "and":
|
|
1091
|
-
return and(...p.args.map((x) => substPred(x, paramName)));
|
|
1092
|
-
default:
|
|
1093
|
-
return p;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
function instantiateConstraint(c, paramName) {
|
|
1097
|
-
if (c.fields) {
|
|
1098
|
-
const parts = [];
|
|
1099
|
-
for (const [key, field] of Object.entries(c.fields)) {
|
|
1100
|
-
if (field.optional || field.constraint.isOptional) continue;
|
|
1101
|
-
const fieldTerm = getTerm(v(paramName), key);
|
|
1102
|
-
parts.push(instantiateOnTerm(field.constraint, fieldTerm));
|
|
1103
|
-
}
|
|
1104
|
-
if (c.prim) parts.push(ptypeof(v(paramName), primToTypeof(c.prim)));
|
|
1105
|
-
if (parts.length === 0) return { op: "true" };
|
|
1106
|
-
return parts.length === 1 ? parts[0] : and(...parts);
|
|
1107
|
-
}
|
|
1108
|
-
if (c.members) {
|
|
1109
|
-
const disj = or(
|
|
1110
|
-
...c.members.map((m) => instantiateOnTerm(m, v(paramName)))
|
|
1111
|
-
);
|
|
1112
|
-
const own = c.preds.map((p) => substPred(p, paramName));
|
|
1113
|
-
return own.length === 0 ? disj : and(...own, disj);
|
|
1114
|
-
}
|
|
1115
|
-
if (c.fn) {
|
|
1116
|
-
const own = c.preds.map((p) => substPred(p, paramName));
|
|
1117
|
-
return own.length === 0 ? pTrue : and(...own);
|
|
1118
|
-
}
|
|
1119
|
-
const preds = c.preds.map((p) => substPred(p, paramName));
|
|
1120
|
-
if (c.prim && c.preds.length === 0) {
|
|
1121
|
-
return ptypeof(v(paramName), primToTypeof(c.prim));
|
|
1122
|
-
}
|
|
1123
|
-
return preds.length === 0 ? { op: "true" } : preds.length === 1 ? preds[0] : and(...preds);
|
|
1124
|
-
}
|
|
1125
|
-
function instantiateOnTerm(c, t) {
|
|
1126
|
-
const subst = (p) => {
|
|
1127
|
-
switch (p.op) {
|
|
1128
|
-
case "gt":
|
|
1129
|
-
case "ge":
|
|
1130
|
-
case "lt":
|
|
1131
|
-
case "le":
|
|
1132
|
-
case "eq":
|
|
1133
|
-
case "ne": {
|
|
1134
|
-
const a = p.a.op === "var" && p.a.id === SELF ? t : p.a;
|
|
1135
|
-
const b = p.b.op === "var" && p.b.id === SELF ? t : p.b;
|
|
1136
|
-
return { op: p.op, a, b };
|
|
1137
|
-
}
|
|
1138
|
-
case "typeof": {
|
|
1139
|
-
const tt = p.t.op === "var" && p.t.id === SELF ? t : p.t;
|
|
1140
|
-
return { op: "typeof", t: tt, type: p.type };
|
|
1141
|
-
}
|
|
1142
|
-
case "and":
|
|
1143
|
-
return and(...p.args.map(subst));
|
|
1144
|
-
default:
|
|
1145
|
-
return p;
|
|
1146
|
-
}
|
|
1147
|
-
};
|
|
1148
|
-
if (c.fields) {
|
|
1149
|
-
const parts = [];
|
|
1150
|
-
for (const [key, field] of Object.entries(c.fields)) {
|
|
1151
|
-
if (field.optional || field.constraint.isOptional) continue;
|
|
1152
|
-
parts.push(instantiateOnTerm(field.constraint, getTerm(t, key)));
|
|
1153
|
-
}
|
|
1154
|
-
if (parts.length === 0) return { op: "true" };
|
|
1155
|
-
return parts.length === 1 ? parts[0] : and(...parts);
|
|
1156
|
-
}
|
|
1157
|
-
if (c.members) {
|
|
1158
|
-
const disj = or(...c.members.map((m) => instantiateOnTerm(m, t)));
|
|
1159
|
-
const own = c.preds.map(subst);
|
|
1160
|
-
return own.length === 0 ? disj : and(...own, disj);
|
|
1161
|
-
}
|
|
1162
|
-
if (c.fn) {
|
|
1163
|
-
const own = c.preds.map(subst);
|
|
1164
|
-
return own.length === 0 ? pTrue : and(...own);
|
|
1165
|
-
}
|
|
1166
|
-
const preds = c.preds.map(subst);
|
|
1167
|
-
if (c.prim && c.preds.length === 0) return ptypeof(t, primToTypeof(c.prim));
|
|
1168
|
-
return preds.length === 0 ? { op: "true" } : preds.length === 1 ? preds[0] : and(...preds);
|
|
1169
|
-
}
|
|
1170
|
-
function constraintToEntryAbs(c, paramName) {
|
|
1171
|
-
const t = v(paramName);
|
|
1172
|
-
if (c.fields) {
|
|
1173
|
-
const slots = {};
|
|
1174
|
-
for (const [key, field] of Object.entries(c.fields)) {
|
|
1175
|
-
const fieldTerm = getTerm(t, key);
|
|
1176
|
-
slots[key] = {
|
|
1177
|
-
value: constraintOnTermAbs(field.constraint, fieldTerm),
|
|
1178
|
-
...field.optional || field.constraint.isOptional ? { optional: true } : {}
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
return abs({ k: "obj", slots }, t, void 0, "path");
|
|
1182
|
-
}
|
|
1183
|
-
return constraintOnTermAbs(c, t);
|
|
1184
|
-
}
|
|
1185
|
-
function memberLitValue(m) {
|
|
1186
|
-
const leaves = [];
|
|
1187
|
-
const visit2 = (p2) => {
|
|
1188
|
-
if (p2.op === "and") {
|
|
1189
|
-
p2.args.forEach(visit2);
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
|
-
leaves.push(p2);
|
|
1193
|
-
};
|
|
1194
|
-
m.preds.forEach(visit2);
|
|
1195
|
-
if (leaves.length !== 1) return { ok: false };
|
|
1196
|
-
const p = leaves[0];
|
|
1197
|
-
if (p.op !== "eq") return { ok: false };
|
|
1198
|
-
if (p.a.op === "var" && p.b.op === "lit") {
|
|
1199
|
-
return { ok: true, v: p.b.value };
|
|
1200
|
-
}
|
|
1201
|
-
if (p.b.op === "var" && p.a.op === "lit") {
|
|
1202
|
-
return { ok: true, v: p.a.value };
|
|
1203
|
-
}
|
|
1204
|
-
return { ok: false };
|
|
1205
|
-
}
|
|
1206
|
-
function samePrimLiteralUnionAbs(members, t) {
|
|
1207
|
-
if (members.length === 0) return void 0;
|
|
1208
|
-
const values = [];
|
|
1209
|
-
let prim;
|
|
1210
|
-
for (const m of members) {
|
|
1211
|
-
const mk = memberLitValue(m);
|
|
1212
|
-
if (!mk.ok) return void 0;
|
|
1213
|
-
const v2 = mk.v;
|
|
1214
|
-
if (v2 === void 0 || v2 === null) return void 0;
|
|
1215
|
-
const mp = m.prim ?? (typeof v2 === "number" ? "number" : typeof v2 === "string" ? "string" : "boolean");
|
|
1216
|
-
if (prim === void 0) prim = mp;
|
|
1217
|
-
else if (prim !== mp) return void 0;
|
|
1218
|
-
values.push(v2);
|
|
1219
|
-
}
|
|
1220
|
-
if (prim === void 0) return void 0;
|
|
1221
|
-
const uniq = [];
|
|
1222
|
-
for (const v2 of values) {
|
|
1223
|
-
if (!uniq.some((u) => Object.is(u, v2))) uniq.push(v2);
|
|
1224
|
-
}
|
|
1225
|
-
const disj = or(
|
|
1226
|
-
...uniq.map((v2) => eq(t, lit(v2)))
|
|
1227
|
-
);
|
|
1228
|
-
return abs({ k: "prim", type: prim }, t, disj, "path");
|
|
1229
|
-
}
|
|
1230
|
-
function constraintOnTermAbs(c, t) {
|
|
1231
|
-
if (c.fields) {
|
|
1232
|
-
const slots = {};
|
|
1233
|
-
for (const [key, field] of Object.entries(c.fields)) {
|
|
1234
|
-
slots[key] = {
|
|
1235
|
-
value: constraintOnTermAbs(field.constraint, getTerm(t, key)),
|
|
1236
|
-
...field.optional || field.constraint.isOptional ? { optional: true } : {}
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
return abs({ k: "obj", slots }, t, void 0, "path");
|
|
1240
|
-
}
|
|
1241
|
-
if (c.members) {
|
|
1242
|
-
const litUnion = samePrimLiteralUnionAbs(c.members, t);
|
|
1243
|
-
if (litUnion) return litUnion;
|
|
1244
|
-
const joined = c.members.map((m) => constraintOnTermAbs(m, t)).reduce((a, b) => joinAbs(a, b));
|
|
1245
|
-
if (joined.shape.k === "prim" && joined.pred === void 0 && c.members.every((m) => m.prim === joined.shape.type)) {
|
|
1246
|
-
const type = joined.shape.type;
|
|
1247
|
-
return abs({ k: "prim", type }, t, ptypeof(t, primToTypeof(type)), "path");
|
|
1248
|
-
}
|
|
1249
|
-
return joined;
|
|
1250
|
-
}
|
|
1251
|
-
if (c.fn) {
|
|
1252
|
-
const paramNames = Object.keys(c.fn.params);
|
|
1253
|
-
const paramTypes = paramNames.map(
|
|
1254
|
-
(p, i) => constraintOnTermAbs(c.fn.params[p], v(`x${i}`))
|
|
1255
|
-
);
|
|
1256
|
-
const returnType = c.fn.returns ? constraintOnTermAbs(c.fn.returns, v("ret")) : unknown;
|
|
1257
|
-
return abs(
|
|
1258
|
-
{ k: "fn", params: paramNames, paramTypes, returnType },
|
|
1259
|
-
t,
|
|
1260
|
-
void 0,
|
|
1261
|
-
"path"
|
|
1262
|
-
);
|
|
1263
|
-
}
|
|
1264
|
-
if (c.element) {
|
|
1265
|
-
const elem = constraintOnTermAbs(c.element, v("x[]"));
|
|
1266
|
-
return abs({ k: "arr", element: elem }, t, void 0, "path");
|
|
1267
|
-
}
|
|
1268
|
-
const pred = instantiateOnTerm(c, t);
|
|
1269
|
-
const predOut = pred.op === "true" ? void 0 : pred;
|
|
1270
|
-
if (c.prim) {
|
|
1271
|
-
return abs({ k: "prim", type: c.prim }, t, predOut, "path");
|
|
1272
|
-
}
|
|
1273
|
-
const allEqNullish = c.preds.length > 0 && c.preds.every(
|
|
1274
|
-
(p) => p.op === "eq" && (p.b.op === "lit" && (p.b.value === null || p.b.value === void 0) || p.a.op === "lit" && (p.a.value === null || p.a.value === void 0))
|
|
1275
|
-
);
|
|
1276
|
-
if (allEqNullish) {
|
|
1277
|
-
let nullish = null;
|
|
1278
|
-
for (const p of c.preds) {
|
|
1279
|
-
if (p.op !== "eq") continue;
|
|
1280
|
-
if (p.b.op === "lit" && (p.b.value === null || p.b.value === void 0)) {
|
|
1281
|
-
nullish = p.b.value;
|
|
1282
|
-
break;
|
|
1283
|
-
}
|
|
1284
|
-
if (p.a.op === "lit" && (p.a.value === null || p.a.value === void 0)) {
|
|
1285
|
-
nullish = p.a.value;
|
|
1286
|
-
break;
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
return abs({ k: "unknown" }, lit(nullish), void 0, "path");
|
|
1290
|
-
}
|
|
1291
|
-
if (c.preds.length > 0) {
|
|
1292
|
-
return abs({ k: "prim", type: "number" }, t, predOut, "path");
|
|
1293
|
-
}
|
|
1294
|
-
return abs({ k: "any" }, t, void 0, "path");
|
|
1295
|
-
}
|
|
1296
|
-
function fnConstraintToEntryReqs(c) {
|
|
1297
|
-
if (!c.fn) throw new Error("nudo fnConstraintToEntryReqs(): constraint is not in fn() form");
|
|
1298
|
-
return Object.entries(c.fn.params).map(([param, constraint]) => ({
|
|
1299
|
-
param,
|
|
1300
|
-
constraint
|
|
1301
|
-
}));
|
|
1302
|
-
}
|
|
1303
|
-
function throwConstraintToKinds(c) {
|
|
1304
|
-
if (!c) return void 0;
|
|
1305
|
-
const out = /* @__PURE__ */ new Set();
|
|
1306
|
-
let any2 = false;
|
|
1307
|
-
const note = (s) => {
|
|
1308
|
-
if (s === "*" || s === "any") any2 = true;
|
|
1309
|
-
else if (s) out.add(s);
|
|
1310
|
-
};
|
|
1311
|
-
const walk = (x) => {
|
|
1312
|
-
if (x.members) {
|
|
1313
|
-
for (const m of x.members) walk(m);
|
|
1314
|
-
return;
|
|
1315
|
-
}
|
|
1316
|
-
for (const p of x.preds) {
|
|
1317
|
-
if (p.op !== "eq" && p.op !== "ne") continue;
|
|
1318
|
-
for (const side of [p.a, p.b]) {
|
|
1319
|
-
if (side.op === "lit" && typeof side.value === "string") note(side.value);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
};
|
|
1323
|
-
walk(c);
|
|
1324
|
-
if (any2) return "*";
|
|
1325
|
-
if (out.size > 0) return [...out];
|
|
1326
|
-
return void 0;
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
803
|
// src/algebra/refine.ts
|
|
1330
804
|
function diagnoseMalformedNudoImports(source) {
|
|
1331
805
|
for (const bad of scanMalformedNudoImports(source)) {
|
|
@@ -1352,8 +826,8 @@ function extractNudoImports(source) {
|
|
|
1352
826
|
var MAX_REFINE_DIAGS = 1024;
|
|
1353
827
|
var refineDiagChannel = createScopedDiagChannel(MAX_REFINE_DIAGS);
|
|
1354
828
|
registerCollectorScopeParticipant((body) => refineDiagChannel.runScoped(body));
|
|
1355
|
-
function setRefineDiagCollector(
|
|
1356
|
-
refineDiagChannel.setCollector(
|
|
829
|
+
function setRefineDiagCollector(fn) {
|
|
830
|
+
refineDiagChannel.setCollector(fn);
|
|
1357
831
|
}
|
|
1358
832
|
function refineDiagCount() {
|
|
1359
833
|
return refineDiagChannel.count();
|
|
@@ -1730,13 +1204,13 @@ function execSidecar(src, opts, chain, preloaded) {
|
|
|
1730
1204
|
const body = `${prologue.length > 0 ? `${prologue.join("\n")}
|
|
1731
1205
|
` : ""}${code}
|
|
1732
1206
|
return { ${returnObj} };`;
|
|
1733
|
-
const
|
|
1207
|
+
const fn = new Function(
|
|
1734
1208
|
...Object.keys(sidecarInjects),
|
|
1735
1209
|
"__nudoInjects",
|
|
1736
1210
|
"__nudoDeps",
|
|
1737
1211
|
body
|
|
1738
1212
|
);
|
|
1739
|
-
return
|
|
1213
|
+
return fn(...Object.values(sidecarInjects), sidecarInjects, deps);
|
|
1740
1214
|
}
|
|
1741
1215
|
function execNudoModule(src, opts) {
|
|
1742
1216
|
return execNudoModuleCached(src, opts ?? {});
|
|
@@ -2250,8 +1724,8 @@ function regionHasGeneratedMarker(stmts, exportIdx, src) {
|
|
|
2250
1724
|
var MAX_INTERFACE_DIAGS = 1024;
|
|
2251
1725
|
var interfaceDiagChannel = createScopedDiagChannel(MAX_INTERFACE_DIAGS);
|
|
2252
1726
|
registerCollectorScopeParticipant((body) => interfaceDiagChannel.runScoped(body));
|
|
2253
|
-
function setInterfaceDiagCollector(
|
|
2254
|
-
interfaceDiagChannel.setCollector(
|
|
1727
|
+
function setInterfaceDiagCollector(fn) {
|
|
1728
|
+
interfaceDiagChannel.setCollector(fn);
|
|
2255
1729
|
}
|
|
2256
1730
|
function interfaceDiagCount() {
|
|
2257
1731
|
return interfaceDiagChannel.count();
|
|
@@ -2512,11 +1986,11 @@ function crossBoundConflict(a, b) {
|
|
|
2512
1986
|
if (x.value !== y.value) return true;
|
|
2513
1987
|
}
|
|
2514
1988
|
}
|
|
2515
|
-
for (const
|
|
2516
|
-
if (typeof
|
|
1989
|
+
for (const eq of eqA) {
|
|
1990
|
+
if (typeof eq.value === "number" && boundExcludes(B, eq.term, eq.value)) return true;
|
|
2517
1991
|
}
|
|
2518
|
-
for (const
|
|
2519
|
-
if (typeof
|
|
1992
|
+
for (const eq of eqB) {
|
|
1993
|
+
if (typeof eq.value === "number" && boundExcludes(A, eq.term, eq.value)) return true;
|
|
2520
1994
|
}
|
|
2521
1995
|
return false;
|
|
2522
1996
|
}
|
|
@@ -2712,9 +2186,9 @@ function predToChain(p) {
|
|
|
2712
2186
|
[a, b],
|
|
2713
2187
|
[b, a]
|
|
2714
2188
|
]) {
|
|
2715
|
-
const
|
|
2716
|
-
const
|
|
2717
|
-
if (
|
|
2189
|
+
const ge = lengthBound(x, "ge");
|
|
2190
|
+
const le = lengthBound(y, "le");
|
|
2191
|
+
if (ge !== void 0 && ge === le) return `.length(${ge})`;
|
|
2718
2192
|
}
|
|
2719
2193
|
}
|
|
2720
2194
|
return p.args.map(predToChain).join("");
|
|
@@ -2724,24 +2198,29 @@ function predToChain(p) {
|
|
|
2724
2198
|
}
|
|
2725
2199
|
return `{${predToString(p)}}`;
|
|
2726
2200
|
}
|
|
2727
|
-
|
|
2201
|
+
var LAZY_DISPLAY_DEPTH = 2;
|
|
2202
|
+
function fmtConstraint(c, depth = LAZY_DISPLAY_DEPTH) {
|
|
2203
|
+
if (c.lazy) {
|
|
2204
|
+
if (depth <= 0) return "\u2026";
|
|
2205
|
+
return fmtConstraint(derefConstraint(c), depth - 1);
|
|
2206
|
+
}
|
|
2728
2207
|
if (c.fn) {
|
|
2729
2208
|
const args = [
|
|
2730
|
-
`{ ${Object.entries(c.fn.params).map(([k, v2]) => `${k}: ${fmtConstraint(v2)}`).join(", ")} }`
|
|
2209
|
+
`{ ${Object.entries(c.fn.params).map(([k, v2]) => `${k}: ${fmtConstraint(v2, depth)}`).join(", ")} }`
|
|
2731
2210
|
];
|
|
2732
|
-
if (c.fn.returns !== void 0) args.push(fmtConstraint(c.fn.returns));
|
|
2733
|
-
if (c.fn.throws !== void 0) args.push(`{ throws: ${fmtConstraint(c.fn.throws)} }`);
|
|
2211
|
+
if (c.fn.returns !== void 0) args.push(fmtConstraint(c.fn.returns, depth));
|
|
2212
|
+
if (c.fn.throws !== void 0) args.push(`{ throws: ${fmtConstraint(c.fn.throws, depth)} }`);
|
|
2734
2213
|
return `fn(${args.join(", ")})`;
|
|
2735
2214
|
}
|
|
2736
|
-
if (c.members) return `union(${c.members.map(fmtConstraint).join(", ")})`;
|
|
2215
|
+
if (c.members) return `union(${c.members.map((m) => fmtConstraint(m, depth)).join(", ")})`;
|
|
2737
2216
|
if (c.fields) {
|
|
2738
2217
|
const fs = Object.entries(c.fields).map(([k, f]) => {
|
|
2739
2218
|
const opt = f.optional || f.constraint.isOptional ? "?" : "";
|
|
2740
|
-
return `${k}${opt}: ${fmtConstraint(f.constraint)}`;
|
|
2219
|
+
return `${k}${opt}: ${fmtConstraint(f.constraint, depth)}`;
|
|
2741
2220
|
});
|
|
2742
2221
|
return `shape({ ${fs.join(", ")} })`;
|
|
2743
2222
|
}
|
|
2744
|
-
if (c.element) return `array(${fmtConstraint(c.element)})`;
|
|
2223
|
+
if (c.element) return `array(${fmtConstraint(c.element, depth)})`;
|
|
2745
2224
|
if (c.preds.length === 1 && c.preds[0].op === "eq" && c.preds[0].a.op === "var" && c.preds[0].b.op === "lit" && !isIntFlag(c)) {
|
|
2746
2225
|
return `lit(${litToString(c.preds[0].b.value)})`;
|
|
2747
2226
|
}
|
|
@@ -3361,8 +2840,8 @@ function alphaOfTerm(t, ctx) {
|
|
|
3361
2840
|
}
|
|
3362
2841
|
function rawTermOf(arg, ctx) {
|
|
3363
2842
|
if (arg?.type === "Identifier") {
|
|
3364
|
-
const
|
|
3365
|
-
if (
|
|
2843
|
+
const lt = ctx.localTerms.get(arg.name);
|
|
2844
|
+
if (lt) return lt;
|
|
3366
2845
|
if (ctx.paramTermId.has(arg.name)) {
|
|
3367
2846
|
return v(ctx.paramTermId.get(arg.name));
|
|
3368
2847
|
}
|
|
@@ -3374,22 +2853,22 @@ function rawTermOf(arg, ctx) {
|
|
|
3374
2853
|
}
|
|
3375
2854
|
function alphaTermOf(arg, ctx) {
|
|
3376
2855
|
if (arg?.type === "Identifier") {
|
|
3377
|
-
const
|
|
3378
|
-
if (
|
|
2856
|
+
const lt = ctx.localTerms.get(arg.name);
|
|
2857
|
+
if (lt) return lt;
|
|
3379
2858
|
if (ctx.paramTermId.has(arg.name)) {
|
|
3380
2859
|
return v(ctx.paramTermId.get(arg.name));
|
|
3381
2860
|
}
|
|
3382
2861
|
}
|
|
3383
2862
|
return alphaOfTerm(void 0, ctx);
|
|
3384
2863
|
}
|
|
3385
|
-
function promoteShape(ctx, param,
|
|
2864
|
+
function promoteShape(ctx, param, shape, loc, recordSite = true) {
|
|
3386
2865
|
const prev = ctx.shapes.get(param);
|
|
3387
2866
|
if (!prev) return;
|
|
3388
2867
|
if (prev.shape.k !== "any" && prev.shape.k !== "unknown") return;
|
|
3389
|
-
const next = { shape
|
|
2868
|
+
const next = { shape, term: prev.term, pred: prev.pred, conf: "path" };
|
|
3390
2869
|
ctx.shapes.set(param, next);
|
|
3391
|
-
ctx.promotedShapes.set(param,
|
|
3392
|
-
if (
|
|
2870
|
+
ctx.promotedShapes.set(param, shape);
|
|
2871
|
+
if (shape.k === "fn") {
|
|
3393
2872
|
if (!ctx.fnRels.has(param) && !ctx.entryShapes.has(param)) {
|
|
3394
2873
|
ctx.fnRels.set(param, { abs: { ...next }, source: "promote" });
|
|
3395
2874
|
}
|
|
@@ -3397,7 +2876,7 @@ function promoteShape(ctx, param, shape2, loc, recordSite = true) {
|
|
|
3397
2876
|
ctx.sites.push({
|
|
3398
2877
|
param,
|
|
3399
2878
|
argTerms: [],
|
|
3400
|
-
result:
|
|
2879
|
+
result: shape.returnType ?? next,
|
|
3401
2880
|
loc
|
|
3402
2881
|
});
|
|
3403
2882
|
}
|
|
@@ -3684,12 +3163,12 @@ function evictGeneralizeMemoForPaths(paths) {
|
|
|
3684
3163
|
}
|
|
3685
3164
|
return n;
|
|
3686
3165
|
}
|
|
3687
|
-
function loadModuleId(
|
|
3688
|
-
if (!
|
|
3689
|
-
let id = loadModuleIds.get(
|
|
3166
|
+
function loadModuleId(fn) {
|
|
3167
|
+
if (!fn) return 0;
|
|
3168
|
+
let id = loadModuleIds.get(fn);
|
|
3690
3169
|
if (id === void 0) {
|
|
3691
3170
|
id = nextLoadModuleId++;
|
|
3692
|
-
loadModuleIds.set(
|
|
3171
|
+
loadModuleIds.set(fn, id);
|
|
3693
3172
|
}
|
|
3694
3173
|
return id;
|
|
3695
3174
|
}
|
|
@@ -3934,9 +3413,9 @@ function extractFn(source, fnName, fileAst) {
|
|
|
3934
3413
|
});
|
|
3935
3414
|
formalsByName.set(scope.name, formals);
|
|
3936
3415
|
}
|
|
3937
|
-
const
|
|
3938
|
-
if (!
|
|
3939
|
-
return { params:
|
|
3416
|
+
const fn = env.fns.get(fnName);
|
|
3417
|
+
if (!fn) return void 0;
|
|
3418
|
+
return { params: fn.params, body: fn.body, env, formals: formalsByName.get(fnName) ?? [] };
|
|
3940
3419
|
}
|
|
3941
3420
|
function generalizeFromAst(fnName, source, opts = {}) {
|
|
3942
3421
|
const { key, depPaths, truncated } = generalizeMemoKey(fnName, source, opts);
|
|
@@ -4099,9 +3578,9 @@ function generalizeFromAstUncached(fnName, source, opts = {}) {
|
|
|
4099
3578
|
return void 0;
|
|
4100
3579
|
} else if (fnName in evalRun) {
|
|
4101
3580
|
const evalArgs = args.map((a, i) => {
|
|
4102
|
-
const
|
|
4103
|
-
if (
|
|
4104
|
-
return { shape
|
|
3581
|
+
const shape = promoteScan.promotedShapes.get(params[i]);
|
|
3582
|
+
if (shape && (a.shape.k === "any" || a.shape.k === "unknown")) {
|
|
3583
|
+
return { shape, term: a.term, pred: a.pred, conf: "path" };
|
|
4105
3584
|
}
|
|
4106
3585
|
return a;
|
|
4107
3586
|
});
|
|
@@ -4288,92 +3767,6 @@ function buildArgsFromAssume(source, fnName, assumeIds) {
|
|
|
4288
3767
|
});
|
|
4289
3768
|
}
|
|
4290
3769
|
|
|
4291
|
-
// src/algebra/domain-membership.ts
|
|
4292
|
-
function literalMeetsConstraint(lv, c) {
|
|
4293
|
-
const ext = c;
|
|
4294
|
-
if (c.fields || c.element) return false;
|
|
4295
|
-
if (ext.fn) return false;
|
|
4296
|
-
if (Array.isArray(ext.members) && ext.members.length > 0) {
|
|
4297
|
-
return ext.members.some((m) => literalMeetsConstraint(lv, m));
|
|
4298
|
-
}
|
|
4299
|
-
if (c.prim === void 0) {
|
|
4300
|
-
return c.preds.every((p) => predHolds(lv, p));
|
|
4301
|
-
}
|
|
4302
|
-
if (!primMatches(c.prim, lv)) return false;
|
|
4303
|
-
if (isIntFlag(c) && c.prim === "number" && !(typeof lv === "number" && Number.isInteger(lv))) {
|
|
4304
|
-
return false;
|
|
4305
|
-
}
|
|
4306
|
-
return c.preds.every((p) => predHolds(lv, p));
|
|
4307
|
-
}
|
|
4308
|
-
function primMatches(prim, lv) {
|
|
4309
|
-
switch (prim) {
|
|
4310
|
-
case "number":
|
|
4311
|
-
return typeof lv === "number";
|
|
4312
|
-
case "string":
|
|
4313
|
-
return typeof lv === "string";
|
|
4314
|
-
case "boolean":
|
|
4315
|
-
return typeof lv === "boolean";
|
|
4316
|
-
case "object":
|
|
4317
|
-
return lv === null;
|
|
4318
|
-
case "undefined":
|
|
4319
|
-
return lv === void 0;
|
|
4320
|
-
default:
|
|
4321
|
-
return false;
|
|
4322
|
-
}
|
|
4323
|
-
}
|
|
4324
|
-
function predHolds(lv, p) {
|
|
4325
|
-
switch (p.op) {
|
|
4326
|
-
case "eq": {
|
|
4327
|
-
const litT = isSelfVar(p.a) && p.b.op === "lit" ? p.b : isSelfVar(p.b) && p.a.op === "lit" ? p.a : void 0;
|
|
4328
|
-
if (!litT) return false;
|
|
4329
|
-
return Object.is(lv, litT.value);
|
|
4330
|
-
}
|
|
4331
|
-
case "gt":
|
|
4332
|
-
case "ge":
|
|
4333
|
-
case "lt":
|
|
4334
|
-
case "le":
|
|
4335
|
-
return boundHolds(lv, p);
|
|
4336
|
-
case "typeof":
|
|
4337
|
-
return p.t.op === "var" && p.t.id === SELF && primMatches(p.type, lv);
|
|
4338
|
-
// and 是合取:逐参数按同一规则判定(string().length(n) 的 preds 是
|
|
4339
|
-
// and 包裹的两个长度界,叶子仍是 gt/ge/lt/le,无假阳性风险)
|
|
4340
|
-
case "and":
|
|
4341
|
-
return p.args.every((x) => predHolds(lv, x));
|
|
4342
|
-
// ne / or / not / true / false 等其余形态:保守不满足
|
|
4343
|
-
default:
|
|
4344
|
-
return false;
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
function cmpHolds(x, op, n) {
|
|
4348
|
-
switch (op) {
|
|
4349
|
-
case "gt":
|
|
4350
|
-
return x > n;
|
|
4351
|
-
case "ge":
|
|
4352
|
-
return x >= n;
|
|
4353
|
-
case "lt":
|
|
4354
|
-
return x < n;
|
|
4355
|
-
case "le":
|
|
4356
|
-
return x <= n;
|
|
4357
|
-
}
|
|
4358
|
-
}
|
|
4359
|
-
function boundHolds(lv, p) {
|
|
4360
|
-
if (p.b.op !== "lit" || typeof p.b.value !== "number") return false;
|
|
4361
|
-
const n = p.b.value;
|
|
4362
|
-
if (isLengthSelf(p.a)) {
|
|
4363
|
-
return typeof lv === "string" && cmpHolds(lv.length, p.op, n);
|
|
4364
|
-
}
|
|
4365
|
-
if (isSelfVar(p.a)) {
|
|
4366
|
-
return typeof lv === "number" && cmpHolds(lv, p.op, n);
|
|
4367
|
-
}
|
|
4368
|
-
return false;
|
|
4369
|
-
}
|
|
4370
|
-
function isSelfVar(t) {
|
|
4371
|
-
return t.op === "var" && t.id === SELF;
|
|
4372
|
-
}
|
|
4373
|
-
function isLengthSelf(t) {
|
|
4374
|
-
return t.op === "app" && t.fn === "length" && t.args.length === 1 && isSelfVar(t.args[0]);
|
|
4375
|
-
}
|
|
4376
|
-
|
|
4377
3770
|
// src/algebra/stable-source-key.ts
|
|
4378
3771
|
function stableAnalyzeKeySource(source) {
|
|
4379
3772
|
let end = source.length;
|
|
@@ -4608,9 +4001,9 @@ function checkInjectedDomainEvidence(fnName, source, records, opts) {
|
|
|
4608
4001
|
if (idx < 0) continue;
|
|
4609
4002
|
const failures = [];
|
|
4610
4003
|
for (const rec of usable) {
|
|
4611
|
-
const
|
|
4612
|
-
if (
|
|
4613
|
-
if (!literalMeetsConstraint(
|
|
4004
|
+
const lit = extractLiteralEvidence(rec, idx);
|
|
4005
|
+
if (lit === void 0) continue;
|
|
4006
|
+
if (!literalMeetsConstraint(lit, constraint)) failures.push(lit);
|
|
4614
4007
|
}
|
|
4615
4008
|
if (failures.length === 0) continue;
|
|
4616
4009
|
const shown = [...new Set(failures)].map(evidenceToString).join(", ");
|
|
@@ -5213,16 +4606,16 @@ function scanLiteralCalls(source, knownFns, phi, opts) {
|
|
|
5213
4606
|
}
|
|
5214
4607
|
if (p.op === "or") {
|
|
5215
4608
|
let pass = false;
|
|
5216
|
-
let
|
|
4609
|
+
let unknown2 = false;
|
|
5217
4610
|
for (const q of p.args) {
|
|
5218
4611
|
const r = judgeLiteralPred(q, lv, strLen);
|
|
5219
4612
|
if (r === true) {
|
|
5220
4613
|
pass = true;
|
|
5221
4614
|
break;
|
|
5222
4615
|
}
|
|
5223
|
-
if (r === void 0)
|
|
4616
|
+
if (r === void 0) unknown2 = true;
|
|
5224
4617
|
}
|
|
5225
|
-
if (!pass && !
|
|
4618
|
+
if (!pass && !unknown2) {
|
|
5226
4619
|
out.push({
|
|
5227
4620
|
severity: "error",
|
|
5228
4621
|
code: "nudo:constraint-violated",
|
|
@@ -5884,34 +5277,6 @@ export {
|
|
|
5884
5277
|
sidecarPathOf,
|
|
5885
5278
|
createDiagChannel,
|
|
5886
5279
|
createScopedDiagChannel,
|
|
5887
|
-
SELF,
|
|
5888
|
-
getTerm,
|
|
5889
|
-
lenTerm,
|
|
5890
|
-
isNudoConstraint,
|
|
5891
|
-
isIntFlag,
|
|
5892
|
-
number,
|
|
5893
|
-
string,
|
|
5894
|
-
boolean,
|
|
5895
|
-
any,
|
|
5896
|
-
array,
|
|
5897
|
-
shape,
|
|
5898
|
-
litC,
|
|
5899
|
-
union,
|
|
5900
|
-
nullable,
|
|
5901
|
-
constraintAdmitsNullish,
|
|
5902
|
-
fn,
|
|
5903
|
-
andC,
|
|
5904
|
-
partial,
|
|
5905
|
-
pick,
|
|
5906
|
-
omit,
|
|
5907
|
-
CONSTRAINT_BUILDERS,
|
|
5908
|
-
CONSTRAINT_BUILDER_NAMES,
|
|
5909
|
-
CONSTRAINT_EXPR_RE,
|
|
5910
|
-
instantiateConstraint,
|
|
5911
|
-
instantiateOnTerm,
|
|
5912
|
-
constraintToEntryAbs,
|
|
5913
|
-
fnConstraintToEntryReqs,
|
|
5914
|
-
throwConstraintToKinds,
|
|
5915
5280
|
extractNudoImports,
|
|
5916
5281
|
setRefineDiagCollector,
|
|
5917
5282
|
refineDiagCount,
|
|
@@ -5957,7 +5322,6 @@ export {
|
|
|
5957
5322
|
generalizeAll,
|
|
5958
5323
|
listFunctionNames,
|
|
5959
5324
|
buildArgsFromAssume,
|
|
5960
|
-
literalMeetsConstraint,
|
|
5961
5325
|
stableAnalyzeKeySource,
|
|
5962
5326
|
listTopFunctions,
|
|
5963
5327
|
scanLiteralCalls,
|