@codehz/json-expr 0.5.2 → 0.5.4

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.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/parser.ts
1
+ //#region src/ast-types.ts
2
2
  const PRECEDENCE = {
3
3
  "||": 1,
4
4
  "??": 1,
@@ -48,697 +48,629 @@ const BUILTIN_CONSTRUCTORS = new Set([
48
48
  "ArrayBuffer",
49
49
  "DataView"
50
50
  ]);
51
- var Parser = class Parser {
52
- pos = 0;
53
- source;
54
- constructor(source) {
55
- this.source = source;
51
+
52
+ //#endregion
53
+ //#region src/generate.ts
54
+ /**
55
+ * 创建新的生成上下文
56
+ */
57
+ function createGenerateContext() {
58
+ return {
59
+ usedParamNames: /* @__PURE__ */ new Set(),
60
+ paramMapping: /* @__PURE__ */ new Map()
61
+ };
62
+ }
63
+ /**
64
+ * 从 AST 生成规范化的代码
65
+ */
66
+ function generate(node) {
67
+ return generateWithContext(node, createGenerateContext());
68
+ }
69
+ /** 需要空格分隔的关键字运算符 */
70
+ const KEYWORD_BINARY_OPERATORS = new Set(["in", "instanceof"]);
71
+ const KEYWORD_UNARY_OPERATORS = new Set(["typeof", "void"]);
72
+ /**
73
+ * 带上下文的代码生成
74
+ */
75
+ function generateWithContext(node, ctx) {
76
+ switch (node.type) {
77
+ case "NumberLiteral": return node.raw;
78
+ case "StringLiteral": return JSON.stringify(node.value);
79
+ case "BooleanLiteral": return node.value ? "true" : "false";
80
+ case "NullLiteral": return "null";
81
+ case "Identifier": return node.name;
82
+ case "Placeholder": return ctx.paramMapping.get(node.id) ?? `$$${node.id.description}$$`;
83
+ case "BinaryExpr": {
84
+ const left = wrapIfNeededWithContext(node.left, node, "left", ctx);
85
+ const right = wrapIfNeededWithContext(node.right, node, "right", ctx);
86
+ const sep = KEYWORD_BINARY_OPERATORS.has(node.operator) ? " " : "";
87
+ return `${left}${sep}${node.operator}${sep}${right}`;
88
+ }
89
+ case "UnaryExpr": {
90
+ if (!node.prefix) return generateWithContext(node.argument, ctx) + node.operator;
91
+ const arg = wrapIfNeededWithContext(node.argument, node, "argument", ctx);
92
+ const sep = KEYWORD_UNARY_OPERATORS.has(node.operator) ? " " : "";
93
+ return `${node.operator}${sep}${arg}`;
94
+ }
95
+ case "ConditionalExpr": return `${wrapIfNeededWithContext(node.test, node, "test", ctx)}?${wrapIfNeededWithContext(node.consequent, node, "consequent", ctx)}:${wrapIfNeededWithContext(node.alternate, node, "alternate", ctx)}`;
96
+ case "MemberExpr": {
97
+ const object = wrapIfNeededWithContext(node.object, node, "object", ctx);
98
+ const property = generateWithContext(node.property, ctx);
99
+ const accessor = node.optional ? "?." : node.computed ? "" : ".";
100
+ return node.computed ? `${object}${accessor}[${property}]` : `${object}${accessor}${property}`;
101
+ }
102
+ case "CallExpr": {
103
+ const callee = wrapIfNeededWithContext(node.callee, node, "callee", ctx);
104
+ const args = node.arguments.map((arg) => generateWithContext(arg, ctx)).join(",");
105
+ return `${node.callee.type === "Identifier" && BUILTIN_CONSTRUCTORS.has(node.callee.name) ? "new " : ""}${callee}${node.optional ? "?." : ""}(${args})`;
106
+ }
107
+ case "ArrayExpr": return `[${node.elements.map((el) => generateWithContext(el, ctx)).join(",")}]`;
108
+ case "ObjectExpr": return `{${node.properties.map((prop) => {
109
+ if (prop.shorthand) return generateWithContext(prop.key, ctx);
110
+ return `${prop.computed ? `[${generateWithContext(prop.key, ctx)}]` : generateWithContext(prop.key, ctx)}:${generateWithContext(prop.value, ctx)}`;
111
+ }).join(",")}}`;
112
+ case "ArrowFunctionExpr": return generateArrowFunction(node, ctx);
113
+ default: {
114
+ const unknownNode = node;
115
+ throw new Error(`Unknown node type: ${unknownNode.type ?? "unknown"}`);
116
+ }
56
117
  }
57
- parse() {
58
- this.skipWhitespace();
59
- const node = this.parseExpression();
60
- this.skipWhitespace();
61
- if (this.pos < this.source.length) throw new Error(`Unexpected token at position ${this.pos}: ${this.source.slice(this.pos, this.pos + 10)}`);
62
- return node;
118
+ }
119
+ /**
120
+ * 生成箭头函数代码
121
+ * 为 Placeholder 参数分配唯一名称,避免嵌套 lambda 冲突
122
+ */
123
+ function generateArrowFunction(node, ctx) {
124
+ const allocatedParams = [];
125
+ const paramNames = [];
126
+ for (const param of node.params) if (param.type === "Identifier") paramNames.push(param.name);
127
+ else {
128
+ const name = allocateUniqueName(ctx.usedParamNames);
129
+ paramNames.push(name);
130
+ allocatedParams.push({
131
+ id: param.id,
132
+ name
133
+ });
134
+ ctx.usedParamNames.add(name);
135
+ ctx.paramMapping.set(param.id, name);
63
136
  }
64
- parseExpression() {
65
- return this.parseConditional();
137
+ const paramsStr = paramNames.length === 1 ? paramNames[0] : `(${paramNames.join(",")})`;
138
+ const bodyStr = node.body.type === "ObjectExpr" ? `(${generateWithContext(node.body, ctx)})` : generateWithContext(node.body, ctx);
139
+ for (const { id, name } of allocatedParams) {
140
+ ctx.paramMapping.delete(id);
141
+ ctx.usedParamNames.delete(name);
66
142
  }
67
- parseConditional() {
68
- let node = this.parseBinary(0);
69
- this.skipWhitespace();
70
- if (this.peek() === "?") {
71
- this.advance();
72
- this.skipWhitespace();
73
- const consequent = this.parseExpression();
74
- this.skipWhitespace();
75
- this.expect(":");
76
- this.skipWhitespace();
77
- const alternate = this.parseExpression();
78
- node = {
79
- type: "ConditionalExpr",
80
- test: node,
81
- consequent,
82
- alternate
83
- };
84
- }
85
- return node;
143
+ return `${paramsStr}=>${bodyStr}`;
144
+ }
145
+ /**
146
+ * 分配一个未使用的参数名 (_0, _1, _2, ...)
147
+ */
148
+ function allocateUniqueName(usedNames) {
149
+ let index = 0;
150
+ while (usedNames.has(`_${index}`)) index++;
151
+ return `_${index}`;
152
+ }
153
+ /**
154
+ * 判断是否需要括号包裹,并生成代码(带上下文版本)
155
+ */
156
+ function wrapIfNeededWithContext(child, parent, position, ctx) {
157
+ const code = generateWithContext(child, ctx);
158
+ if (needsParens(child, parent, position)) return `(${code})`;
159
+ return code;
160
+ }
161
+ /**
162
+ * 判断子节点是否需要括号
163
+ */
164
+ function needsParens(child, parent, position) {
165
+ switch (parent.type) {
166
+ case "BinaryExpr":
167
+ if (child.type === "ConditionalExpr" || child.type === "UnaryExpr") return true;
168
+ if (child.type === "BinaryExpr") {
169
+ const childPrec = PRECEDENCE[child.operator] ?? 0;
170
+ const parentPrec = PRECEDENCE[parent.operator] ?? 0;
171
+ if (childPrec < parentPrec) return true;
172
+ if (childPrec === parentPrec && position === "right" && !RIGHT_ASSOCIATIVE.has(parent.operator)) return true;
173
+ }
174
+ return false;
175
+ case "UnaryExpr": return position === "argument" && (child.type === "BinaryExpr" || child.type === "ConditionalExpr");
176
+ case "MemberExpr":
177
+ case "CallExpr":
178
+ if (position !== "object" && position !== "callee") return false;
179
+ if ([
180
+ "BinaryExpr",
181
+ "ConditionalExpr",
182
+ "UnaryExpr",
183
+ "ArrowFunctionExpr",
184
+ "ObjectExpr"
185
+ ].includes(child.type)) return true;
186
+ if (child.type === "NumberLiteral" && parent.type === "MemberExpr" && !parent.computed) return !child.raw.includes(".") && !child.raw.includes("e") && !child.raw.includes("x");
187
+ return false;
188
+ case "ConditionalExpr": return position === "test" && child.type === "ConditionalExpr";
189
+ default: return false;
86
190
  }
87
- parseBinary(minPrec) {
88
- let left = this.parseUnary();
89
- while (true) {
90
- this.skipWhitespace();
91
- const op = this.peekOperator();
92
- if (!op || PRECEDENCE[op] === void 0 || PRECEDENCE[op] < minPrec) break;
93
- this.pos += op.length;
94
- this.skipWhitespace();
95
- const nextMinPrec = RIGHT_ASSOCIATIVE.has(op) ? PRECEDENCE[op] : PRECEDENCE[op] + 1;
96
- const right = this.parseBinary(nextMinPrec);
97
- left = {
98
- type: "BinaryExpr",
99
- operator: op,
100
- left,
101
- right
102
- };
191
+ }
192
+ /**
193
+ * 转换 AST 中的标识符
194
+ * 回调函数可以返回:
195
+ * - string: 替换标识符名称
196
+ * - ASTNode: 内联该 AST 节点(用于子表达式内联)
197
+ */
198
+ function transformIdentifiers(node, transform) {
199
+ switch (node.type) {
200
+ case "Identifier": {
201
+ const result = transform(node.name);
202
+ return typeof result === "string" ? {
203
+ ...node,
204
+ name: result
205
+ } : result;
103
206
  }
104
- return left;
105
- }
106
- parseUnary() {
107
- this.skipWhitespace();
108
- const ch = this.peek();
109
- if (ch === "!" || ch === "~" || ch === "+" || ch === "-") {
110
- this.advance();
111
- this.skipWhitespace();
207
+ case "Placeholder": return node;
208
+ case "BinaryExpr": return {
209
+ ...node,
210
+ left: transformIdentifiers(node.left, transform),
211
+ right: transformIdentifiers(node.right, transform)
212
+ };
213
+ case "UnaryExpr": return {
214
+ ...node,
215
+ argument: transformIdentifiers(node.argument, transform)
216
+ };
217
+ case "ConditionalExpr": return {
218
+ ...node,
219
+ test: transformIdentifiers(node.test, transform),
220
+ consequent: transformIdentifiers(node.consequent, transform),
221
+ alternate: transformIdentifiers(node.alternate, transform)
222
+ };
223
+ case "MemberExpr": return {
224
+ ...node,
225
+ object: transformIdentifiers(node.object, transform),
226
+ property: node.computed ? transformIdentifiers(node.property, transform) : node.property
227
+ };
228
+ case "CallExpr": return {
229
+ ...node,
230
+ callee: transformIdentifiers(node.callee, transform),
231
+ arguments: node.arguments.map((arg) => transformIdentifiers(arg, transform))
232
+ };
233
+ case "ArrayExpr": return {
234
+ ...node,
235
+ elements: node.elements.map((el) => transformIdentifiers(el, transform))
236
+ };
237
+ case "ObjectExpr": return {
238
+ ...node,
239
+ properties: node.properties.map((prop) => ({
240
+ ...prop,
241
+ key: prop.computed ? transformIdentifiers(prop.key, transform) : prop.key,
242
+ value: transformIdentifiers(prop.value, transform)
243
+ }))
244
+ };
245
+ case "ArrowFunctionExpr": {
246
+ const paramNames = new Set(node.params.filter((p) => p.type === "Identifier").map((p) => p.name));
112
247
  return {
113
- type: "UnaryExpr",
114
- operator: ch,
115
- argument: this.parseUnary(),
116
- prefix: true
248
+ ...node,
249
+ body: transformIdentifiers(node.body, (name) => paramNames.has(name) ? name : transform(name))
117
250
  };
118
251
  }
119
- for (const keyword of ["typeof", "void"]) if (this.matchKeyword(keyword)) {
120
- this.skipWhitespace();
252
+ default: return node;
253
+ }
254
+ }
255
+ /**
256
+ * 转换 AST 中的占位符节点
257
+ * 回调函数接收 symbol,返回 Identifier 节点的名称
258
+ * 如果返回 null/undefined,则保留原始 Placeholder 节点
259
+ */
260
+ function transformPlaceholders(node, transform) {
261
+ switch (node.type) {
262
+ case "Placeholder": {
263
+ const name = transform(node.id);
264
+ return name != null ? {
265
+ type: "Identifier",
266
+ name
267
+ } : node;
268
+ }
269
+ case "Identifier": return node;
270
+ case "BinaryExpr": return {
271
+ ...node,
272
+ left: transformPlaceholders(node.left, transform),
273
+ right: transformPlaceholders(node.right, transform)
274
+ };
275
+ case "UnaryExpr": return {
276
+ ...node,
277
+ argument: transformPlaceholders(node.argument, transform)
278
+ };
279
+ case "ConditionalExpr": return {
280
+ ...node,
281
+ test: transformPlaceholders(node.test, transform),
282
+ consequent: transformPlaceholders(node.consequent, transform),
283
+ alternate: transformPlaceholders(node.alternate, transform)
284
+ };
285
+ case "MemberExpr": return {
286
+ ...node,
287
+ object: transformPlaceholders(node.object, transform),
288
+ property: node.computed ? transformPlaceholders(node.property, transform) : node.property
289
+ };
290
+ case "CallExpr": return {
291
+ ...node,
292
+ callee: transformPlaceholders(node.callee, transform),
293
+ arguments: node.arguments.map((arg) => transformPlaceholders(arg, transform))
294
+ };
295
+ case "ArrayExpr": return {
296
+ ...node,
297
+ elements: node.elements.map((el) => transformPlaceholders(el, transform))
298
+ };
299
+ case "ObjectExpr": return {
300
+ ...node,
301
+ properties: node.properties.map((prop) => ({
302
+ ...prop,
303
+ key: prop.computed ? transformPlaceholders(prop.key, transform) : prop.key,
304
+ value: transformPlaceholders(prop.value, transform)
305
+ }))
306
+ };
307
+ case "ArrowFunctionExpr": {
308
+ const paramSymbols = new Set(node.params.filter((p) => p.type === "Placeholder").map((p) => p.id));
121
309
  return {
122
- type: "UnaryExpr",
123
- operator: keyword,
124
- argument: this.parseUnary(),
125
- prefix: true
310
+ ...node,
311
+ body: transformPlaceholders(node.body, (id) => paramSymbols.has(id) ? null : transform(id))
126
312
  };
127
313
  }
128
- return this.parsePostfix();
314
+ default: return node;
129
315
  }
130
- parsePostfix() {
131
- let node = this.parsePrimary();
132
- while (true) {
133
- this.skipWhitespace();
134
- const ch = this.peek();
135
- if (ch === ".") {
136
- this.advance();
137
- this.skipWhitespace();
138
- const property = this.parseIdentifier();
139
- node = {
140
- type: "MemberExpr",
141
- object: node,
142
- property,
143
- computed: false,
144
- optional: false
145
- };
146
- } else if (ch === "[") {
147
- this.advance();
148
- this.skipWhitespace();
149
- const property = this.parseExpression();
150
- this.skipWhitespace();
151
- this.expect("]");
152
- node = {
153
- type: "MemberExpr",
154
- object: node,
155
- property,
156
- computed: true,
157
- optional: false
158
- };
159
- } else if (ch === "(") {
160
- this.advance();
161
- const args = this.parseArguments();
162
- this.expect(")");
163
- node = {
164
- type: "CallExpr",
165
- callee: node,
166
- arguments: args,
167
- optional: false
168
- };
169
- } else if (ch === "?" && this.peekAt(1) === ".") {
170
- this.advance();
171
- this.advance();
172
- this.skipWhitespace();
173
- if (this.peek() === "[") {
174
- this.advance();
175
- this.skipWhitespace();
176
- const property = this.parseExpression();
177
- this.skipWhitespace();
178
- this.expect("]");
179
- node = {
180
- type: "MemberExpr",
181
- object: node,
182
- property,
183
- computed: true,
184
- optional: true
185
- };
186
- } else if (this.peek() === "(") {
187
- this.advance();
188
- const args = this.parseArguments();
189
- this.expect(")");
190
- node = {
191
- type: "CallExpr",
192
- callee: node,
193
- arguments: args,
194
- optional: true
195
- };
196
- } else {
197
- const property = this.parseIdentifier();
198
- node = {
199
- type: "MemberExpr",
200
- object: node,
201
- property,
202
- computed: false,
203
- optional: true
204
- };
205
- }
206
- } else break;
207
- }
208
- return node;
209
- }
210
- parsePrimary() {
211
- this.skipWhitespace();
212
- const ch = this.peek();
213
- if (this.isDigit(ch) || ch === "." && this.isDigit(this.peekAt(1))) return this.parseNumber();
214
- if (ch === "\"" || ch === "'" || ch === "`") return this.parseString();
215
- if (ch === "[") return this.parseArray();
216
- if (ch === "{") return this.parseObject();
217
- if (ch === "(") {
218
- const arrowFunc = this.tryParseArrowFunction();
219
- if (arrowFunc) return arrowFunc;
220
- this.advance();
221
- this.skipWhitespace();
222
- const expr = this.parseExpression();
223
- this.skipWhitespace();
224
- this.expect(")");
225
- return expr;
226
- }
227
- if (this.matchKeyword("true")) return {
228
- type: "BooleanLiteral",
229
- value: true
230
- };
231
- if (this.matchKeyword("false")) return {
232
- type: "BooleanLiteral",
233
- value: false
234
- };
235
- if (this.matchKeyword("null")) return { type: "NullLiteral" };
236
- if (this.matchKeyword("undefined")) return {
237
- type: "Identifier",
238
- name: "undefined"
239
- };
240
- if (this.isIdentifierStart(ch)) {
241
- const arrowFunc = this.tryParseSingleParamArrowFunction();
242
- if (arrowFunc) return arrowFunc;
243
- return this.parseIdentifier();
244
- }
245
- throw new Error(`Unexpected character at position ${this.pos}: ${ch}`);
246
- }
247
- parseNumber() {
248
- const start = this.pos;
249
- if (this.peek() === "0") {
250
- const next = this.peekAt(1)?.toLowerCase();
251
- if (next === "x" || next === "o" || next === "b") {
252
- this.advance();
253
- this.advance();
254
- while (this.isHexDigit(this.peek())) this.advance();
255
- const raw = this.source.slice(start, this.pos);
256
- return {
257
- type: "NumberLiteral",
258
- value: Number(raw),
259
- raw
260
- };
261
- }
262
- }
263
- while (this.isDigit(this.peek())) this.advance();
264
- if (this.peek() === "." && this.isDigit(this.peekAt(1))) {
265
- this.advance();
266
- while (this.isDigit(this.peek())) this.advance();
267
- }
268
- if (this.peek()?.toLowerCase() === "e") {
269
- this.advance();
270
- if (this.peek() === "+" || this.peek() === "-") this.advance();
271
- while (this.isDigit(this.peek())) this.advance();
272
- }
273
- const raw = this.source.slice(start, this.pos);
274
- return {
275
- type: "NumberLiteral",
276
- value: Number(raw),
277
- raw
278
- };
279
- }
280
- static ESCAPE_CHARS = {
281
- n: "\n",
282
- r: "\r",
283
- t: " ",
284
- "\\": "\\",
285
- "'": "'",
286
- "\"": "\"",
287
- "`": "`"
316
+ }
317
+
318
+ //#endregion
319
+ //#region src/proxy-metadata.ts
320
+ /**
321
+ * 全局 WeakMap 存储
322
+ */
323
+ const proxyMetadata = /* @__PURE__ */ new WeakMap();
324
+ /**
325
+ * 设置 Proxy 元数据
326
+ */
327
+ function setProxyMetadata(proxy, metadata) {
328
+ proxyMetadata.set(proxy, metadata);
329
+ }
330
+ /**
331
+ * 获取 Proxy 元数据
332
+ */
333
+ function getProxyMetadata(proxy) {
334
+ return proxyMetadata.get(proxy);
335
+ }
336
+ /**
337
+ * 检查对象是否是 Proxy variable
338
+ */
339
+ function isProxyVariable(obj) {
340
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
341
+ return proxyMetadata.get(obj)?.type === "variable";
342
+ }
343
+ /**
344
+ * 检查对象是否是 Proxy expression
345
+ */
346
+ function isProxyExpression(obj) {
347
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
348
+ return proxyMetadata.get(obj)?.type === "expression";
349
+ }
350
+ /**
351
+ * 检查对象是否是任意 Proxy (variable 或 expression)
352
+ */
353
+ function isProxy(obj) {
354
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
355
+ return proxyMetadata.has(obj);
356
+ }
357
+
358
+ //#endregion
359
+ //#region src/proxy-variable.ts
360
+ const typedArrayConstructors = [
361
+ "Int8Array",
362
+ "Uint8Array",
363
+ "Uint8ClampedArray",
364
+ "Int16Array",
365
+ "Uint16Array",
366
+ "Int32Array",
367
+ "Uint32Array",
368
+ "Float32Array",
369
+ "Float64Array",
370
+ "BigInt64Array",
371
+ "BigUint64Array"
372
+ ];
373
+ /**
374
+ * 创建占位符 AST 节点
375
+ */
376
+ function placeholder(id) {
377
+ return {
378
+ type: "Placeholder",
379
+ id
288
380
  };
289
- parseString() {
290
- const quote = this.peek();
291
- this.advance();
292
- let value = "";
293
- while (this.pos < this.source.length && this.peek() !== quote) if (this.peek() === "\\") {
294
- this.advance();
295
- const escaped = this.peek();
296
- value += Parser.ESCAPE_CHARS[escaped] ?? escaped;
297
- this.advance();
298
- } else {
299
- value += this.peek();
300
- this.advance();
301
- }
302
- this.expect(quote);
303
- return {
304
- type: "StringLiteral",
305
- value,
306
- quote
307
- };
308
- }
309
- parseArray() {
310
- this.expect("[");
311
- const elements = [];
312
- this.skipWhitespace();
313
- while (this.peek() !== "]") {
314
- elements.push(this.parseExpression());
315
- this.skipWhitespace();
316
- if (this.peek() === ",") {
317
- this.advance();
318
- this.skipWhitespace();
319
- } else break;
320
- }
321
- this.expect("]");
322
- return {
323
- type: "ArrayExpr",
324
- elements
325
- };
326
- }
327
- parseObject() {
328
- this.expect("{");
329
- const properties = [];
330
- this.skipWhitespace();
331
- while (this.peek() !== "}") {
332
- const prop = this.parseObjectProperty();
333
- properties.push(prop);
334
- this.skipWhitespace();
335
- if (this.peek() === ",") {
336
- this.advance();
337
- this.skipWhitespace();
338
- } else break;
339
- }
340
- this.expect("}");
341
- return {
342
- type: "ObjectExpr",
343
- properties
344
- };
345
- }
346
- parseObjectProperty() {
347
- this.skipWhitespace();
348
- let key;
349
- let computed = false;
350
- if (this.peek() === "[") {
351
- this.advance();
352
- this.skipWhitespace();
353
- key = this.parseExpression();
354
- this.skipWhitespace();
355
- this.expect("]");
356
- computed = true;
357
- } else if (this.peek() === "\"" || this.peek() === "'") key = this.parseString();
358
- else key = this.parseIdentifier();
359
- this.skipWhitespace();
360
- if (this.peek() === ":") {
361
- this.advance();
362
- this.skipWhitespace();
363
- const value = this.parseExpression();
364
- return {
365
- key,
366
- value,
367
- computed,
368
- shorthand: false
369
- };
370
- }
371
- if (key.type !== "Identifier") throw new Error("Shorthand property must be an identifier");
372
- return {
373
- key,
374
- value: key,
375
- computed: false,
376
- shorthand: true
377
- };
378
- }
379
- parseIdentifier() {
380
- const start = this.pos;
381
- while (this.isIdentifierPart(this.peek())) this.advance();
382
- const name = this.source.slice(start, this.pos);
383
- if (!name) throw new Error(`Expected identifier at position ${this.pos}`);
384
- return {
385
- type: "Identifier",
386
- name
387
- };
388
- }
389
- /**
390
- * 尝试解析带括号的箭头函数: (a, b) => expr
391
- * 使用回溯机制
392
- */
393
- tryParseArrowFunction() {
394
- const savedPos = this.pos;
395
- try {
396
- this.expect("(");
397
- this.skipWhitespace();
398
- const params = [];
399
- while (this.peek() !== ")") {
400
- if (!this.isIdentifierStart(this.peek())) throw new Error("Expected identifier");
401
- params.push(this.parseIdentifier());
402
- this.skipWhitespace();
403
- if (this.peek() === ",") {
404
- this.advance();
405
- this.skipWhitespace();
406
- } else break;
407
- }
408
- this.expect(")");
409
- this.skipWhitespace();
410
- if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
411
- this.pos += 2;
412
- this.skipWhitespace();
413
- return {
414
- type: "ArrowFunctionExpr",
415
- params,
416
- body: this.parseExpression()
417
- };
418
- } catch {
419
- this.pos = savedPos;
420
- return null;
421
- }
422
- }
423
- /**
424
- * 尝试解析单参数无括号的箭头函数: a => expr
425
- * 使用回溯机制
426
- */
427
- tryParseSingleParamArrowFunction() {
428
- const savedPos = this.pos;
429
- try {
430
- const param = this.parseIdentifier();
431
- this.skipWhitespace();
432
- if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
433
- this.pos += 2;
434
- this.skipWhitespace();
435
- const body = this.parseExpression();
436
- return {
437
- type: "ArrowFunctionExpr",
438
- params: [param],
439
- body
440
- };
441
- } catch {
442
- this.pos = savedPos;
443
- return null;
444
- }
445
- }
446
- parseArguments() {
447
- const args = [];
448
- this.skipWhitespace();
449
- while (this.peek() !== ")") {
450
- args.push(this.parseExpression());
451
- this.skipWhitespace();
452
- if (this.peek() === ",") {
453
- this.advance();
454
- this.skipWhitespace();
455
- } else break;
456
- }
457
- return args;
458
- }
459
- static OPERATORS = [
460
- "instanceof",
461
- ">>>",
462
- "===",
463
- "!==",
464
- "&&",
465
- "||",
466
- "??",
467
- "==",
468
- "!=",
469
- "<=",
470
- ">=",
471
- "<<",
472
- ">>",
473
- "**",
474
- "in",
475
- "+",
476
- "-",
477
- "*",
478
- "/",
479
- "%",
480
- "<",
481
- ">",
482
- "&",
483
- "|",
484
- "^"
485
- ];
486
- static KEYWORD_OPERATORS = new Set(["in", "instanceof"]);
487
- peekOperator() {
488
- for (const op of Parser.OPERATORS) {
489
- if (!this.source.startsWith(op, this.pos)) continue;
490
- if (Parser.KEYWORD_OPERATORS.has(op)) {
491
- const nextChar = this.source[this.pos + op.length];
492
- if (nextChar && this.isIdentifierPart(nextChar)) continue;
493
- }
494
- return op;
495
- }
496
- return null;
497
- }
498
- matchKeyword(keyword) {
499
- if (this.source.startsWith(keyword, this.pos)) {
500
- const nextChar = this.source[this.pos + keyword.length];
501
- if (!nextChar || !this.isIdentifierPart(nextChar)) {
502
- this.pos += keyword.length;
503
- return true;
504
- }
505
- }
506
- return false;
507
- }
508
- peek() {
509
- return this.source[this.pos] || "";
510
- }
511
- peekAt(offset) {
512
- return this.source[this.pos + offset] || "";
513
- }
514
- advance() {
515
- return this.source[this.pos++] || "";
516
- }
517
- expect(ch) {
518
- if (this.peek() !== ch) throw new Error(`Expected '${ch}' at position ${this.pos}, got '${this.peek()}'`);
519
- this.advance();
520
- }
521
- skipWhitespace() {
522
- while (/\s/.test(this.peek())) this.advance();
523
- }
524
- isDigit(ch) {
525
- const code = ch.charCodeAt(0);
526
- return code >= 48 && code <= 57;
527
- }
528
- isHexDigit(ch) {
529
- const code = ch.charCodeAt(0);
530
- return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
531
- }
532
- isIdentifierStart(ch) {
533
- const code = ch.charCodeAt(0);
534
- return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95 || code === 36;
535
- }
536
- isIdentifierPart(ch) {
537
- const code = ch.charCodeAt(0);
538
- return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 95 || code === 36;
539
- }
540
- };
381
+ }
382
+ /**
383
+ * 创建标识符 AST 节点
384
+ */
385
+ function identifier(name) {
386
+ return {
387
+ type: "Identifier",
388
+ name
389
+ };
390
+ }
391
+ /**
392
+ * 创建数字字面量 AST 节点
393
+ */
394
+ function numberLiteral(value) {
395
+ return {
396
+ type: "NumberLiteral",
397
+ value,
398
+ raw: String(value)
399
+ };
400
+ }
401
+ /**
402
+ * 创建字符串字面量 AST 节点
403
+ */
404
+ function stringLiteral(value, quote = "\"") {
405
+ return {
406
+ type: "StringLiteral",
407
+ value,
408
+ quote
409
+ };
410
+ }
411
+ /**
412
+ * 创建成员表达式 AST 节点
413
+ */
414
+ function memberExpr(object, property) {
415
+ return {
416
+ type: "MemberExpr",
417
+ object,
418
+ property,
419
+ computed: false,
420
+ optional: false
421
+ };
422
+ }
541
423
  /**
542
- * 解析 JavaScript 表达式为 AST
424
+ * 创建调用表达式 AST 节点
543
425
  */
544
- function parse(source) {
545
- return new Parser(source).parse();
426
+ function callExpr(callee, arguments_) {
427
+ return {
428
+ type: "CallExpr",
429
+ callee,
430
+ arguments: arguments_,
431
+ optional: false
432
+ };
546
433
  }
547
434
  /**
548
- * AST 生成规范化的代码
435
+ * 创建数组表达式 AST 节点
549
436
  */
550
- function generate(node) {
551
- switch (node.type) {
552
- case "NumberLiteral": return node.raw;
553
- case "StringLiteral": return JSON.stringify(node.value);
554
- case "BooleanLiteral": return node.value ? "true" : "false";
555
- case "NullLiteral": return "null";
556
- case "Identifier": return node.name;
557
- case "BinaryExpr": {
558
- const left = wrapIfNeeded(node.left, node, "left");
559
- const right = wrapIfNeeded(node.right, node, "right");
560
- if (node.operator === "in" || node.operator === "instanceof") return `${left} ${node.operator} ${right}`;
561
- return `${left}${node.operator}${right}`;
437
+ function arrayExpr(elements) {
438
+ return {
439
+ type: "ArrayExpr",
440
+ elements
441
+ };
442
+ }
443
+ /**
444
+ * 检查对象是否为 TypedArray 实例
445
+ */
446
+ function getTypedArrayConstructor(value) {
447
+ for (const constructorName of typedArrayConstructors) {
448
+ const Constructor = globalThis[constructorName];
449
+ if (Constructor && value instanceof Constructor) return Constructor;
450
+ }
451
+ return null;
452
+ }
453
+ /**
454
+ * 序列化参数为 AST 节点
455
+ * - Proxy Variable/Expression:使用 ast 或占位符标识符
456
+ * - 数组:返回 ArrayExpr 节点
457
+ * - 对象:返回 ObjectExpr 节点
458
+ * - 原始值:返回对应的字面量节点
459
+ * - Date, RegExp, BigInt, URL, URLSearchParams, Map, Set, TypedArray, DataView: 构造函数调用
460
+ */
461
+ function serializeArgumentToAST(arg) {
462
+ if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
463
+ const meta = getProxyMetadata(arg);
464
+ if (meta) {
465
+ if (meta.ast) return meta.ast;
466
+ if (meta.rootVariable) return placeholder(meta.rootVariable);
562
467
  }
563
- case "UnaryExpr":
564
- if (node.prefix) {
565
- const arg = wrapIfNeeded(node.argument, node, "argument");
566
- if (node.operator === "typeof" || node.operator === "void") return `${node.operator} ${arg}`;
567
- return `${node.operator}${arg}`;
568
- }
569
- return generate(node.argument) + node.operator;
570
- case "ConditionalExpr": return `${wrapIfNeeded(node.test, node, "test")}?${wrapIfNeeded(node.consequent, node, "consequent")}:${wrapIfNeeded(node.alternate, node, "alternate")}`;
571
- case "MemberExpr": {
572
- const object = wrapIfNeeded(node.object, node, "object");
573
- const property = generate(node.property);
574
- return node.computed ? `${object}${node.optional ? "?." : ""}[${property}]` : `${object}${node.optional ? "?." : "."}${property}`;
468
+ }
469
+ if (Array.isArray(arg)) return arrayExpr(arg.map(serializeArgumentToAST));
470
+ if (typeof arg === "object" && arg !== null) {
471
+ if (arg instanceof Date) return callExpr(identifier("Date"), [numberLiteral(arg.getTime())]);
472
+ if (arg instanceof RegExp) {
473
+ const args = [stringLiteral(arg.source)];
474
+ if (arg.flags) args.push(stringLiteral(arg.flags));
475
+ return callExpr(identifier("RegExp"), args);
575
476
  }
576
- case "CallExpr": {
577
- const callee = wrapIfNeeded(node.callee, node, "callee");
578
- const args = node.arguments.map(generate).join(",");
579
- return `${node.callee.type === "Identifier" && BUILTIN_CONSTRUCTORS.has(node.callee.name) ? "new " : ""}${callee}${node.optional ? "?." : ""}(${args})`;
477
+ if (typeof URL !== "undefined" && arg instanceof URL) return callExpr(identifier("URL"), [stringLiteral(arg.href)]);
478
+ if (typeof URLSearchParams !== "undefined" && arg instanceof URLSearchParams) {
479
+ const entries = [];
480
+ arg.forEach((value, key) => {
481
+ entries.push(arrayExpr([stringLiteral(key), stringLiteral(value)]));
482
+ });
483
+ return callExpr(identifier("URLSearchParams"), [arrayExpr(entries)]);
580
484
  }
581
- case "ArrayExpr": return `[${node.elements.map(generate).join(",")}]`;
582
- case "ObjectExpr": return `{${node.properties.map((prop) => {
583
- if (prop.shorthand) return generate(prop.key);
584
- return `${prop.computed ? `[${generate(prop.key)}]` : generate(prop.key)}:${generate(prop.value)}`;
585
- }).join(",")}}`;
586
- case "ArrowFunctionExpr": {
587
- const params = node.params.map((p) => p.name).join(",");
588
- const body = node.body.type === "ObjectExpr" ? `(${generate(node.body)})` : generate(node.body);
589
- return `${node.params.length === 1 ? params : `(${params})`}=>${body}`;
485
+ if (arg instanceof Map) {
486
+ const entries = [];
487
+ arg.forEach((value, key) => {
488
+ entries.push(arrayExpr([serializeArgumentToAST(key), serializeArgumentToAST(value)]));
489
+ });
490
+ return callExpr(identifier("Map"), [arrayExpr(entries)]);
590
491
  }
591
- default: {
592
- const nodeType = node.type ?? "unknown";
593
- throw new Error(`Unknown node type: ${nodeType}`);
492
+ if (arg instanceof Set) {
493
+ const values = [];
494
+ arg.forEach((value) => values.push(serializeArgumentToAST(value)));
495
+ return callExpr(identifier("Set"), [arrayExpr(values)]);
496
+ }
497
+ const typedArrayConstructor = getTypedArrayConstructor(arg);
498
+ if (typedArrayConstructor) {
499
+ const values = [...arg].map(serializeArgumentToAST);
500
+ const constructorName = typedArrayConstructor.name;
501
+ return callExpr(identifier(constructorName), [arrayExpr(values)]);
502
+ }
503
+ if (arg instanceof ArrayBuffer) {
504
+ const uint8Array = new Uint8Array(arg);
505
+ const values = Array.from(uint8Array).map(numberLiteral);
506
+ return memberExpr(callExpr(identifier("Uint8Array"), [arrayExpr(values)]), identifier("buffer"));
594
507
  }
508
+ if (arg instanceof DataView) return callExpr(identifier("DataView"), [serializeArgumentToAST(arg.buffer)]);
509
+ return {
510
+ type: "ObjectExpr",
511
+ properties: Object.entries(arg).map(([k, v]) => {
512
+ return {
513
+ key: /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? identifier(k) : stringLiteral(k),
514
+ value: serializeArgumentToAST(v),
515
+ computed: false,
516
+ shorthand: false
517
+ };
518
+ })
519
+ };
595
520
  }
521
+ if (arg === null) return { type: "NullLiteral" };
522
+ if (arg === void 0) return identifier("undefined");
523
+ if (typeof arg === "boolean") return {
524
+ type: "BooleanLiteral",
525
+ value: arg
526
+ };
527
+ if (typeof arg === "number") return numberLiteral(arg);
528
+ if (typeof arg === "string") return stringLiteral(arg);
529
+ if (typeof arg === "bigint") return callExpr(identifier("BigInt"), [stringLiteral(arg.toString())]);
530
+ throw new Error(`Unsupported argument type: ${typeof arg}`);
596
531
  }
597
532
  /**
598
- * 判断是否需要括号包裹,并生成代码
533
+ * 从参数中收集依赖的 Symbol
534
+ * 递归遍历数组和对象,收集所有 Proxy 的依赖
599
535
  */
600
- function wrapIfNeeded(child, parent, position) {
601
- const code = generate(child);
602
- if (needsParens(child, parent, position)) return `(${code})`;
603
- return code;
536
+ function collectDepsFromArgs(args, deps) {
537
+ for (const arg of args) if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
538
+ const meta = getProxyMetadata(arg);
539
+ if (meta?.dependencies) for (const dep of meta.dependencies) deps.add(dep);
540
+ else if (Array.isArray(arg)) collectDepsFromArgs(arg, deps);
541
+ else if (typeof arg === "object") collectDepsFromArgs(Object.values(arg), deps);
542
+ }
604
543
  }
605
544
  /**
606
- * 判断子节点是否需要括号
545
+ * 根据路径构建成员表达式 AST
607
546
  */
608
- function needsParens(child, parent, position) {
609
- switch (parent.type) {
610
- case "BinaryExpr":
611
- if (child.type === "ConditionalExpr" || child.type === "UnaryExpr") return true;
612
- if (child.type === "BinaryExpr") {
613
- const childPrec = PRECEDENCE[child.operator] ?? 0;
614
- const parentPrec = PRECEDENCE[parent.operator] ?? 0;
615
- if (childPrec < parentPrec) return true;
616
- if (childPrec === parentPrec && position === "right" && !RIGHT_ASSOCIATIVE.has(parent.operator)) return true;
617
- }
618
- return false;
619
- case "UnaryExpr": return position === "argument" && (child.type === "BinaryExpr" || child.type === "ConditionalExpr");
620
- case "MemberExpr":
621
- case "CallExpr":
622
- if (position !== "object" && position !== "callee") return false;
623
- if ([
624
- "BinaryExpr",
625
- "ConditionalExpr",
626
- "UnaryExpr",
627
- "ArrowFunctionExpr",
628
- "ObjectExpr"
629
- ].includes(child.type)) return true;
630
- if (child.type === "NumberLiteral" && parent.type === "MemberExpr" && !parent.computed) return !child.raw.includes(".") && !child.raw.includes("e") && !child.raw.includes("x");
631
- return false;
632
- case "ConditionalExpr": return position === "test" && child.type === "ConditionalExpr";
633
- default: return false;
634
- }
547
+ function buildMemberExprAst(rootId, path) {
548
+ let ast = placeholder(rootId);
549
+ for (const prop of path) ast = memberExpr(ast, identifier(prop));
550
+ return ast;
635
551
  }
636
552
  /**
637
- * 转换 AST 中的标识符
638
- * 回调函数可以返回:
639
- * - string: 替换标识符名称
640
- * - ASTNode: 内联该 AST 节点(用于子表达式内联)
553
+ * 创建 Proxy 的公共 handler
641
554
  */
642
- function transformIdentifiers(node, transform) {
643
- switch (node.type) {
644
- case "Identifier": {
645
- const result = transform(node.name);
646
- return typeof result === "string" ? {
647
- ...node,
648
- name: result
649
- } : result;
650
- }
651
- case "BinaryExpr": return {
652
- ...node,
653
- left: transformIdentifiers(node.left, transform),
654
- right: transformIdentifiers(node.right, transform)
655
- };
656
- case "UnaryExpr": return {
657
- ...node,
658
- argument: transformIdentifiers(node.argument, transform)
659
- };
660
- case "ConditionalExpr": return {
661
- ...node,
662
- test: transformIdentifiers(node.test, transform),
663
- consequent: transformIdentifiers(node.consequent, transform),
664
- alternate: transformIdentifiers(node.alternate, transform)
665
- };
666
- case "MemberExpr": return {
667
- ...node,
668
- object: transformIdentifiers(node.object, transform),
669
- property: node.computed ? transformIdentifiers(node.property, transform) : node.property
670
- };
671
- case "CallExpr": return {
672
- ...node,
673
- callee: transformIdentifiers(node.callee, transform),
674
- arguments: node.arguments.map((arg) => transformIdentifiers(arg, transform))
675
- };
676
- case "ArrayExpr": return {
677
- ...node,
678
- elements: node.elements.map((el) => transformIdentifiers(el, transform))
679
- };
680
- case "ObjectExpr": return {
681
- ...node,
682
- properties: node.properties.map((prop) => ({
683
- ...prop,
684
- key: prop.computed ? transformIdentifiers(prop.key, transform) : prop.key,
685
- value: transformIdentifiers(prop.value, transform)
686
- }))
687
- };
688
- case "ArrowFunctionExpr": {
689
- const paramNames = new Set(node.params.map((p) => p.name));
690
- return {
691
- ...node,
692
- body: transformIdentifiers(node.body, (name) => paramNames.has(name) ? name : transform(name))
693
- };
555
+ function createProxyHandler(ast, deps) {
556
+ return {
557
+ get(_target, prop) {
558
+ if (typeof prop === "symbol") return void 0;
559
+ return createProxyExpressionWithAST(memberExpr(ast, identifier(String(prop))), deps);
560
+ },
561
+ apply(_target, _thisArg, args) {
562
+ const callAst = callExpr(ast, args.map(serializeArgumentToAST));
563
+ const newDeps = new Set(deps);
564
+ collectDepsFromArgs(args, newDeps);
565
+ return createProxyExpressionWithAST(callAst, newDeps);
694
566
  }
695
- default: return node;
696
- }
567
+ };
568
+ }
569
+ /**
570
+ * 创建根 Variable Proxy
571
+ * 拦截属性访问,返回新的 expression proxy
572
+ * 不可直接调用(apply 应该只在链式调用后可用)
573
+ *
574
+ * @param id - 变量的唯一标识 Symbol
575
+ * @returns Proxy 包装的 Variable
576
+ */
577
+ function createProxyVariable(id) {
578
+ const deps = new Set([id]);
579
+ const proxy = new Proxy(function() {}, {
580
+ get(_target, prop) {
581
+ if (typeof prop === "symbol") return void 0;
582
+ return createProxyExpressionWithAST(buildMemberExprAst(id, [String(prop)]), deps);
583
+ },
584
+ apply() {
585
+ throw new Error("Variable cannot be called directly");
586
+ }
587
+ });
588
+ setProxyMetadata(proxy, {
589
+ type: "variable",
590
+ path: [],
591
+ rootVariable: id,
592
+ dependencies: deps
593
+ });
594
+ return proxy;
697
595
  }
698
-
699
- //#endregion
700
- //#region src/proxy-metadata.ts
701
- /**
702
- * 全局 WeakMap 存储
703
- */
704
- const proxyMetadata = /* @__PURE__ */ new WeakMap();
705
596
  /**
706
- * 设置 Proxy 元数据
597
+ * 创建带完整 AST 的 Proxy(方法调用后)
598
+ * 可以继续链式访问和调用
599
+ *
600
+ * @param ast - 完整的表达式 AST
601
+ * @param deps - 依赖集合
602
+ * @returns Proxy 包装的 Expression
707
603
  */
708
- function setProxyMetadata(proxy, metadata) {
709
- proxyMetadata.set(proxy, metadata);
604
+ function createProxyExpressionWithAST(ast, deps) {
605
+ const proxy = new Proxy(function() {}, createProxyHandler(ast, deps));
606
+ setProxyMetadata(proxy, {
607
+ type: "expression",
608
+ path: [],
609
+ ast,
610
+ dependencies: deps
611
+ });
612
+ return proxy;
710
613
  }
614
+
615
+ //#endregion
616
+ //#region src/variable.ts
711
617
  /**
712
- * 获取 Proxy 元数据
618
+ * 跟踪每个 variable 的唯一 Symbol ID
713
619
  */
714
- function getProxyMetadata(proxy) {
715
- return proxyMetadata.get(proxy);
716
- }
620
+ const variableIds = /* @__PURE__ */ new WeakMap();
717
621
  /**
718
- * 检查对象是否是 Proxy variable
622
+ * 计数器用于生成唯一变量 ID
719
623
  */
720
- function isProxyVariable(obj) {
721
- if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
722
- return proxyMetadata.get(obj)?.type === "variable";
723
- }
624
+ let variableCounter = 0;
724
625
  /**
725
- * 检查对象是否是 Proxy expression
626
+ * 创建一个类型化变量
627
+ * 返回 Proxy 对象,支持链式属性访问和方法调用
628
+ *
629
+ * @example
630
+ * ```ts
631
+ * const x = variable<number>();
632
+ * const config = variable<{ timeout: number }>();
633
+ * const timeout = config.timeout; // Proxy expression
634
+ * ```
726
635
  */
727
- function isProxyExpression(obj) {
728
- if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
729
- return proxyMetadata.get(obj)?.type === "expression";
636
+ function variable() {
637
+ const id = Symbol(`var_${variableCounter++}`);
638
+ const proxy = createProxyVariable(id);
639
+ variableIds.set(proxy, id);
640
+ return proxy;
730
641
  }
731
642
  /**
732
- * 检查对象是否是任意 Proxy (variable expression)
643
+ * 获取 variable 的唯一 Symbol ID
733
644
  */
734
- function isProxy(obj) {
735
- if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
736
- return proxyMetadata.has(obj);
645
+ function getVariableId(variable) {
646
+ if (typeof variable !== "object" && typeof variable !== "function" || variable === null) return void 0;
647
+ return variableIds.get(variable);
737
648
  }
738
649
 
739
650
  //#endregion
740
- //#region src/proxy-variable.ts
741
- const typedArrayConstructors = [
651
+ //#region src/compile.ts
652
+ const ALLOWED_GLOBALS = new Set([
653
+ "Math",
654
+ "JSON",
655
+ "Date",
656
+ "RegExp",
657
+ "Number",
658
+ "String",
659
+ "Boolean",
660
+ "Array",
661
+ "Object",
662
+ "undefined",
663
+ "NaN",
664
+ "Infinity",
665
+ "isNaN",
666
+ "isFinite",
667
+ "parseInt",
668
+ "parseFloat",
669
+ "BigInt",
670
+ "URL",
671
+ "URLSearchParams",
672
+ "Map",
673
+ "Set",
742
674
  "Int8Array",
743
675
  "Uint8Array",
744
676
  "Uint8ClampedArray",
@@ -749,552 +681,738 @@ const typedArrayConstructors = [
749
681
  "Float32Array",
750
682
  "Float64Array",
751
683
  "BigInt64Array",
752
- "BigUint64Array"
753
- ];
754
- /**
755
- * 使用 Symbol.description 生成占位符
756
- * 用于在表达式源码中标识变量
757
- */
758
- function getVariablePlaceholder$1(id) {
759
- return `$$VAR_${id.description}$$`;
760
- }
761
- /**
762
- * 创建标识符 AST 节点
763
- */
764
- function identifier(name) {
765
- return {
766
- type: "Identifier",
767
- name
768
- };
769
- }
770
- /**
771
- * 创建数字字面量 AST 节点
772
- */
773
- function numberLiteral(value) {
774
- return {
775
- type: "NumberLiteral",
776
- value,
777
- raw: String(value)
778
- };
779
- }
780
- /**
781
- * 创建字符串字面量 AST 节点
782
- */
783
- function stringLiteral(value, quote = "\"") {
784
- return {
785
- type: "StringLiteral",
786
- value,
787
- quote
788
- };
789
- }
684
+ "BigUint64Array",
685
+ "ArrayBuffer",
686
+ "DataView"
687
+ ]);
790
688
  /**
791
- * 创建成员表达式 AST 节点
689
+ * Proxy Expression 编译为可序列化的 JSON 结构
690
+ *
691
+ * @template TResult - 表达式结果类型
692
+ * @param expression - Proxy Expression,或包含 Proxy 的对象/数组/原始值
693
+ * @param variables - 所有使用的变量定义
694
+ * @param options - 编译选项
695
+ * @returns 编译后的数据结构 [变量名列表, 表达式1, 表达式2, ...]
696
+ *
697
+ * @throws 如果传入无效的表达式或未定义的变量引用
698
+ *
699
+ * @example
700
+ * ```ts
701
+ * const x = variable<number>()
702
+ * const y = variable<number>()
703
+ * const sum = expr({ x, y })("x + y")
704
+ * const result = expr({ sum, x })("sum * x")
705
+ * const compiled = compile(result, { x, y })
706
+ * // => [["x", "y"], "($0+$1)*$0"]
707
+ * ```
792
708
  */
793
- function memberExpr(object, property) {
794
- return {
795
- type: "MemberExpr",
796
- object,
797
- property,
798
- computed: false,
799
- optional: false
800
- };
709
+ function compile(expression, variables, options = {}) {
710
+ const { shortCircuit = true } = options;
711
+ const ast = serializeArgumentToAST(expression);
712
+ const variableOrder = [];
713
+ const variableToIndex = /* @__PURE__ */ new Map();
714
+ const symbolToName = /* @__PURE__ */ new Map();
715
+ for (const [name, value] of Object.entries(variables)) {
716
+ if (!variableToIndex.has(name)) {
717
+ variableToIndex.set(name, variableOrder.length);
718
+ variableOrder.push(name);
719
+ }
720
+ const id = getVariableId(value);
721
+ if (id) symbolToName.set(id, name);
722
+ }
723
+ const placeholderTransformed = transformPlaceholders(ast, (id) => {
724
+ const name = symbolToName.get(id);
725
+ if (!name) return null;
726
+ const index = variableToIndex.get(name);
727
+ if (index === void 0) return null;
728
+ return `$${index}`;
729
+ });
730
+ const undefinedVars = [];
731
+ const transformed = transformIdentifiers(placeholderTransformed, (name) => {
732
+ if (name.startsWith("$") && /^\$\d+$/.test(name)) return name;
733
+ const index = variableToIndex.get(name);
734
+ if (index !== void 0) return `$${index}`;
735
+ if (!ALLOWED_GLOBALS.has(name)) undefinedVars.push(name);
736
+ return name;
737
+ });
738
+ if (undefinedVars.length > 0) {
739
+ const uniqueVars = [...new Set(undefinedVars)];
740
+ throw new Error(`Undefined variable(s): ${uniqueVars.join(", ")}`);
741
+ }
742
+ const expressions = [];
743
+ if (shortCircuit) {
744
+ let nextIndex = variableOrder.length;
745
+ function compileAst(node) {
746
+ if (node.type === "BinaryExpr" && (node.operator === "||" || node.operator === "&&" || node.operator === "??")) return compileShortCircuit(node);
747
+ if (node.type === "ConditionalExpr") return compileConditional(node);
748
+ const exprStr = generate(node);
749
+ expressions.push(exprStr);
750
+ return nextIndex++;
751
+ }
752
+ function compileShortCircuit(node) {
753
+ const leftIdx = compileAst(node.left);
754
+ const branchConditions = {
755
+ "||": `$${leftIdx}`,
756
+ "&&": `!$${leftIdx}`,
757
+ "??": `$${leftIdx}!=null`
758
+ };
759
+ const branchIdx = expressions.length;
760
+ expressions.push([
761
+ "br",
762
+ branchConditions[node.operator],
763
+ 0
764
+ ]);
765
+ nextIndex++;
766
+ compileAst(node.right);
767
+ const skipCount = expressions.length - branchIdx - 1;
768
+ expressions[branchIdx][2] = skipCount;
769
+ const phiIdx = nextIndex++;
770
+ expressions.push(["phi"]);
771
+ return phiIdx;
772
+ }
773
+ function compileConditional(node) {
774
+ const testIdx = compileAst(node.test);
775
+ const branchIdx = expressions.length;
776
+ expressions.push([
777
+ "br",
778
+ `$${testIdx}`,
779
+ 0
780
+ ]);
781
+ nextIndex++;
782
+ compileAst(node.alternate);
783
+ const jmpIdx = expressions.length;
784
+ expressions.push(["jmp", 0]);
785
+ nextIndex++;
786
+ compileAst(node.consequent);
787
+ const thenEndIdx = expressions.length;
788
+ expressions[branchIdx][2] = jmpIdx - branchIdx;
789
+ expressions[jmpIdx][1] = thenEndIdx - jmpIdx - 1;
790
+ const phiIdx = nextIndex++;
791
+ expressions.push(["phi"]);
792
+ return phiIdx;
793
+ }
794
+ compileAst(transformed);
795
+ } else expressions.push(generate(transformed));
796
+ return [variableOrder, ...expressions];
801
797
  }
798
+
799
+ //#endregion
800
+ //#region src/evaluate.ts
802
801
  /**
803
- * 创建调用表达式 AST 节点
804
- */
805
- function callExpr(callee, arguments_) {
806
- return {
807
- type: "CallExpr",
808
- callee,
809
- arguments: arguments_,
810
- optional: false
811
- };
812
- }
802
+ * 缓存已构造的求值函数,以提升重复执行性能
803
+ */
804
+ const evaluatorCache = /* @__PURE__ */ new Map();
813
805
  /**
814
- * 创建数组表达式 AST 节点
806
+ * 检测编译数据是否包含控制流节点(V2 格式)
815
807
  */
816
- function arrayExpr(elements) {
817
- return {
818
- type: "ArrayExpr",
819
- elements
820
- };
808
+ function isV2Format(expressions) {
809
+ return expressions.some((expr) => Array.isArray(expr));
821
810
  }
822
811
  /**
823
- * 检查对象是否为 TypedArray 实例
812
+ * 执行编译后的表达式
813
+ *
814
+ * @template TResult - 表达式结果类型
815
+ * @param data - 编译后的数据结构 [变量名列表, 表达式1, 表达式2, ...]
816
+ * @param values - 变量值映射,按变量名提供值
817
+ * @returns 最后一个表达式的求值结果
818
+ *
819
+ * @throws 如果运行时类型验证失败或表达式执行出错
820
+ *
821
+ * @example
822
+ * ```ts
823
+ * const compiled = [["x", "y"], "$0+$1", "$1*2"]
824
+ * const result = evaluate<number>(compiled, { x: 2, y: 3 })
825
+ * // => 6 (3 * 2)
826
+ * ```
824
827
  */
825
- function getTypedArrayConstructor(value) {
826
- for (const constructorName of typedArrayConstructors) {
827
- const Constructor = globalThis[constructorName];
828
- if (Constructor && value instanceof Constructor) return Constructor;
828
+ function evaluate(data, values) {
829
+ if (data.length < 1) throw new Error("Invalid compiled data: must have at least variable names");
830
+ const [variableNames, ...expressions] = data;
831
+ if (!Array.isArray(variableNames)) throw new Error("Invalid compiled data: first element must be variable names array");
832
+ for (const varName of variableNames) {
833
+ if (typeof varName !== "string") throw new Error("Invalid compiled data: variable names must be strings");
834
+ if (!(varName in values)) throw new Error(`Missing required variable: ${varName}`);
835
+ }
836
+ const valueArray = [];
837
+ for (const varName of variableNames) valueArray.push(values[varName]);
838
+ const cacheKey = JSON.stringify(data);
839
+ let evaluator = evaluatorCache.get(cacheKey);
840
+ if (!evaluator) {
841
+ const functionBody = isV2Format(expressions) ? buildEvaluatorFunctionBodyV2(expressions, variableNames.length) : buildEvaluatorFunctionBody(expressions, variableNames.length);
842
+ evaluator = new Function("$values", functionBody);
843
+ evaluatorCache.set(cacheKey, evaluator);
844
+ }
845
+ try {
846
+ return evaluator(valueArray);
847
+ } catch (error) {
848
+ throw new Error(`Failed to evaluate expression: ${error instanceof Error ? error.message : String(error)}`);
829
849
  }
830
- return null;
831
850
  }
832
851
  /**
833
- * 序列化参数为 AST 节点
834
- * - Proxy Variable/Expression:使用 ast 或占位符标识符
835
- * - 数组:返回 ArrayExpr 节点
836
- * - 对象:返回 ObjectExpr 节点
837
- * - 原始值:返回对应的字面量节点
838
- * - Date, RegExp, BigInt, URL, URLSearchParams, Map, Set, TypedArray, DataView: 构造函数调用
852
+ * 构造求值函数体
853
+ *
854
+ * @param expressions - 表达式列表
855
+ * @param variableCount - 变量数量
856
+ * @returns 函数体字符串
857
+ *
858
+ * @example
859
+ * ```ts
860
+ * buildEvaluatorFunctionBody(["$0+$1", "$2*2"], 2)
861
+ * // 返回执行 $0+$1 并存储到 $values[2],然后执行 $2*2 的函数体
862
+ * ```
839
863
  */
840
- function serializeArgumentToAST(arg) {
841
- if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
842
- const meta = getProxyMetadata(arg);
843
- if (meta) {
844
- if (meta.ast) return meta.ast;
845
- if (meta.rootVariable) return identifier(getVariablePlaceholder$1(meta.rootVariable));
864
+ function buildEvaluatorFunctionBody(expressions, variableCount) {
865
+ if (expressions.length === 0) throw new Error("No expressions to evaluate");
866
+ return [
867
+ ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
868
+ ...expressions.map((expr, i) => {
869
+ const idx = variableCount + i;
870
+ return `const $${idx} = ${expr}; $values[${idx}] = $${idx};`;
871
+ }),
872
+ `return $values[$values.length - 1];`
873
+ ].join("\n");
874
+ }
875
+ /**
876
+ * 构造带控制流支持的求值函数体(V2 格式)
877
+ *
878
+ * @param expressions - 表达式列表(可包含控制流节点)
879
+ * @param variableCount - 变量数量
880
+ * @returns 函数体字符串
881
+ */
882
+ function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
883
+ if (expressions.length === 0) throw new Error("No expressions to evaluate");
884
+ const lines = [
885
+ ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
886
+ "let $pc = 0;",
887
+ "let $lastValue;",
888
+ ...expressions.map((_, i) => `let $${variableCount + i};`),
889
+ `while ($pc < ${expressions.length}) {`,
890
+ " switch ($pc) {"
891
+ ];
892
+ expressions.forEach((expr, i) => {
893
+ const idx = variableCount + i;
894
+ lines.push(` case ${i}: {`);
895
+ if (typeof expr === "string") {
896
+ lines.push(` $${idx} = $lastValue = ${expr};`);
897
+ lines.push(` $values[${idx}] = $${idx};`);
898
+ lines.push(" $pc++; break;");
899
+ } else {
900
+ const [type] = expr;
901
+ switch (type) {
902
+ case "br":
903
+ lines.push(` if (${expr[1]}) { $pc += ${expr[2] + 1}; } else { $pc++; } break;`);
904
+ break;
905
+ case "jmp":
906
+ lines.push(` $pc += ${expr[1] + 1}; break;`);
907
+ break;
908
+ case "phi":
909
+ lines.push(` $${idx} = $values[${idx}] = $lastValue; $pc++; break;`);
910
+ break;
911
+ }
912
+ }
913
+ lines.push(" }");
914
+ });
915
+ lines.push(" }", "}", "return $values[$values.length - 1];");
916
+ return lines.join("\n");
917
+ }
918
+
919
+ //#endregion
920
+ //#region src/parser.ts
921
+ var Parser = class Parser {
922
+ pos = 0;
923
+ source;
924
+ constructor(source) {
925
+ this.source = source;
926
+ }
927
+ parse() {
928
+ this.skipWhitespace();
929
+ const node = this.parseExpression();
930
+ this.skipWhitespace();
931
+ if (this.pos < this.source.length) throw new Error(`Unexpected token at position ${this.pos}: ${this.source.slice(this.pos, this.pos + 10)}`);
932
+ return node;
933
+ }
934
+ parseExpression() {
935
+ return this.parseConditional();
936
+ }
937
+ parseConditional() {
938
+ let node = this.parseBinary(0);
939
+ this.skipWhitespace();
940
+ if (this.peek() === "?") {
941
+ this.advance();
942
+ this.skipWhitespace();
943
+ const consequent = this.parseExpression();
944
+ this.skipWhitespace();
945
+ this.expect(":");
946
+ this.skipWhitespace();
947
+ const alternate = this.parseExpression();
948
+ node = {
949
+ type: "ConditionalExpr",
950
+ test: node,
951
+ consequent,
952
+ alternate
953
+ };
954
+ }
955
+ return node;
956
+ }
957
+ parseBinary(minPrec) {
958
+ let left = this.parseUnary();
959
+ while (true) {
960
+ this.skipWhitespace();
961
+ const op = this.peekOperator();
962
+ if (!op || PRECEDENCE[op] === void 0 || PRECEDENCE[op] < minPrec) break;
963
+ this.pos += op.length;
964
+ this.skipWhitespace();
965
+ const nextMinPrec = RIGHT_ASSOCIATIVE.has(op) ? PRECEDENCE[op] : PRECEDENCE[op] + 1;
966
+ const right = this.parseBinary(nextMinPrec);
967
+ left = {
968
+ type: "BinaryExpr",
969
+ operator: op,
970
+ left,
971
+ right
972
+ };
973
+ }
974
+ return left;
975
+ }
976
+ parseUnary() {
977
+ this.skipWhitespace();
978
+ const ch = this.peek();
979
+ if (ch === "!" || ch === "~" || ch === "+" || ch === "-") {
980
+ this.advance();
981
+ this.skipWhitespace();
982
+ return {
983
+ type: "UnaryExpr",
984
+ operator: ch,
985
+ argument: this.parseUnary(),
986
+ prefix: true
987
+ };
988
+ }
989
+ for (const keyword of ["typeof", "void"]) if (this.matchKeyword(keyword)) {
990
+ this.skipWhitespace();
991
+ return {
992
+ type: "UnaryExpr",
993
+ operator: keyword,
994
+ argument: this.parseUnary(),
995
+ prefix: true
996
+ };
997
+ }
998
+ return this.parsePostfix();
999
+ }
1000
+ parsePostfix() {
1001
+ let node = this.parsePrimary();
1002
+ while (true) {
1003
+ this.skipWhitespace();
1004
+ const ch = this.peek();
1005
+ if (ch === ".") {
1006
+ this.advance();
1007
+ this.skipWhitespace();
1008
+ const property = this.parseIdentifier();
1009
+ node = {
1010
+ type: "MemberExpr",
1011
+ object: node,
1012
+ property,
1013
+ computed: false,
1014
+ optional: false
1015
+ };
1016
+ } else if (ch === "[") {
1017
+ this.advance();
1018
+ this.skipWhitespace();
1019
+ const property = this.parseExpression();
1020
+ this.skipWhitespace();
1021
+ this.expect("]");
1022
+ node = {
1023
+ type: "MemberExpr",
1024
+ object: node,
1025
+ property,
1026
+ computed: true,
1027
+ optional: false
1028
+ };
1029
+ } else if (ch === "(") {
1030
+ this.advance();
1031
+ const args = this.parseArguments();
1032
+ this.expect(")");
1033
+ node = {
1034
+ type: "CallExpr",
1035
+ callee: node,
1036
+ arguments: args,
1037
+ optional: false
1038
+ };
1039
+ } else if (ch === "?" && this.peekAt(1) === ".") {
1040
+ this.advance();
1041
+ this.advance();
1042
+ this.skipWhitespace();
1043
+ if (this.peek() === "[") {
1044
+ this.advance();
1045
+ this.skipWhitespace();
1046
+ const property = this.parseExpression();
1047
+ this.skipWhitespace();
1048
+ this.expect("]");
1049
+ node = {
1050
+ type: "MemberExpr",
1051
+ object: node,
1052
+ property,
1053
+ computed: true,
1054
+ optional: true
1055
+ };
1056
+ } else if (this.peek() === "(") {
1057
+ this.advance();
1058
+ const args = this.parseArguments();
1059
+ this.expect(")");
1060
+ node = {
1061
+ type: "CallExpr",
1062
+ callee: node,
1063
+ arguments: args,
1064
+ optional: true
1065
+ };
1066
+ } else {
1067
+ const property = this.parseIdentifier();
1068
+ node = {
1069
+ type: "MemberExpr",
1070
+ object: node,
1071
+ property,
1072
+ computed: false,
1073
+ optional: true
1074
+ };
1075
+ }
1076
+ } else break;
846
1077
  }
1078
+ return node;
847
1079
  }
848
- if (Array.isArray(arg)) return arrayExpr(arg.map(serializeArgumentToAST));
849
- if (typeof arg === "object" && arg !== null) {
850
- if (arg instanceof Date) return callExpr(identifier("Date"), [numberLiteral(arg.getTime())]);
851
- if (arg instanceof RegExp) {
852
- const args = [stringLiteral(arg.source)];
853
- if (arg.flags) args.push(stringLiteral(arg.flags));
854
- return callExpr(identifier("RegExp"), args);
855
- }
856
- if (typeof URL !== "undefined" && arg instanceof URL) return callExpr(identifier("URL"), [stringLiteral(arg.href)]);
857
- if (typeof URLSearchParams !== "undefined" && arg instanceof URLSearchParams) {
858
- const entries = [];
859
- arg.forEach((value, key) => {
860
- entries.push(arrayExpr([stringLiteral(key), stringLiteral(value)]));
861
- });
862
- return callExpr(identifier("URLSearchParams"), [arrayExpr(entries)]);
1080
+ parsePrimary() {
1081
+ this.skipWhitespace();
1082
+ const ch = this.peek();
1083
+ if (this.isDigit(ch) || ch === "." && this.isDigit(this.peekAt(1))) return this.parseNumber();
1084
+ if (ch === "\"" || ch === "'" || ch === "`") return this.parseString();
1085
+ if (ch === "[") return this.parseArray();
1086
+ if (ch === "{") return this.parseObject();
1087
+ if (ch === "(") {
1088
+ const arrowFunc = this.tryParseArrowFunction();
1089
+ if (arrowFunc) return arrowFunc;
1090
+ this.advance();
1091
+ this.skipWhitespace();
1092
+ const expr = this.parseExpression();
1093
+ this.skipWhitespace();
1094
+ this.expect(")");
1095
+ return expr;
863
1096
  }
864
- if (arg instanceof Map) {
865
- const entries = [];
866
- arg.forEach((value, key) => {
867
- entries.push(arrayExpr([serializeArgumentToAST(key), serializeArgumentToAST(value)]));
868
- });
869
- return callExpr(identifier("Map"), [arrayExpr(entries)]);
1097
+ if (this.matchKeyword("true")) return {
1098
+ type: "BooleanLiteral",
1099
+ value: true
1100
+ };
1101
+ if (this.matchKeyword("false")) return {
1102
+ type: "BooleanLiteral",
1103
+ value: false
1104
+ };
1105
+ if (this.matchKeyword("null")) return { type: "NullLiteral" };
1106
+ if (this.matchKeyword("undefined")) return {
1107
+ type: "Identifier",
1108
+ name: "undefined"
1109
+ };
1110
+ if (this.isIdentifierStart(ch)) {
1111
+ const arrowFunc = this.tryParseSingleParamArrowFunction();
1112
+ if (arrowFunc) return arrowFunc;
1113
+ return this.parseIdentifier();
870
1114
  }
871
- if (arg instanceof Set) {
872
- const values = [];
873
- arg.forEach((value) => values.push(serializeArgumentToAST(value)));
874
- return callExpr(identifier("Set"), [arrayExpr(values)]);
1115
+ throw new Error(`Unexpected character at position ${this.pos}: ${ch}`);
1116
+ }
1117
+ parseNumber() {
1118
+ const start = this.pos;
1119
+ if (this.peek() === "0") {
1120
+ const next = this.peekAt(1)?.toLowerCase();
1121
+ if (next === "x" || next === "o" || next === "b") {
1122
+ this.advance();
1123
+ this.advance();
1124
+ while (this.isHexDigit(this.peek())) this.advance();
1125
+ const raw = this.source.slice(start, this.pos);
1126
+ return {
1127
+ type: "NumberLiteral",
1128
+ value: Number(raw),
1129
+ raw
1130
+ };
1131
+ }
875
1132
  }
876
- const typedArrayConstructor = getTypedArrayConstructor(arg);
877
- if (typedArrayConstructor) {
878
- const values = [...arg].map(serializeArgumentToAST);
879
- const constructorName = typedArrayConstructor.name;
880
- return callExpr(identifier(constructorName), [arrayExpr(values)]);
1133
+ while (this.isDigit(this.peek())) this.advance();
1134
+ if (this.peek() === "." && this.isDigit(this.peekAt(1))) {
1135
+ this.advance();
1136
+ while (this.isDigit(this.peek())) this.advance();
881
1137
  }
882
- if (arg instanceof ArrayBuffer) {
883
- const uint8Array = new Uint8Array(arg);
884
- const values = Array.from(uint8Array).map(numberLiteral);
885
- return memberExpr(callExpr(identifier("Uint8Array"), [arrayExpr(values)]), identifier("buffer"));
1138
+ if (this.peek()?.toLowerCase() === "e") {
1139
+ this.advance();
1140
+ if (this.peek() === "+" || this.peek() === "-") this.advance();
1141
+ while (this.isDigit(this.peek())) this.advance();
886
1142
  }
887
- if (arg instanceof DataView) return callExpr(identifier("DataView"), [serializeArgumentToAST(arg.buffer)]);
1143
+ const raw = this.source.slice(start, this.pos);
888
1144
  return {
889
- type: "ObjectExpr",
890
- properties: Object.entries(arg).map(([k, v]) => {
891
- return {
892
- key: /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? identifier(k) : stringLiteral(k),
893
- value: serializeArgumentToAST(v),
894
- computed: false,
895
- shorthand: false
896
- };
897
- })
1145
+ type: "NumberLiteral",
1146
+ value: Number(raw),
1147
+ raw
898
1148
  };
899
1149
  }
900
- if (arg === null) return { type: "NullLiteral" };
901
- if (arg === void 0) return identifier("undefined");
902
- if (typeof arg === "boolean") return {
903
- type: "BooleanLiteral",
904
- value: arg
1150
+ static ESCAPE_CHARS = {
1151
+ n: "\n",
1152
+ r: "\r",
1153
+ t: " ",
1154
+ "\\": "\\",
1155
+ "'": "'",
1156
+ "\"": "\"",
1157
+ "`": "`"
905
1158
  };
906
- if (typeof arg === "number") return numberLiteral(arg);
907
- if (typeof arg === "string") return stringLiteral(arg);
908
- if (typeof arg === "bigint") return callExpr(identifier("BigInt"), [stringLiteral(arg.toString())]);
909
- throw new Error(`Unsupported argument type: ${typeof arg}`);
910
- }
911
- /**
912
- * 从参数中收集依赖的 Symbol
913
- * 递归遍历数组和对象,收集所有 Proxy 的依赖
914
- */
915
- function collectDepsFromArgs(args, deps) {
916
- for (const arg of args) if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
917
- const meta = getProxyMetadata(arg);
918
- if (meta?.dependencies) for (const dep of meta.dependencies) deps.add(dep);
919
- else if (Array.isArray(arg)) collectDepsFromArgs(arg, deps);
920
- else if (typeof arg === "object") collectDepsFromArgs(Object.values(arg), deps);
1159
+ parseString() {
1160
+ const quote = this.peek();
1161
+ this.advance();
1162
+ let value = "";
1163
+ while (this.pos < this.source.length && this.peek() !== quote) if (this.peek() === "\\") {
1164
+ this.advance();
1165
+ const escaped = this.peek();
1166
+ value += Parser.ESCAPE_CHARS[escaped] ?? escaped;
1167
+ this.advance();
1168
+ } else {
1169
+ value += this.peek();
1170
+ this.advance();
1171
+ }
1172
+ this.expect(quote);
1173
+ return {
1174
+ type: "StringLiteral",
1175
+ value,
1176
+ quote
1177
+ };
921
1178
  }
922
- }
923
- /**
924
- * 根据路径构建成员表达式 AST
925
- */
926
- function buildMemberExprAst(rootId, path) {
927
- let ast = identifier(getVariablePlaceholder$1(rootId));
928
- for (const prop of path) ast = memberExpr(ast, identifier(prop));
929
- return ast;
930
- }
931
- /**
932
- * 创建 Proxy 的公共 handler
933
- */
934
- function createProxyHandler(ast, deps) {
935
- return {
936
- get(_target, prop) {
937
- if (typeof prop === "symbol") return void 0;
938
- return createProxyExpressionWithAST(memberExpr(ast, identifier(String(prop))), deps);
939
- },
940
- apply(_target, _thisArg, args) {
941
- const callAst = callExpr(ast, args.map(serializeArgumentToAST));
942
- const newDeps = new Set(deps);
943
- collectDepsFromArgs(args, newDeps);
944
- return createProxyExpressionWithAST(callAst, newDeps);
1179
+ parseArray() {
1180
+ this.expect("[");
1181
+ const elements = [];
1182
+ this.skipWhitespace();
1183
+ while (this.peek() !== "]") {
1184
+ elements.push(this.parseExpression());
1185
+ this.skipWhitespace();
1186
+ if (this.peek() === ",") {
1187
+ this.advance();
1188
+ this.skipWhitespace();
1189
+ } else break;
945
1190
  }
946
- };
947
- }
948
- /**
949
- * 创建根 Variable Proxy
950
- * 拦截属性访问,返回新的 expression proxy
951
- * 不可直接调用(apply 应该只在链式调用后可用)
952
- *
953
- * @param id - 变量的唯一标识 Symbol
954
- * @returns Proxy 包装的 Variable
955
- */
956
- function createProxyVariable(id) {
957
- const deps = new Set([id]);
958
- const proxy = new Proxy(function() {}, {
959
- get(_target, prop) {
960
- if (typeof prop === "symbol") return void 0;
961
- return createProxyExpressionWithAST(buildMemberExprAst(id, [String(prop)]), deps);
962
- },
963
- apply() {
964
- throw new Error("Variable cannot be called directly");
1191
+ this.expect("]");
1192
+ return {
1193
+ type: "ArrayExpr",
1194
+ elements
1195
+ };
1196
+ }
1197
+ parseObject() {
1198
+ this.expect("{");
1199
+ const properties = [];
1200
+ this.skipWhitespace();
1201
+ while (this.peek() !== "}") {
1202
+ const prop = this.parseObjectProperty();
1203
+ properties.push(prop);
1204
+ this.skipWhitespace();
1205
+ if (this.peek() === ",") {
1206
+ this.advance();
1207
+ this.skipWhitespace();
1208
+ } else break;
965
1209
  }
966
- });
967
- setProxyMetadata(proxy, {
968
- type: "variable",
969
- path: [],
970
- rootVariable: id,
971
- dependencies: deps
972
- });
973
- return proxy;
974
- }
975
- /**
976
- * 创建带完整 AST Proxy(方法调用后)
977
- * 可以继续链式访问和调用
978
- *
979
- * @param ast - 完整的表达式 AST
980
- * @param deps - 依赖集合
981
- * @returns Proxy 包装的 Expression
982
- */
983
- function createProxyExpressionWithAST(ast, deps) {
984
- const proxy = new Proxy(function() {}, createProxyHandler(ast, deps));
985
- setProxyMetadata(proxy, {
986
- type: "expression",
987
- path: [],
988
- ast,
989
- dependencies: deps
990
- });
991
- return proxy;
992
- }
993
-
994
- //#endregion
995
- //#region src/variable.ts
996
- /**
997
- * 跟踪每个 variable 的唯一 Symbol ID
998
- */
999
- const variableIds = /* @__PURE__ */ new WeakMap();
1000
- /**
1001
- * 计数器用于生成唯一变量 ID
1002
- */
1003
- let variableCounter = 0;
1004
- /**
1005
- * 创建一个类型化变量
1006
- * 返回 Proxy 对象,支持链式属性访问和方法调用
1007
- *
1008
- * @example
1009
- * ```ts
1010
- * const x = variable<number>();
1011
- * const config = variable<{ timeout: number }>();
1012
- * const timeout = config.timeout; // Proxy expression
1013
- * ```
1014
- */
1015
- function variable() {
1016
- const id = Symbol(`var_${variableCounter++}`);
1017
- const proxy = createProxyVariable(id);
1018
- variableIds.set(proxy, id);
1019
- return proxy;
1020
- }
1021
- /**
1022
- * 获取 variable 的唯一 Symbol ID
1023
- */
1024
- function getVariableId(variable) {
1025
- if (typeof variable !== "object" && typeof variable !== "function" || variable === null) return void 0;
1026
- return variableIds.get(variable);
1027
- }
1028
- /**
1029
- * 生成变量占位符字符串
1030
- * 格式:$$VAR_var_N$$
1031
- */
1032
- function getVariablePlaceholder(id) {
1033
- return `$$VAR_${id.description}$$`;
1034
- }
1035
-
1036
- //#endregion
1037
- //#region src/compile.ts
1038
- const ALLOWED_GLOBALS = new Set([
1039
- "Math",
1040
- "JSON",
1041
- "Date",
1042
- "RegExp",
1043
- "Number",
1044
- "String",
1045
- "Boolean",
1046
- "Array",
1047
- "Object",
1048
- "undefined",
1049
- "NaN",
1050
- "Infinity",
1051
- "isNaN",
1052
- "isFinite",
1053
- "parseInt",
1054
- "parseFloat",
1055
- "BigInt",
1056
- "URL",
1057
- "URLSearchParams",
1058
- "Map",
1059
- "Set",
1060
- "Int8Array",
1061
- "Uint8Array",
1062
- "Uint8ClampedArray",
1063
- "Int16Array",
1064
- "Uint16Array",
1065
- "Int32Array",
1066
- "Uint32Array",
1067
- "Float32Array",
1068
- "Float64Array",
1069
- "BigInt64Array",
1070
- "BigUint64Array",
1071
- "ArrayBuffer",
1072
- "DataView"
1073
- ]);
1074
- /**
1075
- * 将 Proxy Expression 编译为可序列化的 JSON 结构
1076
- *
1077
- * @template TResult - 表达式结果类型
1078
- * @param expression - Proxy Expression,或包含 Proxy 的对象/数组/原始值
1079
- * @param variables - 所有使用的变量定义
1080
- * @param options - 编译选项
1081
- * @returns 编译后的数据结构 [变量名列表, 表达式1, 表达式2, ...]
1082
- *
1083
- * @throws 如果传入无效的表达式或未定义的变量引用
1084
- *
1085
- * @example
1086
- * ```ts
1087
- * const x = variable<number>()
1088
- * const y = variable<number>()
1089
- * const sum = expr({ x, y })("x + y")
1090
- * const result = expr({ sum, x })("sum * x")
1091
- * const compiled = compile(result, { x, y })
1092
- * // => [["x", "y"], "($0+$1)*$0"]
1093
- * ```
1094
- */
1095
- function compile(expression, variables, options = {}) {
1096
- const { shortCircuit = true } = options;
1097
- const ast = serializeArgumentToAST(expression);
1098
- const variableOrder = [];
1099
- const variableToIndex = /* @__PURE__ */ new Map();
1100
- const descToName = /* @__PURE__ */ new Map();
1101
- for (const [name, value] of Object.entries(variables)) {
1102
- if (!variableToIndex.has(name)) {
1103
- variableToIndex.set(name, variableOrder.length);
1104
- variableOrder.push(name);
1210
+ this.expect("}");
1211
+ return {
1212
+ type: "ObjectExpr",
1213
+ properties
1214
+ };
1215
+ }
1216
+ parseObjectProperty() {
1217
+ this.skipWhitespace();
1218
+ let key;
1219
+ let computed = false;
1220
+ if (this.peek() === "[") {
1221
+ this.advance();
1222
+ this.skipWhitespace();
1223
+ key = this.parseExpression();
1224
+ this.skipWhitespace();
1225
+ this.expect("]");
1226
+ computed = true;
1227
+ } else if (this.peek() === "\"" || this.peek() === "'") key = this.parseString();
1228
+ else key = this.parseIdentifier();
1229
+ this.skipWhitespace();
1230
+ if (this.peek() === ":") {
1231
+ this.advance();
1232
+ this.skipWhitespace();
1233
+ const value = this.parseExpression();
1234
+ return {
1235
+ key,
1236
+ value,
1237
+ computed,
1238
+ shorthand: false
1239
+ };
1105
1240
  }
1106
- const id = getVariableId(value);
1107
- if (id?.description) descToName.set(id.description, name);
1241
+ if (key.type !== "Identifier") throw new Error("Shorthand property must be an identifier");
1242
+ return {
1243
+ key,
1244
+ value: key,
1245
+ computed: false,
1246
+ shorthand: true
1247
+ };
1108
1248
  }
1109
- const undefinedVars = [];
1110
- const transformed = transformIdentifiers(ast, (name) => {
1111
- const placeholderMatch = name.match(/^\$\$VAR_(.+)\$\$$/);
1112
- const resolvedName = placeholderMatch ? descToName.get(placeholderMatch[1]) : name;
1113
- if (placeholderMatch && !resolvedName) throw new Error(`Unknown variable placeholder: ${name}`);
1114
- const index = variableToIndex.get(resolvedName);
1115
- if (index !== void 0) return `$${index}`;
1116
- if (!ALLOWED_GLOBALS.has(resolvedName)) undefinedVars.push(resolvedName);
1117
- return resolvedName;
1118
- });
1119
- if (undefinedVars.length > 0) {
1120
- const uniqueVars = [...new Set(undefinedVars)];
1121
- throw new Error(`Undefined variable(s): ${uniqueVars.join(", ")}`);
1249
+ parseIdentifier() {
1250
+ const start = this.pos;
1251
+ while (this.isIdentifierPart(this.peek())) this.advance();
1252
+ const name = this.source.slice(start, this.pos);
1253
+ if (!name) throw new Error(`Expected identifier at position ${this.pos}`);
1254
+ return {
1255
+ type: "Identifier",
1256
+ name
1257
+ };
1122
1258
  }
1123
- const expressions = [];
1124
- if (shortCircuit) {
1125
- let nextIndex = variableOrder.length;
1126
- function compileAst(node) {
1127
- if (node.type === "BinaryExpr" && (node.operator === "||" || node.operator === "&&" || node.operator === "??")) return compileShortCircuit(node);
1128
- if (node.type === "ConditionalExpr") return compileConditional(node);
1129
- const exprStr = generate(node);
1130
- expressions.push(exprStr);
1131
- return nextIndex++;
1259
+ /**
1260
+ * 尝试解析带括号的箭头函数: (a, b) => expr
1261
+ * 使用回溯机制
1262
+ */
1263
+ tryParseArrowFunction() {
1264
+ const savedPos = this.pos;
1265
+ try {
1266
+ this.expect("(");
1267
+ this.skipWhitespace();
1268
+ const params = [];
1269
+ while (this.peek() !== ")") {
1270
+ if (!this.isIdentifierStart(this.peek())) throw new Error("Expected identifier");
1271
+ params.push(this.parseIdentifier());
1272
+ this.skipWhitespace();
1273
+ if (this.peek() === ",") {
1274
+ this.advance();
1275
+ this.skipWhitespace();
1276
+ } else break;
1277
+ }
1278
+ this.expect(")");
1279
+ this.skipWhitespace();
1280
+ if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
1281
+ this.pos += 2;
1282
+ this.skipWhitespace();
1283
+ return {
1284
+ type: "ArrowFunctionExpr",
1285
+ params,
1286
+ body: this.parseExpression()
1287
+ };
1288
+ } catch {
1289
+ this.pos = savedPos;
1290
+ return null;
1291
+ }
1292
+ }
1293
+ /**
1294
+ * 尝试解析单参数无括号的箭头函数: a => expr
1295
+ * 使用回溯机制
1296
+ */
1297
+ tryParseSingleParamArrowFunction() {
1298
+ const savedPos = this.pos;
1299
+ try {
1300
+ const param = this.parseIdentifier();
1301
+ this.skipWhitespace();
1302
+ if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
1303
+ this.pos += 2;
1304
+ this.skipWhitespace();
1305
+ const body = this.parseExpression();
1306
+ return {
1307
+ type: "ArrowFunctionExpr",
1308
+ params: [param],
1309
+ body
1310
+ };
1311
+ } catch {
1312
+ this.pos = savedPos;
1313
+ return null;
1314
+ }
1315
+ }
1316
+ parseArguments() {
1317
+ const args = [];
1318
+ this.skipWhitespace();
1319
+ while (this.peek() !== ")") {
1320
+ args.push(this.parseExpression());
1321
+ this.skipWhitespace();
1322
+ if (this.peek() === ",") {
1323
+ this.advance();
1324
+ this.skipWhitespace();
1325
+ } else break;
1132
1326
  }
1133
- function compileShortCircuit(node) {
1134
- const leftIdx = compileAst(node.left);
1135
- const branchConditions = {
1136
- "||": `$${leftIdx}`,
1137
- "&&": `!$${leftIdx}`,
1138
- "??": `$${leftIdx}!=null`
1139
- };
1140
- const branchIdx = expressions.length;
1141
- expressions.push([
1142
- "br",
1143
- branchConditions[node.operator],
1144
- 0
1145
- ]);
1146
- nextIndex++;
1147
- compileAst(node.right);
1148
- const skipCount = expressions.length - branchIdx - 1;
1149
- expressions[branchIdx][2] = skipCount;
1150
- const phiIdx = nextIndex++;
1151
- expressions.push(["phi"]);
1152
- return phiIdx;
1327
+ return args;
1328
+ }
1329
+ static OPERATORS = [
1330
+ "instanceof",
1331
+ ">>>",
1332
+ "===",
1333
+ "!==",
1334
+ "&&",
1335
+ "||",
1336
+ "??",
1337
+ "==",
1338
+ "!=",
1339
+ "<=",
1340
+ ">=",
1341
+ "<<",
1342
+ ">>",
1343
+ "**",
1344
+ "in",
1345
+ "+",
1346
+ "-",
1347
+ "*",
1348
+ "/",
1349
+ "%",
1350
+ "<",
1351
+ ">",
1352
+ "&",
1353
+ "|",
1354
+ "^"
1355
+ ];
1356
+ static KEYWORD_OPERATORS = new Set(["in", "instanceof"]);
1357
+ peekOperator() {
1358
+ for (const op of Parser.OPERATORS) {
1359
+ if (!this.source.startsWith(op, this.pos)) continue;
1360
+ if (Parser.KEYWORD_OPERATORS.has(op)) {
1361
+ const nextChar = this.source[this.pos + op.length];
1362
+ if (nextChar && this.isIdentifierPart(nextChar)) continue;
1363
+ }
1364
+ return op;
1153
1365
  }
1154
- function compileConditional(node) {
1155
- const testIdx = compileAst(node.test);
1156
- const branchIdx = expressions.length;
1157
- expressions.push([
1158
- "br",
1159
- `$${testIdx}`,
1160
- 0
1161
- ]);
1162
- nextIndex++;
1163
- compileAst(node.alternate);
1164
- const jmpIdx = expressions.length;
1165
- expressions.push(["jmp", 0]);
1166
- nextIndex++;
1167
- compileAst(node.consequent);
1168
- const thenEndIdx = expressions.length;
1169
- expressions[branchIdx][2] = jmpIdx - branchIdx;
1170
- expressions[jmpIdx][1] = thenEndIdx - jmpIdx - 1;
1171
- const phiIdx = nextIndex++;
1172
- expressions.push(["phi"]);
1173
- return phiIdx;
1366
+ return null;
1367
+ }
1368
+ matchKeyword(keyword) {
1369
+ if (this.source.startsWith(keyword, this.pos)) {
1370
+ const nextChar = this.source[this.pos + keyword.length];
1371
+ if (!nextChar || !this.isIdentifierPart(nextChar)) {
1372
+ this.pos += keyword.length;
1373
+ return true;
1374
+ }
1174
1375
  }
1175
- compileAst(transformed);
1176
- } else expressions.push(generate(transformed));
1177
- return [variableOrder, ...expressions];
1178
- }
1179
-
1180
- //#endregion
1181
- //#region src/evaluate.ts
1182
- /**
1183
- * 缓存已构造的求值函数,以提升重复执行性能
1184
- */
1185
- const evaluatorCache = /* @__PURE__ */ new Map();
1186
- /**
1187
- * 检测编译数据是否包含控制流节点(V2 格式)
1188
- */
1189
- function isV2Format(expressions) {
1190
- return expressions.some((expr) => Array.isArray(expr));
1191
- }
1192
- /**
1193
- * 执行编译后的表达式
1194
- *
1195
- * @template TResult - 表达式结果类型
1196
- * @param data - 编译后的数据结构 [变量名列表, 表达式1, 表达式2, ...]
1197
- * @param values - 变量值映射,按变量名提供值
1198
- * @returns 最后一个表达式的求值结果
1199
- *
1200
- * @throws 如果运行时类型验证失败或表达式执行出错
1201
- *
1202
- * @example
1203
- * ```ts
1204
- * const compiled = [["x", "y"], "$0+$1", "$1*2"]
1205
- * const result = evaluate<number>(compiled, { x: 2, y: 3 })
1206
- * // => 6 (3 * 2)
1207
- * ```
1208
- */
1209
- function evaluate(data, values) {
1210
- if (data.length < 1) throw new Error("Invalid compiled data: must have at least variable names");
1211
- const [variableNames, ...expressions] = data;
1212
- if (!Array.isArray(variableNames)) throw new Error("Invalid compiled data: first element must be variable names array");
1213
- for (const varName of variableNames) {
1214
- if (typeof varName !== "string") throw new Error("Invalid compiled data: variable names must be strings");
1215
- if (!(varName in values)) throw new Error(`Missing required variable: ${varName}`);
1376
+ return false;
1216
1377
  }
1217
- const valueArray = [];
1218
- for (const varName of variableNames) valueArray.push(values[varName]);
1219
- const cacheKey = JSON.stringify(data);
1220
- let evaluator = evaluatorCache.get(cacheKey);
1221
- if (!evaluator) {
1222
- const functionBody = isV2Format(expressions) ? buildEvaluatorFunctionBodyV2(expressions, variableNames.length) : buildEvaluatorFunctionBody(expressions, variableNames.length);
1223
- evaluator = new Function("$values", functionBody);
1224
- evaluatorCache.set(cacheKey, evaluator);
1378
+ peek() {
1379
+ return this.source[this.pos] || "";
1225
1380
  }
1226
- try {
1227
- return evaluator(valueArray);
1228
- } catch (error) {
1229
- throw new Error(`Failed to evaluate expression: ${error instanceof Error ? error.message : String(error)}`);
1381
+ peekAt(offset) {
1382
+ return this.source[this.pos + offset] || "";
1230
1383
  }
1231
- }
1232
- /**
1233
- * 构造求值函数体
1234
- *
1235
- * @param expressions - 表达式列表
1236
- * @param variableCount - 变量数量
1237
- * @returns 函数体字符串
1238
- *
1239
- * @example
1240
- * ```ts
1241
- * buildEvaluatorFunctionBody(["$0+$1", "$2*2"], 2)
1242
- * // 返回执行 $0+$1 并存储到 $values[2],然后执行 $2*2 的函数体
1243
- * ```
1244
- */
1245
- function buildEvaluatorFunctionBody(expressions, variableCount) {
1246
- if (expressions.length === 0) throw new Error("No expressions to evaluate");
1247
- return [
1248
- ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
1249
- ...expressions.map((expr, i) => {
1250
- const idx = variableCount + i;
1251
- return `const $${idx} = ${expr}; $values[${idx}] = $${idx};`;
1252
- }),
1253
- `return $values[$values.length - 1];`
1254
- ].join("\n");
1255
- }
1384
+ advance() {
1385
+ return this.source[this.pos++] || "";
1386
+ }
1387
+ expect(ch) {
1388
+ if (this.peek() !== ch) throw new Error(`Expected '${ch}' at position ${this.pos}, got '${this.peek()}'`);
1389
+ this.advance();
1390
+ }
1391
+ skipWhitespace() {
1392
+ while (/\s/.test(this.peek())) this.advance();
1393
+ }
1394
+ isDigit(ch) {
1395
+ const code = ch.charCodeAt(0);
1396
+ return code >= 48 && code <= 57;
1397
+ }
1398
+ isHexDigit(ch) {
1399
+ const code = ch.charCodeAt(0);
1400
+ return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
1401
+ }
1402
+ isIdentifierStart(ch) {
1403
+ const code = ch.charCodeAt(0);
1404
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95 || code === 36;
1405
+ }
1406
+ isIdentifierPart(ch) {
1407
+ const code = ch.charCodeAt(0);
1408
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 95 || code === 36;
1409
+ }
1410
+ };
1256
1411
  /**
1257
- * 构造带控制流支持的求值函数体(V2 格式)
1258
- *
1259
- * @param expressions - 表达式列表(可包含控制流节点)
1260
- * @param variableCount - 变量数量
1261
- * @returns 函数体字符串
1412
+ * 解析 JavaScript 表达式为 AST
1262
1413
  */
1263
- function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
1264
- if (expressions.length === 0) throw new Error("No expressions to evaluate");
1265
- const lines = [
1266
- ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
1267
- "let $pc = 0;",
1268
- "let $lastValue;",
1269
- ...expressions.map((_, i) => `let $${variableCount + i};`),
1270
- `while ($pc < ${expressions.length}) {`,
1271
- " switch ($pc) {"
1272
- ];
1273
- expressions.forEach((expr, i) => {
1274
- const idx = variableCount + i;
1275
- lines.push(` case ${i}: {`);
1276
- if (typeof expr === "string") {
1277
- lines.push(` $${idx} = $lastValue = ${expr};`);
1278
- lines.push(` $values[${idx}] = $${idx};`);
1279
- lines.push(" $pc++; break;");
1280
- } else {
1281
- const [type] = expr;
1282
- switch (type) {
1283
- case "br":
1284
- lines.push(` if (${expr[1]}) { $pc += ${expr[2] + 1}; } else { $pc++; } break;`);
1285
- break;
1286
- case "jmp":
1287
- lines.push(` $pc += ${expr[1] + 1}; break;`);
1288
- break;
1289
- case "phi":
1290
- lines.push(` $${idx} = $values[${idx}] = $lastValue; $pc++; break;`);
1291
- break;
1292
- }
1293
- }
1294
- lines.push(" }");
1295
- });
1296
- lines.push(" }", "}", "return $values[$values.length - 1];");
1297
- return lines.join("\n");
1414
+ function parse(source) {
1415
+ return new Parser(source).parse();
1298
1416
  }
1299
1417
 
1300
1418
  //#endregion
@@ -1352,7 +1470,10 @@ function expr(context) {
1352
1470
  }
1353
1471
  return createProxyExpressionWithAST(transformIdentifiers(parse(source), (name) => {
1354
1472
  const id = nameToId.get(name);
1355
- if (id) return getVariablePlaceholder(id);
1473
+ if (id) return {
1474
+ type: "Placeholder",
1475
+ id
1476
+ };
1356
1477
  const exprAST = nameToExprAST.get(name);
1357
1478
  if (exprAST) return exprAST;
1358
1479
  return name;
@@ -1405,7 +1526,7 @@ function lambda(builder) {
1405
1526
  const paramCount = builder.length;
1406
1527
  const { params, paramSymbols } = createLambdaParams(paramCount);
1407
1528
  const { bodyAst, bodyDeps } = extractBodyAstAndDeps(builder(...params));
1408
- const lambdaProxy = createProxyExpressionWithAST(createArrowFunctionAst(transformParamPlaceholders(bodyAst, paramSymbols), paramCount), filterClosureDeps(bodyDeps, paramSymbols));
1529
+ const lambdaProxy = createProxyExpressionWithAST(createArrowFunctionAst(bodyAst, paramCount, paramSymbols), filterClosureDeps(bodyDeps, paramSymbols));
1409
1530
  const existingMeta = getProxyMetadata(lambdaProxy);
1410
1531
  if (existingMeta) setProxyMetadata(lambdaProxy, {
1411
1532
  ...existingMeta,
@@ -1449,27 +1570,15 @@ function extractBodyAstAndDeps(bodyExpr) {
1449
1570
  }
1450
1571
  }
1451
1572
  /**
1452
- * 将参数占位符标识符转换为实际参数名
1453
- */
1454
- function transformParamPlaceholders(bodyAst, paramSymbols) {
1455
- return transformIdentifiers(bodyAst, (name) => {
1456
- for (let i = 0; i < paramSymbols.length; i++) {
1457
- const sym = paramSymbols[i];
1458
- if (!sym) continue;
1459
- if (name === `$$VAR_${sym.description}$$`) return `_${i}`;
1460
- }
1461
- return name;
1462
- });
1463
- }
1464
- /**
1465
1573
  * 创建箭头函数 AST
1574
+ * 使用 Placeholder 节点作为参数,在代码生成时再分配实际参数名
1466
1575
  */
1467
- function createArrowFunctionAst(bodyAst, paramCount) {
1576
+ function createArrowFunctionAst(bodyAst, paramCount, paramSymbols) {
1468
1577
  return {
1469
1578
  type: "ArrowFunctionExpr",
1470
1579
  params: Array.from({ length: paramCount }, (_, i) => ({
1471
- type: "Identifier",
1472
- name: `_${i}`
1580
+ type: "Placeholder",
1581
+ id: paramSymbols[i]
1473
1582
  })),
1474
1583
  body: bodyAst
1475
1584
  };