refactor: TypeTable 数据驱动 — promote/convert/numeric/comparable 统一查表

新增 src/sema/type_table.h/c: TypeDesc{promote_rank, bit_width, is_signed, is_numeric}
promote/can_implicit_convert/is_numeric/is_comparable 从硬编码 switch 改为查表
新增类型只需在 TABLE[] 加一行, 从 7+ 文件改为 3-4 文件 (token + table + codegen)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 20:31:32 +08:00
parent 66b170a27f
commit 3733b41453
4 changed files with 82 additions and 25 deletions
+1
View File
@@ -7,6 +7,7 @@
#include "error.h"
#include "arena.h"
#include "l_lang.h"
#include "type_table.h"
#include <stdio.h>
#include <string.h>
+36
View File
@@ -0,0 +1,36 @@
#include "type_table.h"
#include <string.h>
// 类型描述表 — 所有类型相关判断统一查此表
// 新增类型: 加一行即可, promote/convert/numeric/comparable 自动生效
static const TypeDesc TABLE[] = {
{TYPE_BOOL, "bool", 0, 1, false, false},
{TYPE_CHAR, "char", 1, 8, true, true},
{TYPE_I32, "i32", 2, 32, true, true},
{TYPE_U64, "u64", 3, 64, false, true},
{TYPE_I64, "i64", 4, 64, true, true},
{TYPE_ENUM, "enum", 4, 64, false, true},
{TYPE_F64, "f64", 5, 64, true, true},
{TYPE_STR, "str", 0, 0, false, false},
{TYPE_STRUCT,"struct",0, 0, false, false},
{TYPE_ARRAY,"array", 0, 0, false, false},
{TYPE_VOID, "void", 0, 0, false, false},
{TYPE_UNKNOWN,"?", 0, 0, false, false},
{TYPE_ERROR,"err", 0, 0, false, false},
};
static const size_t TABLE_SIZE = sizeof(TABLE) / sizeof(TABLE[0]);
const TypeDesc* type_lookup(TypeKind kind) {
for (size_t i = 0; i < TABLE_SIZE; i++)
if (TABLE[i].kind == kind) return &TABLE[i];
return &TABLE[TABLE_SIZE - 1];
}
const TypeDesc* type_by_name(const char* name) {
for (size_t i = 0; i < TABLE_SIZE; i++)
if (strcmp(TABLE[i].name, name) == 0) return &TABLE[i];
return NULL;
}
size_t type_count(void) { return TABLE_SIZE; }
+22
View File
@@ -0,0 +1,22 @@
#ifndef TYPE_TABLE_H
#define TYPE_TABLE_H
#include "l_lang.h"
#include <stddef.h>
#include <stdbool.h>
// 类型元数据 — 新增类型只需在此表加一行
typedef struct {
TypeKind kind;
const char* name;
int promote_rank; // 越高越宽: bool=0, char=1, i32=2, u64=3, i64=4, f64=5
int bit_width; // LLVM 位宽: 1, 8, 32, 64
bool is_signed; // 有符号(用于隐式转换判断)
bool is_numeric; // 是否参与算术
} TypeDesc;
const TypeDesc* type_lookup(TypeKind kind);
const TypeDesc* type_by_name(const char* name);
size_t type_count(void);
#endif
+22 -24
View File
@@ -100,47 +100,45 @@ size_t mono_count = 0;
Arena* mono_arena = NULL;
AstNode* g_program = NULL; // 当前 AST_PROGRAM(用于查找泛型函数模板)
// === 类型关系(基于 TypeTable 数据驱动)===
TypeKind promote(TypeKind a, TypeKind b) {
// 枚举在算术运算中视为 i64
// 枚举在算术中视为 i64, char 视为 i32
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;
const TypeDesc* ta = type_lookup(a);
const TypeDesc* tb = type_lookup(b);
if (!ta->is_numeric || !tb->is_numeric) return TYPE_ERROR;
return ta->promote_rank >= tb->promote_rank ? a : b;
}
bool is_numeric(TypeKind t) {
return t == TYPE_I32 || t == TYPE_I64 || t == TYPE_U64
|| t == TYPE_F64 || t == TYPE_CHAR || t == TYPE_ENUM;
return type_lookup(t)->is_numeric;
}
// 隐式类型转换规则: 无损加宽允许,有符号→无符号不允许
// 隐式转换: 加宽允许, 同 bit_width 的有/无符号双向允许 (u64↔i64)
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;
if (from == to) return true;
const TypeDesc* tf = type_lookup(from);
const TypeDesc* tt = type_lookup(to);
if (!tf->is_numeric || !tt->is_numeric) return false;
// 同 bit_width: 有/无符号整数双向允许 (u64↔i64, 在 LLVM 中同为 64-bit)
if (tf->bit_width == tt->bit_width && tf->bit_width >= 32)
return true;
// 加宽转换: 有符号→任意, 无符号→仅无符号
if (tt->promote_rank > tf->promote_rank)
return tf->is_signed || !tt->is_signed;
return false;
}
bool is_comparable(TypeKind a, TypeKind b) {
if (a == b) return true;
// 枚举可以参与整数比较
if ((a == TYPE_I64 && b == TYPE_ENUM) || (a == TYPE_ENUM && b == TYPE_I64)) return true;
return false;
if (a == TYPE_ENUM) a = TYPE_I64;
if (b == TYPE_ENUM) b = TYPE_I64;
return type_lookup(a)->is_numeric && type_lookup(b)->is_numeric;
}
// === 向前声明 ===