Files
ViperC/App/lib/core/Gen/ClassGenBase.vp
T
TermiNexus e770fef0f7 fix(gen): 恢复 ClassGenBase 基类别名解析(_resolve_base_alias)
ClassGenMixin 拆分(47ac2dd)时 _resolve_base_alias 丢失:_get_parent_class
/_collect_parents 不再解析 from-import 别名基类(from t import CStruct as cs
→ class CsPoint(cs)),'cs' 被当真实父类 → find_struct('cs') 失败 → 类 defer
永不注册 → 变量注解解析失败(EdgeCaseTest Test12 回归)。恢复
_resolve_base_alias 并在两处调用;_collect_parents 增 trans 参数透传(别名
解析需 from_imports)。TypeGenResolve 增 [DBG-ANNOT] 插桩待验证后移除。
2026-08-20 00:05:32 +08:00

1119 lines
55 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.StubMerger as StubMerger
import lib.core.CompilerFactory as CompilerFactory
# ============================================================
# 本地常量(阶段 D 拆分时从 ClassGenMixin 顶层遗漏,补回:
# 方法元数据/类元数据/装饰器/异常表容量与编码;本地副本避免跨模块 CDefine 查找)
# ============================================================
# 方法元数据 flag 位(对齐 TPC HandlesBase _METHOD_META_*)
META_TLS: t.CDefine = 32
# 类编译期元数据表容量上限(__provides__/__requires__/__require_must__)
CLASS_META_MAX: t.CDefine = 256
# 自定义装饰器 wrapper 表容量上限(带 @decor 的函数数)
DECOR_FUNC_MAX: t.CDefine = 64
# 装饰器表槽内函数名/wrapper 名长度(含 NUL)
DECOR_NAME_LEN: t.CDefine = 128
# 异常类注册表容量上限(class X(Exception) 自定义异常类)
EXCEPTION_MAX: t.CDefine = 64
# 异常类表槽内类名/父类名长度(含 NUL)
EXCEPTION_NAME_LEN: t.CDefine = 128
# 内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP);
# KeyError=6 IOError=7 OSError=8 AssertionError=9 Exception=99;用户类从 100 起
BUILTIN_EH_VALUE_ERROR: t.CDefine = 1
BUILTIN_EH_RUNTIME_ERROR: t.CDefine = 3
BUILTIN_EH_EXCEPTION: t.CDefine = 99
EH_USER_CODE_START: t.CDefine = 100
# ============================================================
# ClassGenBase - ClassGenMixin 拆分(阶段 D):字段 + 方法元数据/异常/继承检测/装饰器(Meta)
#
# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class ClassGenBase:
"""字段 + 方法元数据/异常/继承检测/装饰器(Meta)"""
# --- 方法元数据表(原 _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
# 变体成员实际 LLVM 类型(对齐 TPC class_members):注册时按注解解析,
# perm_pool 深拷贝持久化。match 绑定用真实成员类型 bitcast 槽位地址
# (Struct.Name: i8*,否则按槽位 i64 读 → is/subscript/strlen 失败)。
RenumAliasTy: t.CSizeT | t.CPtr
# 别名所属变体名(perm_pool 拷贝):同一 payload 位置跨变体类型不同
# (Int.Bits=i32 vs Struct.Fields=Ptr),match 绑定按 (class, 变体, 位置)
# 唯一定位成员类型。
RenumAliasVariant: t.CSizeT | t.CPtr
RenumAliasCount: int
# --- 泛型特化缓存(原 _spec_keys/_spec_names/_spec_count) ---
SpecKeys: t.CSizeT | t.CPtr
SpecNames: t.CSizeT | t.CPtr
SpecCount: int
# --- 类编译期元数据表(__provides__/__requires__/__require_must__) ---
# perm_pool 分配(跨 mark/reset 存活):每槽 kind(4B) + cls(64B) + field(64B)
# FakeDuck:_str.__requires__=['__mbuddy__'] 等(FakeDuck 移植点 1)
ClassMetaKinds: t.CInt | t.CPtr
ClassMetaClss: bytes
ClassMetaFields: bytes
ClassMetaCount: int
# --- 自定义装饰器 wrapper 表(@log/@skip/@repeat 等 → __decor_wrap_{name}) ---
# perm_pool 分配(跨 mark/reset 存活):每槽函数名(128B) + wrapper 名(128B)
# 对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs +
# DecoratorPass.py 的 wrapper 生成。调用点重写经
# lookup_decor_wrapper(translate_call 拦截原函数名 → wrapper 名)。
DecoratorFuncCount: int
DecoratorFuncNames: bytes
DecoratorWrapNames: bytes
# 装饰器首个常量参数(@repeat(3) 的 3),无参数为 0(每槽 8B,i64)
DecoratorArgs: t.CInt64T | t.CPtr
# --- 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61) ---
# perm_pool 分配(跨 mark/reset 存活):每槽类名(128B) + 父类名(128B) + 编码(4B)
# 用户异常类编码从 100 递增;内置编码(ValueError=1 等)不在此表
# (_lookup_exception_code 走内置硬编码)。异常类不生成 struct。
ExceptionCount: int
ExceptionNames: bytes
ExceptionParents: bytes
ExceptionCodes: t.CInt | t.CPtr
# 下一个待分配的异常编码(用户类,从 100 起)
NextExceptionCode: int
# 递归收集子孙编码用的临时计数(collect_descendant_codes 返回后无效)。
# 必须与其它字段一起声明在类顶:方法中间的字段注解可能被编译器
# 当作局部声明处理,破坏 Mixin 布局/this_adjust 对齐。
_exception_codes_tmp_count: int
# --- 泛型特化递归深度(泛型循环套用防护) ---
# _specialize_generic_class 进入时 +1、退出时 -1;超过上限立即报错终止
# (防止 F-bounded 等循环特化把编译变成死循环)
GenericSpecDepth: 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
# 泛型模板来源文件路径(与上面三表同序)。特化翻译模板方法体时
# node.lineno 是模板文件行号,若 CurrentFile 仍是调用方文件,
# fatal_error 会把模板行号套到调用方文件上显示错位(如 vector.vp
# 的 T(...) 错报成 vectortest.vp 的 return 0)。此表用于特化期间
# 临时切换 CurrentFile 到模板文件,翻译完恢复。
GenericClassFiles: list[str] | t.CPtr
# 泛型模板类型参数名表(与 GenericClassNames 同序,stdlib 深拷贝)。
# 模板节点 type_params 是 Phase 1 pool 分配的 list,跨 Phase 引用时内容
# 可能失效(VectorGenericTest 特化 Vector[int].__init__ 的 T.__sizeof__()
# NameError 根因方向);注册时展平深拷贝到 stdlib,特化时从本表恢复。
# 每槽指向一个空格分隔、NUL 结尾的 stdlib 缓冲区(如 "T" 或 "T K")。
GenericClassTpParams: t.CSizeT | 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,
trans: HT.Translator | t.CPtr = None) -> 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 None:
return 0
if string.strcmp(nm.id, "CEnum") == 0:
return 1
# 别名形式: from t import CEnum as en; class Color(en)
# 解析别名原始名(en → CEnum)再比较
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_ce: t.CSizeT = 0
while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0':
og_len_ce += 1
if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 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,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式"""
if cd is None:
return 0
# 装饰器形式: @t.CEnum class Color:(无基类,等价 class Color(t.CEnum):)
if cd.decorator_list is not None:
if self._has_decorator(cd.decorator_list, "CEnum") == 1:
return 1
if cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = len(bases)
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, trans) == 1:
return 1
return 0
def _is_cunion_base(self, base_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> 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 None:
return 0
if string.strcmp(nm.id, "CUnion") == 0:
return 1
# 别名形式: from t import CUnion as un; class Data(un)
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_cu: t.CSizeT = 0
while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0':
og_len_cu += 1
if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 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,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式"""
if cd is None:
return 0
# 装饰器形式: @t.CUnion class Data:
if cd.decorator_list is not None:
if self._has_decorator(cd.decorator_list, "CUnion") == 1:
return 1
if cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = len(bases)
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, trans) == 1:
return 1
return 0
def _is_crenum_base(self, base_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> 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 None:
return 0
if string.strcmp(nm.id, "REnum") == 0:
return 1
# 别名形式: from t import REnum as ren; class Opt(ren)
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_cr: t.CSizeT = 0
while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0':
og_len_cr += 1
if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 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,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式"""
if cd is None:
return 0
# 装饰器形式: @t.REnum class X:
if cd.decorator_list is not None:
if self._has_decorator(cd.decorator_list, "REnum") == 1:
return 1
if cd.bases is None:
return 0
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = len(bases)
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, trans) == 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 = len(decorator_list)
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 = len(decorator_list)
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 string.strcmp(nm.id, "TLS") == 0:
meta |= META_TLS
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
# @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py
# L1223-1231:value 必须为 Name('t');@TLS 裸名走上面 Name 分支)
if vn.id is not None and string.strcmp(vn.id, "t") == 0 \
and string.strcmp(at.attr, "TLS") == 0:
meta |= META_TLS
# @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_class_meta(self, pool: memhub.MemBuddy | t.CPtr,
kind: int, cls: str, field: str) -> int:
"""注册类编译期元数据字段(__provides__/__requires__/__require_must__,幂等)"""
if pool is None or cls is None or field is None:
return -1
if self.ClassMetaKinds is None:
self.ClassMetaKinds = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 4)
self.ClassMetaClss = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64)
self.ClassMetaFields = CompilerFactory.get_perm_pool().alloc(CLASS_META_MAX * 64)
if self.ClassMetaKinds is None or self.ClassMetaClss is None or self.ClassMetaFields is None:
return -1
string.memset(self.ClassMetaKinds, 0, CLASS_META_MAX * 4)
string.memset(self.ClassMetaClss, 0, CLASS_META_MAX * 64)
string.memset(self.ClassMetaFields, 0, CLASS_META_MAX * 64)
self.ClassMetaCount = 0
if self.ClassMetaCount >= CLASS_META_MAX:
return -1
# 幂等:同 (kind, cls, field) 跳过
for i in range(self.ClassMetaCount):
if self.ClassMetaKinds[i] == kind:
if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0:
if string.strcmp(self.ClassMetaFields + i * 64, field) == 0:
return 0
idx_cm: t.CSizeT = t.CSizeT(self.ClassMetaCount) * 64
self.ClassMetaKinds[self.ClassMetaCount] = kind
string.strncpy(self.ClassMetaClss + idx_cm, cls, 63)
self.ClassMetaClss[idx_cm + 63] = '\0'
string.strncpy(self.ClassMetaFields + idx_cm, field, 63)
self.ClassMetaFields[idx_cm + 63] = '\0'
self.ClassMetaCount += 1
return 0
def class_meta_count(self, kind: int, cls: str) -> int:
"""返回某类某元数据类型的字段数"""
if self.ClassMetaKinds is None or cls is None:
return 0
n_cm: int = 0
for i in range(self.ClassMetaCount):
if self.ClassMetaKinds[i] == kind:
if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0:
n_cm += 1
return n_cm
def class_meta_field_at(self, kind: int, cls: str, idx: int) -> str:
"""返回某类某元数据类型的第 idx 个字段名"""
if self.ClassMetaKinds is None or cls is None:
return None
n_cm2: int = 0
for i in range(self.ClassMetaCount):
if self.ClassMetaKinds[i] == kind:
if string.strcmp(self.ClassMetaClss + i * 64, cls) == 0:
if n_cm2 == idx:
return self.ClassMetaFields + i * 64
n_cm2 += 1
return None
def register_decorator(self, pool: memhub.MemBuddy | t.CPtr,
func_name: str, wrapper_name: str,
arg0: t.CInt64T) -> int:
"""注册自定义装饰器函数(@log/@skip/@repeat(3) → __decor_wrap_{name})
对齐 TPC HandlesFunctions.py L1621-1631 的 _decorated_funcs 注册。
arg0 为装饰器首个常量参数(@repeat(3) 的 3),无参数为 0。
"""
if pool is None or func_name is None or wrapper_name is None:
return -1
if self.DecoratorFuncNames is None:
self.DecoratorFuncNames = CompilerFactory.get_perm_pool().alloc(
DECOR_FUNC_MAX * DECOR_NAME_LEN)
self.DecoratorWrapNames = CompilerFactory.get_perm_pool().alloc(
DECOR_FUNC_MAX * DECOR_NAME_LEN)
self.DecoratorArgs = CompilerFactory.get_perm_pool().alloc(
DECOR_FUNC_MAX * 8)
if self.DecoratorFuncNames is None or self.DecoratorWrapNames is None \
or self.DecoratorArgs is None:
return -1
string.memset(self.DecoratorFuncNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN)
string.memset(self.DecoratorWrapNames, 0, DECOR_FUNC_MAX * DECOR_NAME_LEN)
string.memset(self.DecoratorArgs, 0, DECOR_FUNC_MAX * 8)
self.DecoratorFuncCount = 0
if self.DecoratorFuncCount >= DECOR_FUNC_MAX:
return -1
# 幂等:同名函数已注册则跳过(多遍扫描)
for i in range(self.DecoratorFuncCount):
if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0:
return 0
idx_dc: t.CSizeT = t.CSizeT(self.DecoratorFuncCount) * DECOR_NAME_LEN
string.strncpy(self.DecoratorFuncNames + idx_dc, func_name, DECOR_NAME_LEN - 1)
self.DecoratorFuncNames[idx_dc + DECOR_NAME_LEN - 1] = '\0'
string.strncpy(self.DecoratorWrapNames + idx_dc, wrapper_name, DECOR_NAME_LEN - 1)
self.DecoratorWrapNames[idx_dc + DECOR_NAME_LEN - 1] = '\0'
self.DecoratorArgs[self.DecoratorFuncCount] = arg0
self.DecoratorFuncCount += 1
return 0
def lookup_decor_wrapper(self, func_name: str) -> str:
"""按原函数名查 wrapper 名,未注册返回 None"""
if self.DecoratorFuncNames is None or func_name is None:
return None
for i in range(self.DecoratorFuncCount):
if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0:
return self.DecoratorWrapNames + i * DECOR_NAME_LEN
return None
def lookup_decor_arg0(self, func_name: str) -> t.CInt64T:
"""按原函数名查装饰器首个常量参数(无参数为 0)"""
if self.DecoratorFuncNames is None or func_name is None:
return 0
for i in range(self.DecoratorFuncCount):
if string.strcmp(self.DecoratorFuncNames + i * DECOR_NAME_LEN, func_name) == 0:
return self.DecoratorArgs[i]
return 0
# ============================================================
# 异常类注册表(try-except,对齐 TPC HandlesClassDef.py L47-61)
# ============================================================
def _ensure_exception_tables(self) -> int:
"""懒初始化异常表(perm_pool),返回 0 成功"""
if self.ExceptionNames is not None:
return 0
pp_e: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
if pp_e is None:
return -1
self.ExceptionNames = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN)
self.ExceptionParents = pp_e.alloc(EXCEPTION_MAX * EXCEPTION_NAME_LEN)
self.ExceptionCodes = pp_e.alloc(EXCEPTION_MAX * 4)
if self.ExceptionNames is None or self.ExceptionParents is None \
or self.ExceptionCodes is None:
return -1
string.memset(self.ExceptionNames, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN)
string.memset(self.ExceptionParents, 0, EXCEPTION_MAX * EXCEPTION_NAME_LEN)
string.memset(self.ExceptionCodes, 0, EXCEPTION_MAX * 4)
self.ExceptionCount = 0
self.NextExceptionCode = EH_USER_CODE_START
return 0
def register_exception(self, class_name: str, parent_name: str) -> int:
"""注册用户异常类并分配编码(幂等:同名跳过)。返回编码或 -1"""
if class_name is None:
return -1
if self._ensure_exception_tables() != 0:
return -1
# 幂等:已注册则返回既有编码(多遍扫描)
for i in range(self.ExceptionCount):
if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, class_name) == 0:
return self.ExceptionCodes[i]
if self.ExceptionCount >= EXCEPTION_MAX:
return -1
idx_e: t.CSizeT = t.CSizeT(self.ExceptionCount) * EXCEPTION_NAME_LEN
string.strncpy(self.ExceptionNames + idx_e, class_name, EXCEPTION_NAME_LEN - 1)
self.ExceptionNames[idx_e + EXCEPTION_NAME_LEN - 1] = '\0'
if parent_name is not None:
string.strncpy(self.ExceptionParents + idx_e, parent_name, EXCEPTION_NAME_LEN - 1)
self.ExceptionParents[idx_e + EXCEPTION_NAME_LEN - 1] = '\0'
code_e: int = self.NextExceptionCode
self.NextExceptionCode += 1
self.ExceptionCodes[self.ExceptionCount] = code_e
self.ExceptionCount += 1
return code_e
def _builtin_exception_code(self, name: str) -> int:
"""内置异常编码(对齐 TPC HandlesBase.py EXCEPTION_CODE_MAP),非内置返回 0"""
if name is None:
return 0
if string.strcmp(name, "ValueError") == 0: return 1
if string.strcmp(name, "TypeError") == 0: return 2
if string.strcmp(name, "RuntimeError") == 0: return 3
if string.strcmp(name, "ZeroDivisionError") == 0: return 4
if string.strcmp(name, "IndexError") == 0: return 5
if string.strcmp(name, "KeyError") == 0: return 6
if string.strcmp(name, "IOError") == 0: return 7
if string.strcmp(name, "OSError") == 0: return 8
if string.strcmp(name, "AssertionError") == 0: return 9
if string.strcmp(name, "Exception") == 0: return 99
return 0
def lookup_exception_code(self, name: str) -> int:
"""查异常编码:内置表优先,其次用户异常表,都未命中返回 0"""
if name is None:
return 0
bi: int = self._builtin_exception_code(name)
if bi != 0:
return bi
if self.ExceptionNames is None:
return 0
for i in range(self.ExceptionCount):
if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0:
return self.ExceptionCodes[i]
return 0
def lookup_exception_parent(self, name: str) -> str:
"""查用户异常类的父类名,非用户异常返回 None"""
if name is None or self.ExceptionNames is None:
return None
for i in range(self.ExceptionCount):
if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0:
p_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN
if p_e is not None and p_e[0] != '\0':
return p_e
return None
return None
def is_exception_name(self, name: str) -> int:
"""name 是否是内置或用户异常类名(1=是 / 0=否)"""
if name is None:
return 0
if self._builtin_exception_code(name) != 0:
return 1
if self.ExceptionNames is None:
return 0
for i in range(self.ExceptionCount):
if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0:
return 1
return 0
def collect_descendant_codes(self, name: str, out_codes: t.CInt | t.CPtr,
max_codes: int) -> int:
"""把 name 及其所有子孙异常类的编码收集到 out_codes,返回数量
(对齐 TPC HandlesTry.py _get_all_match_codes/_collect_descendant_codes:
编译期静态展开继承树,except X 匹配 X 及全部子孙)。"""
if name is None or out_codes is None:
return 0
self._exception_codes_tmp_count = 0
self._collect_desc_codes_rec(name, out_codes, max_codes, 0)
return self._exception_codes_tmp_count
def _collect_desc_codes_rec(self, name: str, out_codes: t.CInt | t.CPtr,
max_codes: int, depth: int) -> None:
"""递归收集 name 编码 + 全部子孙编码(BFS 语义对齐 TPC)"""
if depth > 32:
return
code_e: int = self.lookup_exception_code(name)
if code_e != 0 and self._exception_codes_tmp_count < max_codes:
# 去重(继承环防护)
dup: int = 0
for i in range(self._exception_codes_tmp_count):
if out_codes[i] == code_e:
dup = 1
break
if dup == 0:
out_codes[self._exception_codes_tmp_count] = code_e
self._exception_codes_tmp_count += 1
# 遍历全部用户异常,找以 name 为父类的子类递归收集
if self.ExceptionNames is None:
return
for i in range(self.ExceptionCount):
cname_e: str = self.ExceptionNames + i * EXCEPTION_NAME_LEN
pname_e: str = self.ExceptionParents + i * EXCEPTION_NAME_LEN
if pname_e is not None and pname_e[0] != '\0':
if string.strcmp(pname_e, name) == 0:
self._collect_desc_codes_rec(cname_e, out_codes, max_codes, depth + 1)
def _is_exception_class_def(self, cd: ast.ClassDef | t.CPtr) -> int:
"""类定义是否是异常类:基类是 Exception 或已注册异常类(1=是)"""
if cd is None or cd.bases is None:
return 0
bases_e: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn_e: t.CSizeT = len(bases_e)
for bi_e in range(bn_e):
base_e: ast.AST | t.CPtr = bases_e.get(bi_e)
if base_e is None:
continue
base_name_e: str = None
if base_e.kind() == ast.ASTKind.Name:
base_name_e = ((ast.Name | t.CPtr)(base_e)).id
elif base_e.kind() == ast.ASTKind.Attribute:
base_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e)
if base_at_e.attr is not None:
base_name_e = base_at_e.attr
if base_name_e is None:
continue
if string.strcmp(base_name_e, "Exception") == 0:
return 1
if self.is_exception_name(base_name_e) != 0:
return 1
return 0
def _get_exception_parent_name(self, cd: ast.ClassDef | t.CPtr) -> str:
"""返回异常类定义的真实父类名(第一个非 Exception 的已注册异常类),无则 None"""
if cd is None or cd.bases is None:
return None
bases_e2: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn_e2: t.CSizeT = len(bases_e2)
for bi_e2 in range(bn_e2):
base_e2: ast.AST | t.CPtr = bases_e2.get(bi_e2)
if base_e2 is None:
continue
base_name_e2: str = None
if base_e2.kind() == ast.ASTKind.Name:
base_name_e2 = ((ast.Name | t.CPtr)(base_e2)).id
elif base_e2.kind() == ast.ASTKind.Attribute:
base_at_e2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_e2)
if base_at_e2.attr is not None:
base_name_e2 = base_at_e2.attr
if base_name_e2 is None:
continue
if string.strcmp(base_name_e2, "Exception") != 0 \
and self.is_exception_name(base_name_e2) != 0:
return base_name_e2
return None
def _register_exception_class_def(self, trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr) -> int:
"""注册异常类(分配编码 + 记录父类),不生成 struct,返回 0"""
if cd is None or cd.name is None:
return 0
parent_e: str = self._get_exception_parent_name(cd)
self.register_exception(cd.name, parent_e)
return 0
def _register_class_meta_list(self, pool: memhub.MemBuddy | t.CPtr,
kind: int, cls: str, value_node: ast.AST | t.CPtr) -> None:
"""解析类体 __provides__/__requires__ 的 list[str] 字面量并注册"""
if value_node is None or cls is None:
return
if value_node.kind() != ast.ASTKind.List:
return
lst_rcm: ast.List | t.CPtr = (ast.List | t.CPtr)(value_node)
if lst_rcm.elts is None:
return
elts_rcm: list[ast.AST | t.CPtr] | t.CPtr = lst_rcm.elts
en_rcm: t.CSizeT = len(elts_rcm)
for ei_rcm in range(en_rcm):
el_rcm: ast.AST | t.CPtr = elts_rcm.get(ei_rcm)
if el_rcm is None or el_rcm.kind() != ast.ASTKind.Constant:
continue
ec_rcm: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(el_rcm)
if ec_rcm.str_val is not None:
self.register_class_meta(pool, kind, cls, ec_rcm.str_val)
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 = CompilerFactory.get_perm_pool().alloc(META_MAX * META_KEY_LEN)
self.MethodMetaFlags = CompilerFactory.get_perm_pool().alloc(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))
# 按位或合并:同一属性名先 @property(getter=4) 再 @x.setter(8)/
# @x.deleter(16) 会多次注册(如 Config.value / Counter.value)。
# 若整值替换,后注册的位会覆盖 GETTER 位 → _try_property_getter_attr
# 不再拦截 obj.prop → 落入字段查找失败返回 None → 上游 llvmlite
# 收到 NULL Value → 编译器进程段错误(BuiltinDecoratorTest Phase A 崩溃)。
flags_ptr[0] = flags_ptr[0] | meta
stdlib.free(key_buf)
return
if self.MethodMetaCount < META_MAX:
# 槽位定长 META_KEY_LEN=128 字节,key 超长时 strncpy 钳制防越界写相邻槽
string.strncpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN,
key_buf, META_KEY_LEN - 1)
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 = len(bases)
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:
# 基类别名解析(from t import CStruct as cs → cs 实际是 CStruct)。
# ClassGen 拆分(47ac2dd)时丢失,EdgeCaseTest Test12 class
# CsPoint(cs) 回归根因:'cs' 被当真实父类 → find_struct("cs")
# 失败 → 类 defer 永不注册 → 变量注解解析失败。
bname = self._resolve_base_alias(bname, trans)
if self._is_marker_base(bname) == 0:
return bname
return None
def _resolve_base_alias(self, base_name: str,
trans: HT.Translator | t.CPtr = None) -> str:
"""解析基类别名:from t import CStruct as cs → 基类 cs 实际是 CStruct。
别名不解析时 "cs" 会被当作真实父类名 → find_struct("cs") 失败 →
PhaseA 预注册把整类 defer(永不注册)→ 变量注解 X 解析失败
(EdgeCaseTest Test12 class CsPoint(cs): 根因)。
"""
if base_name is None or trans is None or trans._from_imports is None:
return base_name
orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, base_name)
if orig is not None:
# lookup_from_import_original 返回 from_imports 内部指针且未 NUL 结尾
# (如 "CStruct myint:t:CInt CChar:t CPtr:t" 整串直到真正的 NUL)。
# 复制到独立缓冲并按空格截断出干净原始名——否则 _is_marker_base 的
# strcmp 对整串比较失败 → 别名基类(CStruct as cs)被当真实父类 →
# find_struct 失败 → 整类 defer 永不注册 → 变量注解解析失败。
og_len: t.CSizeT = 0
while orig[og_len] != ' ' and orig[og_len] != '\0':
og_len += 1
if og_len > 0:
og_buf: str = CompilerFactory.get_perm_pool().alloc(og_len + 1)
if og_buf is not None:
string.strncpy(og_buf, orig, og_len)
og_buf[og_len] = '\0'
return og_buf
return base_name
def _collect_parents(self, pool: memhub.MemBuddy | t.CPtr,
cd: ast.ClassDef | t.CPtr,
parents_buf: t.CSizeT | t.CPtr,
max_parents: int,
trans: HT.Translator | t.CPtr = None) -> 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 = len(bases)
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:
# 基类别名解析(同 _get_parent_class,见 _resolve_base_alias)
bname = self._resolve_base_alias(bname, trans)
if 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 = len(cd.children)
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 = len(bases)
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 有缓存,重复调用安全)
HandlesClassDef._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 = len(children)
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)