feat: 类型别名 type alias (P1 #10)

- 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)
This commit is contained in:
2026-06-05 13:54:58 +08:00
parent da9a7065dd
commit ab88ea2753
13 changed files with 235 additions and 79 deletions
+53 -49
View File
@@ -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 = "顶层只允许 fnstruct";
error->message = "顶层只允许 fnstruct 或 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));
}