From fa734b8a231fb925500336c5e86c668e464067d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sat, 6 Jun 2026 16:09:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A8=A1=E5=9D=97=E7=B3=BB=E7=BB=9F=20?= =?UTF-8?q?mod=20+=20pub=20=E2=80=94=20=E5=A4=9A=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ast/ast.c | 18 ++++- src/ast/ast.h | 13 ++- src/lexer/lexer.c | 1 + src/lexer/token.c | 1 + src/lexer/token.h | 2 +- src/parser/parser.c | 152 ++++++++++++++++++++++++++++++++++-- test/programs/33_mod_main.l | 7 ++ test/programs/math_mod.l | 3 + test/test_codegen.c | 22 +++--- 9 files changed, 197 insertions(+), 22 deletions(-) create mode 100644 test/programs/33_mod_main.l create mode 100644 test/programs/math_mod.l diff --git a/src/ast/ast.c b/src/ast/ast.c index fa0af3e..ab642eb 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -30,12 +30,14 @@ 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, - TypeKind ret, const char* ret_struct_name, AstNode* body, SourceLoc loc) { + TypeKind ret, const char* ret_struct_name, AstNode* body, + bool is_pub, SourceLoc loc) { NEW(alloc, AST_FUNCTION); 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.return_struct_type_name = ret_struct_name; n->as.function.body = body; + n->as.function.is_pub = is_pub; return n; } @@ -255,3 +257,17 @@ AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method n->as.method_call.arg_count = count; return n; } + +AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc) { + NEW(alloc, AST_MOD_DECL); + n->as.mod_decl.name = name; + n->as.mod_decl.ast = sub_ast; + return n; +} + +AstNode* ast_make_use_decl(void* alloc, const char* path, const char* item, SourceLoc loc) { + NEW(alloc, AST_USE_DECL); + n->as.use_decl.path = path; + n->as.use_decl.item = item; + return n; +} diff --git a/src/ast/ast.h b/src/ast/ast.h index 61ef520..cca2cd3 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -30,6 +30,8 @@ typedef enum { AST_ARRAY_ASSIGN_STMT,// arr[i] = expr AST_IMPL_BLOCK, // impl StructName { fn method(...) ... } AST_METHOD_CALL, // receiver.method(args) + AST_MOD_DECL, // mod foo; + AST_USE_DECL, // use foo::bar; } AstKind; typedef enum { @@ -65,7 +67,7 @@ struct AstNode { // AST_FUNCTION struct { const char* name; struct AstNode** params; size_t param_count; TypeKind return_type; const char* return_struct_type_name; - struct AstNode* body; } function; + struct AstNode* body; bool is_pub; } function; // AST_PARAMETER (也用作结构体字段: name + type) struct { const char* name; TypeKind type; const char* struct_type_name; } parameter; // AST_BLOCK @@ -120,6 +122,10 @@ struct AstNode { struct { const char* struct_name; struct AstNode** methods; size_t method_count; } impl_block; // AST_METHOD_CALL struct { struct AstNode* receiver; const char* method_name; struct AstNode** args; const char** arg_names; size_t arg_count; } method_call; + // AST_MOD_DECL + struct { const char* name; struct AstNode* ast; } mod_decl; + // AST_USE_DECL + struct { const char* path; const char* item; } use_decl; } as; }; @@ -130,7 +136,8 @@ AstNode* ast_make_program(void* alloc, AstNode** fns, size_t fn_count, AstNode** enums, size_t enum_count, AstNode** impls, size_t impl_count, SourceLoc loc); AstNode* ast_make_function(void* alloc, const char* name, AstNode** params, size_t pcount, - TypeKind ret, const char* ret_struct_name, AstNode* body, SourceLoc loc); + TypeKind ret, const char* ret_struct_name, AstNode* body, + bool is_pub, 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_let(void* alloc, const char* name, TypeKind annot_type, bool has_type_annot, @@ -164,5 +171,7 @@ AstNode* ast_make_index_expr(void* alloc, AstNode* array, AstNode* index, Source AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc); AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc); AstNode* ast_make_method_call(void* alloc, AstNode* receiver, const char* method, AstNode** args, const char** arg_names, size_t count, SourceLoc loc); +AstNode* ast_make_mod_decl(void* alloc, const char* name, AstNode* sub_ast, SourceLoc loc); +AstNode* ast_make_use_decl(void* alloc, const char* path, const char* item, SourceLoc loc); #endif diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index fd019d0..5e5ca65 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -66,6 +66,7 @@ static TokenKind check_keyword(const Token* tok) { KW("str", TOK_STR); KW("void", TOK_VOID); KW("struct", TOK_STRUCT); KW("type", TOK_TYPE); KW("enum", TOK_ENUM); KW("extend", TOK_EXTEND); KW("match", TOK_MATCH); + KW("pub", TOK_PUB); KW("mod", TOK_MOD); KW("use", TOK_USE); KW("_", TOK_UNDERSCORE); KW("true", TOK_TRUE); KW("false", TOK_FALSE); #undef KW diff --git a/src/lexer/token.c b/src/lexer/token.c index e5dfb52..fcc3a56 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -6,6 +6,7 @@ static const char* NAMES[] = { [TOK_FN] = "fn", [TOK_LET] = "let", [TOK_VAR] = "var", [TOK_IF] = "if", [TOK_GUARD] = "guard", + [TOK_PUB] = "pub", [TOK_MOD] = "mod", [TOK_USE] = "use", [TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return", [TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_ENUM] = "enum", [TOK_EXTEND] = "extend", [TOK_MATCH] = "match", diff --git a/src/lexer/token.h b/src/lexer/token.h index 96eea30..2f5eddb 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -7,7 +7,7 @@ typedef enum { // 关键字 TOK_FN, TOK_LET, TOK_VAR, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD, - TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_MATCH, + TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE, // 类型关键字 TOK_I32, TOK_I64, TOK_U64, TOK_F64, TOK_BOOL, TOK_CHAR, TOK_STR, TOK_VOID, // 字面量 diff --git a/src/parser/parser.c b/src/parser/parser.c index ae3d85e..0bd7872 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,4 +1,5 @@ #include "parser.h" +#include "lexer.h" #include #include #include @@ -72,7 +73,7 @@ static AstNode* parse_expr(Parser* p, ErrorInfo* error); static AstNode* parse_expr_prec(Parser* p, Precedence prec, ErrorInfo* error); static AstNode* parse_block(Parser* p, ErrorInfo* error); static AstNode* parse_statement(Parser* p, ErrorInfo* error); -static AstNode* parse_function(Parser* p, ErrorInfo* error); +static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error); // === 前缀解析 === static AstNode* parse_unary(Parser* p, ErrorInfo* error) { @@ -188,11 +189,56 @@ static AstNode* parse_struct_init(Parser* p, const Token* name, ErrorInfo* error static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) { const Token* name = advance(p); - // 枚举变体引用: Name::Variant 或 Name::Variant(payload) + // 枚举变体或模块函数: Name::Variant 或 Name::fn if (peek(p)->kind == TOK_COLON_COLON) { advance(p); // 跳过 :: const Token* variant = expect(p, TOK_IDENT, error, "枚举变体名"); if (!variant) return NULL; + // Name::fn 或 Name::Variant 或 Name::Variant(payload) + if (peek(p)->kind == TOK_LPAREN) { + // 前进探测: 检查括号内是否有多参数或命名参数(→函数调用)还是单表达式(→枚举payload) + size_t probe = p->pos + 1; + int paren_depth = 1; + bool has_comma = false, has_named = false; + while (paren_depth > 0 && p->tokens[probe].kind != TOK_EOF) { + if (p->tokens[probe].kind == TOK_LPAREN) paren_depth++; + else if (p->tokens[probe].kind == TOK_RPAREN) { paren_depth--; if (paren_depth == 0) break; } + else if (paren_depth == 1 && p->tokens[probe].kind == TOK_COMMA) has_comma = true; + else if (paren_depth == 1 && p->tokens[probe].kind == TOK_COLON) has_named = true; + probe++; + } + if (has_comma || has_named) { + // 模块函数调用: Name::fn(a, b) 或 Name::fn(x: 1) + advance(p); // 跳过 '(' + AstNode* args[16]; const char* arg_names[16]; int arg_count = 0; + bool seen_named = false; + while (peek(p)->kind != TOK_RPAREN && !error->message) { + if (arg_count >= 16) { error->message = "参数过多"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; } + if (peek(p)->kind == TOK_IDENT && (p->tokens[p->pos + 1].kind == TOK_COLON)) { + const Token* aname = advance(p); advance(p); + arg_names[arg_count] = arena_strdup_impl(p->arena, aname->start, aname->length); + seen_named = true; + } else { + if (seen_named) { error->message = "命名参数必须放在位置参数之后"; error->filename = p->filename; error->line = peek(p)->line; error->col = peek(p)->col; return NULL; } + arg_names[arg_count] = NULL; + } + args[arg_count] = parse_expr(p, error); + if (!args[arg_count]) return NULL; + arg_count++; + if (peek(p)->kind == TOK_COMMA) advance(p); else break; + } + if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL; + AstNode** arg_arr = arena_alloc_impl(p->arena, arg_count * sizeof(AstNode*)); + memcpy(arg_arr, args, arg_count * sizeof(AstNode*)); + const char** name_arr = seen_named + ? memcpy(arena_alloc_impl(p->arena, arg_count * sizeof(const char*)), arg_names, arg_count * sizeof(const char*)) + : NULL; + char* full_name = arena_alloc_impl(p->arena, name->length + variant->length + 4); + sprintf(full_name, "%.*s::%.*s", name->length, name->start, variant->length, variant->start); + return ast_make_call(p->arena, full_name, arg_arr, name_arr, arg_count, tok_loc(name)); + } + } + // 枚举 payload: Name::Variant 或 Name::Variant(expr) AstNode* payload = NULL; if (match(p, TOK_LPAREN)) { payload = parse_expr(p, error); @@ -857,7 +903,7 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) { } // === 函数解析 === -static AstNode* parse_function(Parser* p, ErrorInfo* error) { +static AstNode* parse_function(Parser* p, bool is_pub, ErrorInfo* error) { const Token* fn_tok = advance(p); // fn const Token* name = expect(p, TOK_IDENT, error, "fn 后应为函数名"); if (!name) return NULL; @@ -897,7 +943,51 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) { memcpy(parr, params, pcount * sizeof(AstNode*)); return ast_make_function(p->arena, arena_strdup_impl(p->arena, name->start, name->length), - parr, pcount, ret, ret_struct_name, body, tok_loc(fn_tok)); + parr, pcount, ret, ret_struct_name, body, is_pub, tok_loc(fn_tok)); +} + +// === 模块文件加载辅助 === +// parse 前向声明(定义在后面) +AstNode* parse(Arena* a, const Token* tokens, size_t count, + const char* filename, ErrorInfo* error); + +static AstNode* load_module(Arena* a, const char* parent_file, + const char* mod_name, ErrorInfo* error) { + // 构造模块文件路径: 同目录下 mod_name.l + char mod_path[512]; + const char* last_slash = strrchr(parent_file, '/'); + const char* last_bs = strrchr(parent_file, '\\'); + const char* dir_end = parent_file; + if (last_slash && last_slash > dir_end) dir_end = last_slash; + if (last_bs && last_bs > dir_end) dir_end = last_bs; + if (dir_end != parent_file) { + size_t dir_len = dir_end - parent_file + 1; + memcpy(mod_path, parent_file, dir_len); + snprintf(mod_path + dir_len, sizeof(mod_path) - dir_len, "%s.l", mod_name); + } else { + snprintf(mod_path, sizeof(mod_path), "%s.l", mod_name); + } + // 读取文件 + FILE* f = fopen(mod_path, "rb"); + if (!f) { + error->message = "无法打开模块文件"; error->filename = mod_path; + error->line = 0; error->col = 0; + return NULL; + } + fseek(f, 0, SEEK_END); + size_t sz = ftell(f); fseek(f, 0, SEEK_SET); + char* src = malloc(sz + 1); + if (!src) { fclose(f); return NULL; } + fread(src, 1, sz, f); src[sz] = '\0'; fclose(f); + + size_t tc; + ErrorInfo lex_err = {0}; + Token* toks = lex(a, src, mod_path, &tc, &lex_err); + free(src); + if (!toks) { *error = lex_err; return NULL; } + + AstNode* ast = parse(a, toks, tc, mod_path, error); + return ast; } // === 程序入口 === @@ -910,7 +1000,14 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, AstNode* aliases[64]; int alias_count = 0; AstNode* enums[64]; int enum_count = 0; AstNode* impls[64]; int impl_count = 0; + AstNode* mods[64]; int mod_count = 0; + AstNode* uses[64]; int use_count = 0; while (peek(&p)->kind != TOK_EOF && !error->message) { + // pub 前缀 + bool is_pub = false; + if (peek(&p)->kind == TOK_PUB) { + is_pub = true; advance(&p); + } if (peek(&p)->kind == TOK_STRUCT) { if (struct_count >= 64) { error->message = "结构体过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } structs[struct_count++] = parse_struct_decl(&p, error); @@ -975,7 +1072,7 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, while (peek(&p)->kind != TOK_RBRACE && !error->message) { if (mcount >= 64) { error->message = "方法过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } if (peek(&p)->kind != TOK_FN) { error->message = "extend 块内只允许 fn"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } - methods[mcount++] = parse_function(&p, error); + methods[mcount++] = parse_function(&p, false, error); } if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL; AstNode** m_arr = arena_alloc_impl(p.arena, mcount * sizeof(AstNode*)); @@ -984,11 +1081,52 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, impls[impl_count++] = ast_make_impl_block(p.arena, arena_strdup_impl(p.arena, st_name->start, st_name->length), m_arr, mcount, tok_loc(i_tok)); + } else if (peek(&p)->kind == TOK_MOD) { + advance(&p); + const Token* mn = expect(&p, TOK_IDENT, error, "mod 后应为模块名"); + if (!mn) return NULL; + if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL; + const char* mod_name = arena_strdup_impl(p.arena, mn->start, mn->length); + AstNode* sub = load_module(a, filename, mod_name, error); + if (!sub) return NULL; + // 合并子模块项到当前文件(以 mod_name:: 为前缀) + for (size_t i = 0; i < sub->as.program.fn_count; i++) { + AstNode* fn = sub->as.program.functions[i]; + if (fn->as.function.is_pub) { + char* mangled = arena_alloc_impl(p.arena, strlen(mod_name) + strlen(fn->as.function.name) + 4); + sprintf(mangled, "%s::%s", mod_name, fn->as.function.name); + fn->as.function.name = mangled; + if (fn_count >= 256) { error->message = "函数过多"; error->filename = p.filename; return NULL; } + functions[fn_count++] = fn; + } + } + for (size_t i = 0; i < sub->as.program.struct_count; i++) { + if (struct_count >= 64) break; + structs[struct_count++] = sub->as.program.structs[i]; + } + for (size_t i = 0; i < sub->as.program.enum_count; i++) { + if (enum_count >= 64) break; + enums[enum_count++] = sub->as.program.enums[i]; + } + if (mod_count < 64) mods[mod_count++] = ast_make_mod_decl(a, mod_name, sub, tok_loc(mn)); + } else if (peek(&p)->kind == TOK_USE) { + advance(&p); + const Token* path_tok = expect(&p, TOK_IDENT, error, "use 后应为模块名"); + if (!path_tok) return NULL; + if (!expect(&p, TOK_COLON_COLON, error, "缺少 '::'")) return NULL; + const Token* item_tok = expect(&p, TOK_IDENT, error, "use 后应为项目名"); + if (!item_tok) return NULL; + if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL; + if (use_count >= 64) { error->message = "use 过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } + uses[use_count++] = ast_make_use_decl(a, + arena_strdup_impl(p.arena, path_tok->start, path_tok->length), + arena_strdup_impl(p.arena, item_tok->start, item_tok->length), + tok_loc(path_tok)); } else if (peek(&p)->kind == TOK_FN) { if (fn_count >= 256) { error->message = "函数过多 (最多256)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } - functions[fn_count++] = parse_function(&p, error); + functions[fn_count++] = parse_function(&p, is_pub, error); } else { - error->message = "顶层只允许 fn、struct、type、enum 或 extend"; + error->message = "顶层只允许 fn、struct、type、enum、extend、mod 或 use"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; diff --git a/test/programs/33_mod_main.l b/test/programs/33_mod_main.l new file mode 100644 index 0000000..0e8f8e4 --- /dev/null +++ b/test/programs/33_mod_main.l @@ -0,0 +1,7 @@ +mod math_mod; + +fn main() -> i64 { + let result = math_mod::add(3, 4); + print_i64(result); // 7 + return 0; +} diff --git a/test/programs/math_mod.l b/test/programs/math_mod.l new file mode 100644 index 0000000..74d4eb1 --- /dev/null +++ b/test/programs/math_mod.l @@ -0,0 +1,3 @@ +pub fn add(a: i64, b: i64) -> i64 { + return a + b; +} diff --git a/test/test_codegen.c b/test/test_codegen.c index 79a18d1..d5c4215 100644 --- a/test/test_codegen.c +++ b/test/test_codegen.c @@ -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* stmts[] = { ret }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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)); AstNode* stmts[] = { if_stmt }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* stmts[] = { ret }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* stmts[] = { while_stmt, ret }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, fn_body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* stmts[] = { let_stmt, ret }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* stmts[] = { let_stmt, ret }; 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, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* body = ast_make_block(&a, stmts, 3, loc_at(1, 1)); - AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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* body = ast_make_block(&a, stmts, 4, loc_at(1, 1)); - AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1)); + AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, false, loc_at(1, 1)); AstNode* fns[] = { fn }; 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_stmts[] = { ret_body }; 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, 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)); /* fn main() -> i64 { 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* main_stmts[] = { let_stmt, ret_main }; 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, 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* 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)); @@ -486,7 +486,7 @@ void test_codegen_match() { AstNode* main_stmts[] = { let_stmt, outer_if }; 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, 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* fns[] = { main_fn }; AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, enums, 1, NULL, 0, loc_at(1, 1));