@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,27 +0,0 @@
1
- /**
2
- * Session-memo content key. Not cryptographic: dual 32-bit FNV-1a mix + length
3
- * keeps birthday collisions negligible for LRU-sized caches (hundreds of entries)
4
- * without paying for a full digest on every edit.
5
- */
6
- let lastHashSource: string | undefined;
7
- let lastHashOut: string | undefined;
8
-
9
- export function hashSource(s: string): string {
10
- if (s === lastHashSource && lastHashOut !== undefined) return lastHashOut;
11
- let h1 = 2166136261;
12
- let h2 = 0x9e3779b9;
13
- for (let i = 0; i < s.length; i++) {
14
- const c = s.charCodeAt(i);
15
- h1 ^= c;
16
- h1 = Math.imul(h1, 16777619);
17
- h2 = Math.imul(h2 ^ c, 16777619);
18
- }
19
- lastHashSource = s;
20
- lastHashOut = `${(h1 >>> 0).toString(36)}-${(h2 >>> 0).toString(36)}_${s.length.toString(36)}`;
21
- return lastHashOut;
22
- }
23
-
24
- export function resetHashSourceCache(): void {
25
- lastHashSource = undefined;
26
- lastHashOut = undefined;
27
- }
@@ -1,34 +0,0 @@
1
- export * from "./term.ts";
2
- export * from "./pred.ts";
3
- export * from "./phi.ts";
4
- export * from "./abs.ts";
5
- export * from "./abs-fn.ts";
6
- export * from "./arithmetic.ts";
7
- export * from "./surface.ts";
8
- export * from "./builtins.ts";
9
- export * from "./methods.ts";
10
- export * from "./leak.ts";
11
- export * from "./objects.ts";
12
- export * from "./leq.ts";
13
- export * from "./ast-eval.ts";
14
- export * from "./format.ts";
15
- export * from "./generalize.ts";
16
- export * from "./diagnostics.ts";
17
- export * from "./template.ts";
18
- export * from "./language.ts";
19
- export * from "./parse-source.ts";
20
- export * from "./hash-source.ts";
21
- export * from "./stable-source-key.ts";
22
- export * from "./fn-fp.ts";
23
- export * from "./load-deps-fp.ts";
24
- export * from "./check.ts";
25
- export * from "./check-report.ts";
26
- export * from "./refine.ts";
27
- export * from "./constraint.ts";
28
- export * from "./inlay.ts";
29
- export * from "./denote.ts";
30
- export * from "./abs-modules.ts";
31
- export * from "./exec/index.ts";
32
- // modules/fs/path 属于 host(service/cli),不进代数
33
- export * from "./bridge.ts";
34
-
@@ -1,198 +0,0 @@
1
- /**
2
- * Abs inlay hint:把无损约束内联到源码位置。
3
- * 不是 TS 风格 type annotation 复读,而是 term/pred/conf 的计算结果。
4
- */
5
-
6
- import type { Node, FunctionDeclaration } from "@babel/types";
7
- import { parseSource as parse } from "./parse-source.ts";
8
- import { generalizeFromAst } from "./generalize.ts";
9
- import { formatShape } from "./format.ts";
10
- import { predToString, type Pred } from "./pred.ts";
11
- import { termToString } from "./term.ts";
12
-
13
- export type AbsInlay = {
14
- /** 1-based 行号 */
15
- line: number;
16
- /** 0-based 列(label 插入点) */
17
- character: number;
18
- label: string;
19
- kind: "type" | "parameter";
20
- };
21
-
22
- function listFunctions(source: string): Array<{ name: string; node: Node }> {
23
- const file = parse(source);
24
- const out: Array<{ name: string; node: Node }> = [];
25
- const visitDecl = (decl: Node): void => {
26
- if (decl.type === "FunctionDeclaration" && (decl as FunctionDeclaration).id) {
27
- const fd = decl as FunctionDeclaration;
28
- out.push({ name: fd.id!.name, node: fd });
29
- }
30
- if (decl.type === "VariableDeclaration") {
31
- for (const d of (decl as any).declarations ?? []) {
32
- if (
33
- d.id?.type === "Identifier" &&
34
- d.init &&
35
- (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")
36
- ) {
37
- out.push({ name: d.id.name, node: d.init });
38
- }
39
- }
40
- }
41
- };
42
- for (const stmt of file.program.body) {
43
- if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
44
- visitDecl(stmt.declaration as Node);
45
- } else if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
46
- visitDecl(stmt.declaration as Node);
47
- } else {
48
- visitDecl(stmt);
49
- }
50
- }
51
- return out;
52
- }
53
-
54
- /** 从函数体抽 param 的前置 Pred(与 check 同源逻辑的轻量版) */
55
- function paramPreds(
56
- source: string,
57
- fnName: string,
58
- paramNames: string[],
59
- ): Map<string, Pred[]> {
60
- const byIndex = new Map<number, Pred[]>();
61
- const file = parse(source);
62
- const paramIndex = new Map(paramNames.map((p, i) => [p, i]));
63
-
64
- const pushCmp = (
65
- test: Record<string, unknown>,
66
- consequent: Record<string, unknown> | undefined,
67
- ): void => {
68
- if (test?.type !== "BinaryExpression") return;
69
- const left = test.left as { type?: string; name?: string };
70
- const right = test.right as { type?: string; value?: number };
71
- const op = test.operator as string;
72
- if (
73
- left?.type !== "Identifier" ||
74
- !left.name ||
75
- !paramIndex.has(left.name) ||
76
- right?.type !== "NumericLiteral" ||
77
- typeof right.value !== "number"
78
- ) {
79
- return;
80
- }
81
- const isReturnParam =
82
- consequent?.type === "ReturnStatement" &&
83
- (consequent.argument as { type?: string; name?: string })?.type === "Identifier" &&
84
- (consequent.argument as { name?: string }).name === left.name;
85
- if (!isReturnParam) return;
86
- const idx = paramIndex.get(left.name)!;
87
- const t = { op: "var" as const, id: left.name };
88
- const b = { op: "lit" as const, value: right.value };
89
- let pred: Pred | undefined;
90
- if (op === ">") pred = { op: "gt", a: t, b };
91
- else if (op === ">=") pred = { op: "ge", a: t, b };
92
- else if (op === "<") pred = { op: "lt", a: t, b };
93
- else if (op === "<=") pred = { op: "le", a: t, b };
94
- if (!pred) return;
95
- const list = byIndex.get(idx) ?? [];
96
- list.push(pred);
97
- byIndex.set(idx, list);
98
- };
99
-
100
- const visit = (n: unknown): void => {
101
- if (!n || typeof n !== "object") return;
102
- const obj = n as Record<string, unknown> & { type?: string };
103
- if (obj.type === "IfStatement") {
104
- const test = obj.test as Record<string, unknown>;
105
- const consequent = obj.consequent as Record<string, unknown> | undefined;
106
- pushCmp(test, consequent);
107
- if (test?.type === "LogicalExpression" && test.operator === "&&") {
108
- pushCmp(test.left as Record<string, unknown>, consequent);
109
- pushCmp(test.right as Record<string, unknown>, consequent);
110
- }
111
- }
112
- for (const key of Object.keys(obj)) {
113
- if (key === "loc" || key === "start" || key === "end") continue;
114
- const val = obj[key];
115
- if (Array.isArray(val)) val.forEach(visit);
116
- else if (val && typeof val === "object") visit(val);
117
- }
118
- };
119
- visit(file);
120
-
121
- const byName = new Map<string, Pred[]>();
122
- for (const [idx, preds] of byIndex) {
123
- const name = paramNames[idx];
124
- if (name) byName.set(name, preds);
125
- }
126
- return byName;
127
- }
128
-
129
- /**
130
- * 收集源码中函数签名的 Abs inlay:
131
- * - 参数后:前置约束(声明 refine 优先;否则从 if 推)
132
- * - `)` 后:返回 shape + term(类型即计算)
133
- */
134
- export function collectAbsInlays(
135
- source: string,
136
- refineOpts?: { loadModule?: (spec: string, fromFile: string) => string | undefined; fromFile?: string },
137
- ): AbsInlay[] {
138
- const inlays: AbsInlay[] = [];
139
- for (const { name, node } of listFunctions(source)) {
140
- let g: ReturnType<typeof generalizeFromAst>;
141
- try {
142
- g = generalizeFromAst(name, source, refineOpts ? { refine: refineOpts } : {});
143
- } catch {
144
- continue;
145
- }
146
- if (!g) continue;
147
-
148
- const params = g.params;
149
- // 声明契约优先;if 推断作补充
150
- const predsByName = new Map<string, Pred[]>();
151
- if (g.entryReqs) {
152
- for (const r of g.entryReqs) {
153
- predsByName.set(r.param, [r.pred]);
154
- }
155
- }
156
- for (const [k, v] of paramPreds(source, name, params)) {
157
- if (!predsByName.has(k)) predsByName.set(k, v);
158
- }
159
-
160
- const fnNode = node as any;
161
- const paramList: any[] = fnNode.params ?? [];
162
- for (let i = 0; i < paramList.length; i++) {
163
- const p = paramList[i];
164
- const pname = params[i] ?? (p?.name as string | undefined);
165
- if (!p?.loc || !pname) continue;
166
- const preds = predsByName.get(pname);
167
- if (preds && preds.length > 0) {
168
- const text = preds.map(predToString).join(" ∧ ");
169
- inlays.push({
170
- line: p.loc.end.line,
171
- character: p.loc.end.column,
172
- label: ` where ${text}`,
173
- kind: "parameter",
174
- });
175
- }
176
- }
177
-
178
- // 返回:插在函数体 `{` 前(类型即计算)
179
- const bodyLoc = fnNode.body?.loc;
180
- if (bodyLoc?.start) {
181
- const retShape = formatShape(g.symbolic);
182
- let label = `: ${retShape}`;
183
- if (g.symbolic.term && g.symbolic.term.op !== "lit") {
184
- label += ` = ${termToString(g.symbolic.term)}`;
185
- }
186
- if (g.symbolic.pred && g.symbolic.pred.op !== "true") {
187
- label += ` where ${predToString(g.symbolic.pred)}`;
188
- }
189
- inlays.push({
190
- line: bodyLoc.start.line,
191
- character: Math.max(0, bodyLoc.start.column),
192
- label: `${label} `,
193
- kind: "type",
194
- });
195
- }
196
- }
197
- return inlays;
198
- }
@@ -1,289 +0,0 @@
1
- /**
2
- * 语言覆盖:class / new / instanceof / this / async await。
3
- * brand 表示名义类;eff("promise") 表示异步效应。
4
- *
5
- * 方法体:ClassDef.methods 存 AST body,调用时在 this=receiver 下求值。
6
- */
7
-
8
- import type { Node } from "@babel/types";
9
- import type { Abs } from "./abs.ts";
10
- import { abs, confJoin, unknown } from "./abs.ts";
11
- import type { AstEnv } from "./ast-eval.ts";
12
-
13
- export type MethodDef = {
14
- name: string;
15
- params: string[];
16
- body: Node;
17
- kind?: string; // "constructor" | "method" | "get" | ...
18
- async?: boolean;
19
- };
20
-
21
- export type ClassDef = {
22
- name: string;
23
- instanceShape: Abs;
24
- ctorParams: string[];
25
- methods: Map<string, MethodDef>;
26
- superClass?: string;
27
- };
28
-
29
- type EnvWithClasses = AstEnv & { classes?: Map<string, ClassDef> };
30
-
31
- function classesOf(env: AstEnv): Map<string, ClassDef> {
32
- const e = env as EnvWithClasses;
33
- if (!e.classes) e.classes = new Map();
34
- return e.classes;
35
- }
36
-
37
- export function defineClass(env: AstEnv, def: ClassDef): void {
38
- classesOf(env).set(def.name, def);
39
- }
40
-
41
- export function getClass(env: AstEnv, name: string): ClassDef | undefined {
42
- return (env as EnvWithClasses).classes?.get(name) as ClassDef | undefined;
43
- }
44
-
45
- /** 沿继承链找类 */
46
- export function getClassChain(env: AstEnv, name: string): ClassDef[] {
47
- const chain: ClassDef[] = [];
48
- let cur: string | undefined = name;
49
- const seen = new Set<string>();
50
- while (cur && !seen.has(cur)) {
51
- seen.add(cur);
52
- const def = getClass(env, cur);
53
- if (!def) break;
54
- chain.push(def);
55
- cur = def.superClass;
56
- }
57
- return chain;
58
- }
59
-
60
- /** new C(...) → brand 实例;并跑 constructor 以写入字段 */
61
- export function instantiateClass(
62
- env: AstEnv,
63
- className: string,
64
- args: Abs[],
65
- evalBody?: (fn: { params: string[]; body: Node }, args: Abs[], thisVal: Abs, env: AstEnv) => Abs,
66
- ): Abs {
67
- const def = getClass(env, className);
68
- if (!def) {
69
- return abs(
70
- {
71
- k: "brand",
72
- name: className,
73
- shape: abs({ k: "obj", slots: {} }, undefined, undefined, "exact"),
74
- },
75
- undefined,
76
- undefined,
77
- "partial",
78
- );
79
- }
80
-
81
- // 先用声明 shape 建实例(含方法)
82
- let instance = abs(
83
- { k: "brand", name: className, shape: def.instanceShape },
84
- undefined,
85
- undefined,
86
- "path",
87
- );
88
-
89
- // constructor:自身优先;没有则沿继承链找父类构造
90
- const chain = getClassChain(env, className);
91
- let ctor: MethodDef | undefined;
92
- let ctorClass: ClassDef | undefined;
93
- for (const cls of chain) {
94
- const m = cls.methods.get("constructor");
95
- if (m) {
96
- ctor = m;
97
- ctorClass = cls;
98
- break;
99
- }
100
- }
101
- if (ctor && evalBody) {
102
- // 绑定 super → 父类(ctor 所在类的 superClass)
103
- const parentName = ctorClass?.superClass;
104
- const localEnv = parentName
105
- ? withSuperBinding(env, className, parentName)
106
- : env;
107
- const fields = evalBody(ctor, args, instance, localEnv);
108
- instance = mergeInstanceFields(instance, fields, className);
109
- }
110
-
111
- return instance;
112
- }
113
-
114
- /** 在 env 上绑定 super 类名,供 super.method() 派发 */
115
- function withSuperBinding(env: AstEnv, className: string, superName: string): AstEnv {
116
- return { ...env, currentOwner: className };
117
- }
118
-
119
- /** 读取当前 this 所属类的父类名 */
120
- export function superNameOf(env: AstEnv, className: string): string | undefined {
121
- return getClass(env, className)?.superClass;
122
- }
123
-
124
- /** constructor 副作用后的字段并入 brand.shape */
125
- function mergeInstanceFields(instance: Abs, fields: Abs, className: string): Abs {
126
- if (instance.shape.k !== "brand") return instance;
127
- const base = instance.shape.shape;
128
- const slots: Record<string, { value: Abs }> =
129
- base.shape.k === "obj" ? { ...base.shape.slots } : {};
130
-
131
- // fields 可能是更新后的 this(brand)或裸 obj
132
- const fieldObj =
133
- fields.shape.k === "brand" ? fields.shape.shape : fields;
134
- if (fieldObj.shape.k === "obj") {
135
- for (const [k, s] of Object.entries(fieldObj.shape.slots)) {
136
- slots[k] = s;
137
- }
138
- }
139
- return abs(
140
- {
141
- k: "brand",
142
- name: className,
143
- shape: abs({ k: "obj", slots }, undefined, undefined, "exact"),
144
- },
145
- undefined,
146
- undefined,
147
- instance.conf,
148
- );
149
- }
150
-
151
- /**
152
- * instanceof:沿继承链匹配 brand 名。
153
- */
154
- export function instanceOf(
155
- left: Abs,
156
- rightClassName: string,
157
- env?: AstEnv,
158
- ): Abs {
159
- if (left.shape.k === "brand") {
160
- const chainNames = env
161
- ? getClassChain(env, left.shape.name).map((c) => c.name)
162
- : [left.shape.name];
163
- if (chainNames.includes(rightClassName) || left.shape.name === rightClassName) {
164
- return { shape: { k: "prim", type: "boolean" }, term: litTrue(), conf: "exact" };
165
- }
166
- return { shape: { k: "prim", type: "boolean" }, term: litFalse(), conf: "exact" };
167
- }
168
- if (left.shape.k === "unknown") {
169
- return { shape: { k: "prim", type: "boolean" }, conf: "partial" };
170
- }
171
- return { shape: { k: "prim", type: "boolean" }, term: litFalse(), conf: "path" };
172
- }
173
-
174
- function litTrue() {
175
- return { op: "lit" as const, value: true };
176
- }
177
- function litFalse() {
178
- return { op: "lit" as const, value: false };
179
- }
180
-
181
- export function projectBrand(self: Abs, key: string): Abs {
182
- if (self.shape.k !== "brand") return unknown;
183
- const inner = self.shape.shape;
184
- if (inner.shape.k === "obj") {
185
- const slot = inner.shape.slots[key];
186
- if (slot) return slot.value;
187
- }
188
- return unknown;
189
- }
190
-
191
- /** 在 brand 上查找方法定义(含继承) */
192
- export function lookupMethod(
193
- env: AstEnv,
194
- receiver: Abs,
195
- methodName: string,
196
- ): MethodDef | undefined {
197
- if (receiver.shape.k !== "brand") return undefined;
198
- const chain = getClassChain(env, receiver.shape.name);
199
- for (const cls of chain) {
200
- const m = cls.methods.get(methodName);
201
- if (m) return m;
202
- }
203
- return undefined;
204
- }
205
-
206
- /** 沿继承链查找方法,返回定义与所在类名 */
207
- export function lookupMethodWithOwner(
208
- env: AstEnv,
209
- receiver: Abs,
210
- methodName: string,
211
- ): { def: MethodDef; owner: string } | undefined {
212
- if (receiver.shape.k !== "brand") return undefined;
213
- const chain = getClassChain(env, receiver.shape.name);
214
- for (const cls of chain) {
215
- const m = cls.methods.get(methodName);
216
- if (m) return { def: m, owner: cls.name };
217
- }
218
- return undefined;
219
- }
220
-
221
- /** super.method():从父类开始找(跳过当前类) */
222
- export function lookupSuperMethod(
223
- env: AstEnv,
224
- receiver: Abs,
225
- fromClass: string,
226
- methodName: string,
227
- ): { def: MethodDef; owner: string } | undefined {
228
- if (receiver.shape.k !== "brand") return undefined;
229
- const parent = superNameOf(env, fromClass) ?? getClass(env, fromClass)?.superClass;
230
- if (!parent) return undefined;
231
- const chain = getClassChain(env, parent);
232
- for (const cls of chain) {
233
- const m = cls.methods.get(methodName);
234
- if (m) return { def: m, owner: cls.name };
235
- }
236
- return undefined;
237
- }
238
-
239
- export function wrapPromise(inner: Abs): Abs {
240
- return abs(
241
- { k: "eff", eff: "promise", inner },
242
- undefined,
243
- undefined,
244
- confJoin(inner.conf, "path"),
245
- );
246
- }
247
-
248
- export function awaitAbs(v: Abs): Abs {
249
- if (v.shape.k === "eff" && v.shape.eff === "promise") {
250
- return v.shape.inner;
251
- }
252
- return v;
253
- }
254
-
255
- export function coerceAsyncReturn(value: Abs): Abs {
256
- if (value.shape.k === "eff") return value;
257
- return wrapPromise(value);
258
- }
259
-
260
- /** 从 ClassMethod 列表构造 methods map + instance shape */
261
- export function classFromMethods(
262
- name: string,
263
- methods: MethodDef[],
264
- superClass?: string,
265
- superShape?: Abs,
266
- ): ClassDef {
267
- const methodMap = new Map<string, MethodDef>();
268
- const slots: Record<string, { value: Abs }> = {};
269
- if (superShape?.shape.k === "obj") {
270
- for (const [k, s] of Object.entries(superShape.shape.slots)) {
271
- slots[k] = s;
272
- }
273
- }
274
- for (const m of methods) {
275
- methodMap.set(m.name, m);
276
- if (m.kind !== "constructor") {
277
- slots[m.name] = {
278
- value: abs({ k: "fn", params: m.params, name: m.name }, undefined, undefined, "exact"),
279
- };
280
- }
281
- }
282
- return {
283
- name,
284
- instanceShape: abs({ k: "obj", slots }, undefined, undefined, "exact"),
285
- ctorParams: methodMap.get("constructor")?.params ?? [],
286
- methods: methodMap,
287
- superClass,
288
- };
289
- }
@@ -1,68 +0,0 @@
1
- /**
2
- * 项(Term)防爆炸:深度/宽度阈值 → leak 为新鲜 var + 等式约束。
3
- */
4
-
5
- import type { Term } from "./term.ts";
6
- import { v, termToString, termEquals, app, lit } from "./term.ts";
7
- import type { Pred } from "./pred.ts";
8
- import { eq, and } from "./pred.ts";
9
- import type { Abs } from "./abs.ts";
10
- import { abs, confJoin } from "./abs.ts";
11
-
12
- export type LeakBudget = {
13
- maxDepth: number;
14
- maxNodes: number;
15
- };
16
-
17
- export const defaultLeakBudget: LeakBudget = {
18
- maxDepth: 6,
19
- maxNodes: 32,
20
- };
21
-
22
- export function termDepth(t: Term): number {
23
- if (t.op !== "app") return 1;
24
- return 1 + Math.max(0, ...t.args.map(termDepth));
25
- }
26
-
27
- export function termNodes(t: Term): number {
28
- if (t.op !== "app") return 1;
29
- return 1 + t.args.reduce((s, x) => s + termNodes(x), 0);
30
- }
31
-
32
- export function exceedsBudget(t: Term, budget: LeakBudget = defaultLeakBudget): boolean {
33
- return termDepth(t) > budget.maxDepth || termNodes(t) > budget.maxNodes;
34
- }
35
-
36
- let leakCounter = 0;
37
-
38
- export function resetLeakCounter(): void {
39
- leakCounter = 0;
40
- }
41
-
42
- /**
43
- * 若项超预算,替换为新鲜变量,并返回附加等式 pred:fresh = originalTerm。
44
- * 未超预算则原样返回。
45
- */
46
- export function maybeLeak(
47
- a: Abs,
48
- budget: LeakBudget = defaultLeakBudget,
49
- label = "t",
50
- ): Abs {
51
- if (!a.term || a.term.op !== "app") return a;
52
- if (!exceedsBudget(a.term, budget)) return a;
53
-
54
- leakCounter += 1;
55
- const id = `${label}$${leakCounter}`;
56
- const fresh: Term = v(id);
57
- const linkage: Pred = eq(fresh, a.term);
58
- // pred:原 pred 中的 term 无法直接替换(pred 相对旧 term),改为只挂 linkage
59
- // 置信度:仍 path,但标注 leaked
60
- return abs(a.shape, fresh, linkage, confJoin(a.conf, "path"));
61
- }
62
-
63
- /**
64
- * 批量:在算术结果上应用 leak。
65
- */
66
- export function leakIfNeeded(a: Abs, budget?: LeakBudget, label?: string): Abs {
67
- return maybeLeak(a, budget, label);
68
- }