feat: 新增 i32 / u64 / char 类型 + 字符字面量 "'a'"

This commit is contained in:
2026-06-05 20:47:44 +08:00
parent 6fc599e6c2
commit 18172ca724
12 changed files with 146 additions and 16 deletions
+38 -4
View File
@@ -10,13 +10,38 @@ static TypeKind promote(TypeKind a, TypeKind b) {
// 枚举在算术运算中视为 i64
if (a == TYPE_ENUM) a = TYPE_I64;
if (b == TYPE_ENUM) b = TYPE_I64;
// char 在算术中提升为 i32
if (a == TYPE_CHAR) a = TYPE_I32;
if (b == TYPE_CHAR) b = TYPE_I32;
if (a == TYPE_F64 || b == TYPE_F64) return TYPE_F64;
if (a == TYPE_I64 || b == TYPE_I64) return TYPE_I64;
if (a == TYPE_U64 || b == TYPE_U64) return TYPE_U64;
if (a == TYPE_I32 || b == TYPE_I32) return TYPE_I32;
if (a == TYPE_BOOL || b == TYPE_BOOL) return TYPE_BOOL;
return TYPE_ERROR;
}
static bool is_numeric(TypeKind t) { return t == TYPE_I64 || t == TYPE_F64 || t == TYPE_ENUM; }
static bool is_numeric(TypeKind t) {
return t == TYPE_I32 || t == TYPE_I64 || t == TYPE_U64
|| t == TYPE_F64 || t == TYPE_CHAR || t == TYPE_ENUM;
}
// 隐式类型转换规则: 无损加宽允许,有符号→无符号不允许
static bool can_implicit_convert(TypeKind from, TypeKind to) {
if (from == to) return true;
// 枚举视为 i64
if (from == TYPE_ENUM) from = TYPE_I64;
if (to == TYPE_ENUM) to = TYPE_I64;
// char 可转为任意整数
if (from == TYPE_CHAR) return to == TYPE_I32 || to == TYPE_I64 || to == TYPE_U64 || to == TYPE_F64;
// i32 可加宽
if (from == TYPE_I32) return to == TYPE_I64 || to == TYPE_F64;
// i64 可转 f64
if (from == TYPE_I64) return to == TYPE_F64;
// u64 ↔ i64 双向允许(同一位宽,LLVM 同类型)
if (from == TYPE_U64) return to == TYPE_F64 || to == TYPE_I64;
if (from == TYPE_I64) return to == TYPE_F64 || to == TYPE_U64;
return false;
}
static bool is_comparable(TypeKind a, TypeKind b) {
if (a == b) return true;
// 枚举可以参与整数比较
@@ -184,7 +209,10 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
actual_name ? actual_name : type_name(actual));
}
} else if (actual != expected &&
!(expected == TYPE_I64 && actual == TYPE_ENUM)) {
!(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));
@@ -380,7 +408,8 @@ static void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena*
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)) {
!(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;
@@ -618,7 +647,12 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
} else {
var_type = node->as.let_stmt.annot_type;
}
if (inferred != TYPE_ERROR && inferred != var_type) {
bool literal_to_int = (inferred == TYPE_I64
&& node->as.let_stmt.init->kind == AST_LITERAL_EXPR
&& (var_type == TYPE_I32 || var_type == TYPE_U64 || var_type == TYPE_CHAR));
if (inferred != TYPE_ERROR && inferred != var_type
&& !can_implicit_convert(inferred, var_type)
&& !literal_to_int) {
error_add(errors, "<sema>", node->loc.line, node->loc.col,
"变量 '%s' 类型标注为 '%s',但初始化表达式类型为 '%s'",
node->as.let_stmt.name,