feat: 闭包/lambda — 匿名函数表达式
fn(x: T) -> R { body } 作为表达式, 可赋值给变量并间接调用。
全流水线实现:
- Parser: TOK_FN 前缀 → AST_LAMBDA 节点
- Sema: 自动生成 __lambda_N 顶层函数 + 符号注册
- Sema: analyze_call_expr 支持 TYPE_CLOSURE 变量调用
- Codegen: lambda 表达式返回函数指针(i64), 调用点载入+IntToPtr+间接call
- VarEntry.closure_fn 追踪闭包变量对应的生成函数
限制(MVP v0.1): 非捕获 lambda, 返回类型固定 i64
+6 sema 测试 + 1 集成测试, 209 测试全部通过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -226,6 +226,14 @@ bool reorder_named_args(AstNode* node, Symbol* sym, int param_offset,
|
||||
|
||||
void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
Symbol* sym = scope_lookup(scope, node->as.call.name);
|
||||
// 闭包调用: 变量类型为 TYPE_CLOSURE
|
||||
if (sym && sym->kind == SYM_VARIABLE && sym->type == TYPE_CLOSURE) {
|
||||
// 暂不做参数类型检查(MVP), 只分析参数表达式
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++)
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
node->type.kind = TYPE_I64; // 默认返回 i64(MVP 限制)
|
||||
return;
|
||||
}
|
||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的函数 '%s'", node->as.call.name);
|
||||
@@ -523,6 +531,53 @@ void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, Arena*
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
// === lambda 表达式分析 ===
|
||||
static int lambda_counter = 0;
|
||||
|
||||
void analyze_lambda(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
lambda_counter++;
|
||||
int name_len = snprintf(NULL, 0, "__lambda_%d", lambda_counter) + 1;
|
||||
char* gen_name = arena_alloc_impl(a, name_len);
|
||||
snprintf(gen_name, name_len, "__lambda_%d", lambda_counter);
|
||||
node->as.lambda.generated_name = gen_name;
|
||||
|
||||
// 分析 lambda 体(参数作用域)
|
||||
Scope* lambda_scope = scope_new(a, scope);
|
||||
for (size_t i = 0; i < node->as.lambda.param_count; i++) {
|
||||
AstNode* p = node->as.lambda.params[i];
|
||||
scope_insert(lambda_scope, a, p->as.parameter.name, SYM_PARAMETER, p->as.parameter.type);
|
||||
}
|
||||
TypeKind saved_ret = current_return_type;
|
||||
const char* saved_ret_sn = current_return_struct_name;
|
||||
current_return_type = node->as.lambda.return_type;
|
||||
current_return_struct_name = node->as.lambda.return_struct_type_name;
|
||||
analyze_node(node->as.lambda.body, lambda_scope, errors, a);
|
||||
current_return_type = saved_ret;
|
||||
current_return_struct_name = saved_ret_sn;
|
||||
|
||||
// 创建顶层函数 AST 节点, 加入队列供 codegen 使用
|
||||
AstNode* fn = ast_make_function(a, gen_name,
|
||||
node->as.lambda.params, node->as.lambda.param_count,
|
||||
node->as.lambda.return_type,
|
||||
node->as.lambda.return_struct_type_name,
|
||||
node->as.lambda.body, false, NULL, 0, node->loc);
|
||||
if (lambda_count < 256)
|
||||
lambda_queue[lambda_count++] = fn;
|
||||
|
||||
// 注册函数符号(支持递归调用自身)
|
||||
TypeKind* pts = node->as.lambda.param_count > 0
|
||||
? arena_alloc_impl(a, node->as.lambda.param_count * sizeof(TypeKind)) : NULL;
|
||||
for (size_t i = 0; i < node->as.lambda.param_count; i++)
|
||||
pts[i] = node->as.lambda.params[i]->as.parameter.type;
|
||||
scope_insert_function(scope, a, gen_name,
|
||||
node->as.lambda.return_type,
|
||||
node->as.lambda.return_struct_type_name,
|
||||
pts, NULL, NULL, node->as.lambda.param_count, NULL, 0);
|
||||
|
||||
node->type.kind = TYPE_CLOSURE;
|
||||
}
|
||||
|
||||
SEMA_HANDLER(analyze_lambda)
|
||||
SEMA_HANDLER(analyze_ident_expr)
|
||||
SEMA_HANDLER(analyze_unary_expr)
|
||||
SEMA_HANDLER(analyze_binary_expr)
|
||||
@@ -572,6 +627,7 @@ void analyze_expr_init(void) {
|
||||
ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap);
|
||||
ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap);
|
||||
ast_dispatch_set(&sema_dispatch, AST_LIST_COMP, analyze_list_comp_wrap);
|
||||
ast_dispatch_set(&sema_dispatch, AST_LAMBDA, analyze_lambda_wrap);
|
||||
}
|
||||
|
||||
void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
|
||||
Reference in New Issue
Block a user