feat: 结构体 struct — 最后一项 P0 功能

- lexer: TOK_STRUCT, TOK_DOT 关键字和运算符
- ast: AST_STRUCT_DECL/STRUCT_INIT/FIELD_ACCESS 3 种新节点
- parser: struct 声明 + .field 访问 + Name{field:val} 初始化
- sema: struct 类型符号表,字段类型解析,初始化字段检查
- codegen: LLVMStructType + extractvalue/insertvalue 字段操作
- 新增集成测试: 12_struct.l, 13_struct_nested.l
- 基于 Codex 分析报告 P0 #4

所有 P0 功能已全部完成。
This commit is contained in:
2026-06-05 12:21:22 +08:00
parent 620cec4d57
commit b390d390f3
17 changed files with 1521 additions and 47 deletions
+148 -11
View File
@@ -33,6 +33,9 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
node->type.kind = TYPE_ERROR;
} else {
node->type.kind = sym->type;
if (sym->type == TYPE_STRUCT && sym->struct_type_name) {
node->type.struct_name = sym->struct_type_name;
}
}
break;
}
@@ -156,6 +159,99 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
break;
}
case AST_FIELD_ACCESS: {
analyze_expr(node->as.field_access.object, scope, errors, a);
AstNode* obj = node->as.field_access.object;
if (obj->type.kind == TYPE_ERROR) {
node->type.kind = TYPE_ERROR;
break;
}
if (obj->type.kind != TYPE_STRUCT) {
error_add(errors, "<sema>", node->line, node->col,
"类型 '%s' 不是结构体,不能访问字段 '%s'",
type_name(obj->type.kind), node->as.field_access.field);
node->type.kind = TYPE_ERROR;
break;
}
// 查找结构体定义
const char* struct_name = obj->type.struct_name;
if (!struct_name) {
error_add(errors, "<sema>", node->line, node->col,
"无法确定结构体类型");
node->type.kind = TYPE_ERROR;
break;
}
Symbol* struct_sym = scope_lookup_struct(scope, struct_name);
if (!struct_sym) {
error_add(errors, "<sema>", node->line, node->col,
"未定义的结构体 '%s'", struct_name);
node->type.kind = TYPE_ERROR;
break;
}
int fi = scope_struct_field_index(struct_sym, node->as.field_access.field);
if (fi < 0) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 没有字段 '%s'", struct_name, node->as.field_access.field);
node->type.kind = TYPE_ERROR;
break;
}
node->type.kind = struct_sym->struct_field_types[fi];
node->as.field_access.field_index = fi;
// 如果字段也是结构体类型,传播类型名
if (node->type.kind == TYPE_STRUCT &&
struct_sym->struct_field_struct_names &&
struct_sym->struct_field_struct_names[fi]) {
node->type.struct_name = struct_sym->struct_field_struct_names[fi];
}
break;
}
case AST_STRUCT_INIT: {
Symbol* struct_sym = scope_lookup_struct(scope, node->as.struct_init.type_name);
if (!struct_sym) {
error_add(errors, "<sema>", node->line, node->col,
"未定义的结构体类型 '%s'", node->as.struct_init.type_name);
node->type.kind = TYPE_ERROR;
break;
}
if (node->as.struct_init.field_count != struct_sym->struct_field_count) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 有 %zu 个字段,但提供了 %zu 个",
node->as.struct_init.type_name,
struct_sym->struct_field_count,
node->as.struct_init.field_count);
node->type.kind = TYPE_ERROR;
break;
}
// 检查每个字段名和类型匹配
for (size_t i = 0; i < node->as.struct_init.field_count; i++) {
const char* fname = node->as.struct_init.field_names[i];
AstNode* fval = node->as.struct_init.field_values[i];
analyze_expr(fval, scope, errors, a);
int fi = scope_struct_field_index(struct_sym, fname);
if (fi < 0) {
error_add(errors, "<sema>", node->line, node->col,
"结构体 '%s' 没有字段 '%s'",
node->as.struct_init.type_name, fname);
node->type.kind = TYPE_ERROR;
continue;
}
TypeKind expected = struct_sym->struct_field_types[fi];
TypeKind actual = fval->type.kind;
if (actual != TYPE_ERROR && actual != expected) {
error_add(errors, "<sema>", node->line, node->col,
"字段 '%s' 类型不匹配: 期望 '%s',得到 '%s'",
fname, type_name(expected), type_name(actual));
}
}
if (node->type.kind != TYPE_ERROR) {
node->type.kind = TYPE_STRUCT;
node->type.struct_name = node->as.struct_init.type_name;
}
break;
}
default: break;
}
}
@@ -165,7 +261,25 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
switch (node->kind) {
case AST_PROGRAM:
// 第一遍:收集所有函数签名
// 第一遍:收集所有结构体定义
for (size_t i = 0; i < node->as.program.struct_count; i++) {
AstNode* sd = node->as.program.structs[i];
const char** fnames = (const char**)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(const char*));
TypeKind* ftypes = (TypeKind*)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(TypeKind));
const char** fstruct_names = (const char**)arena_alloc_impl(a,
sd->as.struct_decl.field_count * sizeof(const char*));
for (size_t j = 0; j < sd->as.struct_decl.field_count; j++) {
fnames[j] = sd->as.struct_decl.fields[j]->as.parameter.name;
ftypes[j] = sd->as.struct_decl.fields[j]->as.parameter.type;
fstruct_names[j] = sd->as.struct_decl.fields[j]->as.parameter.struct_type_name;
}
scope_insert_struct(scope, a, sd->as.struct_decl.name,
fnames, ftypes, fstruct_names,
sd->as.struct_decl.field_count);
}
// 第二遍:收集所有函数签名
for (size_t i = 0; i < node->as.program.fn_count; i++) {
AstNode* fn = node->as.program.functions[i];
TypeKind* pts = (TypeKind*)arena_alloc_impl(a, fn->as.function.param_count * sizeof(TypeKind));
@@ -176,7 +290,7 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
fn->as.function.return_type, pts,
fn->as.function.param_count);
}
// 第遍:分析每个函数体
// 第遍:分析每个函数体
for (size_t i = 0; i < node->as.program.fn_count; i++) {
analyze_node(node->as.program.functions[i], scope, errors, a);
}
@@ -203,14 +317,29 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
analyze_expr(node->as.let_stmt.init, scope, errors, a);
TypeKind inferred = node->as.let_stmt.init->type.kind;
TypeKind var_type;
const char* var_struct_name = NULL;
if (node->as.let_stmt.has_type_annot) {
// 使用显式类型标注
var_type = node->as.let_stmt.annot_type;
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, "<sema>", node->line, node->col,
"未定义的结构体类型 '%s'", annot_struct);
break;
}
var_type = TYPE_STRUCT;
var_struct_name = annot_struct;
} else {
var_type = node->as.let_stmt.annot_type;
}
if (inferred != TYPE_ERROR && inferred != var_type) {
error_add(errors, "<sema>", node->line, node->col,
"变量 '%s' 类型标注为 '%s',但初始化表达式类型为 '%s'",
node->as.let_stmt.name, type_name(var_type), type_name(inferred));
node->as.let_stmt.name,
annot_struct ? annot_struct : type_name(var_type),
type_name(inferred));
}
} else {
// 类型推断
@@ -220,15 +349,23 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
break;
}
var_type = inferred;
if (inferred == TYPE_STRUCT) {
var_struct_name = node->as.let_stmt.init->type.struct_name;
}
}
node->type.kind = var_type;
node->type.struct_name = var_struct_name;
Symbol* sym = scope_insert(scope, a, node->as.let_stmt.name, SYM_VARIABLE, var_type);
if (!sym) {
error_add(errors, "<sema>", node->line, node->col,
"变量 '%s' 重复定义", node->as.let_stmt.name);
} else {
sym->is_mut = node->as.let_stmt.is_mut;
if (var_struct_name) {
sym->type = TYPE_STRUCT;
sym->struct_type_name = var_struct_name;
}
}
break;
}
@@ -304,17 +441,17 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
}
void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) {
Scope* global = scope_new(arena, NULL);
Scope* global_scope = scope_new(arena, NULL);
// 注册内置函数
TypeKind params_i64[] = {TYPE_I64};
scope_insert_function(global, arena, "print_i64", TYPE_VOID, params_i64, 1);
scope_insert_function(global_scope, arena, "print_i64", TYPE_VOID, params_i64, 1);
TypeKind params_f64[] = {TYPE_F64};
scope_insert_function(global, arena, "print_f64", TYPE_VOID, params_f64, 1);
scope_insert_function(global_scope, arena, "print_f64", TYPE_VOID, params_f64, 1);
TypeKind params_bool[] = {TYPE_BOOL};
scope_insert_function(global, arena, "print_bool", TYPE_VOID, params_bool, 1);
scope_insert_function(global_scope, arena, "print_bool", TYPE_VOID, params_bool, 1);
TypeKind params_str[] = {TYPE_STR};
scope_insert_function(global, arena, "print_str", TYPE_VOID, params_str, 1);
scope_insert_function(global_scope, arena, "print_str", TYPE_VOID, params_str, 1);
analyze_node(ast, global, errors, arena);
analyze_node(ast, global_scope, errors, arena);
}