feat: defer 延迟执行 — defer { stmts; } 在 return 前按 LIFO 执行

Token(73): +TOK_DEFER, AST(28): +AST_DEFER_STMT, 新增 38_defer.l
parser: defer { ... } 块 + defer expr; 表达式两种形式
codegen: defer 栈压入 block, emit_deferred() 在 return 前 LIFO 发射

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 13:51:10 +08:00
parent e60021b684
commit 0088347576
10 changed files with 62 additions and 6 deletions
+16 -3
View File
@@ -77,6 +77,13 @@ void cleanup_emit(CgCtx* ctx, size_t from_mark) {
ctx->cleanup_count = from_mark;
}
// 发射所有 defer 语句(LIFO 顺序)
static void emit_deferred(CgCtx* ctx) {
for (size_t i = ctx->defer_count; i > 0; i--)
codegen_stmt(ctx, ctx->defer_exprs[i - 1]);
ctx->defer_count = 0;
}
// === 语句代码生成 ===
void codegen_stmt(CgCtx* ctx, AstNode* node) {
if (!node) return;
@@ -146,6 +153,11 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
codegen_expr(ctx, node->as.expr_stmt.expr);
break;
case AST_DEFER_STMT:
if (ctx->defer_count < 64)
ctx->defer_exprs[ctx->defer_count++] = node->as.defer_stmt.body;
break;
case AST_RETURN_STMT: {
// 先计算返回值
LLVMValueRef ret_val = NULL;
@@ -168,9 +180,9 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
}
}
}
// return 前释放当前作用域所有 str 堆分配
// defer → cleanup → ret 的顺序
emit_deferred(ctx);
cleanup_emit(ctx, 0);
// 然后 emit ret
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
else LLVMBuildRetVoid(ctx->builder);
break;
@@ -416,11 +428,12 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
}
ctx.defer_count = 0;
codegen_stmt(&ctx, fn->as.function.body);
// 确保函数有终止指令(terminator)
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
// 函数结尾隐式 return: 先释放所有 str 堆分配
emit_deferred(&ctx);
cleanup_emit(&ctx, 0);
if (fn->as.function.return_type == TYPE_VOID)
LLVMBuildRetVoid(ctx.builder);