@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,285 +0,0 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import {
3
- generalizeFromAst,
4
- resetGeneralizeMemo,
5
- getGeneralizeMemoSize,
6
- evictGeneralizeMemoForPaths,
7
- formatAbs,
8
- checkSource,
9
- pTrue,
10
- numLit,
11
- numVar,
12
- gtNum,
13
- and,
14
- v,
15
- litValue,
16
- strLit,
17
- termToString,
18
- } from "../index.ts";
19
-
20
- const SRC = `
21
- function add(a, b) {
22
- return a + b;
23
- }
24
- `;
25
-
26
- beforeEach(() => {
27
- resetGeneralizeMemo();
28
- });
29
-
30
- describe("generalizeFromAst L0 memo", () => {
31
- it("returns the same PolyFn instance for identical (source, name) queries", () => {
32
- const a = generalizeFromAst("add", SRC);
33
- const b = generalizeFromAst("add", SRC);
34
- expect(a).toBeDefined();
35
- expect(b).toBe(a);
36
- });
37
-
38
- it("misses when source content changes", () => {
39
- const a = generalizeFromAst("add", SRC);
40
- const b = generalizeFromAst("add", SRC + "\n// touch\n");
41
- expect(a).toBeDefined();
42
- expect(b).toBeDefined();
43
- expect(b).not.toBe(a);
44
- });
45
-
46
- it("misses for a different function name", () => {
47
- const src = `
48
- function add(a, b) { return a + b; }
49
- function sub(a, b) { return a - b; }
50
- `;
51
- const a = generalizeFromAst("add", src);
52
- const b = generalizeFromAst("sub", src);
53
- expect(a).toBeDefined();
54
- expect(b).toBeDefined();
55
- expect(b).not.toBe(a);
56
- });
57
-
58
- it("caches undefined for missing functions", () => {
59
- expect(generalizeFromAst("nope", SRC)).toBeUndefined();
60
- expect(generalizeFromAst("nope", SRC)).toBeUndefined();
61
- });
62
-
63
- it("misses when label changes", () => {
64
- const a = generalizeFromAst("add", SRC, { label: "A" });
65
- const b = generalizeFromAst("add", SRC, { label: "B" });
66
- expect(a).toBeDefined();
67
- expect(b).toBeDefined();
68
- expect(b).not.toBe(a);
69
- });
70
-
71
- it("misses when refine loadModule identity changes", () => {
72
- const load1 = () => undefined;
73
- const load2 = () => undefined;
74
- const a = generalizeFromAst("add", SRC, { refine: { loadModule: load1, fromFile: "/t.js" } });
75
- const b = generalizeFromAst("add", SRC, { refine: { loadModule: load2, fromFile: "/t.js" } });
76
- expect(a).toBeDefined();
77
- expect(b).toBeDefined();
78
- expect(b).not.toBe(a);
79
- });
80
-
81
- it("hit is consistent with checkSource signatures", () => {
82
- const g1 = generalizeFromAst("add", SRC);
83
- const g2 = generalizeFromAst("add", SRC);
84
- expect(formatAbs(g1!.symbolic)).toBe(formatAbs(g2!.symbolic));
85
- const report = checkSource("t.js", SRC, pTrue, {});
86
- expect(report.signatures.map((s) => s.name)).toContain("add");
87
- });
88
- });
89
-
90
- describe("instantiate L1 memo", () => {
91
- const SRC_SCALE = `
92
- function scale(x) {
93
- return x + 1;
94
- }
95
- function pair(a, b) {
96
- return { a, b };
97
- }
98
- `;
99
-
100
- it("returns the same Abs instance for identical args + Φ", () => {
101
- const g = generalizeFromAst("scale", SRC_SCALE)!;
102
- const a1 = numVar("x", gtNum(v("x"), 0));
103
- const phi = gtNum(v("x"), 0);
104
- const r1 = g.instantiate([a1], phi);
105
- const r2 = g.instantiate([numVar("x", gtNum(v("x"), 0))], phi);
106
- expect(r2).toBe(r1);
107
- expect(r1.term).toBeDefined();
108
- expect(termToString(r1.term!)).toBe("(x + 1)");
109
- });
110
-
111
- it("hits for repeated literal args", () => {
112
- const g = generalizeFromAst("scale", SRC_SCALE)!;
113
- const r1 = g.instantiate([numLit(5)]);
114
- const r2 = g.instantiate([numLit(5)]);
115
- expect(litValue(r1)).toBe(6);
116
- expect(r2).toBe(r1);
117
- });
118
-
119
- it("misses for different args", () => {
120
- const g = generalizeFromAst("scale", SRC_SCALE)!;
121
- const r1 = g.instantiate([numLit(5)]);
122
- const r2 = g.instantiate([numLit(7)]);
123
- expect(litValue(r1)).toBe(6);
124
- expect(litValue(r2)).toBe(8);
125
- expect(r2).not.toBe(r1);
126
- });
127
-
128
- it("misses when Φ differs under same arg shape", () => {
129
- const g = generalizeFromAst("scale", SRC_SCALE)!;
130
- const arg = numVar("x", gtNum(v("x"), 0));
131
- const r1 = g.instantiate([arg], gtNum(v("x"), 0));
132
- const r2 = g.instantiate([arg], pTrue);
133
- // 结果可能同构,但键不同不得错误复用为同一对象(允许 equal,禁止错缓存)
134
- expect(formatAbs(r1)).toBeTypeOf("string");
135
- expect(formatAbs(r2)).toBeTypeOf("string");
136
- });
137
-
138
- it("shares L1 hits across L0 PolyFn identity", () => {
139
- const g1 = generalizeFromAst("scale", SRC_SCALE)!;
140
- const g2 = generalizeFromAst("scale", SRC_SCALE)!;
141
- expect(g2).toBe(g1);
142
- const r = g1.instantiate([numLit(2)]);
143
- expect(g2.instantiate([numLit(2)])).toBe(r);
144
- });
145
-
146
- it("object args key by sorted slots (order-insensitive)", () => {
147
- const g = generalizeFromAst("pair", SRC_SCALE)!;
148
- const o1 = {
149
- shape: {
150
- k: "obj" as const,
151
- slots: {
152
- a: { value: numLit(1) },
153
- b: { value: strLit("x") },
154
- },
155
- },
156
- conf: "exact" as const,
157
- };
158
- const o2 = {
159
- shape: {
160
- k: "obj" as const,
161
- slots: {
162
- b: { value: strLit("x") },
163
- a: { value: numLit(1) },
164
- },
165
- },
166
- conf: "exact" as const,
167
- };
168
- const r1 = g.instantiate([o1, numLit(9)]);
169
- // 第二参不同 → miss;同结构第一参应能命中同一对第一个参数的缓存路径
170
- const r2 = g.instantiate([o2, numLit(9)]);
171
- expect(formatAbs(r1)).toContain("a");
172
- // 同键(slot 顺序无关)应返回同一缓存对象
173
- expect(r2).toBe(r1);
174
- });
175
-
176
- it("resetGeneralizeMemo drops L0 and thus L1 tables", () => {
177
- const g1 = generalizeFromAst("scale", SRC_SCALE)!;
178
- const r1 = g1.instantiate([numLit(5)]);
179
- resetGeneralizeMemo();
180
- const g2 = generalizeFromAst("scale", SRC_SCALE)!;
181
- expect(g2).not.toBe(g1);
182
- const r2 = g2.instantiate([numLit(5)]);
183
- expect(litValue(r2)).toBe(6);
184
- expect(r2).not.toBe(r1);
185
- });
186
- });
187
-
188
- describe("L2 α-equivalence + pred canonicalization", () => {
189
- const SRC_ID = `
190
- function id(x) {
191
- return x;
192
- }
193
- function inc(x) {
194
- return x + 1;
195
- }
196
- `;
197
-
198
- it("hits across renamed free vars and rewrites result vars", () => {
199
- const g = generalizeFromAst("inc", SRC_ID)!;
200
- const r1 = g.instantiate([numVar("x", gtNum(v("x"), 0))], gtNum(v("x"), 0));
201
- const r2 = g.instantiate([numVar("y", gtNum(v("y"), 0))], gtNum(v("y"), 0));
202
- expect(termToString(r1.term!)).toBe("(x + 1)");
203
- expect(termToString(r2.term!)).toBe("(y + 1)");
204
- // 不是同一对象(α 改写后的新 Abs),但结构同构
205
- expect(r2).not.toBe(r1);
206
- expect(formatAbs(r2).replace(/y/g, "x")).toBe(formatAbs(r1).replace(/x/g, "x"));
207
- });
208
-
209
- it("and-order does not cause miss", () => {
210
- const g = generalizeFromAst("id", SRC_ID)!;
211
- const ax = numVar("x", and(gtNum(v("x"), 0), gtNum(v("x"), 1)));
212
- const phiA = and(gtNum(v("x"), 0), gtNum(v("x"), 1));
213
- const phiB = and(gtNum(v("x"), 1), gtNum(v("x"), 0));
214
- const r1 = g.instantiate([ax], phiA);
215
- const r2 = g.instantiate([ax], phiB);
216
- expect(formatAbs(r1)).toBe(formatAbs(r2));
217
- });
218
- });
219
-
220
- describe("L3 deps fingerprint + LRU", () => {
221
- const SRC_REFINE = `
222
- /// @nudo:import { positive } from "./shapes.nudo.js"
223
-
224
- /**
225
- * @nudo:refine x positive
226
- */
227
- function needsPositive(x) {
228
- return x;
229
- }
230
- `;
231
-
232
- it("misses L0 when imported nudo module content changes", () => {
233
- let dep = "export const positive = number().gt(0);\n";
234
- const loadModule = (spec: string) => (spec.includes("shapes") ? dep : undefined);
235
- const refine = { loadModule, fromFile: "/proj/a.js" };
236
- const g1 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
237
- expect(g1).toBeDefined();
238
- dep = "export const positive = number().gt(10);\n";
239
- const g2 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
240
- expect(g2).toBeDefined();
241
- expect(g2).not.toBe(g1);
242
- });
243
-
244
- it("hits L0 when dep is unchanged", () => {
245
- const loadModule = () => "export const positive = number().gt(0);\n";
246
- const refine = { loadModule, fromFile: "/proj/a.js" };
247
- const g1 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
248
- const g2 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
249
- expect(g2).toBe(g1);
250
- });
251
-
252
- it("tracks memo size and can reset", () => {
253
- resetGeneralizeMemo();
254
- expect(getGeneralizeMemoSize()).toBe(0);
255
- generalizeFromAst("add", SRC);
256
- expect(getGeneralizeMemoSize()).toBeGreaterThan(0);
257
- resetGeneralizeMemo();
258
- expect(getGeneralizeMemoSize()).toBe(0);
259
- });
260
-
261
- it("evictGeneralizeMemoForPaths drops only dependents of that dep", () => {
262
- resetGeneralizeMemo();
263
- const loadModule = () => "export const positive = number().gt(0);\n";
264
- const refine = { loadModule, fromFile: "/proj/a.js" };
265
- const g1 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
266
- const gOther = generalizeFromAst("add", SRC);
267
- const sizeAfter = getGeneralizeMemoSize();
268
- const n = evictGeneralizeMemoForPaths(["/proj/shapes.nudo.js"]);
269
- expect(n).toBeGreaterThan(0);
270
- expect(getGeneralizeMemoSize()).toBeLessThan(sizeAfter);
271
- // 无关函数仍在
272
- expect(generalizeFromAst("add", SRC)).toBe(gOther);
273
- // 依赖被逐出 → 重新 generalize 得到新 PolyFn
274
- const g2 = generalizeFromAst("needsPositive", SRC_REFINE, { refine });
275
- expect(g2).not.toBe(g1);
276
- expect(g2).toBeDefined();
277
- });
278
-
279
- it("evict is a no-op for unknown paths", () => {
280
- resetGeneralizeMemo();
281
- generalizeFromAst("add", SRC);
282
- expect(evictGeneralizeMemoForPaths(["/nope/missing.nudo.js"])).toBe(0);
283
- expect(getGeneralizeMemoSize()).toBeGreaterThan(0);
284
- });
285
- });
@@ -1,113 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- generalizeFromAst,
4
- generalizeAll,
5
- numLit,
6
- numVar,
7
- gtNum,
8
- v,
9
- litValue,
10
- termToString,
11
- formatAbs,
12
- } from "../index.ts";
13
-
14
- const SRC = `
15
- const add = (a, b) => a + b;
16
- function scale(x) {
17
- return add(x, 1);
18
- }
19
- function twice(x) {
20
- const c = add(x, 1);
21
- return add(c, 1);
22
- }
23
- function id(x) { return x; }
24
- function pair(a, b) { return { a, b }; }
25
- `;
26
-
27
- describe("generalize", () => {
28
- it("scale generalizes to term = A1+1", () => {
29
- const g = generalizeFromAst("scale", SRC);
30
- expect(g).toBeDefined();
31
- if (!g) return;
32
- expect(g.params).toEqual(["x"]);
33
- expect(g.typeParams.length).toBe(1);
34
- expect(g.symbolic.term).toBeDefined();
35
- expect(termToString(g.symbolic.term!)).toBe("(A1 + 1)");
36
- });
37
-
38
- it("instantiate scale with x>0 gives (x+1)>1", () => {
39
- const g = generalizeFromAst("scale", SRC);
40
- expect(g).toBeDefined();
41
- if (!g) return;
42
- const phi = gtNum(v("x"), 0);
43
- const r = g.instantiate([numVar("x", gtNum(v("x"), 0))], phi);
44
- expect(termToString(r.term!)).toBe("(x + 1)");
45
- expect(r.pred!.op).toBe("gt");
46
- });
47
-
48
- it("instantiate scale with literal 5 gives 6", () => {
49
- const g = generalizeFromAst("scale", SRC);
50
- if (!g) return;
51
- const r = g.instantiate([numLit(5)]);
52
- expect(litValue(r)).toBe(6);
53
- expect(r.conf).toBe("exact");
54
- });
55
-
56
- it("id is identity: term stays A1", () => {
57
- const g = generalizeFromAst("id", SRC);
58
- if (!g) return;
59
- expect(g.symbolic.term?.op).toBe("var");
60
- if (g.symbolic.term?.op === "var") {
61
- expect(g.symbolic.term.id).toBe("A1");
62
- }
63
- });
64
-
65
- it("twice nests to (A1+1)+1", () => {
66
- const g = generalizeFromAst("twice", SRC);
67
- if (!g) return;
68
- const ts = termToString(g.symbolic.term!);
69
- expect(ts === "((A1 + 1) + 1)" || ts === "(A1 + 2)").toBe(true);
70
- });
71
-
72
- it("generalizeAll finds all functions", () => {
73
- const all = generalizeAll(SRC);
74
- const names = all.map((g) => g.name).sort();
75
- expect(names).toContain("add");
76
- expect(names).toContain("scale");
77
- expect(names).toContain("twice");
78
- expect(names).toContain("id");
79
- });
80
-
81
- it("display mentions type params", () => {
82
- const g = generalizeFromAst("scale", SRC);
83
- if (!g) return;
84
- expect(g.display).toContain("scale");
85
- expect(g.display).toContain("A1");
86
- });
87
-
88
- it("attaches @nudo:refine to entry param Abs", () => {
89
- const src = `
90
- /// @nudo:import { positive } from "./x.nudo.js"
91
- /**
92
- * @nudo:refine x positive
93
- */
94
- function scale(x) { return x + 1; }
95
- function bare(x) { return x + 1; }
96
- `;
97
- const loadModule = () => `export const positive = number().gt(0);`;
98
- const g = generalizeFromAst("scale", src, {
99
- refine: { loadModule, fromFile: "/t/a.js" },
100
- });
101
- expect(g).toBeDefined();
102
- expect(g!.typeParams[0]!.value.shape).toEqual({ k: "prim", type: "number" });
103
- expect(g!.entryReqs?.[0]?.param).toBe("x");
104
- expect(g!.display).toContain("x > 0");
105
- expect(formatAbs(g!.symbolic)).toContain("number");
106
-
107
- const b = generalizeFromAst("bare", src, {
108
- refine: { loadModule, fromFile: "/t/a.js" },
109
- });
110
- expect(b!.typeParams[0]!.value.shape.k).toBe("any");
111
- expect(b!.display).toContain("number | string");
112
- });
113
- });
@@ -1,19 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { hashSource, resetHashSourceCache } from "../hash-source.ts";
3
-
4
- describe("hashSource", () => {
5
- it("is stable for identical input and differs on length/content", () => {
6
- resetHashSourceCache();
7
- const a = hashSource("hello world");
8
- expect(hashSource("hello world")).toBe(a);
9
- expect(hashSource("hello world!")).not.toBe(a);
10
- // pure 32-bit FNV can collide on crafted pairs; length+second mix should not
11
- expect(hashSource("a")).not.toBe(hashSource("b"));
12
- });
13
-
14
- it("includes length so truncated prefixes do not alias", () => {
15
- resetHashSourceCache();
16
- // classic FNV pitfalls often involve short suffixes; length disambiguates
17
- expect(hashSource("abc")).not.toBe(hashSource("abcabc"));
18
- });
19
- });
@@ -1,80 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- analyzeFn,
4
- numLit,
5
- strLit,
6
- numVar,
7
- gtNum,
8
- v,
9
- litValue,
10
- termToString,
11
- formatShape,
12
- abs,
13
- unknown,
14
- } from "../index.ts";
15
-
16
- describe("HOF map/reduce from real source", () => {
17
- it("map doubles literals: [1,2,3].map(x=>x*2) → number[] with joined elem", () => {
18
- const src = `
19
- function doubleAll(xs) {
20
- return xs.map((x) => x * 2);
21
- }
22
- `;
23
- // 实参数组:arr(number)
24
- const arr = abs({ k: "arr", element: numLit(1) }, undefined, undefined, "exact");
25
- const r = analyzeFn(src, "doubleAll", [arr]);
26
- expect(r.shape.k).toBe("arr");
27
- if (r.shape.k !== "arr") return;
28
- // x=1, x*2=2
29
- expect(litValue(r.shape.element)).toBe(2);
30
- });
31
-
32
- it("map on symbolic element: Arr(number) map x=>x+1 under Φ elem>0", () => {
33
- // 元素带约束的数组:用 numVar 作为 element 的 term/pred
34
- const elem = {
35
- shape: { k: "prim" as const, type: "number" as const },
36
- term: { op: "var" as const, id: "e" },
37
- pred: { op: "gt" as const, a: { op: "var" as const, id: "e" }, b: { op: "lit" as const, value: 0 } },
38
- conf: "path" as const,
39
- };
40
- const arr = abs({ k: "arr", element: elem }, undefined, undefined, "path");
41
- const src = `
42
- function incAll(xs) {
43
- return xs.map((x) => x + 1);
44
- }
45
- `;
46
- const r = analyzeFn(src, "incAll", [arr]);
47
- expect(r.shape.k).toBe("arr");
48
- if (r.shape.k !== "arr") return;
49
- const el = r.shape.element;
50
- expect(termToString(el.term!)).toBe("(e + 1)");
51
- expect(el.pred!.op).toBe("gt");
52
- });
53
-
54
- it("reduce sum of literals: [1,2,3].reduce((a,n)=>a+n,0) → 6", () => {
55
- const src = `
56
- function sum(xs) {
57
- return xs.reduce((acc, n) => acc + n, 0);
58
- }
59
- `;
60
- const arr = abs({ k: "arr", element: numLit(1) }, undefined, undefined, "exact");
61
- // 用字面量元素 1 反复加不够 —— 用 tuple 语义:我们用 arr(number) 时元素是 1
62
- // 更好:传 tuple
63
- // Phase A:reduce 对 arr(element) 做不动点:0+1=1, 1+1=2, ... 会收敛到 number
64
- const r = analyzeFn(src, "sum", [arr]);
65
- // 0+1=1 exact first iter; join(0,1) 丢 term → number path
66
- // 或者若 first next=1, join(0,1) → number
67
- expect(r.shape).toEqual({ k: "prim", type: "number" });
68
- });
69
-
70
- it("filter preserves element type", () => {
71
- const src = `
72
- function keep(xs) {
73
- return xs.filter((x) => x > 0);
74
- }
75
- `;
76
- const arr = abs({ k: "arr", element: numLit(5) }, undefined, undefined, "exact");
77
- const r = analyzeFn(src, "keep", [arr]);
78
- expect(r.shape.k).toBe("arr");
79
- });
80
- });
@@ -1,30 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { collectAbsInlays } from "../inlay.ts";
3
-
4
- describe("collectAbsInlays", () => {
5
- it("shows param constraint and return Abs", () => {
6
- const src = `
7
- function needsPositive(x) {
8
- if (x > 0) return x;
9
- return 0;
10
- }
11
- `;
12
- const inlays = collectAbsInlays(src);
13
- expect(inlays.length).toBeGreaterThan(0);
14
- const param = inlays.find((i) => i.kind === "parameter");
15
- expect(param).toBeDefined();
16
- expect(param!.label).toContain(">");
17
- const ret = inlays.find((i) => i.kind === "type");
18
- expect(ret).toBeDefined();
19
- expect(ret!.label).toContain(":");
20
- });
21
-
22
- it("shows scale return term", () => {
23
- const src = `function scale(x) { return x + 1; }\n`;
24
- const inlays = collectAbsInlays(src);
25
- const ret = inlays.find((i) => i.kind === "type");
26
- expect(ret).toBeDefined();
27
- // generalize 后是符号项 A1
28
- expect(ret!.label).toContain("A1 + 1");
29
- });
30
- });
@@ -1,77 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- analyzeFn,
4
- numLit,
5
- litValue,
6
- } from "../index.ts";
7
-
8
- describe("language: class / instanceof / async", () => {
9
- it("class + new → brand with methods", () => {
10
- const src = `
11
- class Point {
12
- constructor(x) { this.x = x; }
13
- dist() { return this.x; }
14
- }
15
- function main() {
16
- const p = new Point(3);
17
- return p;
18
- }
19
- `;
20
- const r = analyzeFn(src, "main", []);
21
- expect(r.shape.k).toBe("brand");
22
- if (r.shape.k === "brand") {
23
- expect(r.shape.name).toBe("Point");
24
- }
25
- });
26
-
27
- it("instanceof brand name → true/false exact", () => {
28
- const src = `
29
- class Point { dist() { return 1; } }
30
- class Other { dist() { return 2; } }
31
- function check() {
32
- const p = new Point();
33
- return p instanceof Point;
34
- }
35
- function checkOther() {
36
- const p = new Point();
37
- return p instanceof Other;
38
- }
39
- `;
40
- const r1 = analyzeFn(src, "check", []);
41
- expect(litValue(r1)).toBe(true);
42
- expect(r1.conf).toBe("exact");
43
- const r2 = analyzeFn(src, "checkOther", []);
44
- expect(litValue(r2)).toBe(false);
45
- });
46
-
47
- it("async function returns eff promise", () => {
48
- const src = `
49
- async function load(id) {
50
- return id + 1;
51
- }
52
- `;
53
- const r = analyzeFn(src, "load", [numLit(5)]);
54
- expect(r.shape.k).toBe("eff");
55
- if (r.shape.k === "eff") {
56
- expect(r.shape.eff).toBe("promise");
57
- expect(litValue(r.shape.inner)).toBe(6);
58
- }
59
- });
60
-
61
- it("await unwraps promise", () => {
62
- const src = `
63
- async function load(id) {
64
- return id + 1;
65
- }
66
- async function twice(id) {
67
- const a = await load(id);
68
- return a + 1;
69
- }
70
- `;
71
- const r = analyzeFn(src, "twice", [numLit(5)]);
72
- expect(r.shape.k).toBe("eff");
73
- if (r.shape.k === "eff") {
74
- expect(litValue(r.shape.inner)).toBe(7);
75
- }
76
- });
77
- });