feat: 泛型基础设施 — <T>解析 + 类型推断 (单态化 codegen 待补)

This commit is contained in:
2026-06-06 16:17:15 +08:00
parent fa734b8a23
commit 350eeef3c5
9 changed files with 100 additions and 37 deletions
+1
View File
@@ -18,6 +18,7 @@ typedef enum {
TYPE_STRUCT, // 结构体类型 TYPE_STRUCT, // 结构体类型
TYPE_ENUM, // 枚举类型 TYPE_ENUM, // 枚举类型
TYPE_ARRAY, // 固定大小数组类型 TYPE_ARRAY, // 固定大小数组类型
TYPE_GENERIC, // 泛型类型参数(单态化前)
TYPE_UNKNOWN, // 尚未推断 TYPE_UNKNOWN, // 尚未推断
TYPE_ERROR, // 类型错误 TYPE_ERROR, // 类型错误
} TypeKind; } TypeKind;
+4 -1
View File
@@ -31,13 +31,16 @@ AstNode* ast_make_program(void* alloc, AstNode** fns, size_t fn_count,
AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size_t pcount, AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size_t pcount,
TypeKind ret, const char* ret_struct_name, AstNode* body, TypeKind ret, const char* ret_struct_name, AstNode* body,
bool is_pub, SourceLoc loc) { bool is_pub, const char** type_params, size_t tp_count,
SourceLoc loc) {
NEW(alloc, AST_FUNCTION); NEW(alloc, AST_FUNCTION);
n->as.function.name = name; n->as.function.params = params; n->as.function.name = name; n->as.function.params = params;
n->as.function.param_count = pcount; n->as.function.return_type = ret; n->as.function.param_count = pcount; n->as.function.return_type = ret;
n->as.function.return_struct_type_name = ret_struct_name; n->as.function.return_struct_type_name = ret_struct_name;
n->as.function.body = body; n->as.function.body = body;
n->as.function.is_pub = is_pub; n->as.function.is_pub = is_pub;
n->as.function.type_params = type_params;
n->as.function.type_param_count = tp_count;
return n; return n;
} }
+4 -2
View File
@@ -67,7 +67,8 @@ struct AstNode {
// AST_FUNCTION // AST_FUNCTION
struct { const char* name; struct AstNode** params; size_t param_count; struct { const char* name; struct AstNode** params; size_t param_count;
TypeKind return_type; const char* return_struct_type_name; TypeKind return_type; const char* return_struct_type_name;
struct AstNode* body; bool is_pub; } function; struct AstNode* body; bool is_pub;
const char** type_params; size_t type_param_count; } function;
// AST_PARAMETER (也用作结构体字段: name + type) // AST_PARAMETER (也用作结构体字段: name + type)
struct { const char* name; TypeKind type; const char* struct_type_name; } parameter; struct { const char* name; TypeKind type; const char* struct_type_name; } parameter;
// AST_BLOCK // AST_BLOCK
@@ -137,7 +138,8 @@ AstNode* ast_make_program(void* alloc, AstNode** fns, size_t fn_count,
AstNode** impls, size_t impl_count, SourceLoc loc); AstNode** impls, size_t impl_count, SourceLoc loc);
AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size_t pcount, AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size_t pcount,
TypeKind ret, const char* ret_struct_name, AstNode* body, TypeKind ret, const char* ret_struct_name, AstNode* body,
bool is_pub, SourceLoc loc); bool is_pub, const char** type_params, size_t tp_count,
SourceLoc loc);
AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type, const char* struct_type_name, SourceLoc loc); AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type, const char* struct_type_name, SourceLoc loc);
AstNode* ast_make_block(void* alloc, AstNode** stmts, size_t count, SourceLoc loc); AstNode* ast_make_block(void* alloc, AstNode** stmts, size_t count, SourceLoc loc);
AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot, AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot,
+20 -2
View File
@@ -907,9 +907,22 @@ static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
const Token* fn_tok = advance(p); // fn const Token* fn_tok = advance(p); // fn
const Token* name = expect(p, TOK_IDENT, error, "fn 后应为函数名"); const Token* name = expect(p, TOK_IDENT, error, "fn 后应为函数名");
if (!name) return NULL; if (!name) return NULL;
// 泛型类型参数: <T, U, ...>
const char* type_params[8]; int tp_count = 0;
if (peek(p)->kind == TOK_LT) {
advance(p); // 跳过 '<'
while (peek(p)->kind != TOK_GT && !error->message) {
if (tp_count >= 8) { error->message = "类型参数过多 (最多8)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
const Token* tp = expect(p, TOK_IDENT, error, "类型参数名");
if (!tp) return NULL;
type_params[tp_count++] = arena_strdup_impl(p->arena, tp->start, tp->length);
if (peek(p)->kind == TOK_COMMA) advance(p); else break;
}
if (!expect(p, TOK_GT, error, "缺少 '>'")) return NULL;
}
if (!expect(p, TOK_LPAREN, error, "缺少 '('")) return NULL; if (!expect(p, TOK_LPAREN, error, "缺少 '('")) return NULL;
// 参数列表 // 参数列表(泛型参数可标注为类型参数名)
AstNode* params[64]; int pcount = 0; AstNode* params[64]; int pcount = 0;
while (peek(p)->kind != TOK_RPAREN && !error->message) { while (peek(p)->kind != TOK_RPAREN && !error->message) {
if (pcount >= 64) { error->message = "函数参数过多 (最多64)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; } if (pcount >= 64) { error->message = "函数参数过多 (最多64)"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; }
@@ -941,9 +954,14 @@ static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) {
AstNode** parr = arena_alloc_impl(p->arena, pcount * sizeof(AstNode*)); AstNode** parr = arena_alloc_impl(p->arena, pcount * sizeof(AstNode*));
memcpy(parr, params, pcount * sizeof(AstNode*)); memcpy(parr, params, pcount * sizeof(AstNode*));
const char** tparr = NULL;
if (tp_count > 0) {
tparr = arena_alloc_impl(p->arena, tp_count * sizeof(const char*));
memcpy(tparr, type_params, tp_count * sizeof(const char*));
}
return ast_make_function(p->arena, return ast_make_function(p->arena,
arena_strdup_impl(p->arena, name->start, name->length), arena_strdup_impl(p->arena, name->start, name->length),
parr, pcount, ret, ret_struct_name, body, is_pub, tok_loc(fn_tok)); parr, pcount, ret, ret_struct_name, body, is_pub, tparr, tp_count, tok_loc(fn_tok));
} }
// === 模块文件加载辅助 === // === 模块文件加载辅助 ===
+40 -19
View File
@@ -159,31 +159,39 @@ static void analyze_binary_expr(AstNode* node, Scope* scope, ErrorList* errors,
} }
// 参数类型匹配检查(CALL_EXPR 和 METHOD_CALL 共用) // 参数类型匹配检查(CALL_EXPR 和 METHOD_CALL 共用)
static void check_arg_type(AstNode* arg, TypeKind expected, const char* expected_sname, static bool check_arg_type(AstNode* arg, TypeKind expected, const char* expected_sname,
size_t idx, AstNode* call_node, Scope* scope, size_t idx, AstNode* call_node, Symbol* fn_sym,
ErrorList* errors, Arena* a) { ErrorList* errors, Arena* a) {
(void)scope; (void)a; (void)a;
TypeKind actual = arg->type.kind; TypeKind actual = arg->type.kind;
if (actual == TYPE_ERROR) return; if (actual == TYPE_ERROR) return false;
if (expected == TYPE_STRUCT) { if (expected == TYPE_STRUCT && expected_sname) {
// 检查是否是泛型类型参数(匹配则接受任意类型)
if (fn_sym && fn_sym->type_params) {
for (size_t t = 0; t < fn_sym->type_param_count; t++) {
if (strcmp(expected_sname, fn_sym->type_params[t]) == 0)
return true; // 泛型参数,接受任意类型
}
}
const char* actual_name = arg->type.struct_name; const char* actual_name = arg->type.struct_name;
if (actual != TYPE_STRUCT || !actual_name || !expected_sname || if (actual != TYPE_STRUCT || !actual_name ||
strcmp(actual_name, expected_sname) != 0) { strcmp(actual_name, expected_sname) != 0) {
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col, error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'", "参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
idx + 1, expected_sname ? expected_sname : "struct", idx + 1, expected_sname ? expected_sname : "struct",
actual_name ? actual_name : type_name(actual)); actual_name ? actual_name : type_name(actual));
} }
return; return false;
} }
if (actual == expected) return; if (actual == expected) return false;
if (expected == TYPE_I64 && actual == TYPE_ENUM) return; if (expected == TYPE_I64 && actual == TYPE_ENUM) return false;
if (can_implicit_convert(actual, expected)) return; if (can_implicit_convert(actual, expected)) return false;
if (actual == TYPE_I64 && arg->kind == AST_LITERAL_EXPR if (actual == TYPE_I64 && arg->kind == AST_LITERAL_EXPR
&& (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR)) return; && (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR)) return false;
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col, error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'", "参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
idx + 1, type_name(expected), type_name(actual)); idx + 1, type_name(expected), type_name(actual));
return false;
} }
// 命名参数重排序(CALL_EXPR 和 METHOD_CALL 共用) // 命名参数重排序(CALL_EXPR 和 METHOD_CALL 共用)
@@ -241,9 +249,20 @@ static void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Ar
} }
for (size_t i = 0; i < node->as.call.arg_count; i++) { for (size_t i = 0; i < node->as.call.arg_count; i++) {
analyze_expr(node->as.call.args[i], scope, errors, a); analyze_expr(node->as.call.args[i], scope, errors, a);
check_arg_type(node->as.call.args[i], sym->param_types[i], bool is_generic_param = check_arg_type(node->as.call.args[i], sym->param_types[i],
sym->param_struct_names ? sym->param_struct_names[i] : NULL, sym->param_struct_names ? sym->param_struct_names[i] : NULL,
i, node, scope, errors, a); i, node, sym, errors, a);
// 泛型: 若实参匹配类型参数,传播具体类型到返回值
if (is_generic_param && sym->return_type == TYPE_STRUCT
&& sym->return_struct_type_name && sym->type_params) {
for (size_t t = 0; t < sym->type_param_count; t++) {
if (strcmp(sym->return_struct_type_name, sym->type_params[t]) == 0) {
node->type.kind = node->as.call.args[i]->type.kind;
node->type.struct_name = node->as.call.args[i]->type.struct_name;
return;
}
}
}
} }
node->type.kind = sym->return_type; node->type.kind = sym->return_type;
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name) if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
@@ -422,7 +441,7 @@ static void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors,
analyze_expr(node->as.method_call.args[i], scope, errors, a); analyze_expr(node->as.method_call.args[i], scope, errors, a);
check_arg_type(node->as.method_call.args[i], sym->param_types[i + 1], check_arg_type(node->as.method_call.args[i], sym->param_types[i + 1],
sym->param_struct_names ? sym->param_struct_names[i + 1] : NULL, sym->param_struct_names ? sym->param_struct_names[i + 1] : NULL,
i, node, scope, errors, a); i, node, sym, errors, a);
} }
node->type.kind = sym->return_type; node->type.kind = sym->return_type;
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name) if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
@@ -572,7 +591,9 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
scope_insert_function(scope, a, fn->as.function.name, scope_insert_function(scope, a, fn->as.function.name,
ret_t, ret_sn, ret_t, ret_sn,
pts, pnames, pstruct_names, pts, pnames, pstruct_names,
fn->as.function.param_count); fn->as.function.param_count,
fn->as.function.type_params,
fn->as.function.type_param_count);
} }
// 第三遍:分析每个函数体 // 第三遍:分析每个函数体
for (size_t i = 0; i < node->as.program.fn_count; i++) { for (size_t i = 0; i < node->as.program.fn_count; i++) {
@@ -884,13 +905,13 @@ void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) {
// 注册内置函数 // 注册内置函数
TypeKind params_i64[] = {TYPE_I64}; TypeKind params_i64[] = {TYPE_I64};
scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, NULL, 1); scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, NULL, params_i64, NULL, NULL, 1, NULL, 0);
TypeKind params_f64[] = {TYPE_F64}; TypeKind params_f64[] = {TYPE_F64};
scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, NULL, 1); scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, NULL, params_f64, NULL, NULL, 1, NULL, 0);
TypeKind params_bool[] = {TYPE_BOOL}; TypeKind params_bool[] = {TYPE_BOOL};
scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, NULL, 1); scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, NULL, params_bool, NULL, NULL, 1, NULL, 0);
TypeKind params_str[] = {TYPE_STR}; TypeKind params_str[] = {TYPE_STR};
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1); scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, NULL, params_str, NULL, NULL, 1, NULL, 0);
analyze_node(ast, global_scope, errors, arena); analyze_node(ast, global_scope, errors, arena);
} }
+7 -1
View File
@@ -31,6 +31,7 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
sym->name = name; sym->kind = kind; sym->type = type; sym->name = name; sym->kind = kind; sym->type = type;
sym->is_mut = false; sym->return_type = TYPE_VOID; sym->is_mut = false; sym->return_type = TYPE_VOID;
sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0;
sym->type_params = NULL; sym->type_param_count = 0;
sym->struct_field_names = NULL; sym->struct_field_names = NULL;
sym->struct_field_types = NULL; sym->struct_field_types = NULL;
sym->struct_field_count = 0; sym->struct_field_count = 0;
@@ -49,7 +50,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
TypeKind ret, const char* ret_struct_name, TypeKind ret, const char* ret_struct_name,
TypeKind* pt, const char** pnames, TypeKind* pt, const char** pnames,
const char** pstruct_names, size_t pc) { const char** pstruct_names, size_t pc,
const char** tparams, size_t tpc) {
if (scope->head) { if (scope->head) {
for (Symbol* sym = scope->head; sym; sym = sym->next) { for (Symbol* sym = scope->head; sym; sym = sym->next) {
if (strcmp(sym->name, name) == 0) return NULL; if (strcmp(sym->name, name) == 0) return NULL;
@@ -64,6 +66,8 @@ Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
sym->param_names = pnames; sym->param_names = pnames;
sym->param_struct_names = pstruct_names; sym->param_struct_names = pstruct_names;
sym->param_count = pc; sym->param_count = pc;
sym->type_params = tparams;
sym->type_param_count = tpc;
sym->struct_field_names = NULL; sym->struct_field_names = NULL;
sym->struct_field_types = NULL; sym->struct_field_types = NULL;
sym->struct_field_count = 0; sym->struct_field_count = 0;
@@ -92,6 +96,7 @@ Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name,
sym->name = name; sym->kind = SYM_STRUCT; sym->type = TYPE_STRUCT; sym->name = name; sym->kind = SYM_STRUCT; sym->type = TYPE_STRUCT;
sym->is_mut = false; sym->return_type = TYPE_VOID; sym->is_mut = false; sym->return_type = TYPE_VOID;
sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0;
sym->type_params = NULL; sym->type_param_count = 0;
sym->struct_field_names = fnames; sym->struct_field_names = fnames;
sym->struct_field_types = ftypes; sym->struct_field_types = ftypes;
sym->struct_field_struct_names = fstruct_names; sym->struct_field_struct_names = fstruct_names;
@@ -140,6 +145,7 @@ Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name,
sym->name = name; sym->kind = SYM_ENUM; sym->type = TYPE_ENUM; sym->name = name; sym->kind = SYM_ENUM; sym->type = TYPE_ENUM;
sym->is_mut = false; sym->return_type = TYPE_VOID; sym->is_mut = false; sym->return_type = TYPE_VOID;
sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0; sym->param_types = NULL; sym->param_names = NULL; sym->param_count = 0;
sym->type_params = NULL; sym->type_param_count = 0;
sym->struct_field_names = vnames; sym->struct_field_names = vnames;
sym->struct_field_types = NULL; sym->struct_field_types = NULL;
sym->struct_field_struct_names = NULL; sym->struct_field_struct_names = NULL;
+4 -1
View File
@@ -14,6 +14,8 @@ typedef struct Symbol {
// 函数特有 // 函数特有
TypeKind return_type; TypeKind return_type;
const char* return_struct_type_name; // 返回类型为 struct 时的类型名 const char* return_struct_type_name; // 返回类型为 struct 时的类型名
const char** type_params; // 泛型类型参数名
size_t type_param_count;
TypeKind* param_types; TypeKind* param_types;
const char** param_names; // 参数名(用于命名参数匹配) const char** param_names; // 参数名(用于命名参数匹配)
const char** param_struct_names; // 参数为 struct 时的类型名 const char** param_struct_names; // 参数为 struct 时的类型名
@@ -57,7 +59,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
TypeKind ret, const char* ret_struct_name, TypeKind ret, const char* ret_struct_name,
TypeKind* pt, const char** pnames, TypeKind* pt, const char** pnames,
const char** pstruct_names, size_t pc); const char** pstruct_names, size_t pc,
const char** tparams, size_t tpc);
// 插入结构体符号 // 插入结构体符号
Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name,
+9
View File
@@ -0,0 +1,9 @@
fn id<T>(x: T) -> T {
return x;
}
fn main() -> i64 {
let a = id(42);
print_i64(a); // 42
return 0;
}
+11 -11
View File
@@ -12,7 +12,7 @@ void test_codegen_simple_function() {
AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 42, loc_at(1, 1)), loc_at(1, 1)); AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 42, loc_at(1, 1)), loc_at(1, 1));
AstNode* stmts[] = { ret }; AstNode* stmts[] = { ret };
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -46,7 +46,7 @@ void test_codegen_if_else() {
ast_make_literal_bool(&a, true, loc_at(1, 1)), then_block, else_block, loc_at(1, 1)); ast_make_literal_bool(&a, true, loc_at(1, 1)), then_block, else_block, loc_at(1, 1));
AstNode* stmts[] = { if_stmt }; AstNode* stmts[] = { if_stmt };
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -77,7 +77,7 @@ void test_codegen_binary_ops() {
AstNode* ret = ast_make_return(&a, expr, loc_at(1, 1)); AstNode* ret = ast_make_return(&a, expr, loc_at(1, 1));
AstNode* stmts[] = { ret }; AstNode* stmts[] = { ret };
AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 1, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -107,7 +107,7 @@ void test_codegen_while_loop() {
AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 1, loc_at(1, 1)), loc_at(1, 1)); AstNode* ret = ast_make_return(&a, ast_make_literal_i64(&a, 1, loc_at(1, 1)), loc_at(1, 1));
AstNode* stmts[] = { while_stmt, ret }; AstNode* stmts[] = { while_stmt, ret };
AstNode* fn_body = ast_make_block(&a, stmts, 2, loc_at(1, 1)); AstNode* fn_body = ast_make_block(&a, stmts, 2, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, fn_body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, fn_body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -160,7 +160,7 @@ void test_codegen_struct_decl() {
AstNode* ret = ast_make_return(&a, field_x, loc_at(1, 1)); AstNode* ret = ast_make_return(&a, field_x, loc_at(1, 1));
AstNode* stmts[] = { let_stmt, ret }; AstNode* stmts[] = { let_stmt, ret };
AstNode* body = ast_make_block(&a, stmts, 2, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 2, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -215,7 +215,7 @@ void test_codegen_struct_field_access() {
AstNode* ret = ast_make_return(&a, field_y, loc_at(1, 1)); AstNode* ret = ast_make_return(&a, field_y, loc_at(1, 1));
AstNode* stmts[] = { let_stmt, ret }; AstNode* stmts[] = { let_stmt, ret };
AstNode* body = ast_make_block(&a, stmts, 2, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 2, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -265,7 +265,7 @@ void test_codegen_enum() {
AstNode* stmts[] = { let_stmt, print_call, ret }; AstNode* stmts[] = { let_stmt, print_call, ret };
AstNode* body = ast_make_block(&a, stmts, 3, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 3, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1));
@@ -330,7 +330,7 @@ void test_codegen_array() {
AstNode* stmts[] = { let_stmt, arr_assign, print_call, ret }; AstNode* stmts[] = { let_stmt, arr_assign, print_call, ret };
AstNode* body = ast_make_block(&a, stmts, 4, loc_at(1, 1)); AstNode* body = ast_make_block(&a, stmts, 4, loc_at(1, 1));
AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { fn }; AstNode* fns[] = { fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -373,7 +373,7 @@ void test_codegen_method_call() {
AstNode* ret_body = ast_make_return(&a, field_x, loc_at(1, 1)); AstNode* ret_body = ast_make_return(&a, field_x, loc_at(1, 1));
AstNode* ret_stmts[] = { ret_body }; AstNode* ret_stmts[] = { ret_body };
AstNode* body = ast_make_block(&a, ret_stmts, 1, loc_at(1, 1)); AstNode* body = ast_make_block(&a, ret_stmts, 1, loc_at(1, 1));
AstNode* get_x_fn = ast_make_function(&a, "Point$get_x", params, 1, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* get_x_fn = ast_make_function(&a, "Point$get_x", params, 1, TYPE_I64, NULL, body, false, NULL, 0, loc_at(1, 1));
/* fn main() -> i64 { /* fn main() -> i64 {
let p = Point { x: 42, y: 0 }; let p = Point { x: 42, y: 0 };
@@ -399,7 +399,7 @@ void test_codegen_method_call() {
AstNode* ret_main = ast_make_return(&a, method_call, loc_at(1, 1)); AstNode* ret_main = ast_make_return(&a, method_call, loc_at(1, 1));
AstNode* main_stmts[] = { let_stmt, ret_main }; AstNode* main_stmts[] = { let_stmt, ret_main };
AstNode* main_body = ast_make_block(&a, main_stmts, 2, loc_at(1, 1)); AstNode* main_body = ast_make_block(&a, main_stmts, 2, loc_at(1, 1));
AstNode* main_fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, main_body, false, loc_at(1, 1)); AstNode* main_fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, main_body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { get_x_fn, main_fn }; AstNode* fns[] = { get_x_fn, main_fn };
AstNode* prog = ast_make_program(&a, fns, 2, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 2, structs, 1, NULL, 0, NULL, 0, NULL, 0, loc_at(1, 1));
@@ -486,7 +486,7 @@ void test_codegen_match() {
AstNode* main_stmts[] = { let_stmt, outer_if }; AstNode* main_stmts[] = { let_stmt, outer_if };
AstNode* main_body = ast_make_block(&a, main_stmts, 2, loc_at(1, 1)); AstNode* main_body = ast_make_block(&a, main_stmts, 2, loc_at(1, 1));
AstNode* main_fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, main_body, false, loc_at(1, 1)); AstNode* main_fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, main_body, false, NULL, 0, loc_at(1, 1));
AstNode* fns[] = { main_fn }; AstNode* fns[] = { main_fn };
AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1)); AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1));