@@ -12,8 +12,8 @@ import { BUILTIN_CONSTRUCTORS, PRECEDENCE, RIGHT_ASSOCIATIVE } from "./ast-types
1212export interface GenerateContext {
1313 /** lambda 参数计数器,用于生成唯一参数名 */
1414 lambdaParamCounter : number ;
15- /** 占位符到实际参数名的映射 */
16- paramMapping : Map < string , string > ;
15+ /** 占位符 Symbol 到实际参数名的映射 */
16+ paramMapping : Map < symbol , string > ;
1717}
1818
1919/**
@@ -52,10 +52,15 @@ export function generateWithContext(node: ASTNode, ctx: GenerateContext): string
5252 case "NullLiteral" :
5353 return "null" ;
5454
55- case "Identifier" : {
56- // 检查是否是 lambda 参数占位符
57- const mappedName = ctx . paramMapping . get ( node . name ) ;
58- return mappedName ?? node . name ;
55+ case "Identifier" :
56+ return node . name ;
57+
58+ case "Placeholder" : {
59+ // 查找 lambda 参数映射
60+ const mappedName = ctx . paramMapping . get ( node . id ) ;
61+ if ( mappedName ) return mappedName ;
62+ // 未编译的占位符输出为特殊格式(用于测试/调试)
63+ return `$$${ node . id . description } $$` ;
5964 }
6065
6166 case "BinaryExpr" : {
@@ -118,11 +123,19 @@ export function generateWithContext(node: ASTNode, ctx: GenerateContext): string
118123 case "ArrowFunctionExpr" : {
119124 // 为每个参数分配唯一的参数名
120125 const paramNames : string [ ] = [ ] ;
126+ const placeholderIds : symbol [ ] = [ ] ;
127+
121128 for ( const param of node . params ) {
122- const uniqueName = `_${ ctx . lambdaParamCounter ++ } ` ;
123- paramNames . push ( uniqueName ) ;
124- // 建立占位符到实际参数名的映射
125- ctx . paramMapping . set ( param . name , uniqueName ) ;
129+ if ( param . type === "Placeholder" ) {
130+ // Placeholder 参数:分配唯一名称并建立映射
131+ const uniqueName = `_${ ctx . lambdaParamCounter ++ } ` ;
132+ paramNames . push ( uniqueName ) ;
133+ placeholderIds . push ( param . id ) ;
134+ ctx . paramMapping . set ( param . id , uniqueName ) ;
135+ } else {
136+ // Identifier 参数:直接使用名称
137+ paramNames . push ( param . name ) ;
138+ }
126139 }
127140
128141 const paramsStr = paramNames . length === 1 ? paramNames [ 0 ] ! : `(${ paramNames . join ( "," ) } )` ;
@@ -131,11 +144,9 @@ export function generateWithContext(node: ASTNode, ctx: GenerateContext): string
131144 ? `(${ generateWithContext ( node . body , ctx ) } )`
132145 : generateWithContext ( node . body , ctx ) ;
133146
134- // 清理参数映射(可选,防止污染外层作用域)
135- // 注意:由于我们使用唯一的参数名,不清理也不会冲突
136- // 但为了语义清晰,在函数体生成完成后移除映射
137- for ( const param of node . params ) {
138- ctx . paramMapping . delete ( param . name ) ;
147+ // 清理 Placeholder 参数映射
148+ for ( const id of placeholderIds ) {
149+ ctx . paramMapping . delete ( id ) ;
139150 }
140151
141152 return `${ paramsStr } =>${ body } ` ;
@@ -220,6 +231,10 @@ export function transformIdentifiers(node: ASTNode, transform: (name: string) =>
220231 return typeof result === "string" ? { ...node , name : result } : result ;
221232 }
222233
234+ case "Placeholder" :
235+ // Placeholder 不是 Identifier,保持不变
236+ return node ;
237+
223238 case "BinaryExpr" :
224239 return {
225240 ...node ,
@@ -273,8 +288,11 @@ export function transformIdentifiers(node: ASTNode, transform: (name: string) =>
273288 } ;
274289
275290 case "ArrowFunctionExpr" : {
276- // 箭头函数:参数名不转换,只转换函数体中的非参数标识符
277- const paramNames = new Set ( node . params . map ( ( p ) => p . name ) ) ;
291+ // 箭头函数:只转换 Identifier 参数名,Placeholder 参数保持不变
292+ // 只转换函数体中的非参数标识符
293+ const paramNames = new Set (
294+ node . params . filter ( ( p ) : p is { type : "Identifier" ; name : string } => p . type === "Identifier" ) . map ( ( p ) => p . name )
295+ ) ;
278296 return {
279297 ...node ,
280298 body : transformIdentifiers ( node . body , ( name ) => ( paramNames . has ( name ) ? name : transform ( name ) ) ) ,
@@ -286,6 +304,87 @@ export function transformIdentifiers(node: ASTNode, transform: (name: string) =>
286304 }
287305}
288306
307+ /**
308+ * 转换 AST 中的占位符节点
309+ * 回调函数接收 symbol,返回 Identifier 节点的名称
310+ * 如果返回 null/undefined,则保留原始 Placeholder 节点
311+ */
312+ export function transformPlaceholders ( node : ASTNode , transform : ( id : symbol ) => string | null | undefined ) : ASTNode {
313+ switch ( node . type ) {
314+ case "Placeholder" : {
315+ const name = transform ( node . id ) ;
316+ return name != null ? { type : "Identifier" , name } : node ;
317+ }
318+
319+ case "Identifier" :
320+ return node ;
321+
322+ case "BinaryExpr" :
323+ return {
324+ ...node ,
325+ left : transformPlaceholders ( node . left , transform ) ,
326+ right : transformPlaceholders ( node . right , transform ) ,
327+ } ;
328+
329+ case "UnaryExpr" :
330+ return {
331+ ...node ,
332+ argument : transformPlaceholders ( node . argument , transform ) ,
333+ } ;
334+
335+ case "ConditionalExpr" :
336+ return {
337+ ...node ,
338+ test : transformPlaceholders ( node . test , transform ) ,
339+ consequent : transformPlaceholders ( node . consequent , transform ) ,
340+ alternate : transformPlaceholders ( node . alternate , transform ) ,
341+ } ;
342+
343+ case "MemberExpr" :
344+ return {
345+ ...node ,
346+ object : transformPlaceholders ( node . object , transform ) ,
347+ property : node . computed ? transformPlaceholders ( node . property , transform ) : node . property ,
348+ } ;
349+
350+ case "CallExpr" :
351+ return {
352+ ...node ,
353+ callee : transformPlaceholders ( node . callee , transform ) ,
354+ arguments : node . arguments . map ( ( arg ) => transformPlaceholders ( arg , transform ) ) ,
355+ } ;
356+
357+ case "ArrayExpr" :
358+ return {
359+ ...node ,
360+ elements : node . elements . map ( ( el ) => transformPlaceholders ( el , transform ) ) ,
361+ } ;
362+
363+ case "ObjectExpr" :
364+ return {
365+ ...node ,
366+ properties : node . properties . map ( ( prop ) => ( {
367+ ...prop ,
368+ key : prop . computed ? transformPlaceholders ( prop . key , transform ) : prop . key ,
369+ value : transformPlaceholders ( prop . value , transform ) ,
370+ } ) ) ,
371+ } ;
372+
373+ case "ArrowFunctionExpr" : {
374+ // 箭头函数:参数保持不变(Placeholder 参数在代码生成时处理)
375+ // 函数体中的 Placeholder 需要转换,但要排除参数本身的 symbol
376+ const paramSymbols = new Set ( node . params . filter ( ( p ) => p . type === "Placeholder" ) . map ( ( p ) => p . id ) ) ;
377+ return {
378+ ...node ,
379+ body : transformPlaceholders ( node . body , ( id ) => ( paramSymbols . has ( id ) ? null : transform ( id ) ) ) ,
380+ } ;
381+ }
382+
383+ default :
384+ return node ;
385+ }
386+ }
387+
289388/**
290389 * 收集 AST 中所有使用的标识符名称
291390 */
@@ -341,7 +440,10 @@ export function collectIdentifiers(node: ASTNode): Set<string> {
341440 case "ArrowFunctionExpr" : {
342441 // 箭头函数:收集参数名和函数体中的标识符
343442 // 但从闭包角度,只需收集非参数的自由变量
344- const paramNames = new Set ( n . params . map ( ( p ) => p . name ) ) ;
443+ // 只考虑 Identifier 参数,Placeholder 参数在编译时处理
444+ const paramNames = new Set (
445+ n . params . filter ( ( p ) : p is { type : "Identifier" ; name : string } => p . type === "Identifier" ) . map ( ( p ) => p . name )
446+ ) ;
345447 const bodyIdentifiers = collectIdentifiers ( n . body ) ;
346448 for ( const id of bodyIdentifiers ) {
347449 if ( ! paramNames . has ( id ) ) {
0 commit comments