feat: 表达式作为值 — if/else 和 block 可产生值

This commit is contained in:
2026-06-06 13:52:36 +08:00
parent 380b52930a
commit 0ec3c3d65f
4 changed files with 99 additions and 1 deletions
+42
View File
@@ -451,6 +451,48 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
return LLVMBuildLoad2(ctx->builder, elem_load_ty, elem_ptr, "arr_load");
}
// 块表达式: { stmt*; expr } → 最后表达式的值
case AST_BLOCK: {
LLVMValueRef result = NULL;
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
AstNode* stmt = node->as.block.stmts[i];
bool is_last = (i == node->as.block.stmt_count - 1);
if (is_last && stmt->kind == AST_EXPR_STMT && node->type.kind != TYPE_VOID) {
result = codegen_expr(ctx, stmt->as.expr_stmt.expr);
} else {
codegen_stmt(ctx, stmt);
}
}
return result;
}
// if 表达式: if cond { a } else { b }
case AST_IF_STMT: {
if (node->type.kind == TYPE_VOID) { codegen_stmt(ctx, node); return NULL; }
LLVMValueRef cond_val = codegen_expr(ctx, node->as.if_stmt.cond);
if (!cond_val) return NULL;
LLVMTypeRef res_ty = type_info_to_llvm(ctx, &node->type);
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder, res_ty, "if_res");
LLVMValueRef func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(ctx->builder));
LLVMBasicBlockRef then_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "then");
LLVMBasicBlockRef else_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "else");
LLVMBasicBlockRef merge_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "if_merge");
LLVMBuildCondBr(ctx->builder, cond_val, then_bb, else_bb);
LLVMPositionBuilderAtEnd(ctx->builder, then_bb);
LLVMValueRef then_val = codegen_expr(ctx, node->as.if_stmt.then_block);
if (then_val) LLVMBuildStore(ctx->builder, then_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, else_bb);
LLVMValueRef else_val = codegen_expr(ctx, node->as.if_stmt.else_block);
if (else_val) LLVMBuildStore(ctx->builder, else_val, alloca);
LLVMBuildBr(ctx->builder, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, merge_bb);
return LLVMBuildLoad2(ctx->builder, res_ty, alloca, "if_val");
}
default:
return NULL;
}