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:
+53
-49
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user