Files
TransPyV/App/lib/core/Handles/HandlesStruct.py
2026-07-19 13:18:46 +08:00

976 lines
38 KiB
Python
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 llvmlite
import stdio
import ast
import hashtable
# ============================================================
# HandlesStruct - 结构体类型注册和字段查找
#
# 管理 class 定义的结构体类型信息:
# - 类名 → LLVM StructType
# - 字段名 → 字段索引和类型
#
# 使用全局数组存储,线性查找(结构体数量通常很少)
# ============================================================
STRUCT_MAX: t.CDefine = 512
FIELD_MAX: t.CDefine = 32
FIELD_NAME_MAX: t.CDefine = 64
# ============================================================
# FieldEntry - 字段信息条目
# ============================================================
@t.NoVTable
class FieldEntry:
Name: t.CChar | t.CPtr # 字段名(字符串)
Index: int # 字段在结构体中的索引
Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型
DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点None=无默认值)
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名str 别名在结构体字段中触发编译器 bug改用显式联合类型
# ============================================================
# StructEntry - 结构体注册条目
# ============================================================
@t.NoVTable
class StructEntry:
Name: t.CChar | t.CPtr # 类名
Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType
FieldCount: int # 字段数量
Fields: FieldEntry | t.CPtr # 字段数组FIELD_MAX 个槽位)
IsUnion: int # 1=联合体 / 0=普通结构体
IsOOP: int # 1=OOP结构体有方法 / 0=纯内存结构体
HasInit: int # 1=有__init__方法 / 0=无
HasNew: int # 1=有__new__方法 / 0=无
HasVTable: int # 1=有虚表 / 0=无虚表
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
ParentName: t.CChar | t.CPtr # 父类名None=无父类)
VTableMethodCount: int # 虚表中的方法数量
VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 strVTableMethodCount 个)
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1None=无 SHA1
# ============================================================
# 全局注册表(静态分配)
# ============================================================
_struct_table: StructEntry | t.CPtr = None
_struct_count: int = 0
# ============================================================
# 跨模块命名空间隔离per-file 结构体可见性
#
# _visible_structs: 当前文件可见的结构体名HashTableO(1) 查找)
# _strict_visibility: 1=严格模式(仅本地+import可见/ 0=宽松模式(全部可见)
#
# 每个文件翻译前调用 reset_visible_structs 重置
# ============================================================
_visible_structs: hashtable.HashTable | t.CPtr = None
_strict_visibility: int = 0
# ============================================================
# reset_visible_structs — 重置可见性状态(每个文件翻译前调用)
# ============================================================
def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int):
"""重置可见性状态(每个文件翻译前调用)
pool: 内存分配器(严格模式下创建 HashTable
strict: 1=严格模式用户文件0=宽松模式includes 文件)
"""
global _visible_structs
global _strict_visibility
_strict_visibility = strict
if strict != 0:
# 严格模式:创建新的 HashTable 记录可见结构体
_visible_structs = hashtable.HashTable(pool)
else:
# 宽松模式:全部可见,不需要 HashTable
_visible_structs = None
# ============================================================
# add_visible_struct — 添加可见结构体名
# ============================================================
def add_visible_struct(pool: memhub.MemBuddy | t.CPtr, name: str):
"""添加可见结构体名(类定义时和 from-import 时调用)"""
global _visible_structs
if name is None:
return
# 宽松模式:全部可见,无需记录
if _strict_visibility == 0:
return
if _visible_structs is None:
return
# 已存在则跳过HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配)
if _visible_structs.__contains__(name) != 0:
return
_visible_structs.set_int(name, 1)
# ============================================================
# is_struct_visible — 检查结构体是否在当前文件可见
# ============================================================
def is_struct_visible(name: str) -> int:
"""检查结构体是否可见,返回 1=可见 / 0=不可见"""
if _strict_visibility == 0:
return 1
if name is None or _visible_structs is None:
return 0
return _visible_structs.__contains__(name)
# ============================================================
# 初始化结构体注册表
# ============================================================
def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化结构体注册表,返回 1 成功"""
global _struct_table
global _struct_count
if _struct_table is not None:
return 1
entry_size: t.CSizeT = StructEntry.__sizeof__()
_struct_table = pool.alloc(entry_size * STRUCT_MAX)
if _struct_table is None:
return 0
string.memset(_struct_table, 0, entry_size * STRUCT_MAX)
_struct_count = 0
return 1
# ============================================================
# _get_struct_entry — 获取第 i 个 StructEntry 槽位
# ============================================================
def _get_struct_entry(i: int) -> StructEntry | t.CPtr:
"""获取第 i 个结构体条目"""
if _struct_table is None or i < 0 or i >= STRUCT_MAX:
return None
entry_size: t.CSizeT = StructEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(_struct_table) + i * entry_size
return (StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
# ============================================================
# _get_field_entry — 获取结构体中第 i 个 FieldEntry 槽位
# ============================================================
def _get_field_entry(struct_entry: StructEntry | t.CPtr, i: int) -> FieldEntry | t.CPtr:
"""获取结构体中第 i 个字段条目"""
if struct_entry is None or i < 0 or i >= FIELD_MAX:
return None
field_size: t.CSizeT = FieldEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size
return (FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
# ============================================================
# register_struct — 注册结构体类型
#
# 返回 StructEntry 指针,可用于添加字段
# ============================================================
def register_struct(pool: memhub.MemBuddy | t.CPtr,
name: str,
struct_ty: llvmlite.LLVMType | t.CPtr,
sha1: str = None) -> StructEntry | t.CPtr:
"""注册结构体类型,返回 StructEntry 指针
用类型指针去重is 比较),不用类名去重。
这样跨模块同名类可以共存,各自有独立的字段定义。
sha1 参数在注册时直接设置 ModuleSha1避免 set_struct_sha1 找错 entry
"""
if init_struct_table(pool) == 0:
return None
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
for i in range(_struct_count):
existing: StructEntry | t.CPtr = _get_struct_entry(i)
if existing is not None and existing.Ty is not None:
if existing.Ty is struct_ty:
return existing
if _struct_count >= STRUCT_MAX:
stdio.printf("[STRUCT] table full, cannot register %s\n", name)
return None
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
if entry is None:
return None
# 分配字段数组
field_size: t.CSizeT = FieldEntry.__sizeof__()
entry.Fields = pool.alloc(field_size * FIELD_MAX)
if entry.Fields is None:
return None
string.memset(entry.Fields, 0, field_size * FIELD_MAX)
# 复制类名
name_len: t.CSizeT = string.strlen(name)
name_buf: t.CChar | t.CPtr = pool.alloc(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
if sha1 is not None:
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
if sha1_buf is not None:
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
_struct_count += 1
return entry
# ============================================================
# set_struct_sha1 — 设置结构体所属模块的 SHA1
#
# 在翻译类定义时调用,记录类所属模块的 SHA1。
# 跨模块方法调用时(如 __before_init__/__init__通过 SHA1
# 构造正确的函数名("{sha1}.{ClassName}.{method}")。
# ============================================================
def set_struct_sha1(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: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return 0
# 复制 SHA1 字符串(避免悬空指针)
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
if sha1_buf is None:
return 0
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
return 1
# ============================================================
# get_struct_sha1 — 获取结构体所属模块的 SHA1
#
# 跨模块方法调用时使用,返回 None=无 SHA1本模块定义或无 SHA1
# ============================================================
def get_struct_sha1(class_name: str) -> str:
"""获取结构体所属模块的 SHA1返回 None=无 SHA1"""
if class_name is None or _struct_table is None:
return None
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return None
return entry.ModuleSha1
# ============================================================
# add_field — 向结构体添加字段信息
# ============================================================
def add_field(pool: memhub.MemBuddy | t.CPtr,
struct_entry: StructEntry | t.CPtr,
field_name: str,
field_ty: llvmlite.LLVMType | t.CPtr,
default_val: ast.AST | t.CPtr = None,
annot_class_name: t.CChar | t.CPtr = 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:
stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name)
return -1
idx: int = struct_entry.FieldCount
fe: FieldEntry | t.CPtr = _get_field_entry(struct_entry, idx)
if fe is None:
return -1
# 复制字段名
name_len: t.CSizeT = string.strlen(field_name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, field_name)
fe.Name = name_buf
fe.Index = idx
fe.Ty = field_ty
fe.DefaultVal = default_val
fe.AnnotClassName = annot_class_name
struct_entry.FieldCount = idx + 1
return idx
# ============================================================
# find_struct — 按类名查找结构体
# ============================================================
def find_struct(name: str) -> StructEntry | t.CPtr:
"""按类名查找结构体,返回 StructEntry 或 None"""
if name is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
# ============================================================
# find_struct_by_module — 按类名 + SHA1 查找结构体
#
# 跨模块同名类区分Phase B 重新翻译时,必须找到当前模块
# 注册的结构体(而非第一个同名条目),否则 struct type、
# 字段布局、GEP 索引全部错误。
# ============================================================
def find_struct_by_module(name: str, sha1: str) -> StructEntry | t.CPtr:
"""按类名 + SHA1 查找结构体,返回 StructEntry 或 None
SHA1 非 None 时:精确匹配 name+sha1未找到返回 None不回退避免跨模块同名找错
SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个
"""
if name is None or _struct_table is None:
return None
if sha1 is not None:
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _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 find_struct(name)
# ============================================================
# find_struct_by_type — 按类型指针查找结构体is 身份比较)
#
# 用于 _translate_oop_methods 等已有 struct_ty 的场景,
# 直接用指针身份定位 entry规避跨模块同名类 find_struct 找错的问题。
# ============================================================
def find_struct_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> StructEntry | t.CPtr:
"""按类型指针查找结构体is 比较),返回 StructEntry 或 None"""
if struct_ty is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
return entry
return None
# ============================================================
# lookup_field — 按结构体类型和字段名查找字段信息
# ============================================================
def lookup_field(struct_ty: llvmlite.LLVMType | t.CPtr,
field_name: str) -> FieldEntry | t.CPtr:
"""按结构体类型和字段名查找字段信息
两遍查找策略(跨模块同名类冲突的根本修复):
第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry
第二遍: 名称回退is 未匹配时,按类名/strstr 匹配,字段未找到时 continue
"""
if struct_ty is None or field_name is None or _struct_table is None:
return None
# ============================================================
# 两遍查找策略(跨模块同名类冲突的根本修复):
#
# 第一遍: 用类型指针 is 身份比较(最高优先级)
# - is 匹配唯一确定 entry字段未找到直接返回 None
# - 规避联合类型 == BUG且不受遍历顺序影响
#
# 第二遍: 名称回退is 未匹配到任何 entry 时才执行)
# - 用于未注册类型或 is 不可靠的场景
# - 名称匹配但字段未找到时 continue继续检查其他同名 entry
# ============================================================
# 第一遍: is 身份比较
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
# is 匹配,查找字段
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _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 = _extract_struct_name(struct_ty)
if ty_name is not None:
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _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: FieldEntry | t.CPtr = _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
# ============================================================
# lookup_field_by_class — 按类名和字段名查找字段信息
# ============================================================
def lookup_field_by_class(class_name: str,
field_name: str,
sha1: str = None) -> FieldEntry | t.CPtr:
"""按类名和字段名查找字段信息
优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个
"""
if class_name is None or field_name is None:
return None
# 优先用 SHA1 匹配(跨模块同名类区分)
if sha1 is not None:
sha1_matched: int = 0
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
sha1_matched = 1
# SHA1 + 类名匹配,查找字段
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _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
return None
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = find_struct(class_name)
if entry is None:
return None
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _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
return None
# ============================================================
# get_struct_type — 按类名获取结构体的 LLVM 类型
# ============================================================
def get_struct_type(class_name: str) -> llvmlite.LLVMType | t.CPtr:
"""按类名获取结构体的 LLVM 类型"""
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is not None:
return entry.Ty
return None
# ============================================================
# get_field_by_index — 按类名和字段索引获取字段信息
#
# 用于构造函数 Point(10, 20) 按顺序访问字段
# ============================================================
def get_field_by_index(class_name: str,
idx: int) -> FieldEntry | t.CPtr:
"""按类名和字段索引获取字段信息"""
if class_name is None:
return None
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return None
if idx < 0 or idx >= entry.FieldCount:
return None
return _get_field_entry(entry, idx)
# ============================================================
# struct_has_defaults — 检查结构体是否有任何带默认值的字段
# ============================================================
def struct_has_defaults(class_name: str) -> int:
"""检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无"""
if class_name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return 0
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.DefaultVal is not None:
return 1
return 0
# ============================================================
# get_struct_type_from_value — 从 LLVM Value 的类型推断结构体类型
#
# 如果 value 是 Ptr(Struct(...)),返回 Struct 类型
# ============================================================
def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Struct 类型(独立函数,规避嵌套 match 编译器 BUG"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return 1
case _:
return 0
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
if val is None or val.Ty is None:
return None
match val.Ty:
case llvmlite.LLVMType.Ptr(pointee):
if _is_struct_type(pointee) != 0:
return pointee
return None
case _:
return None
# ============================================================
# 联合体支持函数
# ============================================================
# ============================================================
# mark_as_union — 标记已注册的结构体为联合体
#
# 联合体用 Struct([Array(Int8, max_size)]) 表示,
# 注册时用 register_struct 注册类型,再用此函数标记 IsUnion=1
# ============================================================
def mark_as_union(name: str) -> int:
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsUnion = 1
return 1
# ============================================================
# is_union_by_name — 按类名检查是否为联合体
# ============================================================
def is_union_by_name(name: str) -> int:
"""按类名检查是否为联合体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsUnion
# ============================================================
# is_union_by_type — 按类型指针检查是否为联合体
# ============================================================
def is_union_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""按类型指针检查是否为联合体,返回 1=是 / 0=否
先尝试类型指针 == 比较,失败时回退到名称匹配
"""
if struct_ty is None or _struct_table is None:
return 0
ty_name: str = _extract_struct_name(struct_ty)
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
matched: int = 0
if entry.Ty is struct_ty:
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
# ============================================================
# OOP 支持函数
# ============================================================
# ============================================================
# mark_as_oop — 标记已注册的结构体为 OOP有方法
# ============================================================
def mark_as_oop(name: str) -> int:
"""标记已注册的结构体为 OOP返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsOOP = 1
return 1
# ============================================================
# is_oop_by_name — 按类名检查是否为 OOP 结构体
# ============================================================
def is_oop_by_name(name: str) -> int:
"""按类名检查是否为 OOP 结构体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsOOP
# ============================================================
# mark_has_init — 标记结构体拥有 __init__ 方法
# ============================================================
def mark_has_init(name: str) -> int:
"""标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasInit = 1
return 1
# ============================================================
# has_init_by_name — 按类名检查是否有 __init__ 方法
# ============================================================
def has_init_by_name(name: str) -> int:
"""按类名检查是否有 __init__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasInit
# ============================================================
# mark_has_new — 标记结构体拥有 __new__ 方法
# ============================================================
def mark_has_new(name: str) -> int:
"""标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasNew = 1
return 1
# ============================================================
# has_new_by_name — 按类名检查是否有 __new__ 方法
# ============================================================
def has_new_by_name(name: str) -> int:
"""按类名检查是否有 __new__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasNew
# ============================================================
# get_class_name_by_type — 按 LLVM 类型指针查找类名
#
# 用于方法调用:从变量类型 Ptr(Struct(...)) 反查类名,
# 以构造 ClassName.method_name 进行方法查找
# ============================================================
def get_class_name_by_type(pool: memhub.MemBuddy | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr) -> str:
"""按类型指针查找类名,返回类名字符串或 None"""
if struct_ty is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
return entry.Name
# 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配
# 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式)
ty_name: str = _extract_struct_name(struct_ty)
if ty_name is not None:
for j in range(_struct_count):
entry2: StructEntry | t.CPtr = _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: t.CChar | t.CPtr = 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
# ============================================================
# _extract_struct_name — 从 LLVMType 提取 Struct 变体的 Name 字段
# ============================================================
def _extract_struct_name(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
# ============================================================
# VTable 支持函数
# ============================================================
# ============================================================
# mark_has_vtable — 标记结构体拥有虚表
# ============================================================
def mark_has_vtable(name: str) -> int:
"""标记结构体拥有虚表,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasVTable = 1
return 1
# ============================================================
# has_vtable_by_name — 按类名检查是否有虚表
# ============================================================
def has_vtable_by_name(name: str) -> int:
"""按类名检查是否有虚表,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasVTable
# ============================================================
# mark_novtable — 标记结构体为 @t.NoVTable
# ============================================================
def mark_novtable(name: str) -> int:
"""标记结构体为 NoVTable返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsNoVTable = 1
return 1
# ============================================================
# is_novtable_by_name — 按类名检查是否为 NoVTable
# ============================================================
def is_novtable_by_name(name: str) -> int:
"""按类名检查是否为 NoVTable返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsNoVTable
# ============================================================
# set_parent_name — 设置父类名
# ============================================================
def set_parent_name(name: str, parent_name: str) -> int:
"""设置结构体的父类名,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.ParentName = parent_name
return 1
# ============================================================
# get_parent_name — 获取父类名
# ============================================================
def get_parent_name(name: str) -> str:
"""获取结构体的父类名,返回 None=无父类"""
if name is None:
return None
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return None
return entry.ParentName
# ============================================================
# set_vtable_methods — 设置虚表方法名数组
#
# methods 是一个 str 数组(每个元素是方法名字符串指针),
# count 是方法数量。数组直接引用,不复制。
# ============================================================
def set_vtable_methods(name: str, methods: t.CChar | t.CPtr, count: int) -> int:
"""设置虚表方法名数组,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.VTableMethods = methods
entry.VTableMethodCount = count
return 1
# ============================================================
# get_vtable_method_index — 获取方法在虚表中的索引
#
# 在 VTableMethods 数组中查找方法名,返回索引(-1=未找到)
# ============================================================
def get_vtable_method_index(name: str, method_name: str) -> int:
"""获取方法在虚表中的索引,返回 -1=未找到"""
if name is None or method_name is None:
return -1
entry: StructEntry | t.CPtr = 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
# ============================================================
# get_vtable_method_count — 获取虚表方法数量
# ============================================================
def get_vtable_method_count(name: str) -> int:
"""获取虚表方法数量"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.VTableMethodCount
# ============================================================
# get_vtable_method_name — 获取虚表中第 idx 个方法名
#
# 返回方法名字符串指针None=越界或未设置
# ============================================================
def get_vtable_method_name(name: str, idx: int) -> str:
"""获取虚表中第 idx 个方法名,返回 None=越界"""
if name is None or idx < 0:
return None
entry: StructEntry | t.CPtr = 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))
# ============================================================
# get_field_count — 获取结构体字段数量(访问器,绕过 stub 类型限制)
# ============================================================
def get_field_count(name: str) -> int:
"""获取结构体字段数量,返回 -1=未找到"""
if name is None:
return -1
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return -1
return entry.FieldCount
# ============================================================
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
# ============================================================
def get_field_name_ptr(fe: FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的字段名,返回 None=未设置"""
if fe is None:
return None
return fe.Name
# ============================================================
# get_field_type_ptr — 获取 FieldEntry 的字段类型指针(访问器)
# ============================================================
def get_field_type_ptr(fe: FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""获取 FieldEntry 的字段类型,返回 None=未设置"""
if fe is None:
return None
return fe.Ty
# ============================================================
# get_field_default_ptr — 获取 FieldEntry 的默认值 AST 指针(访问器)
# ============================================================
def get_field_default_ptr(fe: FieldEntry | t.CPtr) -> ast.AST | t.CPtr:
"""获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值"""
if fe is None:
return None
return fe.DefaultVal
# ============================================================
# get_field_annot_class_name — 获取 FieldEntry 的注解类名(访问器)
# ============================================================
def get_field_annot_class_name(fe: FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的原始类型注解类名,返回 None=未设置"""
if fe is None:
return None
return fe.AnnotClassName