Files
ViperC/App/lib/core/Gen/ClassGenEnum.vp
T

1162 lines
53 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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