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:
+16
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user