@nudojs/core 0.3.0 → 0.4.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.
Files changed (123) hide show
  1. package/dist/chunk-N7E2A7IK.js +7216 -0
  2. package/dist/exec.d.ts +2 -0
  3. package/dist/exec.js +174 -0
  4. package/dist/index-DgyudAkw.d.ts +911 -0
  5. package/dist/index.d.ts +64 -710
  6. package/dist/index.js +3269 -8426
  7. package/package.json +18 -5
  8. package/CHANGELOG.md +0 -34
  9. package/src/__tests__/environment.test.ts +0 -48
  10. package/src/__tests__/fn-sig-impl.test.ts +0 -57
  11. package/src/__tests__/ops-refined.test.ts +0 -196
  12. package/src/__tests__/ops.test.ts +0 -84
  13. package/src/__tests__/type-value-phase2.test.ts +0 -117
  14. package/src/__tests__/type-value-phase3.test.ts +0 -94
  15. package/src/__tests__/type-value-refined.test.ts +0 -210
  16. package/src/__tests__/type-value.test.ts +0 -319
  17. package/src/algebra/__tests__/abs-native.test.ts +0 -176
  18. package/src/algebra/__tests__/arithmetic.test.ts +0 -170
  19. package/src/algebra/__tests__/ast-eval.test.ts +0 -154
  20. package/src/algebra/__tests__/bridge.test.ts +0 -160
  21. package/src/algebra/__tests__/call-budget.test.ts +0 -117
  22. package/src/algebra/__tests__/check-case-consistency.test.ts +0 -69
  23. package/src/algebra/__tests__/check-gold.test.ts +0 -290
  24. package/src/algebra/__tests__/check-json.test.ts +0 -57
  25. package/src/algebra/__tests__/check-mini-repo.test.ts +0 -49
  26. package/src/algebra/__tests__/check-real-commander.test.ts +0 -43
  27. package/src/algebra/__tests__/check-real-packages.test.ts +0 -165
  28. package/src/algebra/__tests__/check-recall-gold.test.ts +0 -1024
  29. package/src/algebra/__tests__/check-require-dep-memo.test.ts +0 -45
  30. package/src/algebra/__tests__/check-return-contract.test.ts +0 -90
  31. package/src/algebra/__tests__/check-shape-gold.test.ts +0 -303
  32. package/src/algebra/__tests__/check-source-memo.test.ts +0 -204
  33. package/src/algebra/__tests__/check.test.ts +0 -69
  34. package/src/algebra/__tests__/denote.test.ts +0 -77
  35. package/src/algebra/__tests__/diagnostics.test.ts +0 -64
  36. package/src/algebra/__tests__/differential.test.ts +0 -124
  37. package/src/algebra/__tests__/div-mod.test.ts +0 -38
  38. package/src/algebra/__tests__/example0.test.ts +0 -103
  39. package/src/algebra/__tests__/exec-analyze-throws.test.ts +0 -60
  40. package/src/algebra/__tests__/exec-async.test.ts +0 -46
  41. package/src/algebra/__tests__/exec-bpath.test.ts +0 -193
  42. package/src/algebra/__tests__/exec-class.test.ts +0 -56
  43. package/src/algebra/__tests__/exec-e2e.test.ts +0 -97
  44. package/src/algebra/__tests__/exec-generator.test.ts +0 -53
  45. package/src/algebra/__tests__/exec-inherit-default.test.ts +0 -111
  46. package/src/algebra/__tests__/exec-optional-nested.test.ts +0 -87
  47. package/src/algebra/__tests__/exec-rest.test.ts +0 -55
  48. package/src/algebra/__tests__/exec-spread-forof.test.ts +0 -85
  49. package/src/algebra/__tests__/exec-static-computed.test.ts +0 -61
  50. package/src/algebra/__tests__/exec-switch.test.ts +0 -74
  51. package/src/algebra/__tests__/exec-trycatch.test.ts +0 -71
  52. package/src/algebra/__tests__/fn-fp-memo.test.ts +0 -166
  53. package/src/algebra/__tests__/fn-fp-multidecl.test.ts +0 -49
  54. package/src/algebra/__tests__/format.test.ts +0 -34
  55. package/src/algebra/__tests__/generalize-memo.test.ts +0 -285
  56. package/src/algebra/__tests__/generalize.test.ts +0 -113
  57. package/src/algebra/__tests__/hash-source.test.ts +0 -19
  58. package/src/algebra/__tests__/hof.test.ts +0 -80
  59. package/src/algebra/__tests__/inlay.test.ts +0 -30
  60. package/src/algebra/__tests__/language.test.ts +0 -77
  61. package/src/algebra/__tests__/leq.test.ts +0 -109
  62. package/src/algebra/__tests__/load-deps-fp-memo.test.ts +0 -132
  63. package/src/algebra/__tests__/methods.test.ts +0 -37
  64. package/src/algebra/__tests__/node-types.test.ts +0 -26
  65. package/src/algebra/__tests__/nudo-constraints.ts +0 -46
  66. package/src/algebra/__tests__/objects.test.ts +0 -117
  67. package/src/algebra/__tests__/parse-source-cache.test.ts +0 -42
  68. package/src/algebra/__tests__/refine-import.test.ts +0 -109
  69. package/src/algebra/__tests__/stable-source-key-block.test.ts +0 -23
  70. package/src/algebra/__tests__/stable-source-key.test.ts +0 -31
  71. package/src/algebra/__tests__/surface.test.ts +0 -41
  72. package/src/algebra/__tests__/this-inherit.test.ts +0 -130
  73. package/src/algebra/abs-fn.ts +0 -49
  74. package/src/algebra/abs-modules.ts +0 -139
  75. package/src/algebra/abs.ts +0 -206
  76. package/src/algebra/arithmetic.ts +0 -691
  77. package/src/algebra/ast-eval.ts +0 -1763
  78. package/src/algebra/bridge.ts +0 -350
  79. package/src/algebra/builtins.ts +0 -373
  80. package/src/algebra/check-report.ts +0 -150
  81. package/src/algebra/check.ts +0 -1867
  82. package/src/algebra/constraint.ts +0 -304
  83. package/src/algebra/denote.ts +0 -166
  84. package/src/algebra/diagnostics.ts +0 -210
  85. package/src/algebra/exec/call.ts +0 -29
  86. package/src/algebra/exec/calls.ts +0 -96
  87. package/src/algebra/exec/class-registry.ts +0 -29
  88. package/src/algebra/exec/class.ts +0 -329
  89. package/src/algebra/exec/index.ts +0 -6
  90. package/src/algebra/exec/member-diag.ts +0 -141
  91. package/src/algebra/exec/run.ts +0 -341
  92. package/src/algebra/exec/runtime.ts +0 -583
  93. package/src/algebra/exec/transpile.ts +0 -993
  94. package/src/algebra/fn-fp.ts +0 -294
  95. package/src/algebra/format.ts +0 -91
  96. package/src/algebra/generalize.ts +0 -776
  97. package/src/algebra/hash-source.ts +0 -27
  98. package/src/algebra/index.ts +0 -34
  99. package/src/algebra/inlay.ts +0 -198
  100. package/src/algebra/language.ts +0 -289
  101. package/src/algebra/leak.ts +0 -68
  102. package/src/algebra/leq.ts +0 -301
  103. package/src/algebra/load-deps-fp.ts +0 -97
  104. package/src/algebra/methods.ts +0 -128
  105. package/src/algebra/objects.ts +0 -251
  106. package/src/algebra/parse-source.ts +0 -64
  107. package/src/algebra/phi.ts +0 -42
  108. package/src/algebra/pred.ts +0 -395
  109. package/src/algebra/refine.ts +0 -227
  110. package/src/algebra/stable-source-key.ts +0 -81
  111. package/src/algebra/surface.ts +0 -206
  112. package/src/algebra/template.ts +0 -143
  113. package/src/algebra/term.ts +0 -119
  114. package/src/environment.ts +0 -74
  115. package/src/index.ts +0 -73
  116. package/src/mock-helpers.ts +0 -166
  117. package/src/ops.ts +0 -191
  118. package/src/refinements/range.ts +0 -86
  119. package/src/refinements/template-predicates.ts +0 -11
  120. package/src/refinements/template.ts +0 -176
  121. package/src/strip-types.ts +0 -236
  122. package/src/type-value.ts +0 -513
  123. package/tsconfig.json +0 -8
@@ -1,176 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { analyzeFn, evalSource } from "../ast-eval.ts";
3
- import { abs, num, numLit, unknown } from "../abs.ts";
4
- import { v, lit } from "../term.ts";
5
- import { gt, pTrue } from "../pred.ts";
6
- import { typeValueToString } from "../../type-value.ts";
7
- import { absToTypeValue } from "../bridge.ts";
8
- import { formatAbs } from "../format.ts";
9
-
10
- function show(a: ReturnType<typeof analyzeFn>): string {
11
- return typeValueToString(absToTypeValue(a));
12
- }
13
-
14
- describe("abs-native ast-eval", () => {
15
- it("literal arith", () => {
16
- const r = analyzeFn(`function f(){ return 1+2*3; }`, "f", []);
17
- expect(show(r)).toBe("7");
18
- });
19
-
20
- it("param + 1 with constraint via phi in source", () => {
21
- const src = `
22
- function f(x) {
23
- if (x > 0) return x + 1;
24
- return 0;
25
- }
26
- `;
27
- const r = analyzeFn(src, "f", [abs(num().shape, v("x"), gt(v("x"), lit(0)), "path")]);
28
- // x>0 时 x+1 应带约束
29
- expect(r.shape.k === "prim" || r.shape.k === "sum").toBe(true);
30
- });
31
-
32
- it("logical && short-circuit", () => {
33
- const r = analyzeFn(`function f(){ return false && 1; }`, "f", []);
34
- expect(show(r)).toBe("false");
35
- });
36
-
37
- it("typeof", () => {
38
- const r = analyzeFn(`function f(){ return typeof 1; }`, "f", []);
39
- expect(show(r)).toBe('"number"');
40
- });
41
-
42
- it("template literal", () => {
43
- const r = analyzeFn(`function f(x){ return \`n=\${x}\`; }`, "f", [numLit(3)]);
44
- expect(show(r)).toBe('"n=3"');
45
- });
46
-
47
- it("first-class arrow", () => {
48
- const src = `
49
- function f() {
50
- const add = (a, b) => a + b;
51
- return add(2, 3);
52
- }
53
- `;
54
- const r = analyzeFn(src, "f", []);
55
- expect(show(r)).toBe("5");
56
- });
57
-
58
- it("div and mod", () => {
59
- expect(show(analyzeFn(`function f(){ return 10/2; }`, "f", []))).toBe("5");
60
- expect(show(analyzeFn(`function f(){ return 10%3; }`, "f", []))).toBe("1");
61
- });
62
-
63
- it("nullish === decided", () => {
64
- const r = analyzeFn(`function f(x){ return x === null; }`, "f", [numLit(1)]);
65
- expect(show(r)).toBe("false");
66
- });
67
-
68
- it("for loop runs with update", () => {
69
- const src = `
70
- function f() {
71
- let s = 0;
72
- for (let i = 0; i < 3; i++) s = s + i;
73
- return s;
74
- }
75
- `;
76
- const r = analyzeFn(src, "f", []);
77
- expect(r.shape.k === "prim" || r.shape.k === "unknown").toBe(true);
78
- });
79
-
80
- it("for-of over tuple", () => {
81
- const src = `
82
- function f(xs) {
83
- let s = 0;
84
- for (const x of xs) s = s + x;
85
- return s;
86
- }
87
- `;
88
- const tup = abs({ k: "tuple", elements: [numLit(1), numLit(2)] }, undefined, undefined, "exact");
89
- const r = analyzeFn(src, "f", [tup]);
90
- expect(r.shape.k === "prim" || r.shape.k === "unknown").toBe(true);
91
- });
92
-
93
- it("while with break", () => {
94
- const src = `
95
- function f() {
96
- let i = 0;
97
- while (true) {
98
- i = i + 1;
99
- if (i > 2) break;
100
- }
101
- return i;
102
- }
103
- `;
104
- const r = analyzeFn(src, "f", []);
105
- expect(r.shape.k === "prim" || r.shape.k === "unknown").toBe(true);
106
- });
107
-
108
- it("try/catch binds thrown value", () => {
109
- const src = `
110
- function f() {
111
- try {
112
- throw 1;
113
- } catch (e) {
114
- return e;
115
- }
116
- }
117
- `;
118
- const r = analyzeFn(src, "f", []);
119
- expect(show(r)).toBe("1");
120
- });
121
-
122
- it("string methods fold", () => {
123
- expect(show(analyzeFn(`function f(){ return "abc".startsWith("a"); }`, "f", []))).toBe("true");
124
- expect(show(analyzeFn(`function f(){ return "abc".toUpperCase(); }`, "f", []))).toBe('"ABC"');
125
- expect(show(analyzeFn(`function f(){ return "hello".length; }`, "f", []))).toBe("5");
126
- });
127
-
128
- it("array join returns string", () => {
129
- const r = analyzeFn(`function f(xs){ return xs.join(","); }`, "f", [
130
- abs({ k: "arr", element: abs({ k: "prim", type: "string" }, undefined, undefined, "exact") }, undefined, undefined, "exact"),
131
- ]);
132
- expect(r.shape).toEqual({ k: "prim", type: "string" });
133
- });
134
-
135
- it("Math and global builtins on Abs", () => {
136
- expect(show(analyzeFn(`function f(){ return Math.floor(3.7); }`, "f", []))).toBe("3");
137
- expect(show(analyzeFn(`function f(){ return Math.max(1, 5); }`, "f", []))).toBe("5");
138
- expect(show(analyzeFn(`function f(){ return Array.isArray([]); }`, "f", []))).toBe("true");
139
- expect(show(analyzeFn(`function f(){ return parseInt("42"); }`, "f", []))).toBe("42");
140
- expect(show(analyzeFn(`function f(){ return Number.isInteger(3); }`, "f", []))).toBe("true");
141
- });
142
-
143
- it("Object.keys of object shape", () => {
144
- const src = `function f(){ return Object.keys({ a: 1, b: "x" }); }`;
145
- const r = analyzeFn(src, "f", []);
146
- expect(r.shape.k === "tuple" || r.shape.k === "arr").toBe(true);
147
- });
148
-
149
- it("Promise.resolve and then", () => {
150
- const src = `
151
- function f() {
152
- return Promise.resolve(1).then((x) => x + 1);
153
- }
154
- `;
155
- const r = analyzeFn(src, "f", []);
156
- expect(r.shape.k).toBe("eff");
157
- });
158
-
159
- it("Date.now and RegExp.test", () => {
160
- const n = analyzeFn(`function f(){ return Date.now(); }`, "f", []);
161
- expect(n.shape.k === "prim" && (n.shape as { type: string }).type === "number").toBe(true);
162
- const t = analyzeFn(`function f(){ return /a/.test("a"); }`, "f", []);
163
- // 字面正则:.test 可能走 member 路径;至少 boolean 或 unknown
164
- expect(t.shape.k === "prim" || t.shape.k === "unknown").toBe(true);
165
- });
166
-
167
- it("evalProgramAbs executes top-level", async () => {
168
- const { evalProgramAbs } = await import("../ast-eval.ts");
169
- const { env, last } = evalProgramAbs(`
170
- const x = 1 + 2;
171
- function inc(n) { return n + 1; }
172
- `);
173
- expect(env.vars.get("x")).toBeDefined();
174
- expect(env.fns.has("inc")).toBe(true);
175
- });
176
- });
@@ -1,170 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- add,
4
- sub,
5
- mul,
6
- div,
7
- mod,
8
- cmp,
9
- numLit,
10
- numVar,
11
- strLit,
12
- gtNum,
13
- geNum,
14
- ltNum,
15
- lit,
16
- v,
17
- termToString,
18
- predToString,
19
- litValue,
20
- implies,
21
- simplifyTerm,
22
- app,
23
- } from "../index.ts";
24
-
25
- describe("term simplify", () => {
26
- it("folds 1+3", () => {
27
- expect(simplifyTerm(app("+", [lit(1), lit(3)]))).toEqual(lit(4));
28
- });
29
- it("x+0 = x", () => {
30
- expect(simplifyTerm(app("+", [v("x"), lit(0)]))).toEqual(v("x"));
31
- });
32
- it("0+x = x", () => {
33
- expect(simplifyTerm(app("+", [lit(0), v("x")]))).toEqual(v("x"));
34
- });
35
- it("x*0 = 0", () => {
36
- expect(simplifyTerm(app("*", [v("x"), lit(0)]))).toEqual(lit(0));
37
- });
38
- });
39
-
40
- describe("add monotonicity", () => {
41
- it("unconstrained any + 1: number|string 并集,term kept(real JS)", () => {
42
- // 无契约时 x 是 any;score('x') 合法,+ 可能是拼接也可能是加法
43
- const anyA = {
44
- shape: { k: "any" as const },
45
- term: v("A1"),
46
- conf: "path" as const,
47
- };
48
- const r = add(anyA, numLit(1));
49
- expect(r.shape.k).toBe("sum");
50
- if (r.shape.k === "sum") {
51
- const kinds = r.shape.members.map((m) =>
52
- m.shape.k === "prim" ? (m.shape as { type: string }).type : m.shape.k,
53
- );
54
- expect(kinds.sort()).toEqual(["number", "string"]);
55
- }
56
- expect(termToString(r.term!)).toBe("(A1 + 1)");
57
- });
58
-
59
- it("unconstrained any - * / % → number (JS ToNumber)", () => {
60
- const anyA = {
61
- shape: { k: "any" as const },
62
- term: v("A1"),
63
- conf: "path" as const,
64
- };
65
- const one = numLit(1);
66
- for (const [name, r] of [
67
- ["sub", sub(anyA, one)],
68
- ["mul", mul(anyA, one)],
69
- ["div", div(anyA, one)],
70
- ["mod", mod(anyA, one)],
71
- ] as const) {
72
- expect(r.shape, name).toEqual({ k: "prim", type: "number" });
73
- expect(r.term, name).toBeDefined();
74
- }
75
- expect(termToString(sub(anyA, one).term!)).toBe("(A1 - 1)");
76
- });
77
-
78
- it("x>0 + 1 ⇒ term>1", () => {
79
- const phi = gtNum(v("x"), 0);
80
- const r = add(numVar("x", gtNum(v("x"), 0)), numLit(1), phi);
81
- expect(termToString(r.term!)).toBe("(x + 1)");
82
- expect(r.pred!.op).toBe("gt");
83
- });
84
-
85
- it("x>2 + y>3 ⇒ (x+y)>5", () => {
86
- const phi = { op: "and" as const, args: [gtNum(v("x"), 2), gtNum(v("y"), 3)] };
87
- const r = add(
88
- numVar("x", gtNum(v("x"), 2)),
89
- numVar("y", gtNum(v("y"), 3)),
90
- phi,
91
- );
92
- expect(r.pred!.op).toBe("gt");
93
- if (r.pred!.op === "gt") {
94
- expect(r.pred!.b).toEqual(lit(5));
95
- }
96
- });
97
-
98
- it("x≥1 + 0 literal keeps ≥ via simplify to x", () => {
99
- const phi = geNum(v("x"), 1);
100
- const r = add(numVar("x", geNum(v("x"), 1)), numLit(0), phi);
101
- // x+0 simplifies to x
102
- expect(termToString(r.term!)).toBe("x");
103
- });
104
-
105
- it("literal 2+3 = 5 exact", () => {
106
- const r = add(numLit(2), numLit(3));
107
- expect(litValue(r)).toBe(5);
108
- expect(r.conf).toBe("exact");
109
- });
110
- });
111
-
112
- describe("sub / mul", () => {
113
- it("5-2 = 3", () => {
114
- expect(litValue(sub(numLit(5), numLit(2)))).toBe(3);
115
- });
116
- it("x>0 - 1 ⇒ (x-1)>-1? x>0 ⇒ x-1 > -1", () => {
117
- const phi = gtNum(v("x"), 0);
118
- const r = sub(numVar("x", gtNum(v("x"), 0)), numLit(1), phi);
119
- expect(r.term).toBeDefined();
120
- expect(r.pred!.op).toBe("gt");
121
- if (r.pred!.op === "gt") {
122
- expect(r.pred!.b).toEqual(lit(-1));
123
- }
124
- });
125
- it("3*4 = 12", () => {
126
- expect(litValue(mul(numLit(3), numLit(4)))).toBe(12);
127
- });
128
- it("x>0 * 2 ⇒ (x*2)>0", () => {
129
- const phi = gtNum(v("x"), 0);
130
- const r = mul(numVar("x", gtNum(v("x"), 0)), numLit(2), phi);
131
- expect(r.pred!.op).toBe("gt");
132
- if (r.pred!.op === "gt") {
133
- expect(r.pred!.b).toEqual(lit(0));
134
- }
135
- });
136
- });
137
-
138
- describe("implies", () => {
139
- it("x>0 ⊢ x>0", () => {
140
- expect(implies(gtNum(v("x"), 0), gtNum(v("x"), 0))).toBe(true);
141
- });
142
- it("x>0 ⊢ x≥0", () => {
143
- expect(implies(gtNum(v("x"), 0), geNum(v("x"), 0))).toBe(true);
144
- });
145
- it("x>0 ⊬ x>5", () => {
146
- expect(implies(gtNum(v("x"), 0), gtNum(v("x"), 5))).toBe(false);
147
- });
148
- it("x>5 ⊢ x>0", () => {
149
- expect(implies(gtNum(v("x"), 5), gtNum(v("x"), 0))).toBe(true);
150
- });
151
- it("x>0 ⊢ x+1>1", () => {
152
- const phi = gtNum(v("x"), 0);
153
- expect(implies(phi, gtNum(app("+", [v("x"), lit(1)]), 1))).toBe(true);
154
- });
155
- it("x>0 ⊬ x+1>2", () => {
156
- const phi = gtNum(v("x"), 0);
157
- expect(implies(phi, gtNum(app("+", [v("x"), lit(1)]), 2))).toBe(false);
158
- });
159
- });
160
-
161
- describe("cmp under phi", () => {
162
- it("x>0, cmp(x, 0, >) → true", () => {
163
- const phi = gtNum(v("x"), 0);
164
- const r = cmp("gt", numVar("x"), numLit(0), phi);
165
- expect(litValue(r)).toBe(true);
166
- });
167
- it("1<3 → true", () => {
168
- expect(litValue(cmp("lt", numLit(1), numLit(3)))).toBe(true);
169
- });
170
- });
@@ -1,154 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- analyzeFn,
4
- numLit,
5
- numVar,
6
- gtNum,
7
- geNum,
8
- v,
9
- lit,
10
- termToString,
11
- predToString,
12
- litValue,
13
- leakIfNeeded,
14
- maybeLeak,
15
- exceedsBudget,
16
- termDepth,
17
- termNodes,
18
- app,
19
- resetLeakCounter,
20
- mul,
21
- add,
22
- } from "../index.ts";
23
-
24
- describe("AST eval: source → Abs", () => {
25
- it("add(1,3) from real source → 4", () => {
26
- const src = `
27
- const add = (a, b) => a + b;
28
- function main() { return add(1, 3); }
29
- `;
30
- const r = analyzeFn(src, "main", []);
31
- expect(litValue(r)).toBe(4);
32
- expect(r.conf).toBe("exact");
33
- });
34
-
35
- it("scale(x) = add(x,1) under x>0 ⇒ (x+1)>1", () => {
36
- const src = `
37
- const add = (a, b) => a + b;
38
- function scale(x) { return add(x, 1); }
39
- `;
40
- const phi = gtNum(v("x"), 0);
41
- const r = analyzeFn(src, "scale", [numVar("x", gtNum(v("x"), 0))], phi);
42
- expect(r.term).toBeDefined();
43
- expect(termToString(r.term!)).toBe("(x + 1)");
44
- expect(r.pred!.op).toBe("gt");
45
- if (r.pred!.op === "gt") {
46
- expect(r.pred!.b).toEqual(lit(1));
47
- }
48
- });
49
-
50
- it("twice(x) nested add under x>0 ⇒ >2", () => {
51
- const src = `
52
- const add = (a, b) => a + b;
53
- function twice(x) {
54
- const c = add(x, 1);
55
- return add(c, 1);
56
- }
57
- `;
58
- const phi = gtNum(v("x"), 0);
59
- const r = analyzeFn(src, "twice", [numVar("x", gtNum(v("x"), 0))], phi);
60
- expect(r.term).toBeDefined();
61
- expect(r.pred).toBeDefined();
62
- // ((x+1)+1) > 2 或 (x+2) > 2
63
- const ps = predToString(r.pred!);
64
- expect(ps).toContain("2");
65
- });
66
-
67
- it("if (x > 5) return x; return 0 with x>10 ⇒ x", () => {
68
- const src = `
69
- function pick(x) {
70
- if (x > 5) return x;
71
- return 0;
72
- }
73
- `;
74
- const phi = gtNum(v("x"), 10);
75
- const r = analyzeFn(src, "pick", [numVar("x", gtNum(v("x"), 10))], phi);
76
- // true 分支返回 x(term=x),false 分支 0;join 后丢 term
77
- // 但 true 分支在 Φ 下 x>5 成立,我们至少得到 number
78
- expect(r.shape).toEqual({ k: "prim", type: "number" });
79
- });
80
-
81
- it("if (x > 0) return x + 1; return 0 with Φ x>0 ⇒ true branch", () => {
82
- const src = `
83
- function addOneIfPositive(x) {
84
- if (x > 0) return x + 1;
85
- return 0;
86
- }
87
- `;
88
- const phi = gtNum(v("x"), 0);
89
- const r = analyzeFn(src, "addOneIfPositive", [numVar("x", gtNum(v("x"), 0))], phi);
90
- expect(termToString(r.term!)).toBe("(x + 1)");
91
- expect(r.pred!.op).toBe("gt");
92
- });
93
-
94
- it("literal only function", () => {
95
- const src = `
96
- function f() { return 1 + 2 * 3; }
97
- `;
98
- // 注意:JS 里 1+2*3 = 7,我们的 BinaryExpression 是左结合遍历
99
- // Babel AST: (1 + (2 * 3)) —— 乘法优先,AST 已带优先级
100
- const r = analyzeFn(src, "f", []);
101
- expect(litValue(r)).toBe(7);
102
- });
103
-
104
- it("string concat from source", () => {
105
- const src = `
106
- function greet(name) { return "hi, " + name; }
107
- `;
108
- const r = analyzeFn(src, "greet", [numLit(1)]);
109
- // number + string 在 JS 里是字符串,我们 isStrPrim 一侧即可
110
- // 实参是 number,左侧是 string → 走 string 拼接
111
- expect(r.shape).toEqual({ k: "prim", type: "string" });
112
- });
113
- });
114
-
115
- describe("leak", () => {
116
- it("small term does not leak", () => {
117
- resetLeakCounter();
118
- const t = app("+", [v("x"), lit(1)]);
119
- expect(exceedsBudget(t)).toBe(false);
120
- const a = add(numVar("x"), numLit(1));
121
- const leaked = leakIfNeeded(a);
122
- expect(leaked.term).toEqual(a.term);
123
- });
124
-
125
- it("deep term leaks to fresh var + eq", () => {
126
- resetLeakCounter();
127
- let t = v("x");
128
- for (let i = 0; i < 10; i++) {
129
- t = app("+", [t, lit(1)]);
130
- }
131
- expect(termDepth(t)).toBeGreaterThan(6);
132
- expect(exceedsBudget(t)).toBe(true);
133
-
134
- const a = { shape: { k: "prim" as const, type: "number" as const }, term: t, conf: "path" as const };
135
- const leaked = maybeLeak(a, { maxDepth: 4, maxNodes: 20 }, "acc");
136
- expect(leaked.term?.op).toBe("var");
137
- if (leaked.term?.op === "var") {
138
- expect(leaked.term.id.startsWith("acc$")).toBe(true);
139
- }
140
- expect(leaked.pred?.op).toBe("eq");
141
- });
142
- });
143
-
144
- describe("mul negative flips bounds", () => {
145
- it("x>0 * -2 ⇒ (x*-2) < 0", () => {
146
- const phi = gtNum(v("x"), 0);
147
- const r = mul(numVar("x", gtNum(v("x"), 0)), numLit(-2), phi);
148
- expect(r.pred).toBeDefined();
149
- expect(r.pred!.op).toBe("lt");
150
- if (r.pred!.op === "lt") {
151
- expect(r.pred!.b).toEqual(lit(0));
152
- }
153
- });
154
- });
@@ -1,160 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- absToTypeValue,
4
- typeValueToAbs,
5
- bridgeIsLossy,
6
- getTvConfidence,
7
- numLit,
8
- numVar,
9
- gtNum,
10
- v,
11
- litValue,
12
- formatShape,
13
- analyzeFn,
14
- objOf,
15
- strLit,
16
- boolLit,
17
- } from "../index.ts";
18
- import { typeValueToString, T } from "../../type-value.ts";
19
-
20
- describe("bridge Abs → TypeValue", () => {
21
- it("literal 4 → literal 4 #exact", () => {
22
- const tv = absToTypeValue(numLit(4));
23
- expect(tv.kind).toBe("literal");
24
- if (tv.kind === "literal") expect(tv.value).toBe(4);
25
- expect(getTvConfidence(tv)).toBe("exact");
26
- });
27
-
28
- it("plain number prim → primitive number", () => {
29
- const tv = absToTypeValue({
30
- shape: { k: "prim", type: "number" },
31
- conf: "exact",
32
- });
33
- expect(typeValueToString(tv)).toBe("number");
34
- });
35
-
36
- it("x>0 with pred → refined number", () => {
37
- const a = numVar("x", gtNum(v("x"), 0));
38
- const tv = absToTypeValue(a);
39
- // term 是 var,会丢 term;pred 可 encode 为 refined
40
- expect(tv.kind === "refined" || tv.kind === "primitive").toBe(true);
41
- const lossy = bridgeIsLossy(a);
42
- // 丢 term 是预期的
43
- expect(lossy.reasons.some((r) => r.includes("term"))).toBe(true);
44
- });
45
-
46
- it("object slots map to object TypeValue", () => {
47
- const o = objOf({
48
- host: { value: strLit("localhost") },
49
- port: { value: numLit(8080) },
50
- debug: { value: boolLit(false) },
51
- });
52
- const tv = absToTypeValue(o);
53
- expect(tv.kind).toBe("object");
54
- expect(typeValueToString(tv)).toContain("host");
55
- expect(typeValueToString(tv)).toContain("8080");
56
- });
57
- });
58
-
59
- describe("bridge TypeValue → Abs", () => {
60
- it("literal 6 → Abs exact 6", () => {
61
- const abs = typeValueToAbs(T.literal(6));
62
- expect(litValue(abs)).toBe(6);
63
- expect(abs.conf).toBe("exact");
64
- });
65
-
66
- it("primitive string → prim string", () => {
67
- const abs = typeValueToAbs(T.string);
68
- expect(formatShape(abs)).toBe("string");
69
- });
70
-
71
- it("object → obj slots", () => {
72
- const abs = typeValueToAbs(
73
- T.object({ a: T.literal(1), b: T.string }),
74
- );
75
- expect(abs.shape.k).toBe("obj");
76
- });
77
-
78
- it("round-trip literal", () => {
79
- const tv = absToTypeValue(numLit(42));
80
- const back = typeValueToAbs(tv);
81
- expect(litValue(back)).toBe(42);
82
- });
83
-
84
- it("round-trip primitive (lossless)", () => {
85
- const abs0 = {
86
- shape: { k: "prim" as const, type: "number" as const },
87
- conf: "exact" as const,
88
- };
89
- const tv = absToTypeValue(abs0);
90
- const back = typeValueToAbs(tv);
91
- expect(formatShape(back)).toBe("number");
92
- });
93
- });
94
-
95
- describe("bridgeIsLossy", () => {
96
- it("literal is not lossy", () => {
97
- expect(bridgeIsLossy(numLit(1)).lossy).toBe(false);
98
- });
99
- it("symbolic term is lossy", () => {
100
- const src = `
101
- function scale(x) { return x + 1; }
102
- `;
103
- const r = analyzeFn(src, "scale", [numVar("x")]);
104
- expect(bridgeIsLossy(r).lossy).toBe(true);
105
- });
106
- });
107
-
108
- describe("bridge any / conf / refined reverse (rewrite closeout)", () => {
109
- it("Abs any projects as unknown but keeps path conf (not partial)", () => {
110
- const a: import("../abs.ts").Abs = { shape: { k: "any" }, conf: "path" };
111
- const tv = absToTypeValue(a);
112
- expect(tv.kind).toBe("unknown");
113
- expect(getTvConfidence(tv)).toBe("path");
114
- });
115
-
116
- it("Abs analysis-fail unknown keeps partial conf", () => {
117
- const a: import("../abs.ts").Abs = { shape: { k: "unknown" }, conf: "partial" };
118
- const tv = absToTypeValue(a);
119
- expect(tv.kind).toBe("unknown");
120
- expect(getTvConfidence(tv)).toBe("partial");
121
- });
122
-
123
- it("widened TypeValue does not round-trip as exact", () => {
124
- const src = `
125
- function scale(x) { return x + 1; }
126
- `;
127
- const r = analyzeFn(src, "scale", [numVar("x")]);
128
- const tv = absToTypeValue(r);
129
- const back = typeValueToAbs(tv);
130
- expect(back.conf === "exact").toBe(false);
131
- });
132
-
133
- it("refined numeric pred reverse-encodes into Abs pred", () => {
134
- const a = numVar("x", gtNum(v("x"), 0));
135
- const tv = absToTypeValue(a);
136
- expect(tv.kind).toBe("refined");
137
- const back = typeValueToAbs(tv);
138
- expect(back.shape.k).toBe("prim");
139
- expect(back.pred).toBeDefined();
140
- expect(back.pred!.op).toBe("gt");
141
- // pred 右端恢复为字面量 0
142
- if (back.pred!.op === "gt") {
143
- expect(back.pred!.b.op).toBe("lit");
144
- if (back.pred!.b.op === "lit") expect(back.pred!.b.value).toBe(0);
145
- }
146
- });
147
-
148
- it("refined le reverse-encodes", () => {
149
- const a: import("../abs.ts").Abs = {
150
- shape: { k: "prim", type: "number" },
151
- term: v("n"),
152
- pred: { op: "le", a: v("n"), b: { op: "lit", value: 10 } },
153
- conf: "path",
154
- };
155
- const tv = absToTypeValue(a);
156
- expect(tv.kind).toBe("refined");
157
- const back = typeValueToAbs(tv);
158
- expect(back.pred?.op).toBe("le");
159
- });
160
- });