1162 lines
53 KiB
Plaintext
1162 lines
53 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
|
||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||
|
||
# ============================================================
|
||
# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表
|
||
#
|
||
# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||
"""enum/union/renum 定义与变体表"""
|
||
|
||
def _resolve_enum_member_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||
ann_node: ast.AST | t.CPtr,
|
||
imported_modules: str,
|
||
from_imports: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""解析枚举成员的类型注解为 LLVM 整数类型"""
|
||
if ann_node is None:
|
||
return llvmlite.Int32(pool)
|
||
|
||
k: int = ann_node.kind()
|
||
|
||
# Attribute 节点: t.State / int / t.CInt8T 等
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node)
|
||
if at.attr is None:
|
||
return llvmlite.Int32(pool)
|
||
# t.State → 默认 i32
|
||
if string.strcmp(at.attr, "State") == 0:
|
||
return llvmlite.Int32(pool)
|
||
# 其他 t.CXxx 类型
|
||
ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr)
|
||
if ty is not None:
|
||
return ty
|
||
return llvmlite.Int32(pool)
|
||
|
||
# Name 节点: from-import 形式(State / CInt)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node)
|
||
if nm.id is None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strcmp(nm.id, "State") == 0:
|
||
return llvmlite.Int32(pool)
|
||
ty2: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, nm.id)
|
||
if ty2 is not None:
|
||
return ty2
|
||
return llvmlite.Int32(pool)
|
||
|
||
# BinOp 节点: t.State | t.CInt8T(递归查找实际类型)
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
left_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type(
|
||
pool, bop.left, imported_modules, from_imports)
|
||
# 跳过 t.State(i32 默认),优先返回具体类型
|
||
left_bits: int = HandlesType.get_llvm_type_bits(left_ty)
|
||
if left_bits != 0 and not self._is_state_annotation(bop.left):
|
||
return left_ty
|
||
right_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type(
|
||
pool, bop.right, imported_modules, from_imports)
|
||
if right_ty is not None and not self._is_state_annotation(bop.right):
|
||
return right_ty
|
||
# 两边都是 State 或无法确定,返回较宽的
|
||
right_bits: int = HandlesType.get_llvm_type_bits(right_ty)
|
||
if left_bits >= right_bits:
|
||
return left_ty
|
||
return right_ty
|
||
# fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32
|
||
HandlesType.fatal_error(
|
||
ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
|
||
# fail-fast:未知注解节点 kind,不再静默回退 i32
|
||
HandlesType.fatal_error(
|
||
ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int:
|
||
"""检查注解节点是否为 t.State,返回 1=是 / 0=否"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
if at.attr is not None and string.strcmp(at.attr, "State") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm.id is not None and string.strcmp(nm.id, "State") == 0:
|
||
return 1
|
||
return 0
|
||
return 0
|
||
def _extract_int_value(self, node: ast.AST | t.CPtr) -> t.CInt64T:
|
||
"""从 AST 节点提取整数值,失败返回 0"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
return cn.int_val
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uo.op == ast.OpKind.USub:
|
||
inner: t.CInt64T = self._extract_int_value(uo.operand)
|
||
return -inner
|
||
return 0
|
||
return 0
|
||
def _translate_enum_def(self, trans: HT.Translator | t.CPtr,
|
||
cd: ast.ClassDef | t.CPtr) -> int:
|
||
"""翻译枚举类定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的
|
||
# FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的
|
||
# 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry,
|
||
# add_enum_member 成员名去重,重复处理安全合并。
|
||
|
||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
if children is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||
VLogger.warning(fb, "ENUM")
|
||
return 0
|
||
|
||
cn: t.CSizeT = len(children)
|
||
|
||
# 临时数组存储成员信息
|
||
member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
if member_names_buf is None or member_types_buf is None or member_values_buf is None:
|
||
return 0
|
||
string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
|
||
member_count: int = 0
|
||
next_val: t.CInt64T = 0
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt)
|
||
if aa is None or aa.target is None:
|
||
continue
|
||
|
||
# 获取成员名
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||
if tgt.id is None:
|
||
continue
|
||
|
||
# 解析成员类型
|
||
member_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type(
|
||
pool, aa.annotation, trans._imported_modules, trans._from_imports)
|
||
|
||
# 解析成员值
|
||
has_value: int = 0
|
||
cur_val: t.CInt64T = 0
|
||
if aa.value is not None:
|
||
cur_val = self._extract_int_value(aa.value)
|
||
has_value = 1
|
||
else:
|
||
cur_val = next_val
|
||
|
||
# 下一个自动值
|
||
next_val = cur_val + 1
|
||
|
||
# 存储
|
||
if member_count < ENUM_MEMBER_MAX_LOCAL:
|
||
member_names_buf[member_count] = t.CSizeT(tgt.id)
|
||
member_types_buf[member_count] = t.CSizeT(member_ty)
|
||
member_values_buf[member_count] = cur_val
|
||
member_count += 1
|
||
|
||
elif sk == ast.ASTKind.Assign:
|
||
# 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等
|
||
# CEnum 子类中无类型注释的赋值也视为枚举成员
|
||
ag: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt)
|
||
if ag is None or ag.targets is None:
|
||
continue
|
||
tgts: list[ast.AST | t.CPtr] | t.CPtr = ag.targets
|
||
tn: t.CSizeT = len(tgts)
|
||
if tn == 0:
|
||
continue
|
||
# 取第一个 target 作为成员名
|
||
t0: ast.AST | t.CPtr = tgts.get(0)
|
||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
|
||
if tgt_a.id is None:
|
||
continue
|
||
|
||
# Assign 无类型注释,默认使用 i32
|
||
member_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
|
||
# 解析成员值
|
||
cur_val_a: t.CInt64T = 0
|
||
if ag.value is not None:
|
||
cur_val_a = self._extract_int_value(ag.value)
|
||
else:
|
||
cur_val_a = next_val
|
||
|
||
# 下一个自动值
|
||
next_val = cur_val_a + 1
|
||
|
||
# 存储
|
||
if member_count < ENUM_MEMBER_MAX_LOCAL:
|
||
member_names_buf[member_count] = t.CSizeT(tgt_a.id)
|
||
member_types_buf[member_count] = t.CSizeT(member_ty_a)
|
||
member_values_buf[member_count] = cur_val_a
|
||
member_count += 1
|
||
|
||
if member_count == 0:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "%s has no members", class_name)
|
||
VLogger.warning(fb, "ENUM")
|
||
return 0
|
||
|
||
# 确定基准类型:所有成员类型中 Bits 最大的
|
||
base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
max_bits: int = 0
|
||
for mi in range(member_count):
|
||
ty_addr: t.CSizeT = member_types_buf[mi]
|
||
if ty_addr == 0:
|
||
continue
|
||
mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(ty_addr, t.CPtr))
|
||
bits: int = HandlesType.get_llvm_type_bits(mty)
|
||
if bits > max_bits:
|
||
max_bits = bits
|
||
base_ty = mty
|
||
|
||
# 注册枚举
|
||
entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum(
|
||
pool, class_name, base_ty)
|
||
if entry is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
|
||
VLogger.error(fb, "ENUM")
|
||
return 0
|
||
|
||
# 添加成员
|
||
for mi in range(member_count):
|
||
fname_addr: t.CSizeT = member_names_buf[mi]
|
||
if fname_addr == 0:
|
||
continue
|
||
mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr))
|
||
fty_addr2: t.CSizeT = member_types_buf[mi]
|
||
if fty_addr2 == 0:
|
||
continue
|
||
mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(fty_addr2, t.CPtr))
|
||
mval: t.CInt64T = member_values_buf[mi]
|
||
if mname is not None and mty2 is not None:
|
||
HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2)
|
||
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d",
|
||
class_name, member_count, max_bits)
|
||
VLogger.info(fb, "ENUM")
|
||
return 0
|
||
def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""计算 LLVM 类型的字节大小(含对齐 padding)"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
return (bits + 7) // 8
|
||
case llvmlite.LLVMType.Float(bits):
|
||
return bits // 8
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 8
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
return self._get_type_size(elem_ty) * count
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
# 计算结构体大小,考虑字段对齐 padding
|
||
# 规则: 每个字段的对齐 = 该字段类型的自然对齐
|
||
# 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1
|
||
# 结构体总大小需对齐到最大字段对齐的倍数
|
||
total: int = 0
|
||
max_align: int = 1
|
||
cur: llvmlite.ParamNode | t.CPtr = fields
|
||
i: int = 0
|
||
while cur is not None and i < fcount:
|
||
if cur.Ty is not None:
|
||
fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty)
|
||
fsize: int = self._get_type_size(fty)
|
||
falign: int = self._get_type_align(fty)
|
||
# 对齐当前偏移到字段对齐边界
|
||
if falign > 0:
|
||
rem: int = total % falign
|
||
if rem != 0:
|
||
total += falign - rem
|
||
total += fsize
|
||
if falign > max_align:
|
||
max_align = falign
|
||
cur = cur.Next
|
||
i += 1
|
||
# 结构体总大小对齐到最大字段对齐的倍数
|
||
rem2: int = total % max_align
|
||
if rem2 != 0:
|
||
total += max_align - rem2
|
||
return total
|
||
case _:
|
||
return 8
|
||
def _get_type_align(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""返回类型的自然对齐(字节)"""
|
||
if ty is None:
|
||
return 1
|
||
match ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
if bits <= 8:
|
||
return 1
|
||
elif bits <= 16:
|
||
return 2
|
||
elif bits <= 32:
|
||
return 4
|
||
else:
|
||
return 8
|
||
case llvmlite.LLVMType.Float(bits):
|
||
if bits <= 32:
|
||
return 4
|
||
else:
|
||
return 8
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 8
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
return self._get_type_align(elem_ty)
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
# 结构体的对齐 = 最大字段对齐
|
||
max_align: int = 1
|
||
cur: llvmlite.ParamNode | t.CPtr = fields
|
||
i: int = 0
|
||
while cur is not None and i < fcount:
|
||
if cur.Ty is not None:
|
||
fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty)
|
||
fa: int = self._get_type_align(fty)
|
||
if fa > max_align:
|
||
max_align = fa
|
||
cur = cur.Next
|
||
i += 1
|
||
return max_align
|
||
case _:
|
||
return 8
|
||
def _translate_union_def(self, trans: HT.Translator | t.CPtr,
|
||
cd: ast.ClassDef | t.CPtr) -> int:
|
||
"""翻译联合体定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前)
|
||
HandlesStruct.add_visible_struct(pool, class_name)
|
||
|
||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
|
||
class_name, trans.ModuleSha1)
|
||
if existing is not None:
|
||
# Phase B: 将已存在的命名结构体注册到当前模块
|
||
if existing.Ty is not None:
|
||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||
# SHA1 已在 register_struct 时设置,无需再补
|
||
return 0
|
||
|
||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
if children is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||
VLogger.warning(fb, "UNION")
|
||
return 0
|
||
|
||
cn: t.CSizeT = len(children)
|
||
|
||
# 临时数组存储字段信息
|
||
field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX)
|
||
field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX)
|
||
if field_names_buf is None or field_types_buf is None:
|
||
return 0
|
||
string.memset(field_names_buf, 0, 8 * HandlesStruct.FIELD_MAX)
|
||
string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX)
|
||
|
||
field_count: int = 0
|
||
max_size: int = 0
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt)
|
||
if aa is None or aa.target is None:
|
||
continue
|
||
|
||
# 获取字段名
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||
if tgt.id is None:
|
||
continue
|
||
|
||
# 解析字段类型
|
||
field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||
if field_ty is None:
|
||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
|
||
# 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类)
|
||
if trans._declare_only == 1:
|
||
return 1
|
||
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
|
||
type_name: str = HandlesType.annotation_to_str(aa.annotation)
|
||
HandlesType.fatal_error(
|
||
aa,
|
||
f"'{type_name}' is not defined",
|
||
"NameError")
|
||
field_ty = llvmlite.Int32(pool)
|
||
|
||
# 计算字段大小,更新 max_size
|
||
fsize: int = self._get_type_size(field_ty)
|
||
if fsize > max_size:
|
||
max_size = fsize
|
||
|
||
# 存储到数组
|
||
if field_count < HandlesStruct.FIELD_MAX:
|
||
field_names_buf[field_count] = t.CSizeT(tgt.id)
|
||
field_types_buf[field_count] = t.CSizeT(field_ty)
|
||
field_count += 1
|
||
|
||
if field_count == 0:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "%s has no fields", class_name)
|
||
VLogger.warning(fb, "UNION")
|
||
return 0
|
||
|
||
if max_size < 1:
|
||
max_size = 1
|
||
|
||
# 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)])
|
||
# 即 { [max_size x i8] }
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size)
|
||
|
||
# 构建 ParamNode 链表(单字段:字节数组)
|
||
pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||
if pnode is None:
|
||
return 0
|
||
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
|
||
pnode.Ty = array_ty
|
||
|
||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||
union_type_name: str = class_name
|
||
if trans.ModuleSha1 is not None:
|
||
union_name_buf: str = pool.alloc(64)
|
||
if union_name_buf is not None:
|
||
viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||
union_type_name = union_name_buf
|
||
|
||
union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name)
|
||
if union_ty is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name)
|
||
VLogger.error(fb, "UNION")
|
||
return 0
|
||
|
||
# Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活)
|
||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册
|
||
# includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后
|
||
# entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃
|
||
# (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||
if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0:
|
||
union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||
CompilerFactory.get_perm_pool(), union_ty)
|
||
if union_copy is not None:
|
||
union_ty = union_copy
|
||
|
||
# 注册命名结构体到模块
|
||
llvmlite.module_add_named_type(trans.Module, pool, union_ty)
|
||
|
||
# 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry)
|
||
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
|
||
pool, class_name, union_ty, trans.ModuleSha1)
|
||
if entry is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
|
||
VLogger.error(fb, "UNION")
|
||
return 0
|
||
|
||
# 标记为当前文件可见(命名空间隔离)
|
||
HandlesStruct.add_visible_struct(pool, class_name)
|
||
|
||
# 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错)
|
||
entry.IsUnion = 1
|
||
|
||
# 添加字段信息(所有字段 Index=0,因为共享偏移 0)
|
||
for fi in range(field_count):
|
||
fname_addr: t.CSizeT = field_names_buf[fi]
|
||
if fname_addr == 0:
|
||
continue
|
||
fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr))
|
||
fty_addr2: t.CSizeT = field_types_buf[fi]
|
||
if fty_addr2 == 0:
|
||
continue
|
||
fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(fty_addr2, t.CPtr))
|
||
if fname is not None and fty2 is not None:
|
||
HandlesStruct.add_field(pool, entry, fname, fty2, None, None)
|
||
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d",
|
||
class_name, field_count, max_size)
|
||
VLogger.info(fb, "UNION")
|
||
return 0
|
||
def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int:
|
||
"""计算注解类型的字节大小,用于 REnum 布局计算"""
|
||
if annotation is None:
|
||
return 8
|
||
k: int = annotation.kind()
|
||
# 联合类型 A | B → 指针大小 8
|
||
if k == ast.ASTKind.BinOp:
|
||
return 8
|
||
# Name(id) 或 Attribute(attr) → 解析类型名
|
||
type_name: str = None
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annotation)
|
||
if nm is not None:
|
||
type_name = nm.id
|
||
elif k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation)
|
||
if at is not None:
|
||
type_name = at.attr
|
||
if type_name is None:
|
||
return 8
|
||
# 内置类型
|
||
if string.strcmp(type_name, "int") == 0:
|
||
return 4
|
||
if string.strcmp(type_name, "CInt") == 0:
|
||
return 4
|
||
if string.strcmp(type_name, "CInt8T") == 0:
|
||
return 1
|
||
if string.strcmp(type_name, "CInt16T") == 0:
|
||
return 2
|
||
if string.strcmp(type_name, "CInt32T") == 0:
|
||
return 4
|
||
if string.strcmp(type_name, "CInt64T") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "CChar") == 0:
|
||
return 1
|
||
if string.strcmp(type_name, "CDouble") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "CFloat") == 0:
|
||
return 4
|
||
if string.strcmp(type_name, "CPtr") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "CSizeT") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "str") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "bytes") == 0:
|
||
return 8
|
||
if string.strcmp(type_name, "bool") == 0:
|
||
# bool = t.CBool = i8(1 字节)
|
||
return 1
|
||
# 已注册的结构体类型
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(type_name)
|
||
if struct_ty is not None:
|
||
sz: int = self._get_type_size(struct_ty)
|
||
if sz > 0:
|
||
return sz
|
||
# 未注册类型 → 默认指针大小 8(可能是自引用或前向引用)
|
||
return 8
|
||
def _translate_renum_def(self, trans: HT.Translator | t.CPtr,
|
||
cd: ast.ClassDef | t.CPtr) -> int:
|
||
"""翻译 REnum 类定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 命名空间隔离:标记为当前文件可见
|
||
HandlesStruct.add_visible_struct(pool, class_name)
|
||
|
||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
|
||
class_name, trans.ModuleSha1)
|
||
if existing is not None:
|
||
if existing.Ty is not None:
|
||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||
return 0
|
||
|
||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
if children is None:
|
||
fb: str = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||
VLogger.warning(fb, "RENUM")
|
||
return 0
|
||
|
||
cn: t.CSizeT = len(children)
|
||
|
||
# 变体最多 32 个,每个变体最多 16 个字段
|
||
# variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小
|
||
variant_field_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * 64 * 16)
|
||
if variant_field_sizes is None:
|
||
return 0
|
||
string.memset(variant_field_sizes, 0, 8 * 64 * 16)
|
||
|
||
variant_count: int = 0
|
||
max_field_count: int = 0 # 所有变体中最大字段数
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.ClassDef:
|
||
# 嵌套变体类
|
||
variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt)
|
||
if variant_cd is None or variant_cd.children is None:
|
||
variant_count += 1
|
||
continue
|
||
variant_children: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children
|
||
vcn: t.CSizeT = len(variant_children)
|
||
field_idx: int = 0
|
||
for vi in range(vcn):
|
||
vstmt: ast.AST | t.CPtr = variant_children.get(vi)
|
||
if vstmt is None:
|
||
continue
|
||
vk: int = vstmt.kind()
|
||
if vk != ast.ASTKind.AnnAssign:
|
||
continue
|
||
vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt)
|
||
if vaa is None or vaa.target is None or vaa.annotation is None:
|
||
continue
|
||
if vaa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
# 提取字段名
|
||
vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target)
|
||
# 计算字段大小
|
||
fsize: int = self._get_annotation_field_size(vaa.annotation)
|
||
if variant_count < 32 and field_idx < 16:
|
||
# variant_field_sizes[variant_count][field_idx] = fsize
|
||
offset: t.CSizeT = variant_count * 16 + field_idx
|
||
variant_field_sizes[offset] = t.CSizeT(fsize)
|
||
# 直接注册变体字段名别名(避免 CSizeT→str 转换问题)
|
||
# 同时解析成员实际类型(对齐 TPC class_members,供 match
|
||
# 绑定 bitcast 槽位地址用)。自引用注解(如
|
||
# LLVMType|t.CPtr 引用自身类)此时解析失败返回 None →
|
||
# 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset
|
||
# 后悬空,注册内部会 strcpy 到 perm_pool。
|
||
if vnm is not None and vnm.id is not None:
|
||
mem_ty_l: llvmlite.LLVMType | t.CPtr = None
|
||
if trans is not None:
|
||
mem_ty_l = HandlesType.resolve_annotation_type(
|
||
pool, vaa.annotation,
|
||
trans._imported_modules,
|
||
trans._from_imports, trans)
|
||
self._register_renum_field_alias(
|
||
pool, class_name, vnm.id, field_idx + 1,
|
||
mem_ty_l, variant_cd.name)
|
||
field_idx += 1
|
||
if field_idx > max_field_count:
|
||
max_field_count = field_idx
|
||
variant_count += 1
|
||
|
||
if variant_count == 0:
|
||
fb2: str = VLogger.fmt_buf()
|
||
if fb2 is not None:
|
||
viperlib.snprintf(fb2, 1024, "%s has no variants", class_name)
|
||
VLogger.warning(fb2, "RENUM")
|
||
return 0
|
||
|
||
# 计算每个位置的最大字段大小
|
||
# 位置 0 = __tag (i32, 4 字节)
|
||
# 位置 1+ = 变体字段
|
||
total_positions: int = max_field_count + 1 # +1 for tag
|
||
if total_positions < 2:
|
||
total_positions = 2 # 至少 {i32, i32}
|
||
|
||
position_max_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * total_positions)
|
||
if position_max_sizes is None:
|
||
return 0
|
||
string.memset(position_max_sizes, 0, 8 * total_positions)
|
||
|
||
# 位置 0 = tag = 4 字节
|
||
position_max_sizes[0] = t.CSizeT(4)
|
||
|
||
# 位置 1+ = 每个位置取所有变体的最大字段大小
|
||
for pos in range(1, total_positions):
|
||
pos_max: int = 0
|
||
for vi in range(variant_count):
|
||
if vi >= 64:
|
||
break # variant_field_sizes 64 类槽上限,防读越界
|
||
field_pos: int = pos - 1 # 变体字段从位置 0 开始
|
||
if field_pos >= 16:
|
||
continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过
|
||
offset2: t.CSizeT = vi * 16 + field_pos
|
||
fsize_val: t.CSizeT = variant_field_sizes[offset2]
|
||
if fsize_val > pos_max:
|
||
pos_max = fsize_val
|
||
position_max_sizes[pos] = t.CSizeT(pos_max)
|
||
|
||
# 构建 ParamNode 链表
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
|
||
first_node: llvmlite.ParamNode | t.CPtr = None
|
||
tail_node: llvmlite.ParamNode | t.CPtr = None
|
||
|
||
for pos in range(total_positions):
|
||
psize: int = position_max_sizes[pos]
|
||
field_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if psize > 4:
|
||
field_ty = i64_ty
|
||
pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, field_ty)
|
||
if pnode is None:
|
||
continue
|
||
tail_node = llvmlite.param_list_append(first_node, tail_node, pnode)
|
||
if first_node is None:
|
||
first_node = tail_node
|
||
|
||
if first_node is None:
|
||
fb3: str = VLogger.fmt_buf()
|
||
if fb3 is not None:
|
||
viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name)
|
||
VLogger.error(fb3, "RENUM")
|
||
return 0
|
||
|
||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||
renum_type_name: str = class_name
|
||
if trans.ModuleSha1 is not None:
|
||
renum_name_buf: str = pool.alloc(64)
|
||
if renum_name_buf is not None:
|
||
viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||
renum_type_name = renum_name_buf
|
||
|
||
renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(
|
||
pool, first_node, total_positions, renum_type_name)
|
||
if renum_ty is None:
|
||
fb4: str = VLogger.fmt_buf()
|
||
if fb4 is not None:
|
||
viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name)
|
||
VLogger.error(fb4, "RENUM")
|
||
return 0
|
||
|
||
# Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活,
|
||
# 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效)
|
||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。
|
||
if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0:
|
||
renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||
CompilerFactory.get_perm_pool(), renum_ty)
|
||
if renum_copy is not None:
|
||
renum_ty = renum_copy
|
||
|
||
# 注册命名结构体到模块
|
||
llvmlite.module_add_named_type(trans.Module, pool, renum_ty)
|
||
|
||
# 注册到 HandlesStruct
|
||
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
|
||
pool, class_name, renum_ty, trans.ModuleSha1)
|
||
if entry is None:
|
||
fb5: str = VLogger.fmt_buf()
|
||
if fb5 is not None:
|
||
viperlib.snprintf(fb5, 1024, "failed to register %s", class_name)
|
||
VLogger.error(fb5, "RENUM")
|
||
return 0
|
||
|
||
# 修复 class_name 指针不匹配:
|
||
# 别名注册时用 class_name(= cd.name,AST 原始指针),
|
||
# 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。
|
||
# 两者是不同指针,CSizeT 指针值比较会失败。
|
||
# 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。
|
||
if entry.Name is not None:
|
||
self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name))
|
||
|
||
# 添加 __tag 字段(位置 0,i32)
|
||
HandlesStruct.add_field(pool, entry, "__tag", i32_ty, None, None)
|
||
|
||
# 添加 payload 字段(位置 1+,i32 或 i64)
|
||
for pos in range(1, total_positions):
|
||
psize2: int = position_max_sizes[pos]
|
||
payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if psize2 > 4:
|
||
payload_ty = i64_ty
|
||
field_name_buf: str = pool.alloc(16)
|
||
if field_name_buf is not None:
|
||
viperlib.snprintf(field_name_buf, 16, "_p%d", pos)
|
||
HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None)
|
||
|
||
# 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造)
|
||
self._register_renum_variants(pool, class_name, cd, variant_count)
|
||
|
||
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)
|
||
|
||
fb6: str = VLogger.fmt_buf()
|
||
if fb6 is not None:
|
||
viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions",
|
||
class_name, variant_count, total_positions)
|
||
VLogger.info(fb6, "RENUM")
|
||
return 0
|
||
def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_name: str,
|
||
cd: ast.ClassDef | t.CPtr,
|
||
variant_count: int):
|
||
"""注册 REnum 类的变体名和 tag 值到全局变体表"""
|
||
if pool is None or class_name is None or cd is None:
|
||
return
|
||
if variant_count == 0:
|
||
return
|
||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||
if children is None:
|
||
return
|
||
|
||
# 懒初始化表(首次注册时分配)
|
||
# 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配,
|
||
# 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在
|
||
# parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。
|
||
if self.RenumClassNames is None:
|
||
self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX)
|
||
self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX)
|
||
self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
if (self.RenumClassNames is None or self.RenumClassVariantCounts is None
|
||
or self.RenumVariantNames is None or self.RenumVariantTags is None):
|
||
self.RenumClassNames = None
|
||
return
|
||
string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX)
|
||
string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX)
|
||
string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
self.RenumClassCount = 0
|
||
|
||
# ============ 临时诊断(0xb0 崩溃定位,定位后移除) ============
|
||
# lazy init 后 RenumClassNames 必非空;此时若 RCV 异常(null/小值)
|
||
# 说明字段被越界覆盖或 __init__ 未生效,fail-fast 暴露崩溃现场。
|
||
fb_diag: str = VLogger.fmt_buf()
|
||
if fb_diag is not None:
|
||
viperlib.snprintf(fb_diag, 1024,
|
||
"[RENUM-DIAG] self=%llu RN=%llu RCV=%llu RVN=%llu RVT=%llu RCount=%d class=%s",
|
||
t.CUInt64T(self), t.CUInt64T(self.RenumClassNames),
|
||
t.CUInt64T(self.RenumClassVariantCounts),
|
||
t.CUInt64T(self.RenumVariantNames),
|
||
t.CUInt64T(self.RenumVariantTags),
|
||
self.RenumClassCount, class_name)
|
||
VLogger.info(fb_diag, "RENUM")
|
||
rcv_chk: t.CUInt64T = t.CUInt64T(self.RenumClassVariantCounts)
|
||
if rcv_chk == 0 or rcv_chk < 4096:
|
||
fb_fail: str = VLogger.fmt_buf()
|
||
if fb_fail is not None:
|
||
viperlib.snprintf(fb_fail, 1024,
|
||
"[RENUM-FAIL] RCV=%llu 异常(lazy init 后应为 perm_pool 地址),RenumClassCount=%d class=%s",
|
||
t.CUInt64T(self.RenumClassVariantCounts),
|
||
self.RenumClassCount, class_name)
|
||
VLogger.error(fb_fail, "RENUM")
|
||
stdlib.exit(1)
|
||
# ============ 临时诊断结束 ============
|
||
|
||
# 检查是否已注册(避免重复注册)
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = self.RenumClassNames[i]
|
||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||
return
|
||
|
||
# 表已满
|
||
if self.RenumClassCount >= RENUM_CLASS_MAX:
|
||
return
|
||
|
||
# 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空,
|
||
# _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存)
|
||
idx: int = self.RenumClassCount
|
||
cn_len_rv: t.CSizeT = string.strlen(class_name)
|
||
cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1)
|
||
if cn_buf_rv is None:
|
||
return
|
||
string.strcpy(cn_buf_rv, class_name)
|
||
self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv)
|
||
self.RenumClassVariantCounts[idx] = variant_count
|
||
|
||
# 遍历 children,提取嵌套变体类名并注册
|
||
cn: t.CSizeT = len(children)
|
||
tag: int = 0
|
||
for ci in range(cn):
|
||
if tag >= variant_count:
|
||
break
|
||
if tag >= RENUM_VARIANT_PER_CLASS:
|
||
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
|
||
fb_rv: str = VLogger.fmt_buf()
|
||
if fb_rv is not None:
|
||
viperlib.snprintf(fb_rv, 1024,
|
||
"REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name)
|
||
VLogger.error(fb_rv, "RENUM")
|
||
break
|
||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
if stmt.kind() != ast.ASTKind.ClassDef:
|
||
continue
|
||
vcd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt)
|
||
if vcd is None or vcd.name is None:
|
||
continue
|
||
name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag
|
||
# 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空)
|
||
vn_len_rv: t.CSizeT = string.strlen(vcd.name)
|
||
vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1)
|
||
if vn_buf_rv is None:
|
||
break
|
||
string.strcpy(vn_buf_rv, vcd.name)
|
||
self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv)
|
||
self.RenumVariantTags[name_offset] = tag
|
||
tag += 1
|
||
|
||
self.RenumClassCount = idx + 1
|
||
def _lookup_renum_variant(self, variant_name: str) -> str:
|
||
"""查找变体名所属的 REnum 类名
|
||
|
||
返回: class_name (str),或 None
|
||
"""
|
||
if variant_name is None or self.RenumClassNames is None:
|
||
return None
|
||
|
||
for i in range(self.RenumClassCount):
|
||
vcount: int = self.RenumClassVariantCounts[i]
|
||
for j in range(vcount):
|
||
name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j
|
||
vname: str = self.RenumVariantNames[name_offset]
|
||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||
cls_nm: str = self.RenumClassNames[i]
|
||
return cls_nm
|
||
return None
|
||
def _is_renum_class_name(self, class_name: str) -> int:
|
||
"""检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否"""
|
||
if class_name is None or self.RenumClassNames is None:
|
||
return 0
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = self.RenumClassNames[i]
|
||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||
return 1
|
||
return 0
|
||
def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int:
|
||
"""在指定 REnum 类中查找变体,返回 tag 值或 -1"""
|
||
if class_name is None or variant_name is None or self.RenumClassNames is None:
|
||
return -1
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = self.RenumClassNames[i]
|
||
if existing is None or string.strcmp(existing, class_name) != 0:
|
||
continue
|
||
vcount: int = self.RenumClassVariantCounts[i]
|
||
for j in range(vcount):
|
||
name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j
|
||
vname: str = self.RenumVariantNames[name_offset]
|
||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||
return self.RenumVariantTags[name_offset]
|
||
return -1
|
||
return -1
|
||
def _register_renum_field_alias(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_name: str,
|
||
field_name: str,
|
||
payload_idx: int,
|
||
field_ty: llvmlite.LLVMType | t.CPtr = None,
|
||
variant_name: str = None):
|
||
"""注册 REnum 变体字段名别名到全局表
|
||
|
||
field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如
|
||
LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。
|
||
variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员)
|
||
"""
|
||
if pool is None or class_name is None or field_name is None:
|
||
return
|
||
if payload_idx < 1:
|
||
return
|
||
|
||
# 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收)
|
||
if self.RenumAliasClass is None:
|
||
alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||
self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
if (self.RenumAliasClass is None or self.RenumAliasField is None
|
||
or self.RenumAliasIndex is None or self.RenumAliasTy is None
|
||
or self.RenumAliasVariant is None):
|
||
self.RenumAliasClass = None
|
||
return
|
||
string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasCount = 0
|
||
|
||
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
|
||
return
|
||
|
||
# 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变),
|
||
# field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp
|
||
cls_key: t.CSizeT = t.CSizeT(class_name)
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing: t.CSizeT = self.RenumAliasClass[i]
|
||
if cls_existing == cls_key:
|
||
fld_existing_ptr: str = (str | t.CPtr)(
|
||
t.CVoid(self.RenumAliasField[i], t.CPtr))
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
return
|
||
|
||
idx: int = self.RenumAliasCount
|
||
self.RenumAliasClass[idx] = cls_key
|
||
# field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias
|
||
# 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。
|
||
# class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为
|
||
# entry.Name(perm_pool 拷贝),指针值比较契约不变。
|
||
fn_len_rfa: t.CSizeT = string.strlen(field_name)
|
||
fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1)
|
||
if fn_buf_rfa is None:
|
||
return
|
||
string.strcpy(fn_buf_rfa, field_name)
|
||
self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa)
|
||
self.RenumAliasIndex[idx] = t.CSizeT(payload_idx)
|
||
# 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空;
|
||
# 未解析成功(自引用等)存 0,绑定回退槽位类型)
|
||
self.RenumAliasTy[idx] = 0
|
||
if field_ty is not None:
|
||
ty_copy_rfa: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||
CompilerFactory.get_perm_pool(), field_ty)
|
||
if ty_copy_rfa is not None:
|
||
self.RenumAliasTy[idx] = t.CSizeT(ty_copy_rfa)
|
||
# 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空)
|
||
self.RenumAliasVariant[idx] = 0
|
||
if variant_name is not None:
|
||
vn_len_rfa: t.CSizeT = string.strlen(variant_name)
|
||
vn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(vn_len_rfa + 1)
|
||
if vn_buf_rfa is not None:
|
||
string.strcpy(vn_buf_rfa, variant_name)
|
||
self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa)
|
||
self.RenumAliasCount = idx + 1
|
||
def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT):
|
||
"""更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr"""
|
||
if old_ptr == new_ptr:
|
||
return
|
||
if self.RenumAliasClass is None:
|
||
return
|
||
for i in range(self.RenumAliasCount):
|
||
if self.RenumAliasClass[i] == old_ptr:
|
||
self.RenumAliasClass[i] = new_ptr
|
||
def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int:
|
||
"""查找 REnum 变体字段名的 payload 索引,返回索引或 -1
|
||
|
||
class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针)
|
||
field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针)
|
||
"""
|
||
if class_name is None or field_name is None or self.RenumAliasClass is None:
|
||
return -1
|
||
cls_key: t.CSizeT = t.CSizeT(class_name)
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing: t.CSizeT = self.RenumAliasClass[i]
|
||
if cls_existing == cls_key:
|
||
# field_name 用 strcmp 内容比较(指针不同但内容相同)
|
||
fld_existing_ptr: str = (str | t.CPtr)(
|
||
t.CVoid(self.RenumAliasField[i], t.CPtr))
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
return self.RenumAliasIndex[i]
|
||
return -1
|
||
def _lookup_renum_field_alias_ty(self, class_name: str,
|
||
field_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None
|
||
|
||
与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。
|
||
注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。
|
||
"""
|
||
if class_name is None or field_name is None or self.RenumAliasTy is None:
|
||
return None
|
||
cls_key: t.CSizeT = t.CSizeT(class_name)
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing: t.CSizeT = self.RenumAliasClass[i]
|
||
if cls_existing == cls_key:
|
||
fld_existing_ptr: str = (str | t.CPtr)(
|
||
t.CVoid(self.RenumAliasField[i], t.CPtr))
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
if self.RenumAliasTy[i] == 0:
|
||
return None
|
||
return (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(self.RenumAliasTy[i], t.CPtr))
|
||
return None
|
||
def _lookup_renum_member_ty(self, class_name: str,
|
||
variant_name: str,
|
||
payload_idx: int) -> llvmlite.LLVMType | t.CPtr:
|
||
"""按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型
|
||
|
||
match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs
|
||
Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置
|
||
内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。
|
||
"""
|
||
if class_name is None or variant_name is None or self.RenumAliasVariant is None:
|
||
return None
|
||
if payload_idx < 1:
|
||
return None
|
||
cls_key: t.CSizeT = t.CSizeT(class_name)
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing: t.CSizeT = self.RenumAliasClass[i]
|
||
if cls_existing != cls_key:
|
||
continue
|
||
if self.RenumAliasVariant[i] == 0:
|
||
continue
|
||
vnt_ptr: str = (str | t.CPtr)(
|
||
t.CVoid(self.RenumAliasVariant[i], t.CPtr))
|
||
if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0:
|
||
continue
|
||
if self.RenumAliasIndex[i] != payload_idx:
|
||
continue
|
||
if self.RenumAliasTy[i] == 0:
|
||
return None
|
||
return (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(self.RenumAliasTy[i], t.CPtr))
|
||
return None |