Files
ViperC/App/lib/core/Gen/StructGenMixin.vp
T
TermiNexus 9d3483e97e refactor: 全面 fail-fast 化(去兜底)+ 泛型补译/解引用宽度修复
- 全量降级点改 fail-fast:23 文件约 140+ 处静默 i32/i8*/void/continue 兜底改为 HandlesType.fatal_error(python traceback 风格)或 VLogger.error 终止,暴露上游根因;保留语言语义默认(无注解 i32/infer 链/CIf/star 回退)
- 泛型特化 Phase B 补译 reemit 强制发射方法体(修复 list[...] define 缺失)
- c.Deref 读取宽度仅按赋值直接 RHS 推断(修复 CurAssignAnnot 残留误判 i32)
- 类型别名清理:t.CChar|t.CPtr→str、t.CInt→int 等
2026-08-13 02:11:49 +08:00

1188 lines
54 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 memhub
import string
import stdlib
import llvmlite
import stdio
import ast
import hashtable
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
# StructGenMixin - 结构体注册/字段查找 Mixin(对象化 P2-2,wiki/14-oo-refactor.md)
#
# 从 HandlesStruct.vp 迁移:
# 全局状态(_struct_table/_struct_count/_g_stdlib_alloc/
# _visible_structs/_strict_visibility)→ 本类字段
# 模块级函数(register_struct/find_struct/lookup_field/...)→ 本类方法
#
# 迁移原则(与 TypeGenMixin P2-1 一致,行为零变化):
# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段
# 2. HandlesStruct.vp 原函数保留为"委托":本地模块级单例 _g_gen(BuildPipeline
# /main 注入)cast 成 Generator 类型后调本类方法
# 3. FieldEntry/StructEntry 类型保留在 HandlesStruct.vp(本类字段引用)
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
# ============================================================
# ============================================================
# 常量(与 HandlesStruct 保持一致)
# ============================================================
STRUCT_MAX: t.CDefine = 512
# 字段槽位上限制(与 HandlesStruct 一致:对象化后 Generator 50+ 字段)
FIELD_MAX: t.CDefine = 64
FIELD_NAME_MAX: t.CDefine = 64
PARENT_MAX: t.CDefine = 8
MRO_MAX: t.CDefine = 16
# ============================================================
# StructGenMixin - 结构体注册表/字段查找/可见性
# ============================================================
@t.NoVTable
class StructGenMixin:
"""结构体注册与查找 Mixin(状态从 HandlesStruct 全局变量迁入)"""
# --- 全局注册表(原 _struct_table/_struct_count) ---
StructTable: HandlesStruct.StructEntry | t.CPtr # STRUCT_MAX 槽位数组
StructCount: int
# --- OOM 回收分配模式(原 _g_stdlib_alloc) ---
StdlibAlloc: int
# --- 跨模块命名空间隔离(原 _visible_structs/_strict_visibility) ---
VisibleStructs: hashtable.HashTable | t.CPtr
StrictVisibility: int
def InitStructGen(self) -> int:
"""初始化结构体 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
if self is None:
return 1
self.StructTable = None
self.StructCount = 0
self.StdlibAlloc = 0
self.VisibleStructs = None
self.StrictVisibility = 0
return 0
# ============================================================
# P2-2 迁移方法(函数体来自 HandlesStruct.vp,全局变量改 self.字段,
# 同模块函数调用改 self.方法;签名与 HandlesStruct 原函数一致)
# ============================================================
def set_stdlib_alloc(self, flag: int):
"""设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)"""
self.StdlibAlloc = flag
def get_stdlib_alloc(self) -> int:
"""读取 OOM 回收分配模式(供其他 Mixin 经 HandlesStruct 委托访问,
避免跨 Mixin 直接读 self.StdlibAlloc——Mixin 方法体按自身块内索引编译)"""
return self.StdlibAlloc
def reset_visible_structs(self, pool: memhub.MemBuddy | t.CPtr, strict: int):
"""重置可见性状态(每个文件翻译前调用)
pool: 内存分配器(严格模式下创建 HashTable)
strict: 1=严格模式(用户文件),0=宽松模式(includes 文件)
"""
self.StrictVisibility = strict
if strict != 0:
# 严格模式:创建新的 HashTable 记录可见结构体
self.VisibleStructs = hashtable.HashTable(pool)
else:
# 宽松模式:全部可见,不需要 HashTable
self.VisibleStructs = None
def add_visible_struct(self, pool: memhub.MemBuddy | t.CPtr, name: str):
"""添加可见结构体名(类定义时和 from-import 时调用)"""
if name is None:
return
# 宽松模式:全部可见,无需记录
if self.StrictVisibility == 0:
return
if self.VisibleStructs is None:
return
# 已存在则跳过(HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配)
if self.VisibleStructs.__contains__(name) != 0:
return
self.VisibleStructs.set_int(name, 1)
def is_struct_visible(self, name: str) -> int:
"""检查结构体是否可见,返回 1=可见 / 0=不可见"""
if self.StrictVisibility == 0:
return 1
if name is None or self.VisibleStructs is None:
return 0
return self.VisibleStructs.__contains__(name)
def init_struct_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化结构体注册表,返回 1 成功"""
if self.StructTable is not None:
return 1
entry_size: t.CSizeT = HandlesStruct.StructEntry.__sizeof__()
self.StructTable = pool.alloc(entry_size * STRUCT_MAX)
if self.StructTable is None:
return 0
string.memset(self.StructTable, 0, entry_size * STRUCT_MAX)
self.StructCount = 0
return 1
def _get_struct_entry(self, i: int) -> HandlesStruct.StructEntry | t.CPtr:
"""获取第 i 个结构体条目"""
if self.StructTable is None or i < 0 or i >= STRUCT_MAX:
return None
entry_size: t.CSizeT = HandlesStruct.StructEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(self.StructTable) + i * entry_size
return (HandlesStruct.StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
def _get_field_entry(self, struct_entry: HandlesStruct.StructEntry | t.CPtr, i: int) -> HandlesStruct.FieldEntry | t.CPtr:
"""获取结构体中第 i 个字段条目"""
if struct_entry is None or i < 0 or i >= FIELD_MAX:
return None
field_size: t.CSizeT = HandlesStruct.FieldEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size
return (HandlesStruct.FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
def register_struct(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
struct_ty: llvmlite.LLVMType | t.CPtr,
sha1: str = None) -> HandlesStruct.StructEntry | t.CPtr:
"""注册结构体类型,返回 StructEntry 指针
用类型指针去重(is 比较),不用类名去重。
这样跨模块同名类可以共存,各自有独立的字段定义。
sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。
"""
if self.init_struct_table(pool) == 0:
return None
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
# 用 t.CUInt64T 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty)
st_dedup: t.CUInt64T = t.CUInt64T(struct_ty)
for i in range(self.StructCount):
existing: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if existing is not None and existing.Ty is not None:
if t.CUInt64T(existing.Ty) == st_dedup:
return existing
if self.StructCount >= STRUCT_MAX:
fb_st: str = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
VLogger.error(fb_st, "STRUCT")
return None
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(self.StructCount)
if entry is None:
return None
# 分配字段数组(1b 阶段用 stdlib,避免 reset 回收后 Fields 悬空)
field_size: t.CSizeT = HandlesStruct.FieldEntry.__sizeof__()
if self.StdlibAlloc != 0:
entry.Fields = stdlib.malloc(field_size * FIELD_MAX)
else:
entry.Fields = pool.alloc(field_size * FIELD_MAX)
if entry.Fields is None:
return None
string.memset(entry.Fields, 0, field_size * FIELD_MAX)
# 复制类名(统一 stdlib:1a 阶段注册的 entry 需跨 1b reset 存活。
# 此前 1a 用 pool,1b 阶段 find_struct_by_module 的 strcmp 读悬空
# Name 越界读 → G3 LinkedNode.prepend 挂起根因。stdlib 分配不随
# pool reset 回收,多遍去重(Ty 比较)避免重复分配。)
name_len: t.CSizeT = string.strlen(name)
name_buf: str = stdlib.malloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, name)
entry.Name = name_buf
entry.Ty = struct_ty
entry.FieldCount = 0
# 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry)
# SHA1 同样统一 stdlib(跨 1a/1b 存活,防 strcmp 悬空)
if sha1 is not None:
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: str = stdlib.malloc(sha1_len + 1)
if sha1_buf is not None:
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
self.StructCount += 1
return entry
def set_struct_sha1(self, pool: memhub.MemBuddy | t.CPtr,
class_name: str, sha1: str) -> int:
"""设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败"""
if class_name is None or sha1 is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
if entry is None:
return 0
# 复制 SHA1 字符串(统一 stdlib,跨 1a/1b 存活防 strcmp 悬空)
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: str = stdlib.malloc(sha1_len + 1)
if sha1_buf is None:
return 0
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
return 1
def get_struct_sha1(self, class_name: str) -> str:
"""获取结构体所属模块的 SHA1,返回 None=无 SHA1"""
if class_name is None or self.StructTable is None:
return None
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
if entry is None:
return None
return entry.ModuleSha1
def add_field(self, pool: memhub.MemBuddy | t.CPtr,
struct_entry: HandlesStruct.StructEntry | t.CPtr,
field_name: str,
field_ty: llvmlite.LLVMType | t.CPtr,
default_val: ast.AST | t.CPtr = None,
annot_class_name: str = None) -> int:
"""向结构体添加字段,返回字段索引(-1 失败)
default_val: 字段默认值 AST 节点(可选,None=无默认值)
annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析)
"""
if struct_entry is None or field_name is None or field_ty is None:
return -1
if struct_entry.FieldCount >= FIELD_MAX:
fb_sf: str = VLogger.fmt_buf()
if fb_sf is not None:
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
VLogger.error(fb_sf, "STRUCT")
return -1
idx: int = struct_entry.FieldCount
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx)
if fe is None:
return -1
# 复制字段名(统一 stdlib:1a 注册的字段名跨 1b reset 存活,
# 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起,
# 与 register_struct 的 Name 悬空同根因)
name_len: t.CSizeT = string.strlen(field_name)
name_buf: str = stdlib.malloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, field_name)
fe.Name = name_buf
fe.Index = idx
# 1b 阶段(StdlibAlloc=1)字段类型/注解类名必须深拷贝到 stdlib:
# register_struct 已迁 Fields/Name/ModuleSha1/Ty(translate_class_def L2566
# DeepCopyType),但字段级 Ty/AnnotClassName 仍存 pool 指针,本文件
# reset_to(mark1) 回收后,跨文件读取(字段展平、多继承 this 调整、
# AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty
# 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。
if self.StdlibAlloc != 0:
ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, field_ty)
if ty_copy is not None:
fe.Ty = ty_copy
else:
fe.Ty = field_ty
if annot_class_name is not None:
annot_len: t.CSizeT = string.strlen(annot_class_name)
annot_buf: str = stdlib.malloc(annot_len + 1)
if annot_buf is not None:
string.strcpy(annot_buf, annot_class_name)
fe.AnnotClassName = annot_buf
# DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults)
# 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝
fe.DefaultVal = self._deep_copy_default_ast(default_val)
else:
fe.Ty = field_ty
fe.AnnotClassName = annot_class_name
fe.DefaultVal = default_val
struct_entry.FieldCount = idx + 1
return idx
def _deep_copy_default_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
"""深拷贝字段默认值 AST 到 stdlib(仅常量节点),跨 1b reset 存活。
字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外,
跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在
调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。
支持 Constant(标量)与 List(列表字面量,如 t.CArray[str] = ["py", "pyw"])。
其他非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None
(调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init
仍持有原始 pool 指针,不受影响)。
"""
if default_val is None:
return None
if default_val.kind() == ast.ASTKind.List:
return self._deep_copy_list_ast(default_val)
if default_val.kind() != ast.ASTKind.Constant:
return None
src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val)
dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(
stdlib.malloc(ast.Constant.__sizeof__()))
if dst_c is None:
return None
string.memset(dst_c, 0, ast.Constant.__sizeof__())
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
vt_ptr: t.CVoid | t.CPtr = t.CVoid(
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
c.DerefAs(dst_c, vt_ptr)
# 拷贝位置字段(报错定位用)
dst_c.lineno = src_c.lineno
dst_c.col_offset = src_c.col_offset
dst_c.end_lineno = src_c.end_lineno
dst_c.end_col_offset = src_c.end_col_offset
# 拷贝常量值(int/float/str/bool 由 const_kind 区分)
dst_c.const_kind = src_c.const_kind
dst_c.int_val = src_c.int_val
dst_c.float_val = src_c.float_val
if src_c.str_val is not None:
s_len: t.CSizeT = string.strlen(src_c.str_val)
s_copy: str = stdlib.malloc(s_len + 1)
if s_copy is not None:
string.strcpy(s_copy, src_c.str_val)
dst_c.str_val = s_copy
return (ast.AST | t.CPtr)(dst_c)
def _deep_copy_list_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
"""深拷贝 List 节点(列表字面量默认值)到 stdlib,跨 1b reset 存活。
elts 容器手动在 stdlib 构造(list 的 __pool__ 置 None:深拷贝的 elts
只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。
元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。
"""
src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val)
dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)(
stdlib.malloc(ast.List.__sizeof__()))
if dst_l is None:
return None
string.memset(dst_l, 0, ast.List.__sizeof__())
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
vt_l: t.CVoid | t.CPtr = t.CVoid(
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
c.DerefAs(dst_l, vt_l)
# 拷贝位置字段与 ctx
dst_l.lineno = src_l.lineno
dst_l.col_offset = src_l.col_offset
dst_l.end_lineno = src_l.end_lineno
dst_l.end_col_offset = src_l.end_col_offset
dst_l.ctx = src_l.ctx
# 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器
src_elts_l: list[ast.AST | t.CPtr] | t.CPtr = src_l.elts
if src_elts_l is not None:
cnt_l: t.CSizeT = len(src_elts_l)
lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(
stdlib.malloc(list[ast.AST | t.CPtr].__sizeof__()))
if lst_copy_l is not None:
string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__())
lst_copy_l.__count__ = cnt_l
lst_copy_l.__capacity__ = cnt_l
lst_copy_l.__elem_size__ = 8
lst_copy_l.__pool__ = None
data_l: t.CVoid | t.CPtr = stdlib.malloc(cnt_l * 8)
if data_l is not None:
string.memset(data_l, 0, cnt_l * 8)
lst_copy_l.__data__ = data_l
li_l: t.CSizeT
for li_l in range(cnt_l):
elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l)
if elem_src_l is not None:
elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(elem_src_l)
if elem_dst_l is not None:
slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)(
t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr))
slot_l[0] = elem_dst_l
dst_l.elts = lst_copy_l
return (ast.AST | t.CPtr)(dst_l)
def get_struct_count(self) -> int:
"""返回当前已注册的结构体数量"""
return self.StructCount
def find_struct(self, name: str) -> HandlesStruct.StructEntry | t.CPtr:
"""按类名查找结构体,返回 StructEntry 或 None
支持模块限定名(如 "HT.Translator"):
第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退
"""
if name is None or self.StructTable is None:
return None
# 第一遍:精确匹配
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
if self.StructCount < 0 or self.StructCount > 200000:
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT")
stdlib.exit(1)
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
# 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator")
dot_pos: str = string.strrchr(name, '.')
if dot_pos is not None:
class_name: str = dot_pos + 1
if class_name is not None and class_name[0] != '\0':
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
return entry
return None
def find_struct_by_module(self, name: str, sha1: str) -> HandlesStruct.StructEntry | t.CPtr:
"""按类名 + SHA1 查找结构体,返回 StructEntry 或 None
SHA1 非 None 时:精确匹配 name+sha1,未找到返回 None(不回退,避免跨模块同名找错)
SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个
"""
if name is None or self.StructTable is None:
return None
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
if self.StructCount < 0 or self.StructCount > 200000:
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
stdlib.exit(1)
if sha1 is not None:
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
return entry
# SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry)
# 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路
return None
# 无 SHA1:按类名查找第一个
return self.find_struct(name)
def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> HandlesStruct.StructEntry | t.CPtr:
"""按类型指针查找结构体(指针值比较),返回 StructEntry 或 None
注意: 不能用 `entry.Ty is struct_ty` 的 is 比较——TPV 编译 is 时会触发
translate_compare 的类型安全检查(is_ptr_type/TypePrint 递归打印),
对悬空 entry.Ty(1b 泛型特化类注册后被 reset 回收的 pool 指针)解引用崩溃。
改用 t.CUInt64T 纯指针值比较,不解引用任何内容。
"""
if struct_ty is None or self.StructTable is None:
return None
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
if self.StructCount < 0 or self.StructCount > 200000:
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT")
stdlib.exit(1)
st_val: t.CUInt64T = t.CUInt64T(struct_ty)
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if t.CUInt64T(entry.Ty) == st_val:
return entry
return None
def lookup_field(self, struct_ty: llvmlite.LLVMType | t.CPtr,
field_name: str) -> HandlesStruct.FieldEntry | t.CPtr:
"""按结构体类型和字段名查找字段信息
两遍查找策略(跨模块同名类冲突的根本修复):
第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry)
第二遍: 名称回退(is 未匹配时,按类名/strstr 匹配,字段未找到时 continue)
"""
if struct_ty is None or field_name is None or self.StructTable is None:
return None
# ============================================================
# 两遍查找策略(跨模块同名类冲突的根本修复):
#
# 第一遍: 用类型指针 is 身份比较(最高优先级)
# - is 匹配唯一确定 entry,字段未找到直接返回 None
# - 规避联合类型 == BUG,且不受遍历顺序影响
#
# 第二遍: 名称回退(is 未匹配到任何 entry 时才执行)
# - 用于未注册类型或 is 不可靠的场景
# - 名称匹配但字段未找到时 continue(继续检查其他同名 entry)
# ============================================================
# 第一遍: is 身份比较(用 t.CUInt64T 指针值比较,避免 is 编译路径解引用悬空 Ty)
st_lk: t.CUInt64T = t.CUInt64T(struct_ty)
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if t.CUInt64T(entry.Ty) == st_lk:
# is 匹配,查找字段
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# is 匹配但字段未找到(类型唯一确定,无需继续)
return None
# 第二遍: 名称回退(is 未匹配到)
ty_name: str = self._extract_struct_name(struct_ty)
if ty_name is not None:
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
matched: int = 0
if string.strcmp(entry.Name, ty_name) == 0:
matched = 1
elif string.strstr(ty_name, entry.Name) is not None:
matched = 1
if matched != 0:
# 查找字段
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# 名称匹配但字段未找到,继续检查其他同名 entry(跨模块同名)
continue
# 所有条目都未匹配
return None
def lookup_field_by_class(self, class_name: str,
field_name: str,
sha1: str = None) -> HandlesStruct.FieldEntry | t.CPtr:
"""按类名和字段名查找字段信息
优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个
"""
if class_name is None or field_name is None:
return None
# 优先用 SHA1 匹配(跨模块同名类区分)
# 支持模块限定名:class_name 可能是 "HT.Translator",entry.Name 是 "Translator"
# 先精确匹配,失败后用 strrchr 提取类名部分回退匹配
if sha1 is not None:
sha1_matched: int = 0
# 计算类名回退部分("HT.Translator" → "Translator")
bare_name: str = class_name
dot_pos_lfbc: str = string.strrchr(class_name, '.')
if dot_pos_lfbc is not None:
bare_name = dot_pos_lfbc + 1
if bare_name is None or bare_name[0] == '\0':
bare_name = class_name
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
# 精确匹配或类名回退匹配
name_match: int = 0
if string.strcmp(entry.Name, class_name) == 0:
name_match = 1
elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0:
name_match = 1
if name_match != 0:
if entry.ModuleSha1 is not None \
and string.strcmp(entry.ModuleSha1, sha1) == 0:
sha1_matched = 1
# SHA1 + 类名匹配,查找字段
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None and fe.Name is not None \
and string.strcmp(fe.Name, field_name) == 0:
return fe
return None
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = self.find_struct(class_name)
if entry is None:
# 诊断:目标类未注册
fb_lfbc: str = VLogger.fmt_buf()
if fb_lfbc is not None:
viperlib.snprintf(fb_lfbc, 1024,
"lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)",
class_name, self.StructCount)
VLogger.error(fb_lfbc, "STRUCT")
return None
# 先查找字段(诊断/error 之前返回,否则 error 立即退出导致查找永远失败)
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# 诊断:找到结构体但字段确实未找到,打印字段表
# 注意:VLogger.error 会立即退出进程,字段表须在 error 之前用 warning 打印
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None:
fb_fn: str = VLogger.fmt_buf()
if fb_fn is not None:
if fe.Name is not None:
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name)
else:
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi)
VLogger.warning(fb_fn, "STRUCT")
fb_fields: str = VLogger.fmt_buf()
if fb_fields is not None:
viperlib.snprintf(fb_fields, 1024,
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到",
class_name, entry.FieldCount, field_name)
VLogger.error(fb_fields, "STRUCT")
# 诊断:找到结构体但字段未找到
return None
def get_struct_type(self, class_name: str) -> llvmlite.LLVMType | t.CPtr:
"""按类名获取结构体的 LLVM 类型"""
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
if entry is not None:
return entry.Ty
return None
def get_field_by_index(self, class_name: str,
idx: int) -> HandlesStruct.FieldEntry | t.CPtr:
"""按类名和字段索引获取字段信息"""
if class_name is None:
return None
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
if entry is None:
return None
if idx < 0 or idx >= entry.FieldCount:
return None
return self._get_field_entry(entry, idx)
def struct_has_defaults(self, class_name: str) -> int:
"""检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无"""
if class_name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
if entry is None:
return 0
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None and fe.DefaultVal is not None:
return 1
return 0
def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
if val is None or val.Ty is None:
return None
# 嵌套 match:先匹配 Ptr,再在 case 块内匹配 pointee 是否为 Struct
match val.Ty:
case llvmlite.LLVMType.Ptr(pointee):
match pointee:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return pointee
case _:
return None
case _:
return None
def mark_as_union(self, name: str) -> int:
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.IsUnion = 1
return 1
def is_union_by_name(self, name: str) -> int:
"""按类名检查是否为联合体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.IsUnion
def is_union_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""按类型指针检查是否为联合体,返回 1=是 / 0=否
先尝试类型指针 == 比较,失败时回退到名称匹配
"""
if struct_ty is None or self.StructTable is None:
return 0
ty_name: str = self._extract_struct_name(struct_ty)
st_iu: t.CUInt64T = t.CUInt64T(struct_ty)
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Ty is not None:
matched: int = 0
if t.CUInt64T(entry.Ty) == st_iu:
matched = 1
elif ty_name is not None and entry.Name is not None:
if string.strcmp(entry.Name, ty_name) == 0:
matched = 1
elif string.strstr(ty_name, entry.Name) is not None:
matched = 1
if matched != 0:
return entry.IsUnion
return 0
def mark_as_oop(self, name: str) -> int:
"""标记已注册的结构体为 OOP,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.IsOOP = 1
return 1
def is_oop_by_name(self, name: str) -> int:
"""按类名检查是否为 OOP 结构体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.IsOOP
def mark_has_init(self, name: str) -> int:
"""标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.HasInit = 1
return 1
def has_init_by_name(self, name: str) -> int:
"""按类名检查是否有 __init__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.HasInit
def mark_has_new(self, name: str) -> int:
"""标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.HasNew = 1
return 1
def has_new_by_name(self, name: str) -> int:
"""按类名检查是否有 __new__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.HasNew
def get_class_name_by_type(self, pool: memhub.MemBuddy | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr) -> str:
"""按类型指针查找类名,返回类名字符串或 None"""
if struct_ty is None or self.StructTable is None:
return None
st_cn: t.CUInt64T = t.CUInt64T(struct_ty)
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if t.CUInt64T(entry.Ty) == st_cn:
return entry.Name
# 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配
# 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式)
ty_name: str = self._extract_struct_name(struct_ty)
if ty_name is not None:
for j in range(self.StructCount):
entry2: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(j)
if entry2 is not None and entry2.Name is not None:
# 构造 "SHA1.ClassName" 格式进行比较
entry2_sha1: str = entry2.ModuleSha1
if entry2_sha1 is not None:
full_nm: str = pool.alloc(128)
if full_nm is not None:
viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name)
if string.strcmp(full_nm, ty_name) == 0:
return entry2.Name
# 也直接比较类名(struct_ty 的 Name 可能无 SHA1 前缀)
if string.strcmp(entry2.Name, ty_name) == 0:
return entry2.Name
# 最后回退: strstr 检查包含关系
# ty_name 可能是 "SHA1.Counter",entry2.Name 是 "Counter"
if string.strstr(ty_name, entry2.Name) is not None:
return entry2.Name
return None
def _extract_struct_name(self, ty: llvmlite.LLVMType | t.CPtr) -> str:
"""从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct"""
if ty is None:
return None
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return name
case _:
return None
def mark_has_vtable(self, name: str) -> int:
"""标记结构体拥有虚表,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.HasVTable = 1
return 1
def has_vtable_by_name(self, name: str) -> int:
"""按类名检查是否有虚表,返回 1=有 / 0=无"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.HasVTable
def mark_novtable(self, name: str) -> int:
"""标记结构体为 NoVTable,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.IsNoVTable = 1
return 1
def is_novtable_by_name(self, name: str) -> int:
"""按类名检查是否为 NoVTable,返回 1=是 / 0=否"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.IsNoVTable
def set_parent_name(self, name: str, parent_name: str) -> int:
"""设置结构体的父类名,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.ParentName = parent_name
return 1
def set_parent_names(self, name: str, names_ptr: t.CSizeT | t.CPtr,
count: int) -> int:
"""设置结构体的父类名数组(stdlib 深拷贝,跨文件永久存活)"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
if names_ptr is None or count <= 0:
entry.ParentNames = None
entry.ParentCount = 0
return 1
if count > PARENT_MAX:
count = PARENT_MAX
arr: t.CSizeT | t.CPtr = stdlib.malloc(8 * count)
if arr is None:
return 0
for i in range(count):
addr: t.CSizeT = names_ptr[i]
arr[i] = 0
if addr != 0:
src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
if src is not None:
slen: t.CSizeT = string.strlen(src)
dup: str = stdlib.malloc(slen + 1)
if dup is not None:
string.strcpy(dup, src)
arr[i] = t.CSizeT(dup)
entry.ParentNames = t.CSizeT(arr)
entry.ParentCount = count
return 1
def get_parent_count(self, name: str) -> int:
"""获取父类数量(0=无父类,1=单继承,>1=多继承)"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.ParentCount
def get_parent_name_at(self, name: str, idx: int) -> str:
"""获取第 idx 个父类名,越界返回 None"""
if name is None or idx < 0:
return None
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None or entry.ParentNames is None:
return None
if idx >= entry.ParentCount:
return None
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
addr: t.CSizeT = parr[idx]
if addr == 0:
return None
return (str | t.CPtr)(t.CVoid(addr, t.CPtr))
def get_mro_chain(self, pool: memhub.MemBuddy | t.CPtr,
name: str) -> t.CSizeT | t.CPtr:
"""MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)"""
if pool is None or name is None:
return None
arr: t.CSizeT | t.CPtr = pool.alloc(8 * (MRO_MAX + 1))
if arr is None:
return None
stack: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
if stack is None:
return None
visited: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
if visited is None:
return None
stack_count: int = 0
out_count: int = 0
visit_count: int = 0
# 初始压入自身
stack[0] = t.CSizeT(name)
stack_count = 1
while stack_count > 0:
stack_count -= 1
cur_addr: t.CSizeT = stack[stack_count]
cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr))
if cur is None:
continue
# 已访问检查(线性搜索)
dup: int = 0
for vi in range(visit_count):
va: t.CSizeT = visited[vi]
if va != 0:
vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr))
if vn is not None and string.strcmp(vn, cur) == 0:
dup = 1
break
if dup != 0:
continue
# 加入结果与已访问集合
if out_count < MRO_MAX:
arr[out_count] = t.CSizeT(cur)
out_count += 1
if visit_count < MRO_MAX:
visited[visit_count] = t.CSizeT(cur)
visit_count += 1
# 父类逆序压栈(正向 range 计算逆序索引,保证声明顺序弹出)
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(cur)
if entry is not None and entry.ParentCount > 0 and entry.ParentNames is not None:
pc: int = entry.ParentCount
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
for pi2 in range(pc):
pi: int = pc - 1 - pi2
if stack_count < MRO_MAX:
stack[stack_count] = parr[pi]
stack_count += 1
# 末尾 0 结束
arr[out_count] = 0
return arr
def get_parent_name(self, name: str) -> str:
"""获取结构体的父类名,返回 None=无父类"""
if name is None:
return None
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return None
return entry.ParentName
def set_vtable_methods(self, name: str, methods: str, count: int) -> int:
"""设置虚表方法名数组,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
entry.VTableMethods = methods
entry.VTableMethodCount = count
return 1
def get_vtable_method_index(self, name: str, method_name: str) -> int:
"""获取方法在虚表中的索引,返回 -1=未找到"""
if name is None or method_name is None:
return -1
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None or entry.VTableMethods is None:
return -1
# VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组
# 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
for i in range(entry.VTableMethodCount):
mname_addr: t.CSizeT = methods_arr[i]
if mname_addr == 0:
continue
mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
if mname is not None and string.strcmp(mname, method_name) == 0:
return i
return -1
def get_vtable_method_count(self, name: str) -> int:
"""获取虚表方法数量"""
if name is None:
return 0
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return 0
return entry.VTableMethodCount
def get_vtable_method_name(self, name: str, idx: int) -> str:
"""获取虚表中第 idx 个方法名,返回 None=越界"""
if name is None or idx < 0:
return None
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None or entry.VTableMethods is None:
return None
if idx >= entry.VTableMethodCount:
return None
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
mname_addr: t.CSizeT = methods_arr[idx]
if mname_addr == 0:
return None
return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
def get_field_count(self, name: str) -> int:
"""获取结构体字段数量,返回 -1=未找到"""
if name is None:
return -1
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
if entry is None:
return -1
return entry.FieldCount
def ensure_struct_def_in_module(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用)
处理两种情况:
1. Struct 值类型:需要完整定义(供 alloca 分配空间)
2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明
"""
if ty is None or mod is None or pool is None:
return
# 指针类型:确保 pointee 至少有 opaque 声明
match ty:
case llvmlite.LLVMType.Ptr(pointee):
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
# 如果 pointee 是 Struct,递归复制完整定义
# (GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错)
if pointee is not None:
self.ensure_struct_def_in_module(pool, mod, pointee)
return
case _:
pass
# 获取结构体名称(非 Struct 类型返回 None)
sname: str = llvmlite.get_struct_name(ty)
if sname is None:
return
# 检查是否为跨模块引用(名称包含 '.')
if string.strchr(sname, 46) is None:
return # 非跨模块引用,无需处理
# 提取类名(第一个 '.' 之后的部分)
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]"
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]"
dot_pos: str = string.strchr(sname, '.')
if dot_pos is None:
return
class_name: str = dot_pos + 1
if class_name is None or class_name[0] == '\0':
return
# 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法)
total_len: t.CSizeT = string.strlen(sname)
class_name_len: t.CSizeT = string.strlen(class_name)
sha1_len: t.CSizeT = total_len - class_name_len - 1
sha1_buf: str = pool.alloc(32)
if sha1_buf is None:
return
# 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界
sha1_cp: t.CSizeT = sha1_len
if sha1_cp > 31:
sha1_cp = 31
string.strncpy(sha1_buf, sname, sha1_cp)
sha1_buf[sha1_cp] = '\0'
# 按类名 + SHA1 查找结构体定义
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf)
if entry is None:
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
entry = self.find_struct(class_name)
if entry is None:
return
if entry.Ty is None:
return
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
llvmlite.module_add_named_type(mod, pool, entry.Ty)
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME)
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
self._ensure_field_types_in_module(pool, mod, entry.Ty)
def _ensure_field_types_in_module(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""递归扫描类型树,确保值类型子结构体有完整定义"""
if ty is None or mod is None or pool is None:
return
# 嵌套 match 遍历类型树
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, sname):
# 遍历字段链表
if fields is not None:
fld: llvmlite.ParamNode | t.CPtr = fields
cnt_ef: t.CInt = 0
while fld is not None:
# 步数守卫:字段链表成环(内存损坏)导致无限遍历挂起
# (G3 LinkedNode.prepend 挂起候选),超限立即报错终止
cnt_ef += 1
if cnt_ef > 100000:
VLogger.error(
"字段链表疑似成环(_ensure_field_types_in_module),强制终止",
"STRUCT")
stdlib.exit(1)
if fld.Ty is not None:
# 值类型子结构体(如 FILETIME)需要完整定义
match fld.Ty:
case llvmlite.LLVMType.Struct(f2, fc2, n2):
self.ensure_struct_def_in_module(pool, mod, fld.Ty)
case _:
pass
self._ensure_field_types_in_module(pool, mod, fld.Ty)
fld = fld.Next
case llvmlite.LLVMType.Ptr(pointee):
# 指针类型:pointee 只需 opaque 声明,不需要完整定义
# 但如果 pointee 是 Struct,确保 opaque 声明存在
if pointee is not None:
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
case llvmlite.LLVMType.Array(elem_ty, acount):
# 数组类型:元素如果是值类型结构体,需要完整定义
if elem_ty is not None:
self._ensure_field_types_in_module(pool, mod, elem_ty)
case _:
pass
def get_field_name_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的字段名,返回 None=未设置"""
if fe is None:
return None
return fe.Name
def get_field_type_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""获取 FieldEntry 的字段类型,返回 None=未设置"""
if fe is None:
return None
return fe.Ty
def get_field_default_ptr(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> ast.AST | t.CPtr:
"""获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值"""
if fe is None:
return None
return fe.DefaultVal
def get_field_annot_class_name(self, fe: HandlesStruct.FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的原始类型注解类名,返回 None=未设置"""
if fe is None:
return None
return fe.AnnotClassName