From ab88ea27531c6c318c761161406116bb41b3a3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Fri, 5 Jun 2026 13:54:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=B1=BB=E5=9E=8B=E5=88=AB=E5=90=8D=20?= =?UTF-8?q?type=20alias=20(P1=20#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - lexer: TOK_TYPE 关键字 - ast: AST_TYPE_ALIAS + AST_PROGRAM aliases数组 - parser: parse_type_expr() 抽取, type Name = Type; 解析 - sema: 别名注册+解析, 类型标注/struct字段/函数参数均支持 - 新增测试: 15_type_alias.l, 16_type_alias_struct.l 测试: 112 通过 (41+15+41+15) --- src/ast/ast.c | 14 +++- src/ast/ast.h | 11 ++- src/lexer/lexer.c | 2 +- src/lexer/token.c | 2 +- src/lexer/token.h | 2 +- src/parser/parser.c | 102 +++++++++++++------------ src/sema/sema.c | 110 ++++++++++++++++++++++----- src/sema/symbol.c | 3 + src/sema/symbol.h | 2 + test/programs/15_type_alias.l | 6 ++ test/programs/16_type_alias_struct.l | 8 ++ test/test_codegen.c | 12 +-- test/test_sema.c | 40 ++++++++++ 13 files changed, 235 insertions(+), 79 deletions(-) create mode 100644 test/programs/15_type_alias.l create mode 100644 test/programs/16_type_alias_struct.l diff --git a/src/ast/ast.c b/src/ast/ast.c index a9e552a..c7eae06 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -9,12 +9,15 @@ n->loc = loc AstNode* ast_make_program(void* alloc, AstNode** fns, size_t fn_count, - AstNode** structs, size_t struct_count, SourceLoc loc) { + AstNode** structs, size_t struct_count, + AstNode** aliases, size_t alias_count, SourceLoc loc) { NEW(alloc, AST_PROGRAM); n->as.program.functions = fns; n->as.program.fn_count = fn_count; n->as.program.structs = structs; n->as.program.struct_count = struct_count; + n->as.program.type_aliases = aliases; + n->as.program.alias_count = alias_count; return n; } @@ -165,3 +168,12 @@ AstNode* ast_make_field_access(void* alloc, AstNode* object, const char* field, n->as.field_access.field_index = -1; return n; } + +AstNode* ast_make_type_alias(void* alloc, const char* name, TypeKind aliased, + const char* aliased_struct, SourceLoc loc) { + NEW(alloc, AST_TYPE_ALIAS); + n->as.type_alias.name = name; + n->as.type_alias.aliased_type = aliased; + n->as.type_alias.aliased_struct_name = aliased_struct; + return n; +} diff --git a/src/ast/ast.h b/src/ast/ast.h index fd147ad..db4ec80 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -23,6 +23,7 @@ typedef enum { AST_STRUCT_DECL, // struct Point { x: i64, y: i64 } AST_STRUCT_INIT, // Point { x: 10, y: 20 } AST_FIELD_ACCESS, // p.x + AST_TYPE_ALIAS, // type Meters = i64 } AstKind; typedef enum { @@ -48,7 +49,8 @@ struct AstNode { union { // AST_PROGRAM struct { struct AstNode** functions; size_t fn_count; - struct AstNode** structs; size_t struct_count; } program; + struct AstNode** structs; size_t struct_count; + struct AstNode** type_aliases; size_t alias_count; } program; // AST_FUNCTION struct { const char* name; struct AstNode** params; size_t param_count; TypeKind return_type; const char* return_struct_type_name; @@ -87,12 +89,15 @@ struct AstNode { struct AstNode** field_values; size_t field_count; } struct_init; // AST_FIELD_ACCESS struct { struct AstNode* object; const char* field; int field_index; } field_access; + // AST_TYPE_ALIAS + struct { const char* name; TypeKind aliased_type; const char* aliased_struct_name; } type_alias; } as; }; // 创建节点的辅助函数(内存来自 arena,通过 void* 传递避免循环依赖) AstNode* ast_make_program(void* alloc, AstNode** fns, size_t fn_count, - AstNode** structs, size_t struct_count, SourceLoc loc); + AstNode** structs, size_t struct_count, + AstNode** aliases, size_t alias_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); AstNode* ast_make_parameter(void* alloc, const char* name, TypeKind type, const char* struct_type_name, SourceLoc loc); @@ -115,5 +120,7 @@ AstNode* ast_make_ident(void* alloc, const char* name, SourceLoc loc); AstNode* ast_make_struct_decl(void* alloc, const char* name, AstNode** fields, size_t count, SourceLoc loc); AstNode* ast_make_struct_init(void* alloc, const char* type_name, const char** fnames, AstNode** fvals, size_t count, SourceLoc loc); AstNode* ast_make_field_access(void* alloc, AstNode* object, const char* field, SourceLoc loc); +AstNode* ast_make_type_alias(void* alloc, const char* name, TypeKind aliased, + const char* aliased_struct, SourceLoc loc); #endif diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index d903713..ec9571a 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -62,7 +62,7 @@ static TokenKind check_keyword(const Token* tok) { KW("i64", TOK_I64); KW("f64", TOK_F64); KW("bool", TOK_BOOL); KW("str", TOK_STR); KW("void", TOK_VOID); - KW("struct", TOK_STRUCT); + KW("struct", TOK_STRUCT); KW("type", TOK_TYPE); KW("true", TOK_TRUE); KW("false", TOK_FALSE); #undef KW return TOK_IDENT; diff --git a/src/lexer/token.c b/src/lexer/token.c index a2ba7cf..7c1ff70 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -7,7 +7,7 @@ static const char* NAMES[] = { [TOK_FN] = "fn", [TOK_LET] = "let", [TOK_MUT] = "mut", [TOK_IF] = "if", [TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return", - [TOK_STRUCT] = "struct", + [TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_I64] = "i64", [TOK_F64] = "f64", [TOK_BOOL] = "bool", [TOK_STR] = "str", [TOK_VOID] = "void", [TOK_INT_LIT] = "整数", [TOK_FLOAT_LIT] = "浮点数", [TOK_STR_LIT] = "字符串", [TOK_TRUE] = "true", [TOK_FALSE] = "false", diff --git a/src/lexer/token.h b/src/lexer/token.h index 6b15264..cbf30ee 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -7,7 +7,7 @@ typedef enum { // 关键字 TOK_FN, TOK_LET, TOK_MUT, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, - TOK_STRUCT, + TOK_STRUCT, TOK_TYPE, // 类型关键字 TOK_I64, TOK_F64, TOK_BOOL, TOK_STR, TOK_VOID, // 字面量 diff --git a/src/parser/parser.c b/src/parser/parser.c index ce1bb3e..e963d4e 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -244,6 +244,25 @@ static TypeKind token_to_type(TokenKind k) { default: return TYPE_VOID; } } +// === 类型表达式解析(内置类型/结构体名)=== +static TypeInfo parse_type_expr(Parser* p, ErrorInfo* error) { + const Token* t = peek(p); + TypeInfo ti = {0}; + if (tok_is_type(t->kind)) { + advance(p); + ti.kind = token_to_type(t->kind); + } else if (t->kind == TOK_IDENT) { + advance(p); + ti.kind = TYPE_STRUCT; + ti.struct_name = arena_strdup_impl(p->arena, t->start, t->length); + } else { + error->message = "无效的类型"; error->filename = p->filename; + error->line = t->line; error->col = t->col; + ti.kind = TYPE_ERROR; + } + return ti; +} + // === 结构体声明解析 === static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) { const Token* s_tok = advance(p); // 跳过 'struct' @@ -257,21 +276,14 @@ static AstNode* parse_struct_decl(Parser* p, ErrorInfo* error) { const Token* fname = expect(p, TOK_IDENT, error, "字段名"); if (!fname) return NULL; if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL; - const Token* ftype = advance(p); - TypeKind field_kind; - const char* field_struct_name = NULL; - if (tok_is_type(ftype->kind)) { - field_kind = token_to_type(ftype->kind); - } else if (ftype->kind == TOK_IDENT) { - field_kind = TYPE_STRUCT; - field_struct_name = arena_strdup_impl(p->arena, ftype->start, ftype->length); - } else { - error->message = "无效的字段类型"; error->filename = p->filename; - error->line = ftype->line; error->col = ftype->col; return NULL; + TypeInfo fti = parse_type_expr(p, error); + if (fti.kind == TYPE_ERROR) { + error->filename = p->filename; + return NULL; } fields[fcount++] = ast_make_parameter(p->arena, arena_strdup_impl(p->arena, fname->start, fname->length), - field_kind, field_struct_name, tok_loc(fname)); + fti.kind, fti.struct_name, tok_loc(fname)); if (peek(p)->kind == TOK_COMMA) advance(p); else break; } @@ -322,18 +334,10 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) { bool has_type_annot = false; const char* struct_type_name = NULL; if (match(p, TOK_COLON)) { - const Token* type_tok = advance(p); - if (!tok_is_type(type_tok->kind) && type_tok->kind != TOK_IDENT) { - error->message = "无效的类型标注"; error->filename = p->filename; - error->line = type_tok->line; error->col = type_tok->col; return NULL; - } - if (tok_is_type(type_tok->kind)) { - annot_type = token_to_type(type_tok->kind); - } else { - // struct 类型名 - annot_type = TYPE_STRUCT; - struct_type_name = arena_strdup_impl(p->arena, type_tok->start, type_tok->length); - } + TypeInfo ti = parse_type_expr(p, error); + if (ti.kind == TYPE_ERROR) return NULL; + annot_type = ti.kind; + struct_type_name = ti.struct_name; has_type_annot = true; } if (!expect(p, TOK_ASSIGN, error, "缺少 '='")) return NULL; @@ -511,21 +515,11 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) { const Token* pname = expect(p, TOK_IDENT, error, "参数名"); if (!pname) return NULL; if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL; - const Token* ptype = advance(p); - TypeKind param_kind; - const char* param_struct_name = NULL; - if (tok_is_type(ptype->kind)) { - param_kind = token_to_type(ptype->kind); - } else if (ptype->kind == TOK_IDENT) { - param_kind = TYPE_STRUCT; - param_struct_name = arena_strdup_impl(p->arena, ptype->start, ptype->length); - } else { - error->message = "无效的参数类型"; error->filename = p->filename; - error->line = ptype->line; error->col = ptype->col; return NULL; - } + TypeInfo pti = parse_type_expr(p, error); + if (pti.kind == TYPE_ERROR) return NULL; params[pcount++] = ast_make_parameter(p->arena, arena_strdup_impl(p->arena, pname->start, pname->length), - param_kind, param_struct_name, tok_loc(pname)); + pti.kind, pti.struct_name, tok_loc(pname)); if (match(p, TOK_COMMA)) continue; else break; } @@ -535,16 +529,10 @@ static AstNode* parse_function(Parser* p, ErrorInfo* error) { TypeKind ret = TYPE_VOID; const char* ret_struct_name = NULL; if (match(p, TOK_ARROW)) { - const Token* rt = advance(p); - if (tok_is_type(rt->kind)) { - ret = token_to_type(rt->kind); - } else if (rt->kind == TOK_IDENT) { - ret = TYPE_STRUCT; - ret_struct_name = arena_strdup_impl(p->arena, rt->start, rt->length); - } else { - error->message = "无效的返回类型"; error->filename = p->filename; - error->line = rt->line; error->col = rt->col; return NULL; - } + TypeInfo rti = parse_type_expr(p, error); + if (rti.kind == TYPE_ERROR) return NULL; + ret = rti.kind; + ret_struct_name = rti.struct_name; } AstNode* body = parse_block(p, error); @@ -564,15 +552,28 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, .filename = filename, .arena = a}; AstNode* functions[256]; int fn_count = 0; AstNode* structs[64]; int struct_count = 0; + AstNode* aliases[64]; int alias_count = 0; while (peek(&p)->kind != TOK_EOF && !error->message) { 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); + } else if (peek(&p)->kind == TOK_TYPE) { + if (alias_count >= 64) { error->message = "类型别名过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } + const Token* type_tok = advance(&p); // 跳过 'type' + const Token* alias_name = expect(&p, TOK_IDENT, error, "type 后应为别名"); + if (!alias_name) return NULL; + if (!expect(&p, TOK_ASSIGN, error, "缺少 '='")) return NULL; + TypeInfo rti = parse_type_expr(&p, error); + if (rti.kind == TYPE_ERROR) return NULL; + if (!expect(&p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL; + aliases[alias_count++] = ast_make_type_alias(a, + arena_strdup_impl(a, alias_name->start, alias_name->length), + rti.kind, rti.struct_name, tok_loc(type_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); } else { - error->message = "顶层只允许 fn 或 struct"; + error->message = "顶层只允许 fn、struct 或 type"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; @@ -584,5 +585,8 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, memcpy(fn_arr, functions, fn_count * sizeof(AstNode*)); AstNode** st_arr = arena_alloc_impl(a, struct_count * sizeof(AstNode*)); memcpy(st_arr, structs, struct_count * sizeof(AstNode*)); - return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count, loc_at(0, 0)); + AstNode** al_arr = arena_alloc_impl(a, alias_count * sizeof(AstNode*)); + memcpy(al_arr, aliases, alias_count * sizeof(AstNode*)); + return ast_make_program(a, fn_arr, fn_count, st_arr, struct_count, + al_arr, alias_count, loc_at(0, 0)); } diff --git a/src/sema/sema.c b/src/sema/sema.c index a0d2a59..f459c1f 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -30,6 +30,10 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* error_add(errors, "", node->loc.line, node->loc.col, "未定义的变量 '%s'", node->as.ident.name); node->type.kind = TYPE_ERROR; + } else if (sym->is_type_alias) { + error_add(errors, "", node->loc.line, node->loc.col, + "'%s' 是类型别名,不能作为表达式使用", node->as.ident.name); + node->type.kind = TYPE_ERROR; } else if (sym->kind == SYM_FUNCTION) { error_add(errors, "", node->loc.line, node->loc.col, "'%s' 是函数,不能作为表达式使用", node->as.ident.name); @@ -227,7 +231,18 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* } case AST_STRUCT_INIT: { - Symbol* struct_sym = scope_lookup_struct(scope, node->as.struct_init.type_name); + const char* resolved_type_name = node->as.struct_init.type_name; + Symbol* struct_sym = scope_lookup_struct(scope, resolved_type_name); + if (!struct_sym) { + // 检查是否是类型别名指向结构体 + Symbol* alias_sym = scope_lookup(scope, resolved_type_name); + if (alias_sym && alias_sym->is_type_alias && alias_sym->struct_type_name) { + resolved_type_name = alias_sym->struct_type_name; + struct_sym = scope_lookup_struct(scope, resolved_type_name); + // 更新 type_name 为真实结构体名(codegen 需要) + node->as.struct_init.type_name = resolved_type_name; + } + } if (!struct_sym) { error_add(errors, "", node->loc.line, node->loc.col, "未定义的结构体类型 '%s'", node->as.struct_init.type_name); @@ -267,7 +282,7 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* } if (node->type.kind != TYPE_ERROR) { node->type.kind = TYPE_STRUCT; - node->type.struct_name = node->as.struct_init.type_name; + node->type.struct_name = resolved_type_name; } break; } @@ -281,6 +296,18 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* switch (node->kind) { case AST_PROGRAM: + // Pass 0: 注册类型别名 + for (size_t i = 0; i < node->as.program.alias_count; i++) { + AstNode* alias = node->as.program.type_aliases[i]; + Symbol* sym = scope_insert(scope, a, alias->as.type_alias.name, + SYM_VARIABLE, alias->as.type_alias.aliased_type); + if (sym) { + sym->is_type_alias = true; + if (alias->as.type_alias.aliased_struct_name) { + sym->struct_type_name = alias->as.type_alias.aliased_struct_name; + } + } + } // 第一遍:收集所有结构体定义 for (size_t i = 0; i < node->as.program.struct_count; i++) { AstNode* sd = node->as.program.structs[i]; @@ -305,12 +332,31 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* TypeKind* pts = (TypeKind*)arena_alloc_impl(a, fn->as.function.param_count * sizeof(TypeKind)); const char** pstruct_names = (const char**)arena_alloc_impl(a, fn->as.function.param_count * sizeof(const char*)); for (size_t j = 0; j < fn->as.function.param_count; j++) { - pts[j] = fn->as.function.params[j]->as.parameter.type; - pstruct_names[j] = fn->as.function.params[j]->as.parameter.struct_type_name; + TypeKind pt = fn->as.function.params[j]->as.parameter.type; + const char* psn = fn->as.function.params[j]->as.parameter.struct_type_name; + // 解析参数类型的别名 + if (psn) { + Symbol* as = scope_lookup(scope, psn); + if (as && as->is_type_alias) { + pt = as->type; + psn = as->struct_type_name; + } + } + pts[j] = pt; + pstruct_names[j] = psn; + } + // 解析返回类型的别名 + TypeKind ret_t = fn->as.function.return_type; + const char* ret_sn = fn->as.function.return_struct_type_name; + if (ret_sn) { + Symbol* as = scope_lookup(scope, ret_sn); + if (as && as->is_type_alias) { + ret_t = as->type; + ret_sn = as->struct_type_name; + } } scope_insert_function(scope, a, fn->as.function.name, - fn->as.function.return_type, - fn->as.function.return_struct_type_name, + ret_t, ret_sn, pts, pstruct_names, fn->as.function.param_count); } @@ -322,12 +368,33 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* case AST_FUNCTION: { Scope* fn_scope = scope_new(a, scope); - // 注册参数 + // 注册参数(同时解析类型别名,更新 AST 节点供 codegen 使用) for (size_t i = 0; i < node->as.function.param_count; i++) { AstNode* p = node->as.function.params[i]; - Symbol* sym = scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, p->as.parameter.type); - if (sym && p->as.parameter.type == TYPE_STRUCT && p->as.parameter.struct_type_name) { - sym->struct_type_name = p->as.parameter.struct_type_name; + TypeKind pt = p->as.parameter.type; + const char* psn = p->as.parameter.struct_type_name; + if (psn) { + Symbol* as = scope_lookup(scope, psn); + if (as && as->is_type_alias) { + pt = as->type; + psn = as->struct_type_name; + // 更新 AST 节点 + p->as.parameter.type = pt; + p->as.parameter.struct_type_name = psn; + } + } + Symbol* sym = scope_insert(fn_scope, a, p->as.parameter.name, SYM_PARAMETER, pt); + if (sym && pt == TYPE_STRUCT && psn) { + sym->struct_type_name = psn; + } + } + // 解析返回类型的别名 + const char* ret_sn = node->as.function.return_struct_type_name; + if (ret_sn) { + Symbol* as = scope_lookup(scope, ret_sn); + if (as && as->is_type_alias) { + node->as.function.return_type = as->type; + node->as.function.return_struct_type_name = as->struct_type_name; } } TypeKind saved = current_return_type; @@ -355,15 +422,22 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* if (node->as.let_stmt.has_type_annot) { const char* annot_struct = node->as.let_stmt.struct_type_name; if (annot_struct) { - // struct 类型标注 - Symbol* st_sym = scope_lookup_struct(scope, annot_struct); - if (!st_sym) { - error_add(errors, "", node->loc.line, node->loc.col, - "未定义的结构体类型 '%s'", annot_struct); - break; + // 先检查是否是类型别名 + Symbol* alias_sym = scope_lookup(scope, annot_struct); + if (alias_sym && alias_sym->is_type_alias) { + var_type = alias_sym->type; + var_struct_name = alias_sym->struct_type_name; + } else { + // struct 类型标注 + Symbol* st_sym = scope_lookup_struct(scope, annot_struct); + if (!st_sym) { + error_add(errors, "", node->loc.line, node->loc.col, + "未定义的类型 '%s'", annot_struct); + break; + } + var_type = TYPE_STRUCT; + var_struct_name = annot_struct; } - var_type = TYPE_STRUCT; - var_struct_name = annot_struct; } else { var_type = node->as.let_stmt.annot_type; } diff --git a/src/sema/symbol.c b/src/sema/symbol.c index 4219512..0caebf5 100644 --- a/src/sema/symbol.c +++ b/src/sema/symbol.c @@ -35,6 +35,7 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name, sym->struct_field_types = NULL; sym->struct_field_count = 0; sym->struct_type_name = NULL; + sym->is_type_alias = false; sym->next = scope->head; scope->head = sym; return sym; @@ -60,6 +61,7 @@ Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name, sym->struct_field_types = NULL; sym->struct_field_count = 0; sym->struct_type_name = NULL; + sym->is_type_alias = false; sym->next = scope->head; scope->head = sym; return sym; @@ -83,6 +85,7 @@ Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name, sym->struct_field_struct_names = fstruct_names; sym->struct_field_count = fc; sym->struct_type_name = NULL; + sym->is_type_alias = false; sym->next = scope->head; scope->head = sym; return sym; diff --git a/src/sema/symbol.h b/src/sema/symbol.h index d02a4b4..85b38ff 100644 --- a/src/sema/symbol.h +++ b/src/sema/symbol.h @@ -24,6 +24,8 @@ typedef struct Symbol { size_t struct_field_count; // 变量引用结构体类型时,记录具体类型名 const char* struct_type_name; + // 类型别名标记 + bool is_type_alias; // 链表(同一作用域内的下一个符号) struct Symbol* next; } Symbol; diff --git a/test/programs/15_type_alias.l b/test/programs/15_type_alias.l new file mode 100644 index 0000000..ab04fba --- /dev/null +++ b/test/programs/15_type_alias.l @@ -0,0 +1,6 @@ +type Meters = i64; +fn main() -> i64 { + let x: Meters = 100; + print_i64(x); + return 0; +} diff --git a/test/programs/16_type_alias_struct.l b/test/programs/16_type_alias_struct.l new file mode 100644 index 0000000..a81f855 --- /dev/null +++ b/test/programs/16_type_alias_struct.l @@ -0,0 +1,8 @@ +struct Point { x: i64, y: i64 } +type P = Point; +fn main() -> i64 { + let p: P = Point { x: 10, y: 20 }; + print_i64(p.x); + print_i64(p.y); + return 0; +} diff --git a/test/test_codegen.c b/test/test_codegen.c index f20789d..41fc6bd 100644 --- a/test/test_codegen.c +++ b/test/test_codegen.c @@ -13,7 +13,7 @@ void test_codegen_simple_function() { 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* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx = NULL; @@ -47,7 +47,7 @@ void test_codegen_if_else() { 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* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx2 = NULL; @@ -78,7 +78,7 @@ void test_codegen_binary_ops() { 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* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx3 = NULL; @@ -108,7 +108,7 @@ void test_codegen_while_loop() { 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* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, NULL, 0, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx4 = NULL; @@ -162,7 +162,7 @@ void test_codegen_struct_decl() { AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1)); AstNode* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx = NULL; @@ -217,7 +217,7 @@ void test_codegen_struct_field_access() { AstNode* fn = ast_make_function(&a, "main", NULL, 0, TYPE_I64, NULL, body, loc_at(1, 1)); AstNode* fns[] = { fn }; - AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, loc_at(1, 1)); + AstNode* prog = ast_make_program(&a, fns, 1, structs, 1, NULL, 0, loc_at(1, 1)); const char* err = NULL; LLVMContextRef ctx = NULL; diff --git a/test/test_sema.c b/test/test_sema.c index cba8d08..e3df622 100644 --- a/test/test_sema.c +++ b/test/test_sema.c @@ -168,6 +168,44 @@ void test_struct_field_count_mismatch() { arena_destroy(&a); } +/* === 类型别名测试 === */ + +void test_type_alias_ok() { + Arena a = arena_create(1); + size_t tc; ErrorInfo lex_err = {0}; + Token* toks = lex(&a, + "type Meters = i64; fn main() { let x: Meters = 100; print_i64(x); return; }", + "test", &tc, &lex_err); + ASSERT(toks != NULL); + ErrorInfo parse_err = {0}; + AstNode* ast = parse(&a, toks, tc, "test", &parse_err); + ASSERT(ast != NULL); + ASSERT(ast->as.program.alias_count == 1); + + ErrorList errors; error_init(&errors); + sema_analyze(ast, &errors, &a); + ASSERT(errors.count == 0); + arena_destroy(&a); +} + +void test_type_alias_struct() { + Arena a = arena_create(1); + size_t tc; ErrorInfo lex_err = {0}; + Token* toks = lex(&a, + "struct Point { x: i64, y: i64 } type P = Point; fn main() { let p: P = Point { x: 1, y: 2 }; return; }", + "test", &tc, &lex_err); + ASSERT(toks != NULL); + ErrorInfo parse_err = {0}; + AstNode* ast = parse(&a, toks, tc, "test", &parse_err); + ASSERT(ast != NULL); + ASSERT(ast->as.program.alias_count == 1); + + ErrorList errors; error_init(&errors); + sema_analyze(ast, &errors, &a); + ASSERT(errors.count == 0); + arena_destroy(&a); +} + void test_struct_nested_type_ok() { Arena a = arena_create(1); size_t tc; ErrorInfo lex_err = {0}; @@ -197,5 +235,7 @@ int main(void) { TEST_RUN(test_struct_undefined); TEST_RUN(test_struct_field_count_mismatch); TEST_RUN(test_struct_nested_type_ok); + TEST_RUN(test_type_alias_ok); + TEST_RUN(test_type_alias_struct); return test_summary(); }