feat: in/out 参数 — out 关键字引用传递
fn swap(out x: i64, out y: i64) 声明 out 参数,codegen 层面 函数签名变为 T* 指针,调用点自动传 &variable 地址。 in 是默认行为(值传递),无需显式标注。 Token → Parser → Sema → Codegen 全流水线: - TOK_OUT + "out" 关键字注册 - AST parameter.is_out 字段 - parse_function 解析 out 前缀 - Sema: out 参数注册为 SYM_VARIABLE+is_mut(可赋值) - Codegen: LLVM 函数签名使用 T*,调用点传 alloca Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+31
-9
@@ -23,17 +23,24 @@ LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
|
||||
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn, bool* out_params, size_t pc) {
|
||||
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
||||
if (!e) return;
|
||||
e->name = name; e->fn = fn;
|
||||
e->ret = TYPE_VOID;
|
||||
e->params = NULL;
|
||||
e->pc = 0;
|
||||
e->out_params = out_params;
|
||||
e->pc = pc;
|
||||
e->next = ctx->fn_table;
|
||||
ctx->fn_table = e;
|
||||
}
|
||||
|
||||
FnEntry* find_fn_entry(CgCtx* ctx, const char* name) {
|
||||
for (FnEntry* e = ctx->fn_table; e; e = e->next)
|
||||
if (strcmp(e->name, name) == 0) return e;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === 结构体类型表 ===
|
||||
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
|
||||
StructTypeEntry* e = arena_alloc(ctx->arena, sizeof(*e));
|
||||
@@ -379,14 +386,23 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
||||
AstNode* fn = ast->as.program.functions[i];
|
||||
LLVMTypeRef* ptypes = arena_alloc(ctx.arena,
|
||||
fn->as.function.param_count * sizeof(LLVMTypeRef));
|
||||
bool* out_params = NULL;
|
||||
if (fn->as.function.param_count > 0) {
|
||||
out_params = arena_alloc(ctx.arena,
|
||||
fn->as.function.param_count * sizeof(bool));
|
||||
}
|
||||
for (size_t j = 0; j < fn->as.function.param_count; j++) {
|
||||
AstNode* param = fn->as.function.params[j];
|
||||
bool is_out = param->as.parameter.is_out;
|
||||
if (out_params) out_params[j] = is_out;
|
||||
LLVMTypeRef inner_ty;
|
||||
if (param->as.parameter.type == TYPE_STRUCT &&
|
||||
param->as.parameter.struct_type_name) {
|
||||
ptypes[j] = find_struct_type(&ctx, param->as.parameter.struct_type_name);
|
||||
inner_ty = find_struct_type(&ctx, param->as.parameter.struct_type_name);
|
||||
} else {
|
||||
ptypes[j] = to_llvm_type(&ctx, param->as.parameter.type);
|
||||
inner_ty = to_llvm_type(&ctx, param->as.parameter.type);
|
||||
}
|
||||
ptypes[j] = is_out ? LLVMPointerType(inner_ty, 0) : inner_ty;
|
||||
}
|
||||
LLVMTypeRef ret_ty;
|
||||
if (fn->as.function.return_type == TYPE_STRUCT &&
|
||||
@@ -398,7 +414,8 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
||||
LLVMTypeRef fty = LLVMFunctionType(ret_ty,
|
||||
ptypes, (unsigned)fn->as.function.param_count, false);
|
||||
LLVMValueRef lfn = LLVMAddFunction(ctx.module, fn->as.function.name, fty);
|
||||
add_fn(&ctx, fn->as.function.name, lfn);
|
||||
add_fn(&ctx, fn->as.function.name, lfn, out_params,
|
||||
fn->as.function.param_count);
|
||||
}
|
||||
|
||||
// 第二遍:生成函数体
|
||||
@@ -422,10 +439,15 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
||||
} else {
|
||||
param_ty = to_llvm_type(&ctx, pnode->as.parameter.type);
|
||||
}
|
||||
LLVMValueRef alloca = LLVMBuildAlloca(ctx.builder,
|
||||
param_ty, pnode->as.parameter.name);
|
||||
LLVMBuildStore(ctx.builder, param, alloca);
|
||||
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
||||
if (pnode->as.parameter.is_out) {
|
||||
// out 参数: param 已是指向调用者变量的指针, 直接用作 alloca
|
||||
add_var(&ctx, pnode->as.parameter.name, param, param_ty);
|
||||
} else {
|
||||
LLVMValueRef alloca = LLVMBuildAlloca(ctx.builder,
|
||||
param_ty, pnode->as.parameter.name);
|
||||
LLVMBuildStore(ctx.builder, param, alloca);
|
||||
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.defer_count = 0;
|
||||
|
||||
Reference in New Issue
Block a user