@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,41 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { typeofAbs, negAbs, notAbs, strictEqAbs } from "../surface.ts";
3
- import { numLit, num, abs, strLit, boolLit } from "../abs.ts";
4
- import { lit, v } from "../term.ts";
5
- import { gt, pTrue } from "../pred.ts";
6
- import { typeValueToString } from "../../type-value.ts";
7
- import { absToTypeValue } from "../bridge.ts";
8
-
9
- describe("algebra surface ops", () => {
10
- it("typeof of primitives and null", () => {
11
- expect(typeValueToString(absToTypeValue(typeofAbs(numLit(1))))).toBe('"number"');
12
- expect(typeValueToString(absToTypeValue(typeofAbs(strLit("x"))))).toBe('"string"');
13
- expect(typeValueToString(absToTypeValue(typeofAbs(abs({ k: "unknown" }, lit(null), pTrue, "exact"))))).toBe('"object"');
14
- expect(typeValueToString(absToTypeValue(typeofAbs(abs({ k: "fn", params: [] }, undefined, undefined, "exact"))))).toBe('"function"');
15
- });
16
-
17
- it("typeof of unknown is abstract string (JS always returns string)", () => {
18
- const r = typeofAbs(abs({ k: "unknown" }, undefined, undefined, "partial"));
19
- expect(r.shape).toEqual({ k: "prim", type: "string" });
20
- });
21
-
22
- it("neg folds and flips bounds", () => {
23
- expect(typeValueToString(absToTypeValue(negAbs(numLit(5))))).toBe("-5");
24
- const x = abs(num().shape, v("x"), gt(v("x"), lit(0)), "path");
25
- const nx = negAbs(x);
26
- expect(nx.term).toBeDefined();
27
- expect(nx.pred).toBeDefined();
28
- });
29
-
30
- it("not folds literals including undefined", () => {
31
- expect(typeValueToString(absToTypeValue(notAbs(boolLit(false))))).toBe("true");
32
- expect(typeValueToString(absToTypeValue(notAbs(abs({ k: "unknown" }, lit(undefined), pTrue, "exact"))))).toBe("true");
33
- });
34
-
35
- it("strictEq nullish vs number is false", () => {
36
- const n = abs(num().shape, undefined, undefined, "exact");
37
- const nul = abs({ k: "unknown" }, lit(null), pTrue, "exact");
38
- expect(strictEqAbs(n, nul)).toBe(false);
39
- expect(strictEqAbs(numLit(1), numLit(1))).toBe(true);
40
- });
41
- });
@@ -1,130 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { analyzeFn, numLit, litValue, formatShape } from "../index.ts";
3
-
4
- describe("this method body + inheritance", () => {
5
- it("method reads this field set in constructor", () => {
6
- const src = `
7
- class Counter {
8
- constructor(n) { this.n = n; }
9
- get() { return this.n; }
10
- }
11
- function main() {
12
- const c = new Counter(3);
13
- return c.get();
14
- }
15
- `;
16
- const r = analyzeFn(src, "main", []);
17
- expect(litValue(r)).toBe(3);
18
- expect(r.conf).toBe("exact");
19
- });
20
-
21
- it("method arithmetic on this", () => {
22
- const src = `
23
- class Acc {
24
- constructor(n) { this.n = n; }
25
- add(k) { return this.n + k; }
26
- }
27
- function main() {
28
- return new Acc(10).add(5);
29
- }
30
- `;
31
- const r = analyzeFn(src, "main", []);
32
- expect(litValue(r)).toBe(15);
33
- });
34
-
35
- it("inherited method via super class shape", () => {
36
- const src = `
37
- class Base {
38
- hello() { return "hi"; }
39
- }
40
- class Child extends Base {
41
- hello() { return "child"; }
42
- }
43
- function main() {
44
- return new Child().hello();
45
- }
46
- `;
47
- const r = analyzeFn(src, "main", []);
48
- // 子类覆写
49
- expect(litValue(r)).toBe("child");
50
- });
51
-
52
- it("inherited method not overridden", () => {
53
- const src = `
54
- class Base {
55
- hello() { return "hi"; }
56
- n() { return 1; }
57
- }
58
- class Child extends Base {
59
- hello() { return "child"; }
60
- }
61
- function main() {
62
- return new Child().n();
63
- }
64
- `;
65
- const r = analyzeFn(src, "main", []);
66
- expect(litValue(r)).toBe(1);
67
- });
68
-
69
- it("instanceof super class name → true", () => {
70
- const src = `
71
- class Base { x() { return 1; } }
72
- class Child extends Base { y() { return 2; } }
73
- function main() {
74
- return new Child() instanceof Base;
75
- }
76
- `;
77
- const r = analyzeFn(src, "main", []);
78
- expect(litValue(r)).toBe(true);
79
- });
80
-
81
- it("super.method() dispatches to parent", () => {
82
- const src = `
83
- class Base {
84
- hello() { return "hi"; }
85
- }
86
- class Child extends Base {
87
- hello() { return super.hello() + "!"; }
88
- }
89
- function main() {
90
- return new Child().hello();
91
- }
92
- `;
93
- const r = analyzeFn(src, "main", []);
94
- expect(litValue(r)).toBe("hi!");
95
- expect(r.conf).toBe("exact");
96
- });
97
-
98
- it("inherited constructor writes this fields", () => {
99
- const src = `
100
- class Base {
101
- constructor(n) { this.n = n; }
102
- }
103
- class Child extends Base {
104
- double() { return this.n * 2; }
105
- }
106
- function main() {
107
- return new Child(4).double();
108
- }
109
- `;
110
- const r = analyzeFn(src, "main", []);
111
- expect(litValue(r)).toBe(8);
112
- });
113
-
114
- it("super in multi-level chain", () => {
115
- const src = `
116
- class A { m() { return 1; } }
117
- class B extends A {
118
- m() { return super.m() + 1; }
119
- }
120
- class C extends B {
121
- m() { return super.m() + 1; }
122
- }
123
- function main() {
124
- return new C().m();
125
- }
126
- `;
127
- const r = analyzeFn(src, "main", []);
128
- expect(litValue(r)).toBe(3);
129
- });
130
- });
@@ -1,49 +0,0 @@
1
- /**
2
- * Abs 上的一等函数:shape 是 fn,实现在旁路(不污染 Shape)。
3
- * 与 term-registry 同一纪律:不给共享单例挂 impl。
4
- */
5
-
6
- import type { Node } from "@babel/types";
7
- import type { Abs } from "./abs.ts";
8
- import type { AstEnv } from "./ast-eval.ts";
9
-
10
- export type AbsFnImpl = {
11
- params: string[];
12
- body: Node;
13
- async?: boolean;
14
- /** 声明时捕获的环境(闭包) */
15
- env?: AstEnv;
16
- kind?: string;
17
- /** 调用时直接派发(mock withArgs 等),优先于 body */
18
- apply?: (args: Abs[]) => Abs;
19
- /**
20
- * Optional content key for cache fingerprints. formatAbs cannot see
21
- * WeakMap-side mock semantics (returns/withArgs/callsFake), so hosts that
22
- * build mocks should stamp a stable fingerprint here.
23
- */
24
- fingerprint?: string;
25
- };
26
-
27
- const implByAbs = new WeakMap<object, AbsFnImpl>();
28
-
29
- export function attachFnImpl(a: Abs, impl: AbsFnImpl): void {
30
- if (a && typeof a === "object") implByAbs.set(a as object, impl);
31
- }
32
-
33
- export function getFnImpl(a: Abs): AbsFnImpl | undefined {
34
- if (!a || typeof a !== "object") return undefined;
35
- return implByAbs.get(a as object);
36
- }
37
-
38
- /** 造一个带实现的 Abs 函数值 */
39
- export function absFunction(
40
- params: string[],
41
- impl: Omit<AbsFnImpl, "params">,
42
- ): Abs {
43
- const a: Abs = {
44
- shape: { k: "fn", params },
45
- conf: "exact",
46
- };
47
- attachFnImpl(a, { params, ...impl });
48
- return a;
49
- }
@@ -1,139 +0,0 @@
1
- /**
2
- * Abs 模块面(无 fs):import 绑定 + export 收集。
3
- * 解析路径/读文件在 host;core 只吃「specifier → 导出表」。
4
- */
5
-
6
- import type { File, ImportDeclaration } from "@babel/types";
7
- import type { Abs } from "./abs.ts";
8
- import { unknown, obj } from "./abs.ts";
9
- import type { AstEnv } from "./ast-eval.ts";
10
- import { absFunction } from "./abs-fn.ts";
11
-
12
- export type AbsModuleExports = {
13
- named: Record<string, Abs>;
14
- default?: Abs;
15
- };
16
-
17
- /** 把 import 说明符绑定进 env(宿主已求值依赖) */
18
- export function bindImports(
19
- node: ImportDeclaration,
20
- env: AstEnv,
21
- modules: Record<string, AbsModuleExports>,
22
- ): void {
23
- const mod = modules[node.source.value];
24
- if (!mod) {
25
- for (const s of node.specifiers) {
26
- env.vars.set(s.local.name, unknown);
27
- }
28
- return;
29
- }
30
- for (const s of node.specifiers) {
31
- if (s.type === "ImportDefaultSpecifier") {
32
- env.vars.set(s.local.name, mod.default ?? unknown);
33
- } else if (s.type === "ImportSpecifier") {
34
- const imported = s.imported.type === "Identifier" ? s.imported.name : String(s.imported);
35
- env.vars.set(s.local.name, mod.named[imported] ?? unknown);
36
- } else if (s.type === "ImportNamespaceSpecifier") {
37
- const slots: Record<string, { value: Abs }> = {};
38
- for (const [k, v] of Object.entries(mod.named)) slots[k] = { value: v };
39
- if (mod.default) slots["default"] = { value: mod.default };
40
- env.vars.set(s.local.name, obj(slots));
41
- }
42
- }
43
- }
44
-
45
- function fnToAbs(env: AstEnv, name: string): Abs | undefined {
46
- const impl = env.fns.get(name);
47
- if (!impl) return undefined;
48
- return absFunction(impl.params, {
49
- body: impl.body,
50
- async: impl.async,
51
- env,
52
- });
53
- }
54
-
55
- function lookupExport(env: AstEnv, name: string): Abs | undefined {
56
- if (env.vars.has(name)) return env.vars.get(name);
57
- return fnToAbs(env, name);
58
- }
59
-
60
- /**
61
- * 从已求值 env + AST 收集 ESM 导出。
62
- * 支持:export function/const、export { a, b as c }、export default(具名)、
63
- * 以及带 source 的 re-export(`export { a } from "mod"` / `export * from "mod"`——
64
- * 需 host 传入已求值 modules)。
65
- */
66
- export function collectAbsExports(
67
- file: File,
68
- env: AstEnv,
69
- modules?: Record<string, AbsModuleExports>,
70
- ): AbsModuleExports {
71
- const named: Record<string, Abs> = {};
72
- let defaultExport: Abs | undefined;
73
-
74
- for (const stmt of file.program.body) {
75
- if (stmt.type === "ExportNamedDeclaration") {
76
- // re-export:`export { a, b as c } from "mod"`
77
- if (stmt.source && modules) {
78
- const mod = modules[stmt.source.value];
79
- if (mod) {
80
- for (const spec of stmt.specifiers) {
81
- if (spec.type !== "ExportSpecifier") continue;
82
- const local = spec.local.name;
83
- const exported =
84
- spec.exported.type === "Identifier" ? spec.exported.name : String(spec.exported);
85
- const v = local === "default" ? mod.default : mod.named[local];
86
- if (v === undefined) continue;
87
- if (exported === "default") defaultExport = v;
88
- else named[exported] = v;
89
- }
90
- }
91
- continue;
92
- }
93
- const decl = stmt.declaration;
94
- if (decl) {
95
- if (decl.type === "FunctionDeclaration" && decl.id) {
96
- const v = lookupExport(env, decl.id.name);
97
- if (v) named[decl.id.name] = v;
98
- } else if (decl.type === "ClassDeclaration" && decl.id) {
99
- const v = lookupExport(env, decl.id.name);
100
- if (v) named[decl.id.name] = v;
101
- } else if (decl.type === "VariableDeclaration") {
102
- for (const d of decl.declarations) {
103
- if (d.id.type === "Identifier") {
104
- const v = lookupExport(env, d.id.name);
105
- if (v) named[d.id.name] = v;
106
- }
107
- }
108
- }
109
- }
110
- for (const spec of stmt.specifiers) {
111
- if (spec.type !== "ExportSpecifier") continue;
112
- const local = spec.local.name;
113
- const exported =
114
- spec.exported.type === "Identifier" ? spec.exported.name : String(spec.exported);
115
- const v = lookupExport(env, local);
116
- if (v) named[exported] = v;
117
- }
118
- } else if (stmt.type === "ExportAllDeclaration" && stmt.source && modules) {
119
- // export * from "mod":并入 named(不含 default,与 ESM 一致)
120
- const mod = modules[stmt.source.value];
121
- if (mod?.named) {
122
- for (const [k, v] of Object.entries(mod.named)) named[k] = v;
123
- }
124
- } else if (stmt.type === "ExportDefaultDeclaration") {
125
- const d = stmt.declaration;
126
- if (d.type === "FunctionDeclaration") {
127
- defaultExport = lookupExport(env, d.id ? d.id.name : "default");
128
- } else if (d.type === "ClassDeclaration" && d.id) {
129
- defaultExport = lookupExport(env, d.id.name);
130
- } else if (d.type === "Identifier") {
131
- defaultExport = lookupExport(env, d.name);
132
- }
133
- }
134
- }
135
-
136
- const result: AbsModuleExports = { named };
137
- if (defaultExport) result.default = defaultExport;
138
- return result;
139
- }
@@ -1,206 +0,0 @@
1
- /** 抽象值 Abs = 形状 × 项 × 约束 × 置信度 */
2
-
3
- import type { Term, LiteralValue } from "./term.ts";
4
- import { lit, simplifyTerm, termEquals, termToString } from "./term.ts";
5
- import type { Pred, PrimName } from "./pred.ts";
6
- import {
7
- and,
8
- predToString,
9
- pTrue,
10
- ptypeof,
11
- implies,
12
- type Phi,
13
- } from "./pred.ts";
14
-
15
- export type Confidence = "exact" | "path" | "widened" | "mock" | "partial" | "opaque";
16
-
17
- export type Shape =
18
- | { k: "never" }
19
- /**
20
- * any:JS 里可以是任意值(无约束参数)。
21
- * 运算按真实 JS 语义取并集,不是「分析失败」。
22
- */
23
- | { k: "any" }
24
- /** unknown:分析拿不到信息(求值失败/泄漏),不是「任意值」 */
25
- | { k: "unknown" }
26
- | { k: "prim"; type: PrimName }
27
- | {
28
- k: "obj";
29
- slots: Record<string, { value: Abs; optional?: boolean; readonly?: boolean }>;
30
- index?: { key: Abs; value: Abs };
31
- open?: boolean;
32
- }
33
- | { k: "arr"; element: Abs }
34
- | { k: "tuple"; elements: Abs[]; rest?: Abs }
35
- | { k: "fn"; params: string[]; name?: string; paramTypes?: Abs[]; returnType?: Abs }
36
- | { k: "brand"; name: string; shape: Abs }
37
- | { k: "eff"; eff: "promise" | "generator"; inner: Abs }
38
- | { k: "sum"; members: Abs[] };
39
-
40
- export type Abs = {
41
- shape: Shape;
42
- term?: Term;
43
- pred?: Pred;
44
- conf: Confidence;
45
- };
46
-
47
- // --- 工厂 ---
48
-
49
- export const never: Abs = { shape: { k: "never" }, conf: "exact" };
50
- /** 分析无信息 */
51
- export const unknown: Abs = { shape: { k: "unknown" }, conf: "partial" };
52
-
53
- /** 带 term 的 any(generalize type-var) */
54
- export function anyVar(id: string, conf: Confidence = "path"): Abs {
55
- return { shape: { k: "any" }, term: { op: "var", id }, conf };
56
- }
57
-
58
- export function num(): Abs {
59
- return { shape: { k: "prim", type: "number" }, conf: "exact" };
60
- }
61
-
62
- export function str(): Abs {
63
- return { shape: { k: "prim", type: "string" }, conf: "exact" };
64
- }
65
-
66
- export function bool(): Abs {
67
- return { shape: { k: "prim", type: "boolean" }, conf: "exact" };
68
- }
69
-
70
- export function numLit(value: number): Abs {
71
- return {
72
- shape: { k: "prim", type: "number" },
73
- term: lit(value),
74
- pred: pTrue,
75
- conf: "exact",
76
- };
77
- }
78
-
79
- export function strLit(value: string): Abs {
80
- return {
81
- shape: { k: "prim", type: "string" },
82
- term: lit(value),
83
- pred: pTrue,
84
- conf: "exact",
85
- };
86
- }
87
-
88
- export function boolLit(value: boolean): Abs {
89
- return {
90
- shape: { k: "prim", type: "boolean" },
91
- term: lit(value),
92
- pred: pTrue,
93
- conf: "exact",
94
- };
95
- }
96
-
97
- /** 带项的符号数,例如参数 x */
98
- export function numVar(id: string, pred?: Pred, conf: Confidence = "path"): Abs {
99
- return {
100
- shape: { k: "prim", type: "number" },
101
- term: { op: "var", id },
102
- pred: pred ?? pTrue,
103
- conf,
104
- };
105
- }
106
-
107
- export function obj(
108
- slots: Record<string, { value: Abs; optional?: boolean }>,
109
- ): Abs {
110
- return { shape: { k: "obj", slots }, conf: "exact" };
111
- }
112
-
113
- export function confJoin(a: Confidence, b: Confidence): Confidence {
114
- const rank: Confidence[] = ["exact", "path", "widened", "mock", "partial", "opaque"];
115
- const ia = rank.indexOf(a);
116
- const ib = rank.indexOf(b);
117
- // 取更差的
118
- return rank[Math.max(ia < 0 ? 5 : ia, ib < 0 ? 5 : ib)]!;
119
- }
120
-
121
- export function absToString(a: Abs): string {
122
- const parts: string[] = [shapeToString(a.shape)];
123
- if (a.term) parts.push(`term=${termToString(a.term)}`);
124
- if (a.pred && a.pred.op !== "true") parts.push(predToString(a.pred));
125
- parts.push(`#${a.conf}`);
126
- return parts.join(" ");
127
- }
128
-
129
- export function shapeToString(s: Shape): string {
130
- switch (s.k) {
131
- case "never":
132
- return "never";
133
- case "any":
134
- return "any";
135
- case "unknown":
136
- return "unknown";
137
- case "prim":
138
- return s.type;
139
- case "obj": {
140
- const entries = Object.entries(s.slots).map(
141
- ([k, slot]) =>
142
- `${k}${slot.optional ? "?" : ""}: ${absToString(slot.value)}`,
143
- );
144
- return `{ ${entries.join(", ")} }`;
145
- }
146
- case "arr":
147
- return `${shapeToString(s.element.shape)}[]`;
148
- case "tuple":
149
- return `[${s.elements.map((e) => shapeToString(e.shape)).join(", ")}]`;
150
- case "fn":
151
- return `fn(${s.params.join(", ")})${s.name ? ` ${s.name}` : ""}`;
152
- case "brand":
153
- return s.name;
154
- case "eff":
155
- return `${s.eff}<${shapeToString(s.inner.shape)}>`;
156
- case "sum":
157
- return s.members.map(absToString).join(" | ");
158
- default:
159
- return "·";
160
- }
161
- }
162
-
163
- /** 从 term 反推 prim shape */
164
- export function shapeOfTerm(t: Term): Shape {
165
- if (t.op === "lit") {
166
- const v = t.value;
167
- if (typeof v === "number") return { k: "prim", type: "number" };
168
- if (typeof v === "string") return { k: "prim", type: "string" };
169
- if (typeof v === "boolean") return { k: "prim", type: "boolean" };
170
- if (typeof v === "bigint") return { k: "prim", type: "bigint" };
171
- return { k: "unknown" };
172
- }
173
- return { k: "unknown" };
174
- }
175
-
176
- /** 构造带项的结果 Abs;pred 相对 term */
177
- export function abs(
178
- shape: Shape,
179
- term: Term | undefined,
180
- pred: Pred | undefined,
181
- conf: Confidence,
182
- ): Abs {
183
- return {
184
- shape,
185
- term,
186
- pred: pred && pred.op !== "true" ? pred : undefined,
187
- conf,
188
- };
189
- }
190
-
191
- export function isNumPrim(a: Abs): boolean {
192
- return a.shape.k === "prim" && a.shape.type === "number";
193
- }
194
-
195
- export function isStrPrim(a: Abs): boolean {
196
- return a.shape.k === "prim" && a.shape.type === "string";
197
- }
198
-
199
- /** 置信度:字面量全确定 */
200
- export function isExactLit(a: Abs): boolean {
201
- return a.conf === "exact" && a.term?.op === "lit";
202
- }
203
-
204
- export function litValue(a: Abs): LiteralValue | undefined {
205
- return a.term?.op === "lit" ? a.term.value : undefined;
206
- }