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