@nudojs/core 0.3.0 → 0.3.1

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-BU4A6XJ3.js +6856 -0
  2. package/dist/exec.d.ts +2 -0
  3. package/dist/exec.js +168 -0
  4. package/dist/index-CVYjXnwU.d.ts +902 -0
  5. package/dist/index.d.ts +64 -710
  6. package/dist/index.js +3258 -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,993 +0,0 @@
1
- /**
2
- * B 路径 transpile:JS AST → 可在 Node 上执行的抽象值程序(源码字符串)。
3
- * 运算符改为 $add/$sub/…;if 改为 $fork;for 改为 $for。
4
- * 值类型是 Abs;副作用与模块仍由 host mock/注入。
5
- */
6
-
7
- import type { File, Expression, Statement, Node } from "@babel/types";
8
- import { parseSource } from "../parse-source.ts";
9
-
10
- export type TranspileOptions = {
11
- /** 运行时 import 说明符 */
12
- runtimeImport?: string;
13
- maxLoopIters?: number;
14
- /** 方法体内 this 的绑定名(transpile class 时注入) */
15
- thisParam?: string;
16
- /** 当前类名(super 派发用) */
17
- className?: string;
18
- /** 原始源码(@nudo:replace 按节点文本匹配) */
19
- source?: string;
20
- /** 替换表:归一化目标文本 → 注入变量名;可选语句范围 */
21
- replacements?: Array<{
22
- target: string;
23
- varName: string;
24
- /** 仅该语句范围内生效(1-based 行) */
25
- stmtStart?: number;
26
- stmtEnd?: number;
27
- }>;
28
- /** @nudo:as:覆盖紧随语句的 init / return */
29
- asOverrides?: Array<{ varName: string; stmtStart: number; stmtEnd: number }>;
30
- };
31
-
32
- function matchAsOverride(stmt: Node, opts: TranspileOptions): string | null {
33
- if (!opts.asOverrides?.length || !stmt.loc) return null;
34
- const line = stmt.loc.start.line;
35
- for (const a of opts.asOverrides) {
36
- if (line >= a.stmtStart && line <= a.stmtEnd) return a.varName;
37
- }
38
- return null;
39
- }
40
-
41
- function normWs(s: string): string {
42
- return s.replace(/\s+/g, "");
43
- }
44
-
45
- function matchReplacement(node: Node, opts: TranspileOptions): string | null {
46
- if (!opts.source || !opts.replacements?.length) return null;
47
- if (node.start == null || node.end == null || !node.loc) return null;
48
- const src = opts.source.slice(node.start, node.end);
49
- const n = normWs(src);
50
- const line = node.loc.start.line;
51
- for (const r of opts.replacements) {
52
- if (r.stmtStart != null && line < r.stmtStart) continue;
53
- if (r.stmtEnd != null && line > r.stmtEnd) continue;
54
- if (normWs(r.target) === n) return r.varName;
55
- }
56
- return null;
57
- }
58
-
59
- const BIN_OPS: Record<string, string> = {
60
- "+": "$add",
61
- "-": "$sub",
62
- "*": "$mul",
63
- "/": "$div",
64
- "%": "$mod",
65
- "<": "$lt",
66
- "<=": "$le",
67
- ">": "$gt",
68
- ">=": "$ge",
69
- "===": "$eq",
70
- "!==": "$ne",
71
- };
72
-
73
- export function transpileSource(source: string, opts: TranspileOptions = {}): string {
74
- const file = parseSource(source);
75
- return transpileFile(file, { ...opts, source: opts.source ?? source });
76
- }
77
-
78
- export function transpileFile(file: File, opts: TranspileOptions = {}): string {
79
- const runtime = opts.runtimeImport ?? "@nudojs/core/exec";
80
- const lines: string[] = [
81
- `// nudo B-path transpile — values are Abs; operators are overloaded calls`,
82
- `import { $add, $sub, $mul, $div, $mod, $neg, $typeof, $not, $eq, $ne, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $while, $whileSeq, $arr, $idx, $idxSet, $len, $call, $throw, $class, $new, $invoke, $invokeSuper, $super, $async, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal } from ${JSON.stringify(runtime)};`,
83
- ``,
84
- ];
85
- for (const stmt of file.program.body) {
86
- lines.push(transpileStatement(stmt, 0, opts));
87
- }
88
- return lines.join("\n") + "\n";
89
- }
90
-
91
- function indent(n: number): string {
92
- return " ".repeat(n);
93
- }
94
-
95
- /** 语句或块内是否出现 return/throw(决定 if 是否提升为 return $fork) */
96
- function stmtReturns(stmt: Statement): boolean {
97
- if (stmt.type === "ReturnStatement" || stmt.type === "ThrowStatement") return true;
98
- if (stmt.type === "BlockStatement") return stmt.body.some(stmtReturns);
99
- return false;
100
- }
101
-
102
- /** 递归解构:把 pattern 绑到 fromSrc(已是 Abs 表达式字符串) */
103
- function emitDestructure(
104
- pattern: Node,
105
- fromSrc: string,
106
- kw: string,
107
- pad: string,
108
- opts: TranspileOptions,
109
- out: string[],
110
- tmpSeq: { n: number },
111
- ): void {
112
- if (pattern.type === "Identifier") {
113
- out.push(`${pad}${kw} ${pattern.name} = ${fromSrc};`);
114
- return;
115
- }
116
- if (pattern.type === "ObjectPattern") {
117
- for (const prop of pattern.properties) {
118
- if (prop.type !== "ObjectProperty") continue;
119
- if (prop.key.type !== "Identifier" && prop.key.type !== "StringLiteral") continue;
120
- const key =
121
- prop.key.type === "Identifier" ? prop.key.name : String(prop.key.value);
122
- const keyLit = JSON.stringify(key);
123
- if (prop.value.type === "AssignmentPattern") {
124
- const def = transpileExpression(prop.value.right as Expression, opts);
125
- const left = prop.value.left;
126
- if (left.type === "Identifier") {
127
- out.push(
128
- `${pad}${kw} ${left.name} = $orDefault($get(${fromSrc}, ${keyLit}), () => ${def});`,
129
- );
130
- } else {
131
- // 嵌套 + 默认:const { a: { b } = {} } = o
132
- const t = `_n${tmpSeq.n++}`;
133
- out.push(`${pad}const ${t} = $orDefault($get(${fromSrc}, ${keyLit}), () => ${def});`);
134
- emitDestructure(left, t, kw, pad, opts, out, tmpSeq);
135
- }
136
- continue;
137
- }
138
- if (prop.value.type === "ObjectPattern" || prop.value.type === "ArrayPattern") {
139
- const t = `_n${tmpSeq.n++}`;
140
- out.push(`${pad}const ${t} = $get(${fromSrc}, ${keyLit});`);
141
- emitDestructure(prop.value, t, kw, pad, opts, out, tmpSeq);
142
- continue;
143
- }
144
- if (prop.value.type === "Identifier") {
145
- out.push(`${pad}${kw} ${prop.value.name} = $get(${fromSrc}, ${keyLit});`);
146
- }
147
- }
148
- return;
149
- }
150
- if (pattern.type === "ArrayPattern") {
151
- pattern.elements.forEach((el, i) => {
152
- if (!el) return;
153
- if (el.type === "AssignmentPattern") {
154
- const def = transpileExpression(el.right as Expression, opts);
155
- const idx = `$idx(${fromSrc}, $lit(${i}))`;
156
- if (el.left.type === "Identifier") {
157
- out.push(`${pad}${kw} ${el.left.name} = $orDefault(${idx}, () => ${def});`);
158
- } else {
159
- const t = `_n${tmpSeq.n++}`;
160
- out.push(`${pad}const ${t} = $orDefault(${idx}, () => ${def});`);
161
- emitDestructure(el.left, t, kw, pad, opts, out, tmpSeq);
162
- }
163
- return;
164
- }
165
- if (el.type === "ObjectPattern" || el.type === "ArrayPattern") {
166
- const t = `_n${tmpSeq.n++}`;
167
- out.push(`${pad}const ${t} = $idx(${fromSrc}, $lit(${i}));`);
168
- emitDestructure(el, t, kw, pad, opts, out, tmpSeq);
169
- return;
170
- }
171
- if (el.type === "Identifier") {
172
- out.push(`${pad}${kw} ${el.name} = $idx(${fromSrc}, $lit(${i}));`);
173
- }
174
- });
175
- }
176
- }
177
-
178
- function transpileStatement(stmt: Statement, depth: number, opts: TranspileOptions): string {
179
- const pad = indent(depth);
180
- switch (stmt.type) {
181
- case "ExportNamedDeclaration": {
182
- const decl = stmt.declaration;
183
- if (!decl) return `${pad}/* export specifiers skipped */`;
184
- return transpileStatement(decl as Statement, depth, opts);
185
- }
186
- case "ImportDeclaration": {
187
- // 保留 import;run.ts 会改写为 __nudoBindImport
188
- const specs = stmt.specifiers
189
- .map((s) => {
190
- if (s.type === "ImportSpecifier") {
191
- const imported =
192
- s.imported.type === "Identifier" ? s.imported.name : String(s.imported);
193
- return imported === s.local.name ? imported : `${imported} as ${s.local.name}`;
194
- }
195
- if (s.type === "ImportDefaultSpecifier") return `default as ${s.local.name}`;
196
- if (s.type === "ImportNamespaceSpecifier") return `* as ${s.local.name}`;
197
- return "";
198
- })
199
- .filter(Boolean);
200
- if (specs.length === 0) {
201
- return `${pad}import ${JSON.stringify(stmt.source.value)};`;
202
- }
203
- return `${pad}import { ${specs.join(", ")} } from ${JSON.stringify(stmt.source.value)};`;
204
- }
205
- case "ExportDefaultDeclaration": {
206
- const d = stmt.declaration;
207
- if (d.type === "FunctionDeclaration" || d.type === "ClassDeclaration") {
208
- const inner = transpileStatement(d as Statement, depth, opts);
209
- return inner.replace(/^(\s*)export function /, "$1export default function ");
210
- }
211
- return `${pad}export default ${transpileExpression(d as Expression, opts)};`;
212
- }
213
- case "FunctionDeclaration": {
214
- if (!stmt.id) return `${pad}// <anonymous fn skipped>`;
215
- const paramParts = stmt.params.map((p) => {
216
- if (p.type === "Identifier") return { kind: "id" as const, name: p.name };
217
- if (p.type === "RestElement" && p.argument.type === "Identifier") {
218
- return { kind: "rest" as const, name: p.argument.name };
219
- }
220
- return { kind: "id" as const, name: "_" };
221
- });
222
- const named = paramParts.filter((p) => p.kind === "id" && p.name !== "_").map((p) => p.name);
223
- const rest = paramParts.find((p) => p.kind === "rest");
224
- const paramsSig = rest ? [...named, `...${rest.name}`] : named;
225
- const params = paramsSig.join(", ");
226
- const bodyStmts =
227
- stmt.body.type === "BlockStatement"
228
- ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, opts)).join("\n")
229
- : `${indent(depth + 2)}return ${transpileExpression(stmt.body as unknown as Expression, opts)};`;
230
- const restBind = rest
231
- ? `${indent(depth + 1)}const ${rest.name} = arguments.length > ${named.length} ? $arr(Array.from(arguments).slice(${named.length})) : $arr([]);\n`
232
- : "";
233
- // function* → $gen 收集 yield
234
- if (stmt.generator) {
235
- return [
236
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
237
- restBind,
238
- `${indent(depth + 1)}return $gen(() => {`,
239
- bodyStmts,
240
- `${indent(depth + 1)}});`,
241
- `${pad}}`,
242
- ].join("\n");
243
- }
244
- if (stmt.async) {
245
- return [
246
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
247
- restBind,
248
- `${indent(depth + 1)}return $async(() => {`,
249
- bodyStmts,
250
- `${indent(depth + 1)}});`,
251
- `${pad}}`,
252
- ].join("\n");
253
- }
254
- return [
255
- `${pad}export function ${stmt.id.name}(${named.join(", ")}) {`,
256
- restBind,
257
- bodyStmts,
258
- `${pad}}`,
259
- ].join("\n");
260
- }
261
- case "ReturnStatement": {
262
- const asVar = matchAsOverride(stmt as Node, opts);
263
- if (asVar) return `${pad}return ${asVar};`;
264
- if (!stmt.argument) return `${pad}return $lit(undefined);`;
265
- return `${pad}return ${transpileExpression(stmt.argument, opts)};`;
266
- }
267
- case "ThrowStatement": {
268
- const arg = stmt.argument ? transpileExpression(stmt.argument, opts) : "$lit(undefined)";
269
- return `${pad}$throw(${arg});`;
270
- }
271
- case "ExpressionStatement":
272
- return `${pad}${transpileExpression(stmt.expression, opts)};`;
273
- case "VariableDeclaration": {
274
- const kw = stmt.kind === "const" ? "const" : "let";
275
- const asVar = matchAsOverride(stmt as Node, opts);
276
- const lines: string[] = [];
277
- let tmpSeq = 0;
278
- for (const d of stmt.declarations) {
279
- if (d.id.type === "Identifier") {
280
- // @nudo:as:覆盖整个声明语句的 init
281
- const init = asVar
282
- ? asVar
283
- : d.init
284
- ? transpileExpression(d.init, opts)
285
- : "$lit(undefined)";
286
- lines.push(`${pad}${kw} ${d.id.name} = ${init};`);
287
- continue;
288
- }
289
- // 解构:先绑定 init 到临时,再逐项 $get / $idx
290
- if (!d.init) {
291
- lines.push(`${pad}// destructure without init`);
292
- continue;
293
- }
294
- const initSrc = transpileExpression(d.init, opts);
295
- const tmp = `_d${tmpSeq++}_${stmt.loc?.start.line ?? 0}`;
296
- lines.push(`${pad}const ${tmp} = ${initSrc};`);
297
- emitDestructure(d.id as Node, tmp, kw, pad, opts, lines, { n: 0 });
298
- }
299
- return lines.join("\n");
300
- }
301
- case "IfStatement": {
302
- const test = transpileExpression(stmt.test, opts);
303
- const cons = transpileBlockAsThunk(stmt.consequent, depth, opts);
304
- const alt = stmt.alternate ? transpileBlockAsThunk(stmt.alternate, depth, opts) : "undefined";
305
- // 两分支都以 return/throw 退出时,$fork 即函数返回值
306
- if (
307
- stmtReturns(stmt.consequent) &&
308
- stmt.alternate !== undefined &&
309
- stmt.alternate !== null &&
310
- stmtReturns(stmt.alternate)
311
- ) {
312
- return `${pad}return $fork(${test}, ${cons}, ${alt});`;
313
- }
314
- return `${pad}$fork(${test}, ${cons}, ${alt});`;
315
- }
316
- case "ForStatement": {
317
- const initName = extractForInitName(stmt.init);
318
- if (!initName) return `${pad}// unsupported for-init; use \`let i = …\``;
319
- const initExpr =
320
- stmt.init && stmt.init.type === "VariableDeclaration" && stmt.init.declarations[0]?.init
321
- ? transpileExpression(stmt.init.declarations[0].init, opts)
322
- : "$lit(undefined)";
323
- const testSrc = stmt.test ? transpileExpression(stmt.test, opts) : "$lit(true)";
324
- const updateSrc = stmt.update ? transpileExpression(stmt.update, opts) : `$lit(undefined)`;
325
- const bodyStmts =
326
- stmt.body.type === "BlockStatement"
327
- ? stmt.body.body
328
- .map((s) => transpileStatement(s, depth + 2, opts))
329
- .join("\n")
330
- : transpileStatement(stmt.body, depth + 2, opts);
331
- const max = opts.maxLoopIters ?? 8;
332
- // MVP:经典单变量计数循环(状态 = 计数器 Abs)
333
- return [
334
- `${pad}// for → $for (bounded unroll, max=${max})`,
335
- `${pad}$for(`,
336
- `${indent(depth + 1)}${initExpr},`,
337
- `${indent(depth + 1)}(${initName}) => ${testSrc},`,
338
- `${indent(depth + 1)}(${initName}) => ${updateSrc},`,
339
- `${indent(depth + 1)}(${initName}) => {`,
340
- bodyStmts,
341
- `${indent(depth + 1)} return ${initName};`,
342
- `${indent(depth + 1)}},`,
343
- `${indent(depth + 1)}${max}`,
344
- `${pad});`,
345
- ].join("\n");
346
- }
347
- case "BlockStatement":
348
- return stmt.body.map((s) => transpileStatement(s, depth, opts)).join("\n");
349
- case "SwitchStatement": {
350
- // switch (d) { case 1: … case 2: … default: … } → $switch
351
- const disc = transpileExpression(stmt.discriminant as Expression, opts);
352
- // 合并 fall-through:无语句的 case 与下一有语句 case 同体
353
- type Arm = { tests: string[]; stmts: Statement[]; isDefault: boolean };
354
- const arms: Arm[] = [];
355
- for (const c of stmt.cases) {
356
- const testSrc = c.test
357
- ? transpileExpression(c.test as Expression, opts)
358
- : null;
359
- if (testSrc === null) {
360
- arms.push({ tests: [], stmts: c.consequent, isDefault: true });
361
- } else if (
362
- arms.length > 0 &&
363
- !arms[arms.length - 1]!.isDefault &&
364
- arms[arms.length - 1]!.stmts.length === 0
365
- ) {
366
- // fall-through:把 test 并入空臂,并填入本 case 的语句
367
- const last = arms[arms.length - 1]!;
368
- last.tests.push(testSrc);
369
- last.stmts = c.consequent;
370
- } else {
371
- arms.push({ tests: [testSrc], stmts: c.consequent, isDefault: false });
372
- }
373
- }
374
- // 再合并:连续 case 测试共享同一语句列表(case 2: case 3: body)
375
- const merged: Arm[] = [];
376
- for (const arm of arms) {
377
- if (
378
- merged.length > 0 &&
379
- merged[merged.length - 1]!.stmts === arm.stmts &&
380
- !arm.isDefault
381
- ) {
382
- merged[merged.length - 1]!.tests.push(...arm.tests);
383
- } else {
384
- merged.push({ ...arm, tests: [...arm.tests] });
385
- }
386
- }
387
- const caseLines: string[] = [];
388
- let defaultSrc: string | null = null;
389
- for (const arm of merged) {
390
- const body =
391
- arm.stmts.map((s) => transpileStatement(s, depth + 2, opts)).join("\n") ||
392
- `${indent(depth + 2)}return $lit(undefined);`;
393
- const thunk = `() => {\n${body}\n${indent(depth + 1)}}`;
394
- if (arm.isDefault) {
395
- defaultSrc = thunk;
396
- } else {
397
- // 多 test 共享体:任一命中(具体值);抽象时 $switch 会跑全部 case 体并 join
398
- for (const t of arm.tests) {
399
- caseLines.push(`{ test: ${t}, run: ${thunk} },`);
400
- }
401
- }
402
- }
403
- const dflt = defaultSrc ? `, ${defaultSrc}` : "";
404
- return [
405
- `${pad}return $switch(${disc}, [`,
406
- ...caseLines.map((l) => indent(depth + 1) + l),
407
- `${indent(depth + 1)}]${dflt});`,
408
- ].join("\n");
409
- }
410
- case "TryStatement": {
411
- const tryBody =
412
- stmt.block.type === "BlockStatement"
413
- ? stmt.block.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n")
414
- : transpileStatement(stmt.block, depth + 1, opts);
415
- const lines = [`${pad}try {`, tryBody, `${pad}}`];
416
- if (stmt.handler) {
417
- const param =
418
- stmt.handler.param?.type === "Identifier" ? stmt.handler.param.name : "e";
419
- const catchTmp = `__nudoE_${stmt.loc?.start.line ?? 0}`;
420
- const catchBody =
421
- stmt.handler.body.type === "BlockStatement"
422
- ? stmt.handler.body.body
423
- .map((s) => transpileStatement(s, depth + 1, opts))
424
- .join("\n")
425
- : transpileStatement(stmt.handler.body, depth + 1, opts);
426
- lines.push(`${pad}catch (${catchTmp}) {`);
427
- lines.push(`${indent(depth + 1)}const ${param} = $catchVal(${catchTmp});`);
428
- lines.push(catchBody);
429
- lines.push(`${pad}}`);
430
- }
431
- if (stmt.finalizer) {
432
- const finBody =
433
- stmt.finalizer.type === "BlockStatement"
434
- ? stmt.finalizer.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n")
435
- : transpileStatement(stmt.finalizer, depth + 1, opts);
436
- lines.push(`${pad}finally {`);
437
- lines.push(finBody);
438
- lines.push(`${pad}}`);
439
- }
440
- return lines.join("\n");
441
- }
442
- case "ForOfStatement": {
443
- const iter = transpileExpression(stmt.right as Expression, opts);
444
- // for (const x of xs) / for (const [a,b] of xs)
445
- let bindName = "_item";
446
- if (stmt.left.type === "VariableDeclaration") {
447
- const decl = stmt.left.declarations[0];
448
- if (decl?.id.type === "Identifier") bindName = decl.id.name;
449
- else if (decl?.id.type === "ObjectPattern" || decl?.id.type === "ArrayPattern") {
450
- // 解构绑定:用临时 _item 再 destructure
451
- bindName = `_of${stmt.loc?.start.line ?? 0}`;
452
- }
453
- } else if (stmt.left.type === "Identifier") {
454
- bindName = stmt.left.name;
455
- }
456
- const bodyLines: string[] = [];
457
- if (
458
- stmt.left.type === "VariableDeclaration" &&
459
- stmt.left.declarations[0] &&
460
- (stmt.left.declarations[0].id.type === "ObjectPattern" ||
461
- stmt.left.declarations[0].id.type === "ArrayPattern")
462
- ) {
463
- emitDestructure(
464
- stmt.left.declarations[0].id as Node,
465
- bindName,
466
- "const",
467
- indent(depth + 2),
468
- opts,
469
- bodyLines,
470
- { n: 0 },
471
- );
472
- }
473
- const bodyStmts =
474
- stmt.body.type === "BlockStatement"
475
- ? stmt.body.body.map((s) => transpileStatement(s, depth + 2, opts)).join("\n")
476
- : transpileStatement(stmt.body, depth + 2, opts);
477
- const max = opts.maxLoopIters ?? 8;
478
- return [
479
- `${pad}$forOf(${iter}, (${bindName}, _i) => {`,
480
- ...bodyLines,
481
- bodyStmts,
482
- `${pad}}, ${max});`,
483
- ].join("\n");
484
- }
485
- case "WhileStatement": {
486
- const test = transpileExpression(stmt.test, opts);
487
- const body =
488
- stmt.body.type === "BlockStatement"
489
- ? stmt.body.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n")
490
- : transpileStatement(stmt.body, depth + 1, opts);
491
- const max = opts.maxLoopIters ?? 8;
492
- // 顺序形态:body 内对 JS let 赋值即状态;抽象条件靠预算
493
- return [
494
- `${pad}// while → $whileSeq (bounded, max=${max})`,
495
- `${pad}$whileSeq(() => ${test}, () => {`,
496
- body,
497
- `${pad}}, ${max});`,
498
- ].join("\n");
499
- }
500
- case "ClassDeclaration": {
501
- return transpileClass(stmt, depth, opts);
502
- }
503
- default:
504
- return `${pad}/* skip ${stmt.type} */`;
505
- }
506
- }
507
-
508
- /** class C extends P { ctor, methods } → $class(...) */
509
- function transpileClass(
510
- stmt: {
511
- id?: { name: string } | null;
512
- body: { body: unknown[] };
513
- superClass?: { type: string; name?: string } | null;
514
- },
515
- depth: number,
516
- opts: TranspileOptions,
517
- ): string {
518
- const pad = indent(depth);
519
- const name = stmt.id?.name ?? "AnonymousClass";
520
- const superName =
521
- stmt.superClass?.type === "Identifier" ? stmt.superClass.name : undefined;
522
- const methods = stmt.body.body as Array<{
523
- type: string;
524
- key?: { type: string; name?: string; value?: unknown };
525
- params?: unknown[];
526
- body?: { type: string; body?: unknown[] };
527
- kind?: string;
528
- async?: boolean;
529
- static?: boolean;
530
- value?: unknown;
531
- }>;
532
-
533
- const ctorParts: string[] = [];
534
- const methodParts: string[] = [];
535
- const staticMethodParts: string[] = [];
536
- const staticFieldParts: string[] = [];
537
-
538
- const paramsOf = (m: { params?: unknown[] }): string[] =>
539
- (m.params ?? []).map((p) => {
540
- const id = p as { type?: string; name?: string };
541
- return id?.type === "Identifier" && id.name ? id.name : "_";
542
- });
543
-
544
- const methodOpts: TranspileOptions = {
545
- ...opts,
546
- thisParam: "__this",
547
- className: name,
548
- };
549
-
550
- for (const m of methods) {
551
- // 静态字段 ClassProperty
552
- if (m.type === "ClassProperty" || m.type === "ClassPrivateProperty") {
553
- const fname =
554
- m.key?.type === "Identifier" ? m.key.name : m.key?.type === "StringLiteral" ? String(m.key.value) : null;
555
- if (fname && m.value) {
556
- const vsrc = transpileExpression(m.value as Expression, opts);
557
- staticFieldParts.push(`${indent(depth + 2)}${JSON.stringify(fname)}: ${vsrc},`);
558
- }
559
- continue;
560
- }
561
- if (m.type !== "ClassMethod" && m.type !== "ObjectMethod") continue;
562
- const mname =
563
- m.key?.type === "Identifier" ? m.key.name : m.key?.type === "StringLiteral" ? String(m.key.value) : "method";
564
- const params = paramsOf(m);
565
- const paramList = params.filter((p) => p !== "_").join(", ");
566
- const bodyStmts =
567
- m.body?.type === "BlockStatement"
568
- ? (m.body.body as Statement[])
569
- .map((s) => transpileStatement(s, depth + 3, m.static ? opts : methodOpts))
570
- .join("\n")
571
- : "";
572
- if (m.static) {
573
- staticMethodParts.push(
574
- `${indent(depth + 3)}${mname}: (${paramList}) => {`,
575
- bodyStmts,
576
- `${indent(depth + 3)}},`,
577
- );
578
- continue;
579
- }
580
- if (m.kind === "constructor" || mname === "constructor") {
581
- ctorParts.push(
582
- `${indent(depth + 2)}ctor: (__this, ${paramList}) => {`,
583
- bodyStmts,
584
- `${indent(depth + 3)}return __this;`,
585
- `${indent(depth + 2)}},`,
586
- );
587
- } else if (m.async) {
588
- methodParts.push(
589
- `${indent(depth + 3)}${mname}: (__this, ${paramList}) => {`,
590
- `${indent(depth + 4)}return $async(() => {`,
591
- bodyStmts,
592
- `${indent(depth + 4)}});`,
593
- `${indent(depth + 3)}},`,
594
- );
595
- } else {
596
- methodParts.push(
597
- `${indent(depth + 3)}${mname}: (__this, ${paramList}) => {`,
598
- bodyStmts,
599
- `${indent(depth + 3)}},`,
600
- );
601
- }
602
- }
603
-
604
- const specLines: string[] = [];
605
- if (superName) {
606
- specLines.push(`${indent(depth + 2)}extends: ${JSON.stringify(superName)},`);
607
- }
608
- if (staticFieldParts.length) {
609
- specLines.push(`${indent(depth + 2)}statics: {`, ...staticFieldParts, `${indent(depth + 2)}},`);
610
- }
611
- if (staticMethodParts.length) {
612
- specLines.push(
613
- `${indent(depth + 2)}staticMethods: {`,
614
- ...staticMethodParts,
615
- `${indent(depth + 2)}},`,
616
- );
617
- }
618
- if (ctorParts.length) {
619
- specLines.push(...ctorParts);
620
- }
621
- if (methodParts.length) {
622
- specLines.push(`${indent(depth + 2)}methods: {`, ...methodParts, `${indent(depth + 2)}},`);
623
- }
624
-
625
- return [
626
- `${pad}const ${name} = $class(${JSON.stringify(name)}, {`,
627
- ...specLines,
628
- `${pad}});`,
629
- ].join("\n");
630
- }
631
-
632
- function transpileBlockAsThunk(stmt: Statement, depth: number, opts: TranspileOptions): string {
633
- if (stmt.type === "BlockStatement") {
634
- const inner = stmt.body.map((s) => transpileStatement(s, depth + 1, opts)).join("\n");
635
- return `() => {\n${inner}\n${indent(depth)}}`;
636
- }
637
- if (stmt.type === "ReturnStatement") {
638
- const v = stmt.argument ? transpileExpression(stmt.argument, opts) : "$lit(undefined)";
639
- return `() => ${v}`;
640
- }
641
- const one = transpileStatement(stmt, depth + 1, opts);
642
- return `() => {\n${one}\n${indent(depth)}}`;
643
- }
644
-
645
- function extractForInitName(init: Statement | Expression | null | undefined): string | null {
646
- if (!init || init.type !== "VariableDeclaration") return null;
647
- const d = init.declarations[0];
648
- return d?.id.type === "Identifier" ? d.id.name : null;
649
- }
650
-
651
- export function transpileExpression(expr: Expression, opts: TranspileOptions = {}): string {
652
- // @nudo:replace:节点源码文本匹配则换成注入变量
653
- const rep = matchReplacement(expr as Node, opts);
654
- if (rep) return rep;
655
- // ChainExpression 不在 Expression 联合里,先剥一层
656
- const anyExpr = expr as unknown as { type: string; expression?: Expression };
657
- if (anyExpr.type === "ChainExpression" && anyExpr.expression) {
658
- return transpileExpression(anyExpr.expression, opts);
659
- }
660
- switch (expr.type) {
661
- case "NumericLiteral":
662
- case "StringLiteral":
663
- case "BooleanLiteral":
664
- return `$lit(${JSON.stringify(expr.value)})`;
665
- case "NullLiteral":
666
- return `$lit(null)`;
667
- case "Identifier":
668
- if (expr.name === "undefined") return "$lit(undefined)";
669
- return expr.name;
670
- case "ThisExpression":
671
- return opts.thisParam ?? "$lit(undefined)";
672
- case "Super":
673
- return `/* super */`;
674
- case "NewExpression": {
675
- const callee = expr.callee;
676
- const cname =
677
- callee.type === "Identifier" ? callee.name : isExpression(callee) ? transpileExpression(callee, opts) : "$lit(undefined)";
678
- const args = expr.arguments
679
- .map((a) => (a.type === "SpreadElement" ? "$lit(undefined)" : transpileExpression(a as Expression, opts)))
680
- .join(", ");
681
- return `$new(${cname}, [${args}])`;
682
- }
683
- case "LogicalExpression": {
684
- const op = expr.operator;
685
- const l = transpileExpression(expr.left, opts);
686
- const r = transpileExpression(expr.right, opts);
687
- return op === "&&"
688
- ? `$fork(${l}, () => ${r}, () => ${l})`
689
- : `$fork(${l}, () => ${l}, () => ${r})`;
690
- }
691
- case "BinaryExpression": {
692
- const fn = BIN_OPS[expr.operator];
693
- if (!fn) return `/* unsupported ${expr.operator} */ $lit(undefined)`;
694
- const l = isExpression(expr.left) ? transpileExpression(expr.left, opts) : "$lit(undefined)";
695
- const r = isExpression(expr.right) ? transpileExpression(expr.right, opts) : "$lit(undefined)";
696
- return `${fn}(${l}, ${r})`;
697
- }
698
- case "UnaryExpression": {
699
- const arg = transpileExpression(expr.argument as Expression, opts);
700
- if (expr.operator === "-") return `$neg(${arg})`;
701
- if (expr.operator === "!") return `$not(${arg})`;
702
- if (expr.operator === "typeof") return `$typeof(${arg})`;
703
- if (expr.operator === "+") return arg;
704
- return `/* unary ${expr.operator} */ $lit(undefined)`;
705
- }
706
- case "AwaitExpression": {
707
- const arg = transpileExpression(expr.argument as Expression, opts);
708
- return `$await(${arg})`;
709
- }
710
- case "YieldExpression": {
711
- const arg = expr.argument
712
- ? transpileExpression(expr.argument as Expression, opts)
713
- : "$lit(undefined)";
714
- return `$yield(${arg})`;
715
- }
716
- case "TemplateLiteral": {
717
- const quasis = expr.quasis;
718
- const exprs = expr.expressions;
719
- // `a${b}c` → $add($add($lit("a"), b), $lit("c"))
720
- let acc: string | null = null;
721
- for (let i = 0; i < quasis.length; i++) {
722
- const cooked = quasis[i]!.value.cooked ?? quasis[i]!.value.raw;
723
- const piece = `$lit(${JSON.stringify(cooked)})`;
724
- acc = acc === null ? piece : `$add(${acc}, ${piece})`;
725
- if (i < exprs.length) {
726
- const e = transpileExpression(exprs[i] as Expression, opts);
727
- acc = `$add(${acc}, ${e})`;
728
- }
729
- }
730
- return acc ?? `$lit("")`;
731
- }
732
- case "SequenceExpression":
733
- return expr.expressions.map((e) => transpileExpression(e, opts)).join(", ");
734
- case "ObjectExpression": {
735
- // 支持 { ...a, b: 1 } → $spread($spread(a, $obj({b:1})), ...)
736
- let acc: string | null = null;
737
- const props: string[] = [];
738
- const flushProps = () => {
739
- if (props.length === 0) return;
740
- const obj = `$obj({ ${props.join(", ")} })`;
741
- acc = acc === null ? obj : `$spread(${acc}, ${obj})`;
742
- props.length = 0;
743
- };
744
- for (const prop of expr.properties) {
745
- if (prop.type === "SpreadElement") {
746
- flushProps();
747
- const arg = transpileExpression(prop.argument as Expression, opts);
748
- acc = acc === null ? arg : `$spread(${acc}, ${arg})`;
749
- continue;
750
- }
751
- if (prop.type !== "ObjectProperty") continue;
752
- // 计算属性 { [expr]: v } → $setKey
753
- if (prop.computed) {
754
- flushProps();
755
- const k = transpileExpression(prop.key as Expression, opts);
756
- const v = transpileExpression(prop.value as Expression, opts);
757
- const base = acc === null ? `$obj({})` : acc;
758
- acc = `$setKey(${base}, ${k}, ${v})`;
759
- continue;
760
- }
761
- const key =
762
- prop.key.type === "Identifier"
763
- ? JSON.stringify(prop.key.name)
764
- : prop.key.type === "StringLiteral"
765
- ? JSON.stringify(prop.key.value)
766
- : null;
767
- if (key === null) continue;
768
- const valSrc = transpileExpression(prop.value as Expression, opts);
769
- props.push(`${key}: ${valSrc}`);
770
- }
771
- flushProps();
772
- return acc ?? `$obj({})`;
773
- }
774
- case "MemberExpression":
775
- case "OptionalMemberExpression": {
776
- const optional = (expr as { optional?: boolean }).optional === true;
777
- if (expr.computed) {
778
- const obj = transpileExpression(expr.object as Expression, opts);
779
- const key = expr.property;
780
- if (key.type === "StringLiteral") {
781
- return optional
782
- ? `$optionalGet(${obj}, ${JSON.stringify(key.value)})`
783
- : `$get(${obj}, ${JSON.stringify(key.value)})`;
784
- }
785
- if (key.type === "NumericLiteral") {
786
- return optional
787
- ? `$optionalGet(${obj}, ${JSON.stringify(String(key.value))})`
788
- : `$idx(${obj}, $lit(${key.value}))`;
789
- }
790
- if (isExpression(key)) {
791
- const k = transpileExpression(key, opts);
792
- return `$idx(${obj}, ${k})`;
793
- }
794
- return `/* computed member */ $lit(undefined)`;
795
- }
796
- if (expr.property.type !== "Identifier") {
797
- return `/* member */ $lit(undefined)`;
798
- }
799
- // o.length
800
- if (expr.property.name === "length") {
801
- return `$len(${transpileExpression(expr.object as Expression, opts)})`;
802
- }
803
- const recv = transpileExpression(expr.object as Expression, opts);
804
- const key = JSON.stringify(expr.property.name);
805
- return optional ? `$optionalGet(${recv}, ${key})` : `$get(${recv}, ${key})`;
806
- }
807
- case "ArrayExpression": {
808
- // [...a, b] → $concat
809
- let acc: string | null = null;
810
- for (const el of expr.elements) {
811
- if (!el) continue;
812
- let piece: string;
813
- if (el.type === "SpreadElement") {
814
- piece = transpileExpression(el.argument as Expression, opts);
815
- } else {
816
- piece = `$arr([${transpileExpression(el, opts)}])`;
817
- }
818
- acc = acc === null ? piece : `$concat(${acc}, ${piece})`;
819
- }
820
- return acc ?? `$arr([])`;
821
- }
822
- case "AssignmentExpression": {
823
- // obj.field = v → $set;标识符赋值保持 JS 绑定(值是 Abs)
824
- if (expr.operator !== "=") return `/* assign ${expr.operator} */ $lit(undefined)`;
825
- const right = transpileExpression(expr.right, opts);
826
- if (expr.left.type === "MemberExpression") {
827
- // this.x = v → __this = $set(__this, "x", v)
828
- if (
829
- !expr.left.computed &&
830
- expr.left.object.type === "ThisExpression" &&
831
- expr.left.property.type === "Identifier" &&
832
- opts.thisParam
833
- ) {
834
- return `${opts.thisParam} = $set(${opts.thisParam}, ${JSON.stringify(expr.left.property.name)}, ${right})`;
835
- }
836
- if (!expr.left.computed && expr.left.property.type === "Identifier") {
837
- const obj = transpileExpression(expr.left.object as Expression, opts);
838
- return `$set(${obj}, ${JSON.stringify(expr.left.property.name)}, ${right})`;
839
- }
840
- if (expr.left.computed) {
841
- const obj = transpileExpression(expr.left.object as Expression, opts);
842
- const k = expr.left.property;
843
- if (k.type === "NumericLiteral") {
844
- return `$idxSet(${obj}, $lit(${k.value}), ${right})`;
845
- }
846
- if (k.type === "StringLiteral") {
847
- return `$set(${obj}, ${JSON.stringify(k.value)}, ${right})`;
848
- }
849
- if (isExpression(k)) {
850
- return `$idxSet(${obj}, ${transpileExpression(k, opts)}, ${right})`;
851
- }
852
- }
853
- }
854
- if (expr.left.type === "Identifier") {
855
- return `${expr.left.name} = ${right}`;
856
- }
857
- return `/* assign */ $lit(undefined)`;
858
- }
859
- case "CallExpression":
860
- case "OptionalCallExpression": {
861
- const exprAny = expr as {
862
- type: string;
863
- callee: Node;
864
- arguments: unknown[];
865
- optional?: boolean;
866
- };
867
- const optionalCall = exprAny.type === "OptionalCallExpression" || exprAny.optional === true;
868
- const callee = expr.callee;
869
- // super() → __this = $super(__this, Child, [...])
870
- if (callee.type === "Super" && opts.thisParam && opts.className) {
871
- const args = expr.arguments
872
- .map((a) => (a.type === "SpreadElement" ? "$lit(undefined)" : transpileExpression(a as Expression, opts)))
873
- .join(", ");
874
- return `${opts.thisParam} = $super(${opts.thisParam}, ${JSON.stringify(opts.className)}, [${args}])`;
875
- }
876
- // super.method(args) → $invokeSuper(...)
877
- if (
878
- callee.type === "MemberExpression" &&
879
- !callee.computed &&
880
- callee.object.type === "Super" &&
881
- callee.property.type === "Identifier" &&
882
- opts.thisParam &&
883
- opts.className
884
- ) {
885
- const args = expr.arguments
886
- .map((a) => (a.type === "SpreadElement" ? "$lit(undefined)" : transpileExpression(a as Expression, opts)))
887
- .join(", ");
888
- return `$invokeSuper(${opts.thisParam}, ${JSON.stringify(opts.className)}, ${JSON.stringify(callee.property.name)}, [${args}])`;
889
- }
890
- // obj.method(args) / obj?.method(args) → $invoke / $optionalInvoke
891
- if (
892
- (callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") &&
893
- !callee.computed &&
894
- callee.property.type === "Identifier"
895
- ) {
896
- const recv = transpileExpression(callee.object as Expression, opts);
897
- const args = expr.arguments
898
- .map((a) => (a.type === "SpreadElement" ? "$lit(undefined)" : transpileExpression(a as Expression, opts)))
899
- .join(", ");
900
- const name = JSON.stringify(callee.property.name);
901
- const opt = optionalCall || (callee as { optional?: boolean }).optional === true;
902
- const loc = expr.loc;
903
- const locArg = loc ? `, [${loc.start.line}, ${loc.start.column}]` : "";
904
- return opt
905
- ? `$optionalInvoke(${recv}, ${name}, [${args}])`
906
- : `$invoke(${recv}, ${name}, [${args}]${locArg})`;
907
- }
908
- // require("spec") → __nudoRequire("spec")
909
- if (
910
- callee.type === "Identifier" &&
911
- callee.name === "require" &&
912
- expr.arguments[0]?.type === "StringLiteral"
913
- ) {
914
- const spec = (expr.arguments[0] as { value: string }).value;
915
- return `__nudoRequire(${JSON.stringify(spec)})`;
916
- }
917
- // 标识符调用 → $callNamed(可采集 call@ + 实参 provenance)
918
- if (callee.type === "Identifier" && callee.name !== "undefined") {
919
- const argSrcs: string[] = [];
920
- const argLocSrcs: string[] = [];
921
- for (const a of expr.arguments) {
922
- if (a.type === "SpreadElement") {
923
- argSrcs.push("$lit(undefined)");
924
- argLocSrcs.push("null");
925
- } else {
926
- argSrcs.push(transpileExpression(a as Expression, opts));
927
- const al = (a as { loc?: { start: { line: number; column: number } } }).loc;
928
- argLocSrcs.push(al ? `[${al.start.line}, ${al.start.column}]` : "null");
929
- }
930
- }
931
- const loc = expr.loc;
932
- const locArg = loc ? `, [${loc.start.line}, ${loc.start.column}]` : "";
933
- const argLocArg = loc ? `, [${argLocSrcs.join(", ")}]` : "";
934
- return `$callNamed(${JSON.stringify(callee.name)}, ${callee.name}, [${argSrcs.join(", ")}]${locArg}${argLocArg})`;
935
- }
936
- const args = expr.arguments
937
- .map((a) =>
938
- a.type === "SpreadElement" ? `/* spread */` : transpileExpression(a as Expression, opts),
939
- )
940
- .join(", ");
941
- const c =
942
- callee.type === "Identifier"
943
- ? callee.name
944
- : isExpression(callee)
945
- ? transpileExpression(callee, opts)
946
- : "/* callee */";
947
- return `${c}(${args})`;
948
- }
949
- case "ArrowFunctionExpression":
950
- case "FunctionExpression": {
951
- const fn = expr as {
952
- params: Node[];
953
- body: Node;
954
- async?: boolean;
955
- };
956
- const paramParts = fn.params.map((p) => {
957
- if (p.type === "Identifier") return (p as { name: string }).name;
958
- if (p.type === "RestElement" && (p as { argument?: Node }).argument?.type === "Identifier") {
959
- return `...${(p as { argument: { name: string } }).argument.name}`;
960
- }
961
- return "_p";
962
- });
963
- // 一等 fn Abs:参数名进 shape(bridge/dts 可展示);
964
- // 异步 body 包 $async 保持 eff(promise) 语义(裸 JS async 会泄漏 Promise)。
965
- const nameList = `[${paramParts.map((p) => JSON.stringify(p.startsWith("...") ? p.slice(3) : p)).join(", ")}]`;
966
- if (fn.body.type === "BlockStatement") {
967
- const inner = (fn.body as { body: Statement[] }).body
968
- .map((s) => transpileStatement(s, 1, opts))
969
- .join("\n");
970
- if (fn.async) {
971
- return `$fnVal(${nameList}, (${paramParts.join(", ")}) => $async(() => {\n${inner}\n}))`;
972
- }
973
- return `$fnVal(${nameList}, (${paramParts.join(", ")}) => {\n${inner}\n})`;
974
- }
975
- const bodySrc = transpileExpression(fn.body as Expression, opts);
976
- if (fn.async) {
977
- return `$fnVal(${nameList}, (${paramParts.join(", ")}) => $async(() => ${bodySrc}))`;
978
- }
979
- return `$fnVal(${nameList}, (${paramParts.join(", ")}) => ${bodySrc})`;
980
- }
981
- default:
982
- return `/* ${expr.type} */ $lit(undefined)`;
983
- }
984
- }
985
-
986
- /** 解析 + transpile */
987
- export function transpile(source: string, opts?: TranspileOptions): string {
988
- return transpileSource(source, opts);
989
- }
990
-
991
- function isExpression(n: { type: string }): n is Expression {
992
- return n.type !== "PrivateName" && !n.type.endsWith("Statement") && !n.type.endsWith("Declaration");
993
- }