refactor: 拆分 sema analyze_expr 为 9 个辅助函数 + 调度器
This commit is contained in:
+342
-407
@@ -52,442 +52,377 @@ static bool is_comparable(TypeKind a, TypeKind b) {
|
||||
// === 向前声明 ===
|
||||
static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a);
|
||||
|
||||
// === 检查表达式 ===
|
||||
static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
switch (node->kind) {
|
||||
case AST_LITERAL_EXPR:
|
||||
break; // 类型已在创建时设置
|
||||
// === 表达式类型检查辅助函数 ===
|
||||
static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a);
|
||||
|
||||
case AST_IDENT_EXPR: {
|
||||
Symbol* sym = scope_lookup(scope, node->as.ident.name);
|
||||
if (!sym) {
|
||||
static void analyze_ident_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
(void)a;
|
||||
Symbol* sym = scope_lookup(scope, node->as.ident.name);
|
||||
if (!sym) {
|
||||
error_add(errors, "<sema>", 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, "<sema>", 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, "<sema>", node->loc.line, node->loc.col,
|
||||
"'%s' 是函数,不能作为表达式使用", node->as.ident.name);
|
||||
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;
|
||||
if (sym->type == TYPE_ARRAY) {
|
||||
node->type.element_type = sym->array_element_type;
|
||||
node->type.element_struct_name = sym->array_element_struct_name;
|
||||
node->type.array_size = sym->array_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_unary_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
analyze_expr(node->as.unary.operand, scope, errors, a);
|
||||
TypeKind inner = node->as.unary.operand->type.kind;
|
||||
if (node->as.unary.op == OP_NEG) {
|
||||
if (!is_numeric(inner)) {
|
||||
error_add(errors, "<sema>", 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, "<sema>", 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, "<sema>", node->loc.line, node->loc.col,
|
||||
"'%s' 是函数,不能作为表达式使用", node->as.ident.name);
|
||||
"一元 '-' 只能用于数值类型");
|
||||
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;
|
||||
}
|
||||
if (sym->type == TYPE_ARRAY) {
|
||||
node->type.element_type = sym->array_element_type;
|
||||
node->type.element_struct_name = sym->array_element_struct_name;
|
||||
node->type.array_size = sym->array_size;
|
||||
}
|
||||
node->type.kind = inner;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_UNARY_EXPR: {
|
||||
analyze_expr(node->as.unary.operand, scope, errors, a);
|
||||
TypeKind inner = node->as.unary.operand->type.kind;
|
||||
if (node->as.unary.op == OP_NEG) {
|
||||
if (!is_numeric(inner)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"一元 '-' 只能用于数值类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = inner;
|
||||
}
|
||||
} else { // OP_NOT
|
||||
if (inner != TYPE_BOOL) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"'!' 只能用于布尔类型,得到 '%s'", type_name(inner));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_BINARY_EXPR: {
|
||||
analyze_expr(node->as.binary.left, scope, errors, a);
|
||||
analyze_expr(node->as.binary.right, scope, errors, a);
|
||||
TypeKind l = node->as.binary.left->type.kind;
|
||||
TypeKind r = node->as.binary.right->type.kind;
|
||||
if (l == TYPE_ERROR || r == TYPE_ERROR) { node->type.kind = TYPE_ERROR; break; }
|
||||
|
||||
switch (node->as.binary.op) {
|
||||
case OP_ADD:
|
||||
if (l == TYPE_STR || r == TYPE_STR) {
|
||||
// 字符串拼接:两边都必须是 str 类型
|
||||
if (l != TYPE_STR || r != TYPE_STR) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"字符串拼接需要两边都是 str 类型,得到 '%s' + '%s'",
|
||||
type_name(l), type_name(r));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_STR;
|
||||
}
|
||||
} else if (!is_numeric(l) || !is_numeric(r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"算术运算需要数值类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = promote(l, r);
|
||||
}
|
||||
break;
|
||||
case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD:
|
||||
if (!is_numeric(l) || !is_numeric(r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"算术运算需要数值类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = promote(l, r);
|
||||
}
|
||||
break;
|
||||
case OP_EQ: case OP_NE: case OP_LT: case OP_GT: case OP_LE: case OP_GE:
|
||||
if (!is_comparable(l, r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"类型 '%s' 和 '%s' 无法比较", type_name(l), type_name(r));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
break;
|
||||
case OP_AND: case OP_OR:
|
||||
if (l != TYPE_BOOL || r != TYPE_BOOL) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"逻辑运算需要布尔类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_CALL_EXPR: {
|
||||
Symbol* sym = scope_lookup(scope, node->as.call.name);
|
||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||
} else { // OP_NOT
|
||||
if (inner != TYPE_BOOL) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的函数 '%s'", node->as.call.name);
|
||||
"'!' 只能用于布尔类型,得到 '%s'", type_name(inner));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
// 即使函数未定义,也要分析参数表达式(它们可能有更多错误)
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
if (node->as.call.arg_count != sym->param_count) {
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_binary_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
analyze_expr(node->as.binary.left, scope, errors, a);
|
||||
analyze_expr(node->as.binary.right, scope, errors, a);
|
||||
TypeKind l = node->as.binary.left->type.kind;
|
||||
TypeKind r = node->as.binary.right->type.kind;
|
||||
if (l == TYPE_ERROR || r == TYPE_ERROR) { node->type.kind = TYPE_ERROR; return; }
|
||||
|
||||
switch (node->as.binary.op) {
|
||||
case OP_ADD:
|
||||
if (l == TYPE_STR || r == TYPE_STR) {
|
||||
if (l != TYPE_STR || r != TYPE_STR) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"字符串拼接需要两边都是 str 类型,得到 '%s' + '%s'",
|
||||
type_name(l), type_name(r));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_STR;
|
||||
}
|
||||
} else if (!is_numeric(l) || !is_numeric(r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col, "算术运算需要数值类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = promote(l, r);
|
||||
}
|
||||
break;
|
||||
case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD:
|
||||
if (!is_numeric(l) || !is_numeric(r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col, "算术运算需要数值类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = promote(l, r);
|
||||
}
|
||||
break;
|
||||
case OP_EQ: case OP_NE: case OP_LT: case OP_GT: case OP_LE: case OP_GE:
|
||||
if (!is_comparable(l, r)) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"函数 '%s' 需要 %zu 个参数,但提供了 %zu 个",
|
||||
node->as.call.name, sym->param_count, node->as.call.arg_count);
|
||||
"类型 '%s' 和 '%s' 无法比较", type_name(l), type_name(r));
|
||||
node->type.kind = TYPE_ERROR;
|
||||
// 即使参数数量不匹配,也分析已有的参数
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
// 命名参数重排序: 将命名 arg 按参数名映射到正确位置
|
||||
if (node->as.call.arg_names) {
|
||||
AstNode* reordered[16] = {0};
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||
if (node->as.call.arg_names[i]) {
|
||||
// 查找参数名匹配
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < sym->param_count; j++) {
|
||||
if (sym->param_names && sym->param_names[j] &&
|
||||
strcmp(node->as.call.arg_names[i], sym->param_names[j]) == 0) {
|
||||
reordered[j] = node->as.call.args[i];
|
||||
found = true; break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"函数 '%s' 没有名为 '%s' 的参数",
|
||||
node->as.call.name, node->as.call.arg_names[i]);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
} else {
|
||||
// 位置参数保持原位
|
||||
reordered[i] = node->as.call.args[i];
|
||||
break;
|
||||
case OP_AND: case OP_OR:
|
||||
if (l != TYPE_BOOL || r != TYPE_BOOL) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col, "逻辑运算需要布尔类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
} else {
|
||||
node->type.kind = TYPE_BOOL;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// 参数类型匹配检查(CALL_EXPR 和 METHOD_CALL 共用)
|
||||
static void check_arg_type(AstNode* arg, TypeKind expected, const char* expected_sname,
|
||||
size_t idx, AstNode* call_node, Scope* scope,
|
||||
ErrorList* errors, Arena* a) {
|
||||
(void)scope; (void)a;
|
||||
TypeKind actual = arg->type.kind;
|
||||
if (actual == TYPE_ERROR) return;
|
||||
if (expected == TYPE_STRUCT) {
|
||||
const char* actual_name = arg->type.struct_name;
|
||||
if (actual != TYPE_STRUCT || !actual_name || !expected_sname ||
|
||||
strcmp(actual_name, expected_sname) != 0) {
|
||||
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
idx + 1, expected_sname ? expected_sname : "struct",
|
||||
actual_name ? actual_name : type_name(actual));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (actual == expected) return;
|
||||
if (expected == TYPE_I64 && actual == TYPE_ENUM) return;
|
||||
if (can_implicit_convert(actual, expected)) return;
|
||||
if (actual == TYPE_I64 && arg->kind == AST_LITERAL_EXPR
|
||||
&& (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR)) return;
|
||||
error_add(errors, "<sema>", call_node->loc.line, call_node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
idx + 1, type_name(expected), type_name(actual));
|
||||
}
|
||||
|
||||
// 命名参数重排序(CALL_EXPR 和 METHOD_CALL 共用)
|
||||
static bool reorder_named_args(AstNode* node, Symbol* sym, int param_offset,
|
||||
ErrorList* errors, const char* call_name) {
|
||||
AstNode** args = node->as.call.args;
|
||||
const char** arg_names = node->as.call.arg_names;
|
||||
size_t arg_count = node->as.call.arg_count;
|
||||
if (!arg_names) return true;
|
||||
AstNode* reordered[16] = {0};
|
||||
for (size_t i = 0; i < arg_count; i++) {
|
||||
if (arg_names[i]) {
|
||||
bool found = false;
|
||||
for (size_t j = param_offset; j < sym->param_count; j++) {
|
||||
if (sym->param_names && sym->param_names[j] &&
|
||||
strcmp(arg_names[i], sym->param_names[j]) == 0) {
|
||||
reordered[j - param_offset] = args[i];
|
||||
found = true; break;
|
||||
}
|
||||
}
|
||||
// 填充未指定的命名参数(用 NULL 跳过,后续检查会报错)
|
||||
memcpy(node->as.call.args, reordered, node->as.call.arg_count * sizeof(AstNode*));
|
||||
if (!found) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"'%s' 没有名为 '%s' 的参数", call_name, arg_names[i]);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
reordered[i] = args[i];
|
||||
}
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||
}
|
||||
memcpy(args, reordered, arg_count * sizeof(AstNode*));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void analyze_call_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
Symbol* sym = scope_lookup(scope, node->as.call.name);
|
||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的函数 '%s'", node->as.call.name);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++)
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
TypeKind actual = node->as.call.args[i]->type.kind;
|
||||
TypeKind expected = sym->param_types[i];
|
||||
if (actual != TYPE_ERROR) {
|
||||
if (expected == TYPE_STRUCT) {
|
||||
// 结构体参数:比较具体类型名
|
||||
const char* actual_name = node->as.call.args[i]->type.struct_name;
|
||||
const char* expected_name = sym->param_struct_names ? sym->param_struct_names[i] : NULL;
|
||||
if (actual != TYPE_STRUCT || !actual_name || !expected_name ||
|
||||
strcmp(actual_name, expected_name) != 0) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
i + 1,
|
||||
expected_name ? expected_name : "struct",
|
||||
actual_name ? actual_name : type_name(actual));
|
||||
}
|
||||
} else if (actual != expected &&
|
||||
!(expected == TYPE_I64 && actual == TYPE_ENUM) &&
|
||||
!can_implicit_convert(actual, expected) &&
|
||||
!(actual == TYPE_I64 && node->as.call.args[i]->kind == AST_LITERAL_EXPR
|
||||
&& (expected == TYPE_I32 || expected == TYPE_U64 || expected == TYPE_CHAR))) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
i + 1, type_name(expected), type_name(actual));
|
||||
}
|
||||
}
|
||||
}
|
||||
node->type.kind = sym->return_type;
|
||||
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name) {
|
||||
node->type.struct_name = sym->return_struct_type_name;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
if (node->as.call.arg_count != sym->param_count) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"函数 '%s' 需要 %zu 个参数,但提供了 %zu 个",
|
||||
node->as.call.name, sym->param_count, node->as.call.arg_count);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++)
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
return;
|
||||
}
|
||||
if (!reorder_named_args(node, sym, 0, errors, node->as.call.name)) {
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
for (size_t i = 0; i < node->as.call.arg_count; i++) {
|
||||
analyze_expr(node->as.call.args[i], scope, errors, a);
|
||||
check_arg_type(node->as.call.args[i], sym->param_types[i],
|
||||
sym->param_struct_names ? sym->param_struct_names[i] : NULL,
|
||||
i, node, scope, errors, a);
|
||||
}
|
||||
node->type.kind = sym->return_type;
|
||||
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
|
||||
node->type.struct_name = sym->return_struct_type_name;
|
||||
}
|
||||
|
||||
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;
|
||||
static void analyze_field_access(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
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; return; }
|
||||
if (obj->type.kind != TYPE_STRUCT) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"类型 '%s' 不是结构体,不能访问字段 '%s'",
|
||||
type_name(obj->type.kind), node->as.field_access.field);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
const char* struct_name = obj->type.struct_name;
|
||||
if (!struct_name) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col, "无法确定结构体类型");
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
Symbol* struct_sym = scope_lookup_struct(scope, struct_name);
|
||||
if (!struct_sym) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的结构体 '%s'", struct_name);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
int fi = scope_struct_field_index(struct_sym, node->as.field_access.field);
|
||||
if (fi < 0) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"结构体 '%s' 没有字段 '%s'", struct_name, node->as.field_access.field);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
static void analyze_struct_init(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
const char* resolved = node->as.struct_init.type_name;
|
||||
Symbol* struct_sym = scope_lookup_struct(scope, resolved);
|
||||
if (!struct_sym) {
|
||||
Symbol* alias_sym = scope_lookup(scope, resolved);
|
||||
if (alias_sym && alias_sym->is_type_alias && alias_sym->struct_type_name) {
|
||||
resolved = alias_sym->struct_type_name;
|
||||
struct_sym = scope_lookup_struct(scope, resolved);
|
||||
node->as.struct_init.type_name = resolved;
|
||||
}
|
||||
if (obj->type.kind != TYPE_STRUCT) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.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->loc.line, node->loc.col,
|
||||
"无法确定结构体类型");
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
Symbol* struct_sym = scope_lookup_struct(scope, struct_name);
|
||||
if (!struct_sym) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的结构体 '%s'", struct_name);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
int fi = scope_struct_field_index(struct_sym, node->as.field_access.field);
|
||||
}
|
||||
if (!struct_sym) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的结构体类型 '%s'", node->as.struct_init.type_name);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
if (node->as.struct_init.field_count != struct_sym->struct_field_count) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.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; return;
|
||||
}
|
||||
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->loc.line, node->loc.col,
|
||||
"结构体 '%s' 没有字段 '%s'", struct_name, node->as.field_access.field);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
"结构体 '%s' 没有字段 '%s'", node->as.struct_init.type_name, fname);
|
||||
node->type.kind = TYPE_ERROR; continue;
|
||||
}
|
||||
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;
|
||||
TypeKind expected = struct_sym->struct_field_types[fi];
|
||||
TypeKind actual = fval->type.kind;
|
||||
if (actual != TYPE_ERROR && actual != expected)
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"字段 '%s' 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
fname, type_name(expected), type_name(actual));
|
||||
}
|
||||
|
||||
case AST_STRUCT_INIT: {
|
||||
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, "<sema>", node->loc.line, node->loc.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->loc.line, node->loc.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->loc.line, node->loc.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->loc.line, node->loc.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 = resolved_type_name;
|
||||
}
|
||||
break;
|
||||
if (node->type.kind != TYPE_ERROR) {
|
||||
node->type.kind = TYPE_STRUCT;
|
||||
node->type.struct_name = resolved;
|
||||
}
|
||||
}
|
||||
|
||||
case AST_ENUM_VARIANT: {
|
||||
Symbol* enum_sym = scope_lookup_struct(scope, node->as.enum_variant.enum_name);
|
||||
if (!enum_sym || enum_sym->kind != SYM_ENUM) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的枚举 '%s'", node->as.enum_variant.enum_name);
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
int vi = scope_enum_variant_index(enum_sym, node->as.enum_variant.variant_name);
|
||||
if (vi < 0) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"枚举 '%s' 没有变体 '%s'",
|
||||
node->as.enum_variant.enum_name,
|
||||
node->as.enum_variant.variant_name);
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
node->as.enum_variant.variant_index = vi;
|
||||
node->type.kind = TYPE_ENUM;
|
||||
break;
|
||||
static void analyze_enum_variant(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
(void)a;
|
||||
Symbol* enum_sym = scope_lookup_struct(scope, node->as.enum_variant.enum_name);
|
||||
if (!enum_sym || enum_sym->kind != SYM_ENUM) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"未定义的枚举 '%s'", node->as.enum_variant.enum_name);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
|
||||
case AST_INDEX_EXPR: {
|
||||
analyze_expr(node->as.index_expr.array, scope, errors, a);
|
||||
analyze_expr(node->as.index_expr.index, scope, errors, a);
|
||||
AstNode* arr = node->as.index_expr.array;
|
||||
AstNode* idx = node->as.index_expr.index;
|
||||
|
||||
if (arr->type.kind == TYPE_ERROR) { node->type.kind = TYPE_ERROR; break; }
|
||||
if (arr->type.kind != TYPE_ARRAY) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"类型 '%s' 不支持索引操作", type_name(arr->type.kind));
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
if (idx->type.kind == TYPE_ERROR) { node->type.kind = TYPE_ERROR; break; }
|
||||
if (idx->type.kind != TYPE_I64) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"数组索引必须是 i64 类型, 得到 '%s'", type_name(idx->type.kind));
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
// 结果类型 = 元素类型
|
||||
node->type.kind = arr->type.element_type;
|
||||
node->type.struct_name = arr->type.element_struct_name;
|
||||
break;
|
||||
int vi = scope_enum_variant_index(enum_sym, node->as.enum_variant.variant_name);
|
||||
if (vi < 0) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"枚举 '%s' 没有变体 '%s'",
|
||||
node->as.enum_variant.enum_name, node->as.enum_variant.variant_name);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
node->as.enum_variant.variant_index = vi;
|
||||
node->type.kind = TYPE_ENUM;
|
||||
}
|
||||
|
||||
case AST_METHOD_CALL: {
|
||||
analyze_expr(node->as.method_call.receiver, scope, errors, a);
|
||||
const char* recv_struct = node->as.method_call.receiver->type.struct_name;
|
||||
if (node->as.method_call.receiver->type.kind != TYPE_STRUCT || !recv_struct) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"只有结构体类型支持方法调用");
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
// 构造改名后的函数名并查找
|
||||
char mangled[256];
|
||||
snprintf(mangled, sizeof(mangled), "%s$%s", recv_struct,
|
||||
node->as.method_call.method_name);
|
||||
Symbol* sym = scope_lookup(scope, mangled);
|
||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"结构体 '%s' 没有方法 '%s'", recv_struct,
|
||||
node->as.method_call.method_name);
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
// 检查参数数量(用户提供的参数 + 隐含的 self)
|
||||
if (node->as.method_call.arg_count + 1 != sym->param_count) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"方法 '%s' 需要 %zu 个参数,提供了 %zu 个",
|
||||
node->as.method_call.method_name,
|
||||
sym->param_count > 0 ? sym->param_count - 1 : 0,
|
||||
node->as.method_call.arg_count);
|
||||
node->type.kind = TYPE_ERROR; break;
|
||||
}
|
||||
// 命名参数重排序(同 CALL_EXPR 逻辑)
|
||||
if (node->as.method_call.arg_names) {
|
||||
AstNode* reordered[16] = {0};
|
||||
for (size_t i = 0; i < node->as.method_call.arg_count; i++) {
|
||||
if (node->as.method_call.arg_names[i]) {
|
||||
bool found = false;
|
||||
for (size_t j = 1; j < sym->param_count; j++) { // skip self
|
||||
if (sym->param_names && sym->param_names[j] &&
|
||||
strcmp(node->as.method_call.arg_names[i], sym->param_names[j]) == 0) {
|
||||
reordered[j - 1] = node->as.method_call.args[i];
|
||||
found = true; break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"方法 '%s' 没有名为 '%s' 的参数",
|
||||
node->as.method_call.method_name, node->as.method_call.arg_names[i]);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
} else {
|
||||
reordered[i] = node->as.method_call.args[i];
|
||||
}
|
||||
}
|
||||
memcpy(node->as.method_call.args, reordered, node->as.method_call.arg_count * sizeof(AstNode*));
|
||||
}
|
||||
// 对每个参数进行类型检查(跳过 self 参数,即 sym->param_types[0] 是 self 的类型)
|
||||
for (size_t i = 0; i < node->as.method_call.arg_count; i++) {
|
||||
analyze_expr(node->as.method_call.args[i], scope, errors, a);
|
||||
TypeKind actual = node->as.method_call.args[i]->type.kind;
|
||||
TypeKind expected = sym->param_types[i + 1];
|
||||
if (actual != TYPE_ERROR && actual != expected &&
|
||||
!(expected == TYPE_I64 && actual == TYPE_ENUM) &&
|
||||
!can_implicit_convert(actual, expected)) {
|
||||
if (expected == TYPE_STRUCT) {
|
||||
// 结构体类型参数:比较具体类型名
|
||||
const char* actual_name = node->as.method_call.args[i]->type.struct_name;
|
||||
const char* expected_name = sym->param_struct_names ? sym->param_struct_names[i + 1] : NULL;
|
||||
if (!actual_name || !expected_name || strcmp(actual_name, expected_name) != 0) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
i + 1,
|
||||
expected_name ? expected_name : "struct",
|
||||
actual_name ? actual_name : type_name(actual));
|
||||
}
|
||||
} else {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"参数 %zu 类型不匹配: 期望 '%s',得到 '%s'",
|
||||
i + 1, type_name(expected), type_name(actual));
|
||||
}
|
||||
}
|
||||
}
|
||||
node->type.kind = sym->return_type;
|
||||
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name) {
|
||||
node->type.struct_name = sym->return_struct_type_name;
|
||||
}
|
||||
break;
|
||||
static void analyze_index_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
analyze_expr(node->as.index_expr.array, scope, errors, a);
|
||||
analyze_expr(node->as.index_expr.index, scope, errors, a);
|
||||
AstNode* arr = node->as.index_expr.array;
|
||||
AstNode* idx = node->as.index_expr.index;
|
||||
if (arr->type.kind == TYPE_ERROR) { node->type.kind = TYPE_ERROR; return; }
|
||||
if (arr->type.kind != TYPE_ARRAY) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"类型 '%s' 不支持索引操作", type_name(arr->type.kind));
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
if (idx->type.kind == TYPE_ERROR) { node->type.kind = TYPE_ERROR; return; }
|
||||
if (idx->type.kind != TYPE_I64) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"数组索引必须是 i64 类型, 得到 '%s'", type_name(idx->type.kind));
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
node->type.kind = arr->type.element_type;
|
||||
node->type.struct_name = arr->type.element_struct_name;
|
||||
}
|
||||
|
||||
static void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
analyze_expr(node->as.method_call.receiver, scope, errors, a);
|
||||
const char* recv_struct = node->as.method_call.receiver->type.struct_name;
|
||||
if (node->as.method_call.receiver->type.kind != TYPE_STRUCT || !recv_struct) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"只有结构体类型支持方法调用");
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
char mangled[256];
|
||||
snprintf(mangled, sizeof(mangled), "%s$%s", recv_struct,
|
||||
node->as.method_call.method_name);
|
||||
Symbol* sym = scope_lookup(scope, mangled);
|
||||
if (!sym || sym->kind != SYM_FUNCTION) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"结构体 '%s' 没有方法 '%s'", recv_struct,
|
||||
node->as.method_call.method_name);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
if (node->as.method_call.arg_count + 1 != sym->param_count) {
|
||||
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||
"方法 '%s' 需要 %zu 个参数,提供了 %zu 个",
|
||||
node->as.method_call.method_name,
|
||||
sym->param_count > 0 ? sym->param_count - 1 : 0,
|
||||
node->as.method_call.arg_count);
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
if (!reorder_named_args(node, sym, 1, errors, node->as.method_call.method_name)) {
|
||||
node->type.kind = TYPE_ERROR; return;
|
||||
}
|
||||
for (size_t i = 0; i < node->as.method_call.arg_count; i++) {
|
||||
analyze_expr(node->as.method_call.args[i], scope, errors, a);
|
||||
check_arg_type(node->as.method_call.args[i], sym->param_types[i + 1],
|
||||
sym->param_struct_names ? sym->param_struct_names[i + 1] : NULL,
|
||||
i, node, scope, errors, a);
|
||||
}
|
||||
node->type.kind = sym->return_type;
|
||||
if (sym->return_type == TYPE_STRUCT && sym->return_struct_type_name)
|
||||
node->type.struct_name = sym->return_struct_type_name;
|
||||
}
|
||||
|
||||
// === 表达式类型检查(调度器) ===
|
||||
static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
switch (node->kind) {
|
||||
case AST_LITERAL_EXPR: break;
|
||||
case AST_IDENT_EXPR: analyze_ident_expr(node, scope, errors, a); break;
|
||||
case AST_UNARY_EXPR: analyze_unary_expr(node, scope, errors, a); break;
|
||||
case AST_BINARY_EXPR: analyze_binary_expr(node, scope, errors, a); break;
|
||||
case AST_CALL_EXPR: analyze_call_expr(node, scope, errors, a); break;
|
||||
case AST_FIELD_ACCESS: analyze_field_access(node, scope, errors, a); break;
|
||||
case AST_STRUCT_INIT: analyze_struct_init(node, scope, errors, a); break;
|
||||
case AST_ENUM_VARIANT: analyze_enum_variant(node, scope, errors, a); break;
|
||||
case AST_INDEX_EXPR: analyze_index_expr(node, scope, errors, a); break;
|
||||
case AST_METHOD_CALL: analyze_method_call(node, scope, errors, a); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user