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

3717 lines
176 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.StubMerger as StubMerger
# ============================================================
# ClassGenMixin - 类定义/泛型特化/vtable 生成 Mixin(对象化 P5-2)
#
# 从 HandlesClassDef.vp 迁移:模块级纯函数(trans 首参)→ 类方法;
# 全局状态(_g_method_meta_*/_renum_*/_spec_*/_g_vt_*)→ 本类字段。
#
# 迁移原则(与 P2-P5-1 一致,行为零变化):
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesType.xxx/HandlesStruct.xxx 等)保留模块前缀
# 3. HandlesClassDef.vp 原函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型
# 4. 多继承/vtable/泛型特化等 M5 成果逻辑零改动
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# 常量(与 HandlesClassDef 保持一致)
# ============================================================
ENUM_MEMBER_MAX_LOCAL: t.CDefine = 128
RENUM_CLASS_MAX: t.CDefine = 64
SCOPE_FUNCTION: t.CDefine = 1
RENUM_VARIANT_PER_CLASS: t.CDefine = 32
RENUM_FIELD_PER_VARIANT: t.CDefine = 16
# 方法元数据位掩码(与 HandlesClassDef.META_* 一致)
META_STATIC: t.CDefine = 1
META_CLASS: t.CDefine = 2
META_PROP_GETTER: t.CDefine = 4
META_PROP_SETTER: t.CDefine = 8
META_PROP_DELETER: t.CDefine = 16
META_MAX: t.CDefine = 512
META_KEY_LEN: t.CDefine = 128
# 泛型特化缓存容量上限(与 HandlesClassDef.SPEC_CACHE_MAX 一致)
SPEC_CACHE_MAX: t.CDefine = 512
# vtable 方法最大数量(与 HandlesClassDef.VTBL_METHOD_MAX 一致)
VTBL_METHOD_MAX: t.CDefine = 32
# ============================================================
# ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum
# ============================================================
@t.NoVTable
class ClassGenMixin:
"""类定义处理 Mixin(状态从 HandlesClassDef 全局变量迁入)"""
# --- 方法元数据表(原 _g_method_meta_keys/_g_method_meta_flags/_g_method_meta_count) ---
MethodMetaKeys: bytes
MethodMetaFlags: bytes
MethodMetaCount: int
# --- REnum 变体表(原 _renum_class_names/_renum_class_variant_counts/
# _renum_variant_names/_renum_variant_tags/_renum_class_count) ---
RenumClassNames: t.CSizeT | t.CPtr
RenumClassVariantCounts: t.CSizeT | t.CPtr
RenumVariantNames: t.CSizeT | t.CPtr
RenumVariantTags: t.CSizeT | t.CPtr
RenumClassCount: int
# --- REnum 字段别名表(原 _renum_alias_class/_renum_alias_field/
# _renum_alias_index/_renum_alias_count) ---
RenumAliasClass: t.CSizeT | t.CPtr
RenumAliasField: t.CSizeT | t.CPtr
RenumAliasIndex: t.CSizeT | t.CPtr
RenumAliasCount: int
# --- 泛型特化缓存(原 _spec_keys/_spec_names/_spec_count) ---
SpecKeys: t.CSizeT | t.CPtr
SpecNames: t.CSizeT | t.CPtr
SpecCount: int
# --- 泛型模板表(原 HandlesClassDef._generic_class_names/
# _generic_class_nodes/_generic_class_sha1s) ---
GenericClassNames: list[str] | t.CPtr
GenericClassNodes: list[ast.ClassDef | t.CPtr] | t.CPtr
GenericClassSha1s: list[str] | t.CPtr
# --- vtable 方法收集表(原 _g_vt_full_names/_g_vt_method_names/
# _g_vt_parent_sha1s/_g_vt_method_count) ---
VtFullNames: t.CSizeT | t.CPtr
VtMethodNames: t.CSizeT | t.CPtr
VtParentSha1s: t.CSizeT | t.CPtr
VtMethodCount: int
# ============================================================
# 以下方法由 P5-2 分簇迁移填充(函数体来自 HandlesClassDef.vp,
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
# ============================================================
def _is_cenum_base(self, base_node: ast.AST | t.CPtr) -> int:
"""检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否"""
if base_node is None:
return 0
k: int = base_node.kind()
# Name('CEnum') 形式(from t import CEnum)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "CEnum") == 0:
return 1
return 0
# Attribute(t.CEnum) 形式
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
if at.attr is not None and string.strcmp(at.attr, "CEnum") == 0:
return 1
return 0
return 0
def _is_enum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
"""检查 ClassDef 是否继承自 t.CEnum,返回 1=是 / 0=否"""
if cd is None or cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return 0
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_cenum_base(base_node) == 1:
return 1
return 0
def _is_cunion_base(self, base_node: ast.AST | t.CPtr) -> int:
"""检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否"""
if base_node is None:
return 0
k: int = base_node.kind()
# Name('CUnion') 形式(from t import CUnion)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "CUnion") == 0:
return 1
return 0
# Attribute(t.CUnion) 形式
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
if at.attr is not None and string.strcmp(at.attr, "CUnion") == 0:
return 1
return 0
return 0
def _is_union_class(self, cd: ast.ClassDef | t.CPtr) -> int:
"""检查 ClassDef 是否继承自 t.CUnion,返回 1=是 / 0=否"""
if cd is None or cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return 0
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_cunion_base(base_node) == 1:
return 1
return 0
def _is_crenum_base(self, base_node: ast.AST | t.CPtr) -> int:
"""检查 base 节点是否为 t.REnum,返回 1=是 / 0=否"""
if base_node is None:
return 0
k: int = base_node.kind()
# Name('REnum') 形式(from t import REnum)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "REnum") == 0:
return 1
return 0
# Attribute(t.REnum) 形式
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
if at.attr is not None and string.strcmp(at.attr, "REnum") == 0:
return 1
return 0
return 0
def _is_renum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
"""检查 ClassDef 是否继承自 t.REnum,返回 1=是 / 0=否"""
if cd is None or cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return 0
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_crenum_base(base_node) == 1:
return 1
return 0
def _has_decorator(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
deco_name: str) -> int:
"""检查 decorator_list 中是否有指定装饰器名"""
if decorator_list is None:
return 0
dn: t.CSizeT = decorator_list.__len__()
if dn == 0:
return 0
for di in range(dn):
deco: ast.AST | t.CPtr = decorator_list.get(di)
if deco is None:
continue
k: int = deco.kind()
# @t.NoVTable 形式(Attribute)
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco)
if at.attr is not None and string.strcmp(at.attr, deco_name) == 0:
# 检查 value 是 Name('t')
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if vn.id is not None and string.strcmp(vn.id, "t") == 0:
return 1
return 0
# @NoVTable 形式(Name,from t import NoVTable)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco)
if nm.id is not None and string.strcmp(nm.id, deco_name) == 0:
return 1
return 0
def _extract_func_meta(self, decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> int:
"""从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据"""
meta: int = 0
if decorator_list is None:
return meta
dn: t.CSizeT = decorator_list.__len__()
if dn == 0:
return meta
for di in range(dn):
deco: ast.AST | t.CPtr = decorator_list.get(di)
if deco is None:
continue
k: int = deco.kind()
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco)
if nm.id is not None:
if string.strcmp(nm.id, "staticmethod") == 0:
meta |= META_STATIC
elif string.strcmp(nm.id, "property") == 0:
meta |= META_PROP_GETTER
elif string.strcmp(nm.id, "classmethod") == 0:
meta |= META_CLASS
elif k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco)
if at.attr is not None and at.value is not None:
if at.value.kind() == ast.ASTKind.Name:
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
is_prop_name: int = 0
if vn.id is not None and string.strcmp(vn.id, "property") == 0:
is_prop_name = 1
# @property.setter 或 @x.setter/getter/deleter 都识别
if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \
or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0:
if string.strcmp(at.attr, "setter") == 0:
meta |= META_PROP_SETTER
elif string.strcmp(at.attr, "getter") == 0:
meta |= META_PROP_GETTER
elif string.strcmp(at.attr, "deleter") == 0:
meta |= META_PROP_DELETER
return meta
def register_method_meta(self, class_name: str, method_name: str,
meta: int) -> None:
"""注册方法元数据(幂等)"""
if class_name is None or method_name is None or meta == 0:
return
# 懒初始化
if self.MethodMetaKeys is None:
self.MethodMetaKeys = stdlib.malloc(META_MAX * META_KEY_LEN)
self.MethodMetaFlags = stdlib.malloc(META_MAX * 4)
if self.MethodMetaKeys is None or self.MethodMetaFlags is None:
return
string.memset(self.MethodMetaKeys, 0, META_MAX * META_KEY_LEN)
string.memset(self.MethodMetaFlags, 0, META_MAX * 4)
# 构造 key "ClassName.method"
cl_len: t.CSizeT = string.strlen(class_name)
mn_len: t.CSizeT = string.strlen(method_name)
key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2)
if key_buf is None:
return
viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name)
# 去重更新
i: int
for i in range(self.MethodMetaCount):
if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0:
flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(
t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr))
flags_ptr[0] = meta
stdlib.free(key_buf)
return
if self.MethodMetaCount < META_MAX:
string.strcpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN, key_buf)
flags_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(
t.CUInt64T(self.MethodMetaFlags) + self.MethodMetaCount * 4, t.CPtr))
flags_ptr2[0] = meta
self.MethodMetaCount += 1
stdlib.free(key_buf)
def lookup_method_meta(self, class_name: str, method_name: str) -> int:
"""查找方法元数据位掩码,返回 0=未注册或非装饰器方法"""
if class_name is None or method_name is None:
return 0
if self.MethodMetaKeys is None or self.MethodMetaCount <= 0:
return 0
cl_len: t.CSizeT = string.strlen(class_name)
mn_len: t.CSizeT = string.strlen(method_name)
key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2)
if key_buf is None:
return 0
viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name)
found: int = 0
i: int
for i in range(self.MethodMetaCount):
if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0:
flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(
t.CUInt64T(self.MethodMetaFlags) + i * 4, t.CPtr))
found = flags_ptr[0]
break
stdlib.free(key_buf)
return found
def _is_marker_base(self, base_name: str) -> int:
"""检查基类名是否为标记基类,返回 1=是 / 0=否
含 t.Struct:t.py 未定义 Struct 类(不被编译),`class X(t.Struct)`
的 Struct 只是"普通结构体"标记。若不当成标记基类,会被误判为真实父类:
- 自动启用虚表 → 结构体多出 i8* 槽位(与 TPC 的 {i32,i32} 布局不符)
- Phase A-pre(declare_only=1)父类延迟检查找不到 "Struct" → 类被延迟注册
→ forward_declare 时类型未注册 → 裸类形参退化为 i32 → 函数签名与
函数体 alloca(Ptr(struct))不一致 → llc 报 "'%p' defined with type
'i32' but expected 'ptr'"。
与 TPC(_resolve_base_kind 对 t.Struct 返回 None → 无父类)保持一致。
"""
if base_name is None:
return 0
if string.strcmp(base_name, "Object") == 0:
return 1
if string.strcmp(base_name, "CVTable") == 0:
return 1
if string.strcmp(base_name, "Exception") == 0:
return 1
if string.strcmp(base_name, "CEnum") == 0:
return 1
if string.strcmp(base_name, "Enum") == 0:
return 1
if string.strcmp(base_name, "CStruct") == 0:
return 1
if string.strcmp(base_name, "Struct") == 0:
return 1
if string.strcmp(base_name, "CUnion") == 0:
return 1
if string.strcmp(base_name, "REnum") == 0:
return 1
return 0
def _get_base_name(self, base_node: ast.AST | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = None) -> str:
"""从 base AST 节点提取基类名,返回 None=失败
对于 Subscript 节点,需要 pool 分配内存拼接特化名;
pool=None 时降级返回基类名(不含类型实参)
"""
if base_node is None:
return None
k: int = base_node.kind()
# Name(id) 形式
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
return nm.id
# Attribute(attr) 形式
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
return at.attr
# Subscript(value, slice) 形式 — 如 GSListNode[Value]
if k == ast.ASTKind.Subscript:
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node)
if sub is None or sub.value is None or sub.slice is None:
return None
# 提取基类名(如 "GSListNode")
base_nm: str = self._get_base_name(sub.value, pool)
if base_nm is None:
return None
# 提取类型实参名(如 "Value")
slice_k: int = sub.slice.kind()
arg_nm: str = None
if slice_k == ast.ASTKind.Name:
sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice)
arg_nm = sl_nm.id
# 如果无法提取类型实参,返回基类名(降级)
if arg_nm is None:
return base_nm
# 无 pool 时返回基类名(降级,无法拼接特化名)
if pool is None:
return base_nm
# 拼接特化名 "GSListNode[Value]"
base_len: t.CSizeT = string.strlen(base_nm)
arg_len: t.CSizeT = string.strlen(arg_nm)
total_len: t.CSizeT = base_len + arg_len + 3 # "[" + arg + "]" + NUL
mangled: str = pool.alloc(total_len)
if mangled is None:
return base_nm # 降级
mangled[0] = '\0'
string.strcat(mangled, base_nm)
string.strcat(mangled, "[")
string.strcat(mangled, arg_nm)
string.strcat(mangled, "]")
return mangled
return None
def _get_parent_class(self, cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> str:
"""获取 ClassDef 的真实父类名,返回 None=无真实父类"""
if cd is None or cd.bases is None:
return None
pool: memhub.MemBuddy | t.CPtr = None
if trans is not None:
pool = trans.Pool
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return None
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bname: str = self._get_base_name(base_node, pool)
if bname is not None and self._is_marker_base(bname) == 0:
return bname
return None
def _collect_parents(self, pool: memhub.MemBuddy | t.CPtr,
cd: ast.ClassDef | t.CPtr,
parents_buf: t.CSizeT | t.CPtr,
max_parents: int) -> int:
"""收集所有非 marker 父类名到 parents_buf,返回数量"""
if pool is None or cd is None or cd.bases is None or parents_buf is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
count: int = 0
for bi in range(bn):
if count >= max_parents:
break
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bname: str = self._get_base_name(base_node, pool)
if bname is not None and self._is_marker_base(bname) == 0:
parents_buf[count] = t.CSizeT(bname)
count += 1
return count
def _field_name_exists(self, names_buf: t.CSizeT | t.CPtr,
count: int, name: str) -> int:
"""检查字段名是否已在 names_buf 中(先声明父类优先,重复跳过)"""
if names_buf is None or name is None:
return 0
for fi in range(count):
addr: t.CSizeT = names_buf[fi]
if addr != 0:
existing: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
if existing is not None and string.strcmp(existing, name) == 0:
return 1
return 0
def _class_body_has_field(self, cd: ast.ClassDef | t.CPtr) -> int:
"""检查类体是否声明了字段(AnnAssign),0=纯方法/无字段类"""
if cd is None or cd.children is None:
return 0
cn: t.CSizeT = cd.children.__len__()
for ci in range(cn):
stmt: ast.AST | t.CPtr = cd.children.get(ci)
if stmt is None:
continue
if stmt.kind() == ast.ASTKind.AnnAssign:
return 1
return 0
def _trigger_base_specialization(self, trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr):
"""触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])"""
if trans is None or cd is None or cd.bases is None:
return
pool: memhub.MemBuddy | t.CPtr = trans.Pool
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bk: int = base_node.kind()
if bk != ast.ASTKind.Subscript:
continue
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node)
if sub is None or sub.value is None or sub.slice is None:
continue
# 提取泛型类名(如 "GSListNode")
gen_class_name: str = self._get_base_name(sub.value, pool)
if gen_class_name is None:
continue
# 跳过标记基类
if self._is_marker_base(gen_class_name) == 1:
continue
# 提取类型实参名(如 "Value")
slice_k: int = sub.slice.kind()
arg_nm: str = None
if slice_k == ast.ASTKind.Name:
sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice)
arg_nm = sl_nm.id
if arg_nm is None:
continue
# 构建 type_args 列表(elem_size=8:str 是指针,1 会导致双元素重叠损坏)
type_args: list[str] | t.CPtr = list[str](pool, 8)
if type_args is None:
continue
type_args.append(arg_nm)
# 触发特化(_specialize_generic_class 有缓存,重复调用安全)
self._specialize_generic_class(trans, gen_class_name, type_args)
def _has_any_func_cvtable(self, cd: ast.ClassDef | t.CPtr) -> int:
"""检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无"""
if cd is None or cd.children is None:
return 0
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
cn: t.CSizeT = children.__len__()
for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None:
continue
if stmt.kind() != ast.ASTKind.FunctionDef:
continue
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
if fd is None or fd.name is None:
continue
# 跳过构造函数
if string.strcmp(fd.name, "__init__") == 0:
continue
if string.strcmp(fd.name, "__before_init__") == 0:
continue
if string.strcmp(fd.name, "__new__") == 0:
continue
if fd.decorator_list is not None:
if self._has_decorator(fd.decorator_list, "CVTable") == 1:
return 1
return 0
def _should_method_be_virtual(self, cd: ast.ClassDef | t.CPtr,
fd: ast.FunctionDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""判断方法是否应该进入虚表,返回 1=包含 / 0=排除"""
if fd is None:
return 0
# 1. 检查函数级 @t.NoVTable(最高优先级,排除)
if fd.decorator_list is not None:
if self._has_decorator(fd.decorator_list, "NoVTable") == 1:
return 0
# 2. 检查函数级 @t.CVTable(明确包含)
if self._has_decorator(fd.decorator_list, "CVTable") == 1:
return 1
# 3. 检查类级别 @t.CVTable
if cd is not None and cd.decorator_list is not None:
if self._has_decorator(cd.decorator_list, "CVTable") == 1:
return 1
# 4. 检查继承关系
parent_name: str = self._get_parent_class(cd, trans)
if parent_name is not None:
# 用 SHA1 感知查找父类,规避跨模块同名找错
is_nvt: int = 0
if trans is not None:
p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
parent_name, trans.ModuleSha1)
if p_entry is None:
# 跨模块父类回退全局查找(父类注册在父模块 SHA1 下,如 linkedlist.LinkedNode),
# 与字段展平(1.5 节)的回退保持一致,否则父类 NoVTable 被误判为有虚表 → 子类插 vptr
# 导致子类布局比父类多一个指针,父类方法按无 vptr 布局操作错位
p_entry = HandlesStruct.find_struct(parent_name)
if p_entry is not None:
is_nvt = p_entry.IsNoVTable
else:
is_nvt = HandlesStruct.is_novtable_by_name(parent_name)
if is_nvt != 1:
# 继承链统一虚表:父类有虚表 → 方法进虚表;父类无虚表 → 静态方法。
# 与 _detect_vtable_status 规则一致,避免父类无 vptr 布局/子类有 vptr 的错位。
if p_entry is None:
return 1 # 父类信息未知,保守进虚表
if p_entry.HasVTable == 1:
return 1
return 0
# 5. 默认排除
return 0
def _detect_vtable_status(self, cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检测类是否应该启用虚表"""
if cd is None:
return 0
# 检查类装饰器
if cd.decorator_list is not None:
# @t.CVTable 优先级最高,直接启用
if self._has_decorator(cd.decorator_list, "CVTable") == 1:
return 1
# @t.NoVTable:类级别禁用,但检查函数级 @t.CVTable
if self._has_decorator(cd.decorator_list, "NoVTable") == 1:
return self._has_any_func_cvtable(cd)
# 检查是否有真实父类(继承自动启用 CVTable)
parent_name: str = self._get_parent_class(cd, trans)
if parent_name is not None:
# 用 SHA1 感知查找父类,规避跨模块同名找错
is_nvt: int = 0
if trans is not None:
p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
parent_name, trans.ModuleSha1)
if p_entry is None:
# 跨模块父类回退全局查找(同 _detect_vtable_status 的回退)
p_entry = HandlesStruct.find_struct(parent_name)
if p_entry is not None:
is_nvt = p_entry.IsNoVTable
else:
is_nvt = HandlesStruct.is_novtable_by_name(parent_name)
if is_nvt == 1:
# 父类是 NoVTable,检查函数级 @t.CVTable
return self._has_any_func_cvtable(cd)
# 继承链统一虚表:父类有虚表 → 子类启用;父类无虚表 → 子类静态。
# 若父类无 vtable 而子类有,父类方法按无 vptr 布局(self.field@0)操作
# 子类实例(有 vptr@0)会字段错位 → 运行时错误(父类方法读 vptr 当字段)。
if p_entry is None:
return 1 # 父类信息未知(跨模块/未注册),保守启用虚表
if p_entry.HasVTable == 1:
return 1
return 0
# 默认(无装饰器无继承),检查函数级 @t.CVTable
return self._has_any_func_cvtable(cd)
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
return llvmlite.Int32(pool)
return llvmlite.Int32(pool)
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
# 已注册则跳过
if HandlesEnum.is_enum_class(class_name) == 1:
return 0
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
fb: t.CChar | t.CPtr = 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 = children.__len__()
# 临时数组存储成员信息
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 = tgts.__len__()
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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 = children.__len__()
# 临时数组存储字段信息
field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
if field_names_buf is None or field_types_buf is None:
return 0
string.memset(field_names_buf, 0, 8 * 64)
string.memset(field_types_buf, 0, 8 * 64)
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 < 64:
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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 存活)
if trans._declare_only == 0:
union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 = children.__len__()
# 变体最多 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 = variant_children.__len__()
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 转换问题)
if vnm is not None and vnm.id is not None:
self._register_renum_field_alias(pool, class_name, vnm.id, field_idx + 1)
field_idx += 1
if field_idx > max_field_count:
max_field_count = field_idx
variant_count += 1
if variant_count == 0:
fb2: t.CChar | t.CPtr = 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):
field_pos: int = pos - 1 # 变体字段从位置 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 匹配不失效)
if trans._declare_only == 0:
renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 = stdlib.malloc(8 * RENUM_CLASS_MAX)
self.RenumClassVariantCounts = stdlib.malloc(8 * RENUM_CLASS_MAX)
self.RenumVariantNames = stdlib.malloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
self.RenumVariantTags = stdlib.malloc(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
# 检查是否已注册(避免重复注册)
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
# 注册类名
idx: int = self.RenumClassCount
self.RenumClassNames[idx] = t.CSizeT(class_name)
self.RenumClassVariantCounts[idx] = variant_count
# 遍历 children,提取嵌套变体类名并注册
cn: t.CSizeT = children.__len__()
tag: int = 0
for ci in range(cn):
if tag >= variant_count:
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
self.RenumVariantNames[name_offset] = t.CSizeT(vcd.name)
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):
"""注册 REnum 变体字段名别名到全局表"""
if pool is None or class_name is None or field_name is None:
return
if payload_idx < 1:
return
# 懒初始化表
if self.RenumAliasClass is None:
self.RenumAliasClass = pool.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasField = pool.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasIndex = pool.alloc(8 * RENUM_ALIAS_MAX)
if (self.RenumAliasClass is None or self.RenumAliasField is None
or self.RenumAliasIndex 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)
self.RenumAliasCount = 0
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
return
# 检查是否已注册(避免重复)— 用 CSizeT 指针值比较,避免 CSizeT→str 转换问题
cls_key: t.CSizeT = t.CSizeT(class_name)
fld_key: t.CSizeT = t.CSizeT(field_name)
for i in range(self.RenumAliasCount):
cls_existing: t.CSizeT = self.RenumAliasClass[i]
fld_existing: t.CSizeT = self.RenumAliasField[i]
if cls_existing == cls_key and fld_existing == fld_key:
return
idx: int = self.RenumAliasCount
self.RenumAliasClass[idx] = cls_key
self.RenumAliasField[idx] = fld_key
self.RenumAliasIndex[idx] = t.CSizeT(payload_idx)
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
# ============================================================
# 簇 C:泛型模板注册/特化(P5-2 第三阶段迁移,函数体来自
# HandlesClassDef.vp,逻辑零改动)
#
# 说明:
# - _generic_class_* 全局表已迁入 self.GenericClassNames/
# GenericClassNodes/GenericClassSha1s(P5-2 收尾)
# - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount
# ============================================================
def _is_generic_class(self, tp: list[str] | t.CPtr) -> int:
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否
接收 type_params 而非 cd,避免 cd.type_params 属性访问
因跨模块类型推断失败返回 None。
"""
if tp is None:
return 0
return 1
def _register_generic_template(self, pool: memhub.MemBuddy | t.CPtr,
cd: ast.ClassDef | t.CPtr,
module_sha1: str):
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)"""
if self.GenericClassNames is None:
self.GenericClassNames = list[str](pool, 8)
self.GenericClassNodes = list[ast.ClassDef | t.CPtr](pool, 8)
self.GenericClassSha1s = list[str](pool, 8)
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
names_local: list[str] | t.CPtr = self.GenericClassNames
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, cd.name) == 0:
return
self.GenericClassNames.append(cd.name)
self.GenericClassNodes.append(cd)
self.GenericClassSha1s.append(module_sha1)
# 诊断日志:确认泛型模板注册
fb_rg: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_rg is not None:
viperlib.snprintf(fb_rg, 1024, "注册泛型模板: %s (module=%s)", cd.name, module_sha1)
VLogger.info(fb_rg, "SPEC")
def _find_generic_template(self, class_name: str) -> ast.ClassDef | t.CPtr:
"""查找泛型类模板,返回 ClassDef 节点或 None"""
if self.GenericClassNames is None or class_name is None:
return None
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
names_local: list[str] | t.CPtr = self.GenericClassNames
nodes_local: list[ast.ClassDef | t.CPtr] | t.CPtr = self.GenericClassNodes
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, class_name) == 0:
node: ast.ClassDef | t.CPtr = nodes_local.get(i)
return node
return None
def _find_generic_template_sha1(self, class_name: str) -> str:
"""查找泛型类模板的来源模块 SHA1,未找到返回 None"""
if self.GenericClassNames is None or class_name is None:
return None
# 用局部变量接收 list,触发类型推断
names_local: list[str] | t.CPtr = self.GenericClassNames
sha1s_local: list[str] | t.CPtr = self.GenericClassSha1s
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, class_name) == 0:
sha1_val: str = sha1s_local.get(i)
return sha1_val
return None
def _mangle_generic_class_name(self, pool: memhub.MemBuddy | t.CPtr,
class_name: str,
type_args: list[str] | t.CPtr) -> str:
"""生成特化类名: list + [int] -> list[int]
分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出
"""
if class_name is None or type_args is None or pool is None:
return class_name
n: t.CSizeT = type_args.__len__()
if n == 0:
return class_name
# 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL
total_len: t.CSizeT = string.strlen(class_name) + 2 # "[" 和 "]"
i: t.CSizeT
for i in range(n):
if i > 0:
total_len += 1 # ","
ta: str = type_args.get(i)
if ta is not None:
total_len += string.strlen(ta)
total_len += 1 # NUL
# 分配新缓冲区
mangled: str = pool.alloc(total_len)
if mangled is None:
return class_name
mangled[0] = '\0'
string.strcat(mangled, class_name)
string.strcat(mangled, "[")
for i in range(n):
if i > 0:
string.strcat(mangled, ",")
ta: str = type_args.get(i)
if ta is not None:
string.strcat(mangled, ta)
string.strcat(mangled, "]")
return mangled
def _clone_annotation(self, pool: memhub.MemBuddy | t.CPtr,
node: ast.AST | t.CPtr,
tp_names: list[str] | t.CPtr,
type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr:
"""拷贝类型注解表达式,替换类型参数 T 为具体类型名
tp_names: 类型参数名列表 ['T']
type_args: 类型实参名列表 ['int']
"""
if node is None:
return None
k: int = node.kind()
# Name: 可能是类型参数 T
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is not None:
n: t.CSizeT = tp_names.__len__() if tp_names is not None else 0
i: t.CSizeT
for i in range(n):
tpn: str = tp_names.get(i)
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
ta: str = type_args.get(i)
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
parsed_node: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, ta, nm.ctx)
return parsed_node
return ast.Name(pool, nm.id, nm.ctx)
return None
# Attribute: t.CPtr 等
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
new_value: ast.AST | t.CPtr = self._clone_annotation(pool, at.value, tp_names, type_args)
return ast.Attribute(pool, new_value, at.attr, at.ctx)
# BinOp: T | t.CPtr 等
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
new_left: ast.AST | t.CPtr = self._clone_annotation(pool, bop.left, tp_names, type_args)
new_right: ast.AST | t.CPtr = self._clone_annotation(pool, bop.right, tp_names, type_args)
return ast.BinOp(pool, new_left, bop.op, new_right)
# Subscript: list[int] 等
if k == ast.ASTKind.Subscript:
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
new_value2: ast.AST | t.CPtr = self._clone_annotation(pool, sub.value, tp_names, type_args)
new_slice: ast.AST | t.CPtr = self._clone_annotation(pool, sub.slice, tp_names, type_args)
return ast.Subscript(pool, new_value2, new_slice, sub.ctx)
# Tuple: (T, int) 等
if k == ast.ASTKind.Tuple:
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
new_elts: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8)
if tup.elts is not None:
tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
en: t.CSizeT = tup_elts.__len__()
ei: t.CSizeT
for ei in range(en):
el: ast.AST | t.CPtr = tup_elts.get(ei)
new_el: ast.AST | t.CPtr = self._clone_annotation(pool, el, tp_names, type_args)
if new_el is not None:
new_elts.append(new_el)
return ast.Tuple(pool, new_elts, tup.ctx)
# Constant: 默认值等
if k == ast.ASTKind.Constant:
cnst: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val,
cnst.str_val, cnst.lineno, cnst.col_offset)
# 其他: 直接引用(不拷贝)
return node
def _clone_arguments(self, pool: memhub.MemBuddy | t.CPtr,
args: ast.AST | t.CPtr,
tp_names: list[str] | t.CPtr,
type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr:
"""拷贝 Arguments 节点,替换 arg annotation 中的 T"""
if args is None:
return None
if args.kind() != ast.ASTKind.Arguments:
return args
old_args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args)
# 拷贝 args 列表,替换每个 Arg 的 annotation
new_arg_list: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8)
if old_args.args is not None:
old_arg_list: list[ast.AST | t.CPtr] | t.CPtr = old_args.args
an: t.CSizeT = old_arg_list.__len__()
ai: t.CSizeT
for ai in range(an):
arg_node: ast.AST | t.CPtr = old_arg_list.get(ai)
if arg_node is None:
continue
if arg_node.kind() == ast.ASTKind.Arg:
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_node)
new_anno: ast.AST | t.CPtr = self._clone_annotation(pool, ag.annotation, tp_names, type_args)
new_arg: ast.Arg | t.CPtr = ast.Arg(pool, ag.arg, new_anno)
new_arg_list.append(new_arg)
else:
new_arg_list.append(arg_node)
return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg,
old_args.defaults, old_args.kw_defaults)
def _clone_classdef_for_spec(self, pool: memhub.MemBuddy | t.CPtr,
cd: ast.ClassDef | t.CPtr,
spec_name: str,
tp_names: list[str] | t.CPtr,
type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr:
"""拷贝 ClassDef 节点用于泛型特化
- 替换类名为 spec_name
- 清除 type_params(特化后不是泛型类)
- 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T
- 方法体直接引用原始节点(通过 type_map 上下文处理 T)
"""
# 创建新 ClassDef(type_params=None 表示非泛型)
new_cd: ast.ClassDef | t.CPtr = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords,
cd.decorator_list, None)
# 拷贝 children
if cd.children is not None:
cd_children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
cn: t.CSizeT = cd_children.__len__()
ci: t.CSizeT
for ci in range(cn):
child: ast.AST | t.CPtr = cd_children.get(ci)
if child is None:
continue
ck: int = child.kind()
if ck == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child)
new_target: ast.AST | t.CPtr = aa.target
new_anno2: ast.AST | t.CPtr = self._clone_annotation(pool, aa.annotation, tp_names, type_args)
new_value3: ast.AST | t.CPtr = aa.value
new_aa: ast.AnnAssign | t.CPtr = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple)
new_cd.append(new_aa)
elif ck == ast.ASTKind.FunctionDef:
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
new_args2: ast.AST | t.CPtr = self._clone_arguments(pool, fd.args, tp_names, type_args)
new_returns2: ast.AST | t.CPtr = self._clone_annotation(pool, fd.returns, tp_names, type_args)
new_fd: ast.FunctionDef | t.CPtr = ast.FunctionDef(pool, fd.name, new_args2,
fd.decorator_list, new_returns2, 0)
# 方法体直接引用原始节点
if fd.children is not None:
fd_children: list[ast.AST | t.CPtr] | t.CPtr = fd.children
bcn: t.CSizeT = fd_children.__len__()
bci: t.CSizeT
for bci in range(bcn):
body_stmt: ast.AST | t.CPtr = fd_children.get(bci)
if body_stmt is not None:
new_fd.append(body_stmt)
new_cd.append(new_fd)
else:
new_cd.append(child)
return new_cd
def _find_cached_spec(self, spec_key: str) -> str:
"""查找已缓存的特化名,未找到返回 None"""
if self.SpecKeys is None or spec_key is None:
return None
i: int
for i in range(self.SpecCount):
key_addr: t.CSizeT = self.SpecKeys[i]
if key_addr != 0:
k: str = (str | t.CPtr)(t.CVoid(key_addr, t.CPtr))
if k is not None and string.strcmp(k, spec_key) == 0:
name_addr: t.CSizeT = self.SpecNames[i]
if name_addr != 0:
return (str | t.CPtr)(t.CVoid(name_addr, t.CPtr))
return None
def _cache_spec(self, pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str):
"""缓存特化结果(stdlib 深拷贝存储,跨文件安全)"""
if spec_key is None or spec_name is None:
return
if self.SpecKeys is None:
self.SpecKeys = stdlib.malloc(SPEC_CACHE_MAX * 8)
self.SpecNames = stdlib.malloc(SPEC_CACHE_MAX * 8)
if self.SpecKeys is None or self.SpecNames is None:
return
string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8)
string.memset(self.SpecNames, 0, SPEC_CACHE_MAX * 8)
self.SpecCount = 0
if self.SpecCount >= SPEC_CACHE_MAX:
return
# 深拷贝字符串到 stdlib 区
key_len: t.CSizeT = string.strlen(spec_key)
name_len: t.CSizeT = string.strlen(spec_name)
key_copy: t.CChar | t.CPtr = stdlib.malloc(key_len + 1)
name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
if key_copy is None or name_copy is None:
return
string.strcpy(key_copy, spec_key)
string.strcpy(name_copy, spec_name)
self.SpecKeys[self.SpecCount] = t.CSizeT(key_copy)
self.SpecNames[self.SpecCount] = t.CSizeT(name_copy)
self.SpecCount += 1
def _merge_template_imports(self, trans: HT.Translator | t.CPtr,
template_sha1: str) -> None:
"""将模板模块的 imports 并入 trans._imported_modules(空格分隔)"""
if trans is None or template_sha1 is None:
return
tdeps: str = StubMerger.LookupIncludesDeps(template_sha1)
if tdeps is None or tdeps[0] == '\0':
return
cur: str = trans._imported_modules
if cur is None or cur[0] == '\0':
trans._imported_modules = tdeps
return
cur_len: t.CSizeT = string.strlen(cur)
td_len: t.CSizeT = string.strlen(tdeps)
merged: str = trans.Pool.alloc(cur_len + td_len + 2)
if merged is None:
return
string.strcpy(merged, cur)
merged[cur_len] = ' '
string.strcpy(merged + cur_len + 1, tdeps)
trans._imported_modules = merged
def _specialize_generic_class(self, trans: HT.Translator | t.CPtr,
class_name: str,
type_args: list[str] | t.CPtr) -> str:
"""特化泛型类,返回特化类名
1. 查找泛型模板
2. 生成特化名
3. 检查缓存
4. 拷贝 ClassDef 节点(替换类型注解中的 T)
5. 设置 type_map 上下文(用于方法体中的 T 替换)
6. 调用 translate_class_def 翻译特化类
7. 返回特化名
"""
if trans is None or class_name is None or type_args is None:
return None
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
ta_cnt_g: t.CSizeT = type_args.__len__()
ta_i_g: t.CSizeT
for ta_i_g in range(ta_cnt_g):
ta_raw_g: str = type_args.get(ta_i_g)
if ta_raw_g is not None:
ta_rsv_g: str = HandlesType.resolve_generic_type_name(ta_raw_g)
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
type_args.set(ta_i_g, ta_rsv_g)
pool: memhub.MemBuddy | t.CPtr = trans.Pool
# ============================================================
# 诊断输出:追踪 GSListNode 特化调用路径
# ============================================================
if string.strcmp(class_name, "GSListNode") == 0:
VLogger.debug("=== _specialize_generic_class ===", "SPEC")
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "class=%s module=%s", class_name, trans.ModuleSha1)
VLogger.debug(fb, "SPEC")
if type_args is not None:
ta_n: t.CSizeT = type_args.__len__()
ta_i: t.CSizeT
for ta_i in range(ta_n):
ta: str = type_args.get(ta_i)
if ta is not None:
if fb is not None:
viperlib.snprintf(fb, 1024, " type_arg[%d]=%s", ta_i, ta)
VLogger.debug(fb, "SPEC")
# 1. 查找泛型模板
template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name)
if template_cd is None:
if string.strcmp(class_name, "GSListNode") == 0:
VLogger.debug("template NOT FOUND, return None", "SPEC")
return None
# 2. 生成特化名
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args)
if spec_name is None:
return None
# 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前)
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
# Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define,
# 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。
# 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。
if trans._declare_only == 0:
pre_existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
# 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。
pre_existing.MethodsEmitted = 1
tp_names_pre: list[str] | t.CPtr = template_cd.type_params
spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
pool, template_cd, spec_name, tp_names_pre, type_args)
if spec_cd_pre is not None:
trans.GenericTypeParamNames = tp_names_pre
trans.GenericTypeArgs = type_args
HandlesType.set_generic_context(tp_names_pre, type_args)
saved_ms_pre: str = trans.ModuleSha1
saved_imp_pre: str = trans._imported_modules
template_sha1_pre: str = self._find_generic_template_sha1(class_name)
if template_sha1_pre is not None:
trans.ModuleSha1 = template_sha1_pre
self._merge_template_imports(trans, template_sha1_pre)
self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0)
trans.ModuleSha1 = saved_ms_pre
trans._imported_modules = saved_imp_pre
trans.GenericTypeParamNames = None
trans.GenericTypeArgs = None
HandlesType.clear_generic_context()
# 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突)
# 分配新缓冲区避免原地 strcat 溢出
sk_n: t.CSizeT = type_args.__len__()
sk_total: t.CSizeT = string.strlen(class_name) + 2 # "<" 和 ">"
sk_i: t.CSizeT
for sk_i in range(sk_n):
if sk_i > 0:
sk_total += 1 # ","
sk_ta: str = type_args.get(sk_i)
if sk_ta is not None:
sk_total += string.strlen(sk_ta)
sk_total += 1 # NUL
spec_key: str = pool.alloc(sk_total)
if spec_key is None:
return None
spec_key[0] = '\0'
string.strcat(spec_key, class_name)
string.strcat(spec_key, "<")
for sk_i in range(sk_n):
if sk_i > 0:
string.strcat(spec_key, ",")
sk_ta: str = type_args.get(sk_i)
if sk_ta is not None:
string.strcat(spec_key, sk_ta)
string.strcat(spec_key, ">")
cached: str = self._find_cached_spec(spec_key)
if cached is not None:
if string.strcmp(class_name, "GSListNode") == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "CACHE HIT, return cached=%s", cached)
VLogger.debug(fb, "SPEC")
return cached
# 4. 检查是否已注册(Phase B 重复特化)
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if existing is not None:
if string.strcmp(class_name, "GSListNode") == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "EXISTING registered, return spec_name=%s field_count=%d",
spec_name, existing.FieldCount)
VLogger.debug(fb, "SPEC")
self._cache_spec(pool, spec_key, spec_name)
return spec_name
# 预注册缓存(防止递归)
self._cache_spec(pool, spec_key, spec_name)
# 5. 拷贝 ClassDef 节点
tp_names: list[str] | t.CPtr = template_cd.type_params
spec_cd: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
pool, template_cd, spec_name, tp_names, type_args)
if spec_cd is None:
return None
# 6. 设置 type_map 上下文(用于方法体中的 T 替换)
trans.GenericTypeParamNames = tp_names
trans.GenericTypeArgs = type_args
HandlesType.set_generic_context(tp_names, type_args)
# 7. 翻译特化类
# 切换 trans.ModuleSha1 为泛型模板定义模块的 SHA1,
# 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀,
# 与调用端 get_struct_sha1(class_name) 查到的 SHA1 一致。
# 同时并入模板模块的 imports(见 _merge_template_imports 注释),
# 避免模板方法体内的跨模块调用被误报"模块未导入"。
saved_module_sha1: str = trans.ModuleSha1
saved_imported: str = trans._imported_modules
template_sha1: str = self._find_generic_template_sha1(class_name)
if template_sha1 is not None:
trans.ModuleSha1 = template_sha1
self._merge_template_imports(trans, template_sha1)
self.translate_class_def(trans, spec_cd)
# 恢复原始 ModuleSha1 与 imports
trans.ModuleSha1 = saved_module_sha1
trans._imported_modules = saved_imported
# 8. 清除 type_map 上下文
trans.GenericTypeParamNames = None
trans.GenericTypeArgs = None
HandlesType.clear_generic_context()
# 诊断输出:检查特化结果
if string.strcmp(class_name, "GSListNode") == 0:
result_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if result_entry is not None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "DONE spec_name=%s field_count=%d",
spec_name, result_entry.FieldCount)
VLogger.debug(fb, "SPEC")
# 打印每个字段的类型信息
ri: int
for ri in range(result_entry.FieldCount):
rfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
result_entry, ri)
if rfe is not None:
rfn: str = HandlesStruct.get_field_name_ptr(rfe)
rft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(rfe)
if fb is not None:
viperlib.snprintf(fb, 1024, " field[%d] name=%s type=%d",
ri, rfn if rfn is not None else "(null)",
t.CSizeT(rft) if rft is not None else 0)
VLogger.debug(fb, "SPEC")
else:
VLogger.debug("DONE but result NOT FOUND in struct table!", "SPEC")
return spec_name
# ============================================================
# translate_class_def — 翻译 class 定义(簇 D)
# ============================================================
def translate_class_def(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 class 定义,返回 0"""
if node is None or trans is None:
return 0
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
if cd is None or cd.name is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
class_name: str = cd.name
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前,
# 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类)
HandlesStruct.add_visible_struct(pool, class_name)
# 枚举类:交给 HandlesEnum 处理
if self._is_enum_class(cd) == 1:
return self._translate_enum_def(trans, cd)
# 联合体类:交给联合体处理
if self._is_union_class(cd) == 1:
return self._translate_union_def(trans, cd)
# REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局)
if self._is_renum_class(cd) == 1:
return self._translate_renum_def(trans, cd)
# 泛型类:存储为模板,不发射 IR(等实例化时特化)
# 用局部变量接收 cd.type_params,触发类型推断
tp_val: list[str] | t.CPtr = cd.type_params
if self._is_generic_class(tp_val) == 1:
self._register_generic_template(pool, cd, trans.ModuleSha1)
return 0
# 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
class_name, trans.ModuleSha1)
if existing is not None:
# BUG 5 方案1修改点2:existing 时字段完整性检查
# 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整)
# 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法),
# 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。
if existing.FieldCount == 0 and trans._declare_only == 0:
if self._class_body_has_field(cd) != 0:
# Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册)
HandlesType.fatal_error(
node,
f"结构体已注册但字段数为0,类: {class_name},可能注册不完整",
"InternalCompilerError")
# 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法
if existing.Ty is not None:
# Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty,
# 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1
# 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/
# self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。
# 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。
if trans._declare_only == 0:
old_name: t.CChar | t.CPtr = llvmlite.get_struct_name(existing.Ty)
if old_name is not None:
on_len: t.CSizeT = string.strlen(old_name)
on_copy: t.CChar | t.CPtr = stdlib.malloc(on_len + 1)
if on_copy is not None:
string.strcpy(on_copy, old_name)
c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct(
llvmlite.get_struct_fields(existing.Ty),
llvmlite.get_struct_fcount(existing.Ty),
on_copy))
# Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行)
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
# Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体
# Phase B(declare_only=0)时全量翻译方法体
if trans._declare_only == 1:
self._translate_oop_methods(trans, cd, existing.Ty, class_name, 1)
else:
self._translate_oop_methods(trans, cd, existing.Ty, class_name)
# SHA1 已在 register_struct 时设置,无需再补
return 0
# ============================================================
# 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])
# 必须在 _detect_vtable_status 和父类字段继承之前调用,
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None
# ============================================================
self._trigger_base_specialization(trans, cd)
# ============================================================
# VTable 检测:判断是否启用虚表
# ============================================================
has_vtable: int = self._detect_vtable_status(cd, trans)
parent_name: str = self._get_parent_class(cd, trans)
# 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用
parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.PARENT_MAX)
parents_count: int = 0
if parents_buf is not None:
parents_count = self._collect_parents(pool, cd, parents_buf, HandlesStruct.PARENT_MAX)
is_novtable_deco: int = 0
if cd.decorator_list is not None:
if self._has_decorator(cd.decorator_list, "NoVTable") == 1:
is_novtable_deco = 1
# ============================================================
# PhaseA 预注册延迟检查:父类未注册时延迟注册当前类
#
# 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass,
# 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前),
# field_count=1(不是0),field_count==0 静默返回不触发,
# AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。
# 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans
#
# 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。
# 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。
# Phase B(declare_only==0)不延迟,避免死锁。
# ============================================================
if trans._declare_only == 1 and parent_name is not None:
parent_check: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
parent_name, trans.ModuleSha1)
if parent_check is None:
parent_check = HandlesStruct.find_struct(parent_name)
if parent_check is None:
return 0
# ============================================================
# 1. 遍历 class body,收集字段信息
# ============================================================
# 用 CSizeT 数组存储指针值(64 位系统上 8 字节)
field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 64)
if field_names_buf is None or field_types_buf is None or field_defaults_buf is None:
return 0
if field_annot_buf is None:
return 0
string.memset(field_names_buf, 0, 8 * 64)
string.memset(field_types_buf, 0, 8 * 64)
string.memset(field_defaults_buf, 0, 8 * 64)
string.memset(field_annot_buf, 0, 8 * 64)
field_count: int = 0
# ============================================================
# 1.5 继承父类字段(字段展平)
# ============================================================
#
# 父类字段排在子类字段之前,结构体布局:
# [vtable_ptr?, parent_field1, ..., child_field1, ...]
# 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针)
# ============================================================
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先)
if parents_count > 0 and parents_buf is not None:
for pi in range(parents_count):
pname_addr: t.CSizeT = parents_buf[pi]
if pname_addr == 0:
continue
pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr))
if pname is None:
continue
# 用 SHA1 感知查找父类,规避跨模块同名找错
parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
pname, trans.ModuleSha1)
if parent_entry is None:
# 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin),
# find_struct_by_module 不回退全局查找,此处手动回退到 find_struct,
# 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败
parent_entry = HandlesStruct.find_struct(pname)
if parent_entry is None:
continue
pfc: int = parent_entry.FieldCount
for pfi in range(pfc):
pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
parent_entry, pfi)
if pfe is None:
continue
pfn: str = HandlesStruct.get_field_name_ptr(pfe)
if pfn is None:
continue
# 跳过父类的 vtable 指针字段
if string.strcmp(pfn, "__vtable__") == 0:
continue
# 多继承去重:字段名已存在跳过(先声明父类优先)
if self._field_name_exists(field_names_buf, field_count, pfn) != 0:
continue
if field_count < 64:
pft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(pfe)
pfd: ast.AST | t.CPtr = HandlesStruct.get_field_default_ptr(pfe)
pfa: str = HandlesStruct.get_field_annot_class_name(pfe)
field_names_buf[field_count] = t.CSizeT(pfn)
field_types_buf[field_count] = t.CSizeT(pft)
if pfd is not None:
field_defaults_buf[field_count] = t.CSizeT(pfd)
else:
field_defaults_buf[field_count] = 0
if pfa is not None:
stored_val: t.CSizeT = t.CSizeT(pfa)
field_annot_buf[field_count] = stored_val
else:
field_annot_buf[field_count] = 0
field_count += 1
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
return 0
cn: t.CSizeT = children.__len__()
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: continue
# AnnAssign(target=Name(id), annotation=type, value=...)
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
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
# 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码
# 避免类体中 list 字面量翻译失败(类体无 pool 变量上下文)
if string.strcmp(tgt.id, "__provides__") == 0:
continue
if string.strcmp(tgt.id, "__requires__") == 0:
continue
if string.strcmp(tgt.id, "__require_must__") == 0:
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:
# BUG 5 方案1修改点1:消除 i32 静默回退
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译
# 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱)
# 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8),
# 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name
# 供 translate_attribute 做后续 bitcast。
is_generic_sub: int = 0
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript:
is_generic_sub = 1
if is_generic_sub != 0:
# 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复
field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool))
else:
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
# 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功)
if trans._declare_only == 1:
return 0
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
type_name2: str = HandlesType.annotation_to_str(aa.annotation)
HandlesType.fatal_error(
aa,
f"'{type_name2}' is not defined",
"NameError")
return 0
# 存储到数组(指针转 CSizeT)
if field_count < 64:
diag_name_val: t.CSizeT = t.CSizeT(tgt.id)
field_names_buf[field_count] = diag_name_val
field_types_buf[field_count] = t.CSizeT(field_ty)
# 存储默认值 AST 指针(None=无默认值)
if aa.value is not None:
field_defaults_buf[field_count] = t.CSizeT(aa.value)
else:
field_defaults_buf[field_count] = 0
# 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体)
# BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]")
if aa.annotation is not None:
annot_cn: str = HandlesType.extract_class_name_from_annotation(
aa.annotation, trans._imported_modules, pool)
if annot_cn is not None:
diag_cn_val: t.CSizeT = t.CSizeT(annot_cn)
field_annot_buf[field_count] = diag_cn_val
else:
field_annot_buf[field_count] = 0
else:
field_annot_buf[field_count] = 0
field_count += 1
if field_count == 0:
# PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描),
# 导致子类无法继承父类字段 → field_count==0。
# 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。
if trans._declare_only == 1 and parent_name is not None:
return 0
# 无字段类(接口/标记类):不能整体跳过——类可能只有方法
# (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。
# 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "%s has no fields", class_name)
VLogger.info(fb_cf, "CLASS")
# ============================================================
# 2. 创建 LLVM StructType
# ============================================================
# 构建 ParamNode 链表
first_node: llvmlite.ParamNode | t.CPtr = None
prev_node: llvmlite.ParamNode | t.CPtr = None
total_field_count: int = field_count
# 如果有虚表,首字段添加 i8* vtable 指针
if has_vtable == 1:
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
if vtable_node is None:
fb_vn: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_vn is not None:
viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name)
VLogger.error(fb_vn, "CLASS")
return 0
string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__())
vtable_node.Ty = i8_ptr_ty
first_node = vtable_node
prev_node = vtable_node
total_field_count = field_count + 1
for fi in range(field_count):
fty_addr: t.CSizeT = field_types_buf[fi]
if fty_addr == 0:
continue
fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr))
# 创建 ParamNode
pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
if pnode is None:
continue
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
pnode.Ty = fty
if first_node is None:
first_node = pnode
if prev_node is not None:
prev_node.Next = pnode
prev_node = pnode
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
# 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续
# 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件
# reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。
type_name: str = class_name
if trans.ModuleSha1 is not None:
name_buf: t.CChar | t.CPtr = pool.alloc(64)
if name_buf is not None:
viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
type_name = name_buf
if trans._declare_only == 0 and type_name is not None:
tn_len: t.CSizeT = string.strlen(type_name)
tn_copy: t.CChar | t.CPtr = stdlib.malloc(tn_len + 1)
if tn_copy is not None:
string.strcpy(tn_copy, type_name)
type_name = tn_copy
# 创建 StructType(命名结构体)
struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name)
if struct_ty is None:
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name)
VLogger.error(fb_st, "CLASS")
return 0
# Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件
# 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType
# 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树
# 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty
# 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。
if trans._declare_only == 0:
st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, struct_ty)
if st_copy is not None:
struct_ty = st_copy
type_name = llvmlite.get_struct_name(struct_ty)
# 注册命名结构体到模块(输出 %"name" = type { ... } 定义行)
llvmlite.module_add_named_type(trans.Module, pool, struct_ty)
# 扫描字段类型,为跨模块结构体引用添加 opaque 声明
# 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque
for fi in range(field_count):
fty_addr_op: t.CSizeT = field_types_buf[fi]
if fty_addr_op == 0:
continue
fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr))
llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op)
# ============================================================
# 3. 注册到 HandlesStruct
# ============================================================
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
pool, class_name, struct_ty, trans.ModuleSha1)
if entry is None:
fb_re: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_re is not None:
viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name)
VLogger.error(fb_re, "CLASS")
return 0
# 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错)
if has_vtable == 1:
entry.HasVTable = 1
if is_novtable_deco == 1:
entry.IsNoVTable = 1
if parent_name is not None:
entry.ParentName = parent_name
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
if parents_count > 0 and parents_buf is not None:
HandlesStruct.set_parent_names(class_name, parents_buf, parents_count)
# 添加字段信息
# 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始
if has_vtable == 1:
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
HandlesStruct.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None)
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))
# 恢复默认值 AST 指针
fdef_addr: t.CSizeT = field_defaults_buf[fi]
fdef: ast.AST | t.CPtr = None
if fdef_addr != 0:
fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr))
# 恢复注解类名指针
fannot_addr: t.CSizeT = field_annot_buf[fi]
fannot: t.CChar | t.CPtr = None
if fannot_addr != 0:
fannot = (t.CChar | t.CPtr)(t.CVoid(fannot_addr, t.CPtr))
if fname is not None and fty2 is not None:
HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot)
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
if trans._declare_only == 1:
self._translate_oop_methods(trans, cd, struct_ty, class_name, 1)
return 0
# ============================================================
# 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__
# ============================================================
self._translate_oop_methods(trans, cd, struct_ty, class_name)
return 0
# ============================================================
# _vtable_strcat — 将 src 追加到 dst 末尾
# ============================================================
def _vtable_strcat(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None:
return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0:
return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号
# ============================================================
def _vtable_name_needs_quote(self, name: str) -> int:
"""检查 LLVM 标识符是否需要引号(以数字开头或含 '.')"""
if name is None:
return 0
if '0' <= name[0] <= '9':
return 1
for i in name:
if i == '.':
return 1
return 0
# ============================================================
# _format_func_type_str — 从 Function 对象生成函数类型字符串
#
# 格式: ret_ty (param1_ty, param2_ty, ...)
# 例如: void ({i32, i32}*, i32)
# ============================================================
def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
buf: t.CChar | t.CPtr, buf_size: t.CSizeT,
func: llvmlite.Function | t.CPtr) -> int:
"""从 Function 对象生成函数类型字符串"""
if buf is None or func is None or buf_size == 0:
return 0
buf[0] = '\0'
# 打印返回类型(使用访问器函数避免跨模块直接字段访问)
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_buf: t.CChar | t.CPtr = pool.alloc(128)
if ret_buf is not None and ret_ty is not None:
ret_buf[0] = '\0'
llvmlite.TypePrint(ret_buf, 128, ret_ty, pool)
self._vtable_strcat(buf, buf_size, ret_buf)
self._vtable_strcat(buf, buf_size, " (")
# 遍历参数(使用访问器函数避免跨模块直接字段访问)
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
first: int = 1
param_buf: t.CChar | t.CPtr = pool.alloc(128)
_pc: int = 0
while cur is not None:
_pc += 1
if _pc > 100:
break
if first == 0:
self._vtable_strcat(buf, buf_size, ", ")
if param_buf is not None:
param_buf[0] = '\0'
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur)
if param_ty is not None:
llvmlite.TypePrint(param_buf, 128, param_ty, pool)
self._vtable_strcat(buf, buf_size, param_buf)
cur = llvmlite.param_get_next(cur)
first = 0
self._vtable_strcat(buf, buf_size, ")")
return 1
# ============================================================
# _collect_vtable_methods — 收集类的虚方法信息
#
# 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致)
# 2. 收集当前类虚方法(跳过已继承的)
#
# 结果存入 self.VtFullNames/VtMethodNames/VtParentSha1s/VtMethodCount
# (原模块级 _g_vt_*),并设置 entry.VTableMethodCount /
# VTableMethods(stdlib 分配,供虚分派跨模块查询)。
#
# 返回 1=有虚方法 / 0=无方法或失败
# ============================================================
def _collect_vtable_methods(self, trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr,
class_name: str) -> int:
"""收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount"""
if trans is None or cd is None or class_name is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
# 懒导入(find_func_global 探测方法实际定义类用)
import lib.core.Handles.HandlesExprCall as HandlesExprCall
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
return 0
cn: t.CSizeT = children.__len__()
# 1. 收集虚方法信息
# stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活),
# 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。
full_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
method_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
# 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法)
method_parent_sha1s: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None:
return 0
string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX)
string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX)
string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX)
method_count: int = 0
# ============================================================
# 1.5 继承父类虚方法
#
# 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。
# 如果子类覆盖了方法,full_name 用子类的;否则用父类的。
# 用 SHA1 感知查找,规避跨模块同名 find_struct 找错
# ============================================================
vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
class_name, trans.ModuleSha1)
# 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先)
parent_count: int = HandlesStruct.get_parent_count(class_name)
if parent_count > 0:
for pi in range(parent_count):
pname: str = HandlesStruct.get_parent_name_at(class_name, pi)
if pname is None:
continue
# 查找父类 entry(优先同模块 SHA1 匹配)
vt_parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
pname, trans.ModuleSha1)
if vt_parent_entry is None:
# 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找
vt_parent_entry = HandlesStruct.find_struct(pname)
parent_vt_count: int = 0
if vt_parent_entry is not None:
parent_vt_count = vt_parent_entry.VTableMethodCount
if parent_vt_count > 0:
for pvi in range(parent_vt_count):
if method_count >= VTBL_METHOD_MAX:
break
pmethod_name: str = None
if vt_parent_entry is not None:
pmethod_name = HandlesStruct.get_vtable_method_name(pname, pvi)
if pmethod_name is None:
continue
# 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先)
if self._field_name_exists(method_names_buf, method_count, pmethod_name) != 0:
continue
# 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable
child_overrides: int = 0
child_nvt: int = 0
for ci2 in range(cn):
stmt2: ast.AST | t.CPtr = children.get(ci2)
if stmt2 is None:
continue
if stmt2.kind() != ast.ASTKind.FunctionDef:
continue
fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2)
if fd2 is not None and fd2.name is not None:
if string.strcmp(fd2.name, pmethod_name) == 0:
child_overrides = 1
# 检查子类覆盖方法是否标记 @t.NoVTable
if fd2.decorator_list is not None:
if self._has_decorator(fd2.decorator_list, "NoVTable") == 1:
child_nvt = 1
break
# 构造 full_name
# 子类覆盖且未标记 NoVTable → 用子类实现
# 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位)
#
# 多层继承修复: 直接父类可能只是继承而非定义该方法
# (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle),
# 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类,
# 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。
def_class: str = class_name
if child_overrides == 1 and child_nvt == 0:
def_class = class_name
else:
def_class = pname
# 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先)
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, pname)
mro_i: int = 1
while mro_ptr is not None and mro_ptr[mro_i] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr))
if anc is not None:
probe_buf: t.CChar | t.CPtr = pool.alloc(128)
if probe_buf is not None:
viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name)
if HandlesExprCall.find_func_global(probe_buf) is not None:
def_class = anc
break
mro_i += 1
pfname_buf: t.CChar | t.CPtr = pool.alloc(128)
if pfname_buf is not None:
viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name)
full_names_buf[method_count] = t.CSizeT(pfname_buf)
# 复制方法名(短名)
pmname_len: t.CSizeT = string.strlen(pmethod_name)
pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1)
if pmname_buf is not None:
string.strcpy(pmname_buf, pmethod_name)
method_names_buf[method_count] = t.CSizeT(pmname_buf)
# 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1)
if child_overrides == 1 and child_nvt == 0:
# 子类覆盖: 用当前模块 SHA1(保持 0)
method_parent_sha1s[method_count] = 0
else:
# 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确)
def_entry2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
def_class)
if def_entry2 is not None and def_entry2.ModuleSha1 is not None:
method_parent_sha1s[method_count] = t.CSizeT(def_entry2.ModuleSha1)
else:
method_parent_sha1s[method_count] = 0
method_count += 1
# 2. 收集当前类的虚方法(跳过已从父类继承的)
for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None:
continue
if stmt.kind() != ast.ASTKind.FunctionDef:
continue
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
if fd is None or fd.name is None:
continue
if method_count >= VTBL_METHOD_MAX:
break
mname: str = fd.name
# 跳过构造函数和特殊方法(不应放入虚表)
if string.strcmp(mname, "__init__") == 0:
continue
if string.strcmp(mname, "__before_init__") == 0:
continue
if string.strcmp(mname, "__new__") == 0:
continue
# 函数级装饰器过滤:判断方法是否应该进入虚表
if self._should_method_be_virtual(cd, fd, trans) == 0:
continue
# 检查是否已从父类继承(避免重复)
already_in_vt: int = 0
for mi in range(method_count):
exist_addr: t.CSizeT = method_names_buf[mi]
if exist_addr != 0:
exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr))
if exist_name is not None and string.strcmp(exist_name, mname) == 0:
already_in_vt = 1
break
if already_in_vt == 1:
continue
# 构造 full_name = "ClassName.method_name"
fname_buf: t.CChar | t.CPtr = pool.alloc(128)
if fname_buf is not None:
viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname)
full_names_buf[method_count] = t.CSizeT(fname_buf)
# 复制方法名
mname_len: t.CSizeT = string.strlen(mname)
mname_buf: t.CChar | t.CPtr = stdlib.malloc(mname_len + 1)
if mname_buf is not None:
string.strcpy(mname_buf, mname)
method_names_buf[method_count] = t.CSizeT(mname_buf)
method_count += 1
# 暂存结果(_generate_vtable 复用)
self.VtFullNames = full_names_buf
self.VtMethodNames = method_names_buf
self.VtParentSha1s = method_parent_sha1s
self.VtMethodCount = method_count
# 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪,
# 否则方法体内 self.虚方法 调用无法虚分派)
if vt_self_entry is not None and method_count > 0:
vt_self_entry.VTableMethodCount = method_count
vt_self_entry.VTableMethods = method_names_buf
if method_count == 0:
return 0
return 1
# ============================================================
# _generate_vtable — 生成 VTable 全局变量
#
# 1. 收集 class body 中所有 FunctionDef 作为虚方法
# 2. 构造 VTable 类型 { i8*, i8*, ... }
# 3. 构造初始化字符串 { i8* bitcast (...), ... }
# 4. 创建全局变量 @"SHA1.ClassName.vtable"
# 5. 存储虚方法名列表到 StructEntry
# ============================================================
def _generate_vtable(self, trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr,
class_name: str) -> int:
"""生成 VTable 全局变量"""
if trans is None or cd is None or class_name is None:
return 0
# 懒导入
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesExprCall as HandlesExprCall
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
# 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区)
# 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用)
if self._collect_vtable_methods(trans, cd, class_name) == 0:
return 0
full_names_buf: t.CSizeT | t.CPtr = self.VtFullNames
method_names_buf: t.CSizeT | t.CPtr = self.VtMethodNames
method_parent_sha1s: t.CSizeT | t.CPtr = self.VtParentSha1s
method_count: int = self.VtMethodCount
# 重新获取 entry(后续存储 VTableMethods 用)
vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
class_name, trans.ModuleSha1)
# 2. 构造 VTable 类型: { i8*, i8*, ..., i8* }
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
first_node: llvmlite.ParamNode | t.CPtr = None
tail_node: llvmlite.ParamNode | t.CPtr = None
for i in range(method_count):
pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_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
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None)
if vtable_ty is None:
return 0
# 3. 构造初始化字符串
# 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节,
# 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。
init_buf: t.CChar | t.CPtr = pool.alloc(16384)
if init_buf is None:
return 0
init_buf[0] = '\0'
self._vtable_strcat(init_buf, 16384, "{ ")
for i in range(method_count):
if i > 0:
self._vtable_strcat(init_buf, 16384, ", ")
full_name_addr: t.CSizeT = full_names_buf[i]
if full_name_addr == 0:
self._vtable_strcat(init_buf, 16384, "i8* null")
continue
full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr))
# 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling)
parent_sha1_addr: t.CSizeT = method_parent_sha1s[i]
if parent_sha1_addr != 0:
# 继承方法: 用父类模块 SHA1 做 mangling
parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr))
mangled_name: str = HandlesFunctions._mangle_name_with_sha1(parent_sha1, full_name)
# 从全局函数表查找(跨模块函数不在当前模块表中)
func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_global(full_name)
else:
# 当前类方法: 用当前模块 SHA1
mangled_name: str = HandlesFunctions._mangle_name(trans, full_name)
func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_table(
trans._funcs, trans._func_count, full_name)
# 当前模块表找不到时,回退到全局表
if func is None:
func = HandlesExprCall.find_func_global(full_name)
# func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。
# 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链
# 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。
# 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。
func_valid: int = 0
if func is not None:
if trans.Pool is not None:
# 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译
# 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍
# 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。
if parent_sha1_addr != 0:
func_valid = 0
elif trans.Pool._is_valid_ptr(func) != 0:
func_valid = 1
if func_valid == 0:
# 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。
ge: HandlesExprCall.FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_global(full_name)
if ge is not None and ge.TypeStr is not None:
self._vtable_strcat(init_buf, 16384, "i8* bitcast (")
self._vtable_strcat(init_buf, 16384, ge.TypeStr)
self._vtable_strcat(init_buf, 16384, "* @")
if self._vtable_name_needs_quote(mangled_name) != 0:
self._vtable_strcat(init_buf, 16384, "\"")
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, "\"")
else:
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, " to i8*)")
continue
self._vtable_strcat(init_buf, 16384, "i8* null")
continue
# 构造函数类型字符串
func_ty_buf: t.CChar | t.CPtr = pool.alloc(512)
if func_ty_buf is None:
self._vtable_strcat(init_buf, 16384, "i8* null")
continue
self._format_func_type_str(pool, func_ty_buf, 512, func)
# 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*)
self._vtable_strcat(init_buf, 16384, "i8* bitcast (")
self._vtable_strcat(init_buf, 16384, func_ty_buf)
self._vtable_strcat(init_buf, 16384, "* @")
if self._vtable_name_needs_quote(mangled_name) != 0:
self._vtable_strcat(init_buf, 16384, "\"")
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, "\"")
else:
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, " to i8*)")
self._vtable_strcat(init_buf, 16384, " }")
# 4. 构造 VTable 全局变量名
vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if vtable_name_buf is None:
return 0
viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name)
vtable_mangled: str = HandlesFunctions._mangle_name(trans, vtable_name_buf)
# 5. 创建全局变量
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
pool, vtable_mangled, vtable_ty)
if gv is None:
return 0
gv.Initializer = init_buf
gv.IsConstant = 1
gv.Linkage = "internal"
# 添加到模块
llvmlite.module_add_global(mod, gv)
# 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错)
if vt_self_entry is not None:
vt_self_entry.VTableMethods = method_names_buf
vt_self_entry.VTableMethodCount = method_count
return 0
# ============================================================
# _translate_oop_methods — 扫描 class body 中的方法并翻译
#
# 遍历 ClassDef.children,对每个 FunctionDef:
# - 标记 OOP(mark_as_oop)
# - 如果是 __init__,标记 has_init
# - 翻译方法(生成 SHA1.ClassName.method_name 函数)
# 翻译完所有方法后,生成 __before_init__ 函数
# ============================================================
def _translate_oop_methods(self, trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
mark_only: int = 0) -> int:
"""扫描 class body 中的方法并翻译,生成 __before_init__
mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体)
"""
if trans is None or cd is None or struct_ty is None or class_name is None:
return 0
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
return 0
cn: t.CSizeT = children.__len__()
has_method: int = 0
has_init: int = 0
has_new: int = 0
# 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错)
oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
# 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据
for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None:
continue
if stmt.kind() == ast.ASTKind.FunctionDef:
has_method = 1
fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
if fd_check is not None and fd_check.name is not None:
if string.strcmp(fd_check.name, "__init__") == 0:
has_init = 1
if string.strcmp(fd_check.name, "__new__") == 0:
has_new = 1
# 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。
# 此处(含 mark_only=1 的 struct 预注册阶段)注册,
# 确保其他模块在 App 文件翻译时能识别属性访问。
fd_meta: int = self._extract_func_meta(fd_check.decorator_list)
if fd_meta != 0:
self.register_method_meta(class_name, fd_check.name, fd_meta)
if has_method == 0:
# 子类没有自己的方法,但可能继承了父类的虚方法
# 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错
parent_name: str = None
if oop_entry is not None:
parent_name = oop_entry.ParentName
if parent_name is not None:
parent_vt_count: int = HandlesStruct.get_vtable_method_count(parent_name)
if parent_vt_count > 0:
has_method = 1 # 标记为有方法(继承的虚方法)
if has_method == 0:
return 0
# 标记为 OOP 结构体
if oop_entry is not None:
oop_entry.IsOOP = 1
if has_init != 0:
oop_entry.HasInit = 1
if has_new != 0:
oop_entry.HasNew = 1
# mark_only 模式:只设置标志,不翻译方法体
if mark_only != 0:
return 0
# 防重入:方法体翻译前先标记 MethodsEmitted=1。
# 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时,
# 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted
# 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。
if oop_entry is not None:
oop_entry.MethodsEmitted = 1
# 第二遍:翻译每个方法
# 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。
# 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的
# self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到
# VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回
# None),导致 calloc 永远返回 NULL。
oop_has_vt_pre: int = 0
if oop_entry is not None:
oop_has_vt_pre = oop_entry.HasVTable
if oop_has_vt_pre == 1:
self._collect_vtable_methods(trans, cd, class_name)
for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None:
continue
if stmt.kind() == ast.ASTKind.FunctionDef:
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
if fd is not None and fd.name is not None:
self._translate_method(trans, fd, struct_ty, class_name)
# 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount)
# 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount
# 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错
has_vt_flag: int = 0
if oop_entry is not None:
has_vt_flag = oop_entry.HasVTable
if has_vt_flag == 1:
self._generate_vtable(trans, cd, class_name)
# 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置)
self._generate_before_init(trans, struct_ty, class_name)
return 0
# ============================================================
# _translate_method — 翻译单个方法
#
# 生成: define <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...)
#
# self 参数处理:
# - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca)
# - 使 self.field 能通过 GEP 直接访问原始结构体
# ============================================================
def _translate_method(self, trans: HT.Translator | t.CPtr,
fd: ast.FunctionDef | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str) -> int:
"""翻译单个方法,返回 0"""
if trans is None or fd is None or struct_ty is None or class_name is None:
return 0
# 懒导入
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExprCall as HandlesExprCall
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
func_count: int = trans._func_count
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
method_name: str = fd.name
# 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter)
func_meta: int = self._extract_func_meta(fd.decorator_list)
# property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突
method_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if method_name_buf is None:
return 0
viperlib.snprintf(method_name_buf, 128, "%s", fd.name)
if func_meta & META_PROP_SETTER != 0:
string.strcat(method_name_buf, "$set")
elif func_meta & META_PROP_DELETER != 0:
string.strcat(method_name_buf, "$del")
method_name = method_name_buf
is_static_m: int = 0
is_class_m: int = 0
if func_meta & META_STATIC != 0:
is_static_m = 1
if func_meta & META_CLASS != 0:
is_class_m = 1
# 构建方法全名: ClassName.method_name
full_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if full_name_buf is None:
return 0
viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name)
full_name: str = full_name_buf
# SHA1 命名空间混淆
mangled_name: str = HandlesFunctions._mangle_name(trans, full_name)
# 推断返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = None
if fd.returns is not None:
ret_ty = HandlesType.resolve_annotation_type(
pool, fd.returns, imported_modules, from_imports, trans)
if ret_ty is None and fd.returns is not None:
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
ret_ty = llvmlite.Void(pool)
if ret_ty is None:
# __init__ 和 __before_init__ 返回 void
if string.strcmp(method_name, "__init__") == 0:
ret_ty = llvmlite.Void(pool)
# __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间)
elif string.strcmp(method_name, "__new__") == 0:
ret_ty = llvmlite.Ptr(pool, struct_ty)
else:
param_types_str: str = HandlesType.build_param_types_str(pool, fd.args)
ret_ty = HandlesType.infer_return_type(
pool, fd.children, param_types_str)
# 创建 LLVM 函数
func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, mangled_name, ret_ty)
if func is None:
return 0
# 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中;
# @staticmethod 无 self,param_count 为完整参数数)
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
md_defaults: t.CVoid | t.CPtr = None
md_default_count: int = 0
md_param_count: int = 0
md_args_node: ast.Arguments | t.CPtr = fd.args
if md_args_node is not None:
md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node)
if md_ags.args is not None:
md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args
if is_static_m != 0:
md_param_count = md_alist.__len__()
else:
md_param_count = md_alist.__len__() - 1
if md_ags.defaults is not None:
md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults
md_defaults = md_dlist
md_default_count = md_dlist.__len__()
# 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配)
max_funcs: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs,
md_defaults, md_default_count, md_param_count,
pool) == 0:
trans._func_count = func_count + 1
# 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过
# @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls)
if is_static_m == 0:
first_pname: str = "self"
if is_class_m != 0 and fd.args is not None:
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if fd_ags.args is not None and fd_ags.args.__len__() > 0:
fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0))
if fd_first_arg is not None and fd_first_arg.arg is not None:
first_pname = fd_first_arg.arg
first_pname_buf: t.CChar | t.CPtr = pool.alloc(32)
if first_pname_buf is not None:
viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname)
llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf)
# 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls)
args_node: ast.Arguments | t.CPtr = fd.args
if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = alist.__len__()
start_idx: int = 0
if is_static_m == 0:
start_idx = 1
for ai in range(start_idx, an):
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is not None and arg.arg is not None:
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct):按"对象即指针"引用传参。
# 若按 struct 值传参,self.Head = node 会取局部拷贝地址
# (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用)
HandlesExprCall.update_global_func_typestr(pool, full_name, func)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
return 0
# 创建方法专属 builder
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# 进入函数作用域
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过
# 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次
# 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃
if is_static_m == 0:
self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty)
if self_alloca is not None:
self_var_name: str = "self"
self_ssa_name: str = "%self"
if is_class_m != 0 and args_node is not None:
cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if cags.args is not None and cags.args.__len__() > 0:
cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0))
if cfirst is not None and cfirst.arg is not None:
self_var_name = cfirst.arg
self_ssa_name_buf: t.CChar | t.CPtr = pool.alloc(32)
if self_ssa_name_buf is not None:
viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg)
self_ssa_name = self_ssa_name_buf
HandlesVar.define_var(trans.SymTab, self_var_name, self_alloca)
# 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用)
HandlesVar.set_var_annot_class_name(trans.SymTab, self_var_name, class_name)
self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name)
llvmlite.build_store(func_builder, self_val, self_alloca)
# 为其他参数创建 alloca 并 store(与普通函数一致;
# @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数)
if args_node is not None:
ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags2.args is not None:
alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
an2: t.CSizeT = alist2.__len__()
start_idx2: int = 0
if is_static_m == 0:
start_idx2 = 1
for ai2 in range(start_idx2, an2):
arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
if arg2 is not None and arg2.arg is not None:
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
match resolved2:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty2 = llvmlite.Ptr(pool, resolved2)
case _:
param_ty2 = resolved2
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
if alloca is not None:
HandlesVar.define_var(trans.SymTab, arg2.arg, alloca)
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
if arg2.annotation is not None:
cls_nm_oc: str = HandlesType.extract_class_name_from_annotation(
arg2.annotation, imported_modules)
if cls_nm_oc is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, arg2.arg, cls_nm_oc)
pname2: t.CChar | t.CPtr = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
pool, param_ty2, pname2)
llvmlite.build_store(func_builder, param_val, alloca)
# 保存模块级作用域状态
old_func: llvmlite.Function | t.CPtr = trans._cur_func
old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
old_global_count: int = trans._global_name_count
old_nonlocal_count: int = trans._nonlocal_name_count
old_env_count: int = trans._closure_env_count
trans._cur_func = func
trans._cur_builder = func_builder
HT.clear_scope_names(trans)
# 预扫描方法体:为局部变量提前创建 alloca
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
if body is not None:
bn: t.CSizeT = body.__len__()
for bi in range(bn):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.pre_scan_allocas(trans, stmt)
# 翻译方法体
if body is not None:
bn2: t.CSizeT = body.__len__()
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = body.get(bi2)
if stmt2 is not None:
HandlesBody.translate_stmt(trans, stmt2)
# 如果返回类型为 void,添加 ret void;否则添加隐式 ret 0
is_void: int = 0
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
is_void = 1
if is_void != 0:
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
llvmlite.build_ret_void(func_builder)
else:
last_is_return: int = 0
if body is not None:
bn3: t.CSizeT = body.__len__()
if bn3 > 0:
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
last_is_return = 1
if last_is_return == 0:
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
# 根据返回类型生成正确的零值返回
_m_is_void: int = 0
_m_is_ptr: int = 0
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
_m_is_void = 1
case llvmlite.LLVMType.Ptr(_m_pe):
_m_is_ptr = 1
if _m_is_void != 0:
llvmlite.build_ret_void(func_builder)
elif _m_is_ptr != 0:
_m_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(func_builder, _m_null_val)
else:
_m_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, _m_zero_val)
# 恢复模块级作用域
HandlesVar.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._global_name_count = old_global_count
trans._nonlocal_name_count = old_nonlocal_count
trans._closure_env_count = old_env_count
return 0
# ============================================================
# _generate_before_init — 生成 __before_init__ 函数
#
# 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self)
#
# 执行:
# 1. store zeroinitializer 到 %self(零值填充)
# 2. 逐字段 store 默认值(如有)
# 3. ret void
# ============================================================
def _generate_before_init(self, trans: HT.Translator | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str) -> int:
"""生成 __before_init__ 函数,返回 0"""
if trans is None or struct_ty is None or class_name is None:
return 0
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
func_count: int = trans._func_count
self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
# 构建函数名: ClassName.__before_init__
full_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if full_name_buf is None:
return 0
viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name)
full_name: str = full_name_buf
mangled_name: str = HandlesFunctions._mangle_name(trans, full_name)
# 创建函数
func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, mangled_name, void_ty)
if func is None:
return 0
# 注册到函数表
max_funcs: int = 256
rc_add: int = HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool)
if rc_add == 0:
trans._func_count = func_count + 1
# 添加 self 参数
llvmlite.add_param(pool, func, self_ptr_ty, "%self")
# 参数添加完成,补全全局函数表的 TypeStr
rc_ut: int = HandlesExprCall.update_global_func_typestr(pool, full_name, func)
# 创建 entry 块 + builder
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
return 0
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
if func_builder is None:
return 0
llvmlite.position_at_end(func_builder, entry_blk)
# 注册 self 为 SSA 值
self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self")
# 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self
# 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant),
# 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充;
# @t.CVTable 类必有 vtable 指针字段(非空),不受影响。
struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty)
if struct_fcount_zi > 0:
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
if zero is not None:
llvmlite.build_store(func_builder, zero, self_val)
# 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0)
# 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错
bi_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
bi_has_vt: int = 0
if bi_entry is not None:
bi_has_vt = bi_entry.HasVTable
if bi_has_vt == 1:
vt_method_count: int = 0
if bi_entry is not None:
vt_method_count = bi_entry.VTableMethodCount
if vt_method_count > 0:
# 构造 vtable 类型 { i8*, i8*, ..., i8* }
vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty)
vt_first_node: llvmlite.ParamNode | t.CPtr = None
vt_prev_node: llvmlite.ParamNode | t.CPtr = None
for vti in range(vt_method_count):
vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty)
if vtnode is None:
continue
if vt_first_node is None:
vt_first_node = vtnode
if vt_prev_node is not None:
llvmlite.paramnode_set_next(vt_prev_node, vtnode)
vt_prev_node = vtnode
vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None)
vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty)
# 构造 vtable 全局变量名
vt_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if vt_name_buf is not None:
viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name)
vt_full_name: str = vt_name_buf
vt_mangled: str = HandlesFunctions._mangle_name(trans, vt_full_name)
# GEP 到 __vtable__ 字段(索引 0)
vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0)
if vt_slot is not None:
# 创建全局变量引用 Value
vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
if vt_ref is not None:
llvmlite.value_set_ty(vt_ref, vt_ptr_ty)
llvmlite.value_set_isconst(vt_ref, 1)
# Name 格式: @"mangled" 或 @mangled
vt_ref_name: t.CChar | t.CPtr = pool.alloc(256)
if vt_ref_name is not None:
vt_ref_name[0] = '\0'
if self._vtable_name_needs_quote(vt_mangled) != 0:
viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled)
else:
viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled)
llvmlite.value_set_name(vt_ref, vt_ref_name)
# bitcast 到 i8*
vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
func_builder, vt_ref, vt_i8_ptr_ty)
if vt_as_i8 is not None:
llvmlite.build_store(func_builder, vt_as_i8, vt_slot)
# 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错)
if bi_entry is not None:
for fi in range(bi_entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
bi_entry, fi)
if fe is None or fe.DefaultVal is None:
continue
# 翻译默认值表达式
default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
func_builder, pool, mod, fe.DefaultVal, None, 0, trans)
if default_val is None:
continue
# GEP 到字段
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
func_builder, struct_ty, fe.Ty, self_val, fe.Index)
if field_ptr is None:
continue
# 类型转换并 store
default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal)
llvmlite.build_store(func_builder, default_val, field_ptr)
# 3. ret void
llvmlite.build_ret_void(func_builder)
return 0