From 47ac2dd57cc1df8aa645157ff8f5b0bc2cc7f5ba Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 07:23:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20ClassGenMixin=20=E6=8B=86=205?= =?UTF-8?q?=20=E7=BB=84=EF=BC=88Base/Enum/Generic/VTable/Def=EF=BC=8C4768?= =?UTF-8?q?=E2=86=92=E7=A9=BA=E5=A3=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/ClassGenBase.vp | 1058 +++++ App/lib/core/Gen/ClassGenDef.vp | 577 +++ App/lib/core/Gen/ClassGenEnum.vp | 1137 ++++++ App/lib/core/Gen/ClassGenGeneric.vp | 675 ++++ App/lib/core/Gen/ClassGenMixin.vp | 4752 +---------------------- App/lib/core/Gen/ClassGenVTable.vp | 1310 +++++++ App/lib/core/Gen/Generator.vp | 10 +- App/lib/core/Handles/HandlesClassDef.vp | 33 + 8 files changed, 4807 insertions(+), 4745 deletions(-) create mode 100644 App/lib/core/Gen/ClassGenBase.vp create mode 100644 App/lib/core/Gen/ClassGenDef.vp create mode 100644 App/lib/core/Gen/ClassGenEnum.vp create mode 100644 App/lib/core/Gen/ClassGenGeneric.vp create mode 100644 App/lib/core/Gen/ClassGenVTable.vp diff --git a/App/lib/core/Gen/ClassGenBase.vp b/App/lib/core/Gen/ClassGenBase.vp new file mode 100644 index 0000000..94f9b12 --- /dev/null +++ b/App/lib/core/Gen/ClassGenBase.vp @@ -0,0 +1,1058 @@ +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 + + + +# ============================================================ +# 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 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 = 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 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 = 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) \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenDef.vp b/App/lib/core/Gen/ClassGenDef.vp new file mode 100644 index 0000000..5267d1e --- /dev/null +++ b/App/lib/core/Gen/ClassGenDef.vp @@ -0,0 +1,577 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenDef(ClassGenBase.ClassGenBase): + """translate_class_def 主入口""" + + # ============================================================ + # 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 + + if trans.ModuleSha1 is None: + # fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)—— + VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS") + HandlesType.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError") + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, + # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) + HandlesStruct.add_visible_struct(pool, class_name) + + # 枚举类:交给 HandlesEnum 处理 + if HandlesClassDef._is_enum_class(cd, trans) == 1: + return HandlesClassDef._translate_enum_def(trans, cd) + + # 联合体类:交给联合体处理 + if HandlesClassDef._is_union_class(cd, trans) == 1: + return HandlesClassDef._translate_union_def(trans, cd) + + # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) + if HandlesClassDef._is_renum_class(cd, trans) == 1: + return HandlesClassDef._translate_renum_def(trans, cd) + + # 泛型类:存储为模板,不发射 IR(等实例化时特化) + # 用局部变量接收 cd.type_params,触发类型推断 + tp_val: list[str] | t.CPtr = cd.type_params + if HandlesClassDef._is_generic_class(tp_val) == 1: + HandlesClassDef._register_generic_template(pool, cd, trans.ModuleSha1) + return 0 + + # 异常类(try-except):注册编码+继承树,不生成 struct + # (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class → + # _RegisterExceptionClass → return,异常类不编译为结构体) + if HandlesClassDef._is_exception_class_def(cd) == 1: + return HandlesClassDef._register_exception_class_def(trans, cd) + + # 检查是否已注册(用 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 HandlesClassDef._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: + # 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空, + # _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表 + # 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType + # 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。 + ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), existing.Ty) + if ty_deep is not None: + existing.Ty = ty_deep + old_name: str = llvmlite.get_struct_name(existing.Ty) + if old_name is not None: + on_len: t.CSizeT = string.strlen(old_name) + on_copy: str = CompilerFactory.get_perm_pool().alloc(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: + HandlesClassDef._translate_oop_methods(trans, cd, existing.Ty, class_name, 1) + else: + HandlesClassDef._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 + # ============================================================ + HandlesClassDef._trigger_base_specialization(trans, cd) + + # ============================================================ + # VTable 检测:判断是否启用虚表 + # ============================================================ + has_vtable: int = HandlesClassDef._detect_vtable_status(cd, trans) + parent_name: str = HandlesClassDef._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 = HandlesClassDef._collect_parents(pool, cd, parents_buf, HandlesStruct.PARENT_MAX) + is_novtable_deco: int = 0 + if cd.decorator_list is not None: + if HandlesClassDef._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 * HandlesStruct.FIELD_MAX) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) + field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) + field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) + 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 * HandlesStruct.FIELD_MAX) + string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) + string.memset(field_defaults_buf, 0, 8 * HandlesStruct.FIELD_MAX) + string.memset(field_annot_buf, 0, 8 * HandlesStruct.FIELD_MAX) + + 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: + # 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能 + # 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时 + # **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool + # 分配(init_struct_table L136-140),残缺条目跨 pass 存活, + # 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类 + # __init__ 写父类字段(self.TraceFrames)每遍永久失败。 + # 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级 + # 变量/函数参数解析失败静默降级 i32(handle_module_level_var + # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 + if trans is not None: + trans._deps_pending = 1 + return 0 + 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 HandlesClassDef._field_name_exists(field_names_buf, field_count, pfn) != 0: + continue + if field_count < HandlesStruct.FIELD_MAX: + 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 = len(children) + 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 + + # 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。 + # 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查 + # CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册 + # 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。 + if HandlesAnnAssign.is_cdefine_annotation(aa.annotation) != 0: + if aa.value is not None: + HandlesAnnAssign._register_cdefine_from_value(pool, tgt.id, aa.value) + # CDefine 字段类型固定 i32,直接收集后跳过通用注解解析: + # resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef + # 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发 + # 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。 + # 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。 + if field_count < HandlesStruct.FIELD_MAX: + cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cdef_ty_l is not None: + field_names_buf[field_count] = t.CSizeT(tgt.id) + field_types_buf[field_count] = t.CSizeT(cdef_ty_l) + if aa.value is not None: + field_defaults_buf[field_count] = t.CSizeT(aa.value) + else: + field_defaults_buf[field_count] = 0 + field_count += 1 + continue + + # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) + # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 + # (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str] + # 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。 + if string.strcmp(tgt.id, "__provides__") == 0: + HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_PROVIDES, class_name, aa.value) + continue + if string.strcmp(tgt.id, "__requires__") == 0: + HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRES, class_name, aa.value) + continue + if string.strcmp(tgt.id, "__require_must__") == 0: + HandlesClassDef._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRE_MUST, class_name, aa.value) + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) + # 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem] + # (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义): + # 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**), + # for x in self.field 会误走指针迭代(元素非整数 → null 终止符 + # 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。 + if field_ty is not None: + field_ty = HandlesAnnAssign._infer_static_array_ty_from_literal( + pool, aa.annotation, aa.value, field_ty) + 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 A(declare_only=0,Phase2.vp L573 多遍):依赖模块按 + # 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp + # H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记 + # _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。 + # 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成 + # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 + if trans is not None: + trans._deps_pending = 1 + return 0 + # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 + # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) + + # 存储到数组(指针转 CSizeT) + if field_count < HandlesStruct.FIELD_MAX: + 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 指针字段。 + + # ============================================================ + # 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: str = 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: str = 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: str = CompilerFactory.get_perm_pool().alloc(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: str = 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 拷贝(指针匹配不失效)且跨文件永久存活。 + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1) + # 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 → + # 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields + # 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 + if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: + st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_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: str = 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: + # 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空; + # _translate_oop_methods/_detect_vtable_status 会在后续文件 + # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 + if HandlesStruct.get_stdlib_alloc() != 0: + pn_len: t.CSizeT = string.strlen(parent_name) + pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1) + if pn_buf is not None: + string.strcpy(pn_buf, parent_name) + entry.ParentName = pn_buf + else: + entry.ParentName = parent_name + # 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活) + if parents_count > 0 and parents_buf is not None: + HandlesStruct.set_parent_names(pool, 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: str = None + if fannot_addr != 0: + fannot = (str)(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: + HandlesClassDef._translate_oop_methods(trans, cd, struct_ty, class_name, 1) + return 0 + + # ============================================================ + # 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__ + # ============================================================ + HandlesClassDef._translate_oop_methods(trans, cd, struct_ty, class_name) + + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenEnum.vp b/App/lib/core/Gen/ClassGenEnum.vp new file mode 100644 index 0000000..12ee859 --- /dev/null +++ b/App/lib/core/Gen/ClassGenEnum.vp @@ -0,0 +1,1137 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenEnum(ClassGenBase.ClassGenBase): + """enum/union/renum 定义与变体表""" + + def _resolve_enum_member_type(self, pool: memhub.MemBuddy | t.CPtr, + ann_node: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str) -> llvmlite.LLVMType | t.CPtr: + """解析枚举成员的类型注解为 LLVM 整数类型""" + if ann_node is None: + return llvmlite.Int32(pool) + + k: int = ann_node.kind() + + # Attribute 节点: t.State / int / t.CInt8T 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node) + if at.attr is None: + return llvmlite.Int32(pool) + # t.State → 默认 i32 + if string.strcmp(at.attr, "State") == 0: + return llvmlite.Int32(pool) + # 其他 t.CXxx 类型 + ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr) + if ty is not None: + return ty + return llvmlite.Int32(pool) + + # Name 节点: from-import 形式(State / CInt) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node) + if nm.id is None: + return llvmlite.Int32(pool) + if string.strcmp(nm.id, "State") == 0: + return llvmlite.Int32(pool) + ty2: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, nm.id) + if ty2 is not None: + return ty2 + return llvmlite.Int32(pool) + + # BinOp 节点: t.State | t.CInt8T(递归查找实际类型) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node) + if bop.op == ast.OpKind.BitOr: + left_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, bop.left, imported_modules, from_imports) + # 跳过 t.State(i32 默认),优先返回具体类型 + left_bits: int = HandlesType.get_llvm_type_bits(left_ty) + if left_bits != 0 and not self._is_state_annotation(bop.left): + return left_ty + right_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, bop.right, imported_modules, from_imports) + if right_ty is not None and not self._is_state_annotation(bop.right): + return right_ty + # 两边都是 State 或无法确定,返回较宽的 + right_bits: int = HandlesType.get_llvm_type_bits(right_ty) + if left_bits >= right_bits: + return left_ty + return right_ty + # fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32 + HandlesType.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) + + # fail-fast:未知注解节点 kind,不再静默回退 i32 + HandlesType.fatal_error( + ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") + return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) + def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int: + """检查注解节点是否为 t.State,返回 1=是 / 0=否""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None and string.strcmp(at.attr, "State") == 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "State") == 0: + return 1 + return 0 + return 0 + def _extract_int_value(self, node: ast.AST | t.CPtr) -> t.CInt64T: + """从 AST 节点提取整数值,失败返回 0""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + return cn.int_val + return 0 + if k == ast.ASTKind.UnaryOp: + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo.op == ast.OpKind.USub: + inner: t.CInt64T = self._extract_int_value(uo.operand) + return -inner + return 0 + return 0 + def _translate_enum_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译枚举类定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的 + # FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的 + # 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry, + # add_enum_member 成员名去重,重复处理安全合并。 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "ENUM") + return 0 + + cn: t.CSizeT = len(children) + + # 临时数组存储成员信息 + member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + if member_names_buf is None or member_types_buf is None or member_values_buf is None: + return 0 + string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + + member_count: int = 0 + next_val: t.CInt64T = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取成员名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析成员类型 + member_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + + # 解析成员值 + has_value: int = 0 + cur_val: t.CInt64T = 0 + if aa.value is not None: + cur_val = self._extract_int_value(aa.value) + has_value = 1 + else: + cur_val = next_val + + # 下一个自动值 + next_val = cur_val + 1 + + # 存储 + if member_count < ENUM_MEMBER_MAX_LOCAL: + member_names_buf[member_count] = t.CSizeT(tgt.id) + member_types_buf[member_count] = t.CSizeT(member_ty) + member_values_buf[member_count] = cur_val + member_count += 1 + + elif sk == ast.ASTKind.Assign: + # 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等 + # CEnum 子类中无类型注释的赋值也视为枚举成员 + ag: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if ag is None or ag.targets is None: + continue + tgts: list[ast.AST | t.CPtr] | t.CPtr = ag.targets + tn: t.CSizeT = len(tgts) + if tn == 0: + continue + # 取第一个 target 作为成员名 + t0: ast.AST | t.CPtr = tgts.get(0) + if t0 is None or t0.kind() != ast.ASTKind.Name: + continue + tgt_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + if tgt_a.id is None: + continue + + # Assign 无类型注释,默认使用 i32 + member_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 解析成员值 + cur_val_a: t.CInt64T = 0 + if ag.value is not None: + cur_val_a = self._extract_int_value(ag.value) + else: + cur_val_a = next_val + + # 下一个自动值 + next_val = cur_val_a + 1 + + # 存储 + if member_count < ENUM_MEMBER_MAX_LOCAL: + member_names_buf[member_count] = t.CSizeT(tgt_a.id) + member_types_buf[member_count] = t.CSizeT(member_ty_a) + member_values_buf[member_count] = cur_val_a + member_count += 1 + + if member_count == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no members", class_name) + VLogger.warning(fb, "ENUM") + return 0 + + # 确定基准类型:所有成员类型中 Bits 最大的 + base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + max_bits: int = 0 + for mi in range(member_count): + ty_addr: t.CSizeT = member_types_buf[mi] + if ty_addr == 0: + continue + mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(ty_addr, t.CPtr)) + bits: int = HandlesType.get_llvm_type_bits(mty) + if bits > max_bits: + max_bits = bits + base_ty = mty + + # 注册枚举 + entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum( + pool, class_name, base_ty) + if entry is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to register %s", class_name) + VLogger.error(fb, "ENUM") + return 0 + + # 添加成员 + for mi in range(member_count): + fname_addr: t.CSizeT = member_names_buf[mi] + if fname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = member_types_buf[mi] + if fty_addr2 == 0: + continue + mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + mval: t.CInt64T = member_values_buf[mi] + if mname is not None and mty2 is not None: + HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d", + class_name, member_count, max_bits) + VLogger.info(fb, "ENUM") + return 0 + def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算 LLVM 类型的字节大小(含对齐 padding)""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return (bits + 7) // 8 + case llvmlite.LLVMType.Float(bits): + return bits // 8 + case llvmlite.LLVMType.Ptr(pointee): + return 8 + case llvmlite.LLVMType.Array(elem_ty, count): + return self._get_type_size(elem_ty) * count + case llvmlite.LLVMType.Struct(fields, fcount, name): + # 计算结构体大小,考虑字段对齐 padding + # 规则: 每个字段的对齐 = 该字段类型的自然对齐 + # 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1 + # 结构体总大小需对齐到最大字段对齐的倍数 + total: int = 0 + max_align: int = 1 + cur: llvmlite.ParamNode | t.CPtr = fields + i: int = 0 + while cur is not None and i < fcount: + if cur.Ty is not None: + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) + fsize: int = self._get_type_size(fty) + falign: int = self._get_type_align(fty) + # 对齐当前偏移到字段对齐边界 + if falign > 0: + rem: int = total % falign + if rem != 0: + total += falign - rem + total += fsize + if falign > max_align: + max_align = falign + cur = cur.Next + i += 1 + # 结构体总大小对齐到最大字段对齐的倍数 + rem2: int = total % max_align + if rem2 != 0: + total += max_align - rem2 + return total + case _: + return 8 + def _get_type_align(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """返回类型的自然对齐(字节)""" + if ty is None: + return 1 + match ty: + case llvmlite.LLVMType.Int(bits): + if bits <= 8: + return 1 + elif bits <= 16: + return 2 + elif bits <= 32: + return 4 + else: + return 8 + case llvmlite.LLVMType.Float(bits): + if bits <= 32: + return 4 + else: + return 8 + case llvmlite.LLVMType.Ptr(pointee): + return 8 + case llvmlite.LLVMType.Array(elem_ty, count): + return self._get_type_align(elem_ty) + case llvmlite.LLVMType.Struct(fields, fcount, name): + # 结构体的对齐 = 最大字段对齐 + max_align: int = 1 + cur: llvmlite.ParamNode | t.CPtr = fields + i: int = 0 + while cur is not None and i < fcount: + if cur.Ty is not None: + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) + fa: int = self._get_type_align(fty) + if fa > max_align: + max_align = fa + cur = cur.Next + i += 1 + return max_align + case _: + return 8 + def _translate_union_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译联合体定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前) + HandlesStruct.add_visible_struct(pool, class_name) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + # Phase B: 将已存在的命名结构体注册到当前模块 + if existing.Ty is not None: + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + # SHA1 已在 register_struct 时设置,无需再补 + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "UNION") + return 0 + + cn: t.CSizeT = len(children) + + # 临时数组存储字段信息 + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) + if field_names_buf is None or field_types_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * HandlesStruct.FIELD_MAX) + string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) + + field_count: int = 0 + max_size: int = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取字段名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) + if field_ty is None: + # Phase A-pre(declare_only=1):依赖的类可能尚未注册, + # 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类) + if trans._declare_only == 1: + return 1 + # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 + type_name: str = HandlesType.annotation_to_str(aa.annotation) + HandlesType.fatal_error( + aa, + f"'{type_name}' is not defined", + "NameError") + field_ty = llvmlite.Int32(pool) + + # 计算字段大小,更新 max_size + fsize: int = self._get_type_size(field_ty) + if fsize > max_size: + max_size = fsize + + # 存储到数组 + if field_count < HandlesStruct.FIELD_MAX: + field_names_buf[field_count] = t.CSizeT(tgt.id) + field_types_buf[field_count] = t.CSizeT(field_ty) + field_count += 1 + + if field_count == 0: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no fields", class_name) + VLogger.warning(fb, "UNION") + return 0 + + if max_size < 1: + max_size = 1 + + # 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)]) + # 即 { [max_size x i8] } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size) + + # 构建 ParamNode 链表(单字段:字节数组) + pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode is None: + return 0 + string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) + pnode.Ty = array_ty + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + union_type_name: str = class_name + if trans.ModuleSha1 is not None: + union_name_buf: str = pool.alloc(64) + if union_name_buf is not None: + viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + union_type_name = union_name_buf + + union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) + if union_ty is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name) + VLogger.error(fb, "UNION") + return 0 + + # Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活) + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册 + # includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后 + # entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃 + # (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 + if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: + union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), union_ty) + if union_copy is not None: + union_ty = union_copy + + # 注册命名结构体到模块 + llvmlite.module_add_named_type(trans.Module, pool, union_ty) + + # 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry) + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( + pool, class_name, union_ty, trans.ModuleSha1) + if entry is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "failed to register %s", class_name) + VLogger.error(fb, "UNION") + return 0 + + # 标记为当前文件可见(命名空间隔离) + HandlesStruct.add_visible_struct(pool, class_name) + + # 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错) + entry.IsUnion = 1 + + # 添加字段信息(所有字段 Index=0,因为共享偏移 0) + for fi in range(field_count): + fname_addr: t.CSizeT = field_names_buf[fi] + if fname_addr == 0: + continue + fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = field_types_buf[fi] + if fty_addr2 == 0: + continue + fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + if fname is not None and fty2 is not None: + HandlesStruct.add_field(pool, entry, fname, fty2, None, None) + + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d", + class_name, field_count, max_size) + VLogger.info(fb, "UNION") + return 0 + def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int: + """计算注解类型的字节大小,用于 REnum 布局计算""" + if annotation is None: + return 8 + k: int = annotation.kind() + # 联合类型 A | B → 指针大小 8 + if k == ast.ASTKind.BinOp: + return 8 + # Name(id) 或 Attribute(attr) → 解析类型名 + type_name: str = None + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annotation) + if nm is not None: + type_name = nm.id + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) + if at is not None: + type_name = at.attr + if type_name is None: + return 8 + # 内置类型 + if string.strcmp(type_name, "int") == 0: + return 4 + if string.strcmp(type_name, "CInt") == 0: + return 4 + if string.strcmp(type_name, "CInt8T") == 0: + return 1 + if string.strcmp(type_name, "CInt16T") == 0: + return 2 + if string.strcmp(type_name, "CInt32T") == 0: + return 4 + if string.strcmp(type_name, "CInt64T") == 0: + return 8 + if string.strcmp(type_name, "CChar") == 0: + return 1 + if string.strcmp(type_name, "CDouble") == 0: + return 8 + if string.strcmp(type_name, "CFloat") == 0: + return 4 + if string.strcmp(type_name, "CPtr") == 0: + return 8 + if string.strcmp(type_name, "CSizeT") == 0: + return 8 + if string.strcmp(type_name, "str") == 0: + return 8 + if string.strcmp(type_name, "bytes") == 0: + return 8 + if string.strcmp(type_name, "bool") == 0: + # bool = t.CBool = i8(1 字节) + return 1 + # 已注册的结构体类型 + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(type_name) + if struct_ty is not None: + sz: int = self._get_type_size(struct_ty) + if sz > 0: + return sz + # 未注册类型 → 默认指针大小 8(可能是自引用或前向引用) + return 8 + def _translate_renum_def(self, trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译 REnum 类定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见 + HandlesStruct.add_visible_struct(pool, class_name) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + if existing.Ty is not None: + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + fb: str = VLogger.fmt_buf() + if fb is not None: + viperlib.snprintf(fb, 1024, "%s has no body", class_name) + VLogger.warning(fb, "RENUM") + return 0 + + cn: t.CSizeT = len(children) + + # 变体最多 32 个,每个变体最多 16 个字段 + # variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小 + variant_field_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * 64 * 16) + if variant_field_sizes is None: + return 0 + string.memset(variant_field_sizes, 0, 8 * 64 * 16) + + variant_count: int = 0 + max_field_count: int = 0 # 所有变体中最大字段数 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.ClassDef: + # 嵌套变体类 + variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + if variant_cd is None or variant_cd.children is None: + variant_count += 1 + continue + variant_children: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children + vcn: t.CSizeT = len(variant_children) + field_idx: int = 0 + for vi in range(vcn): + vstmt: ast.AST | t.CPtr = variant_children.get(vi) + if vstmt is None: + continue + vk: int = vstmt.kind() + if vk != ast.ASTKind.AnnAssign: + continue + vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt) + if vaa is None or vaa.target is None or vaa.annotation is None: + continue + if vaa.target.kind() != ast.ASTKind.Name: + continue + # 提取字段名 + vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target) + # 计算字段大小 + fsize: int = self._get_annotation_field_size(vaa.annotation) + if variant_count < 32 and field_idx < 16: + # variant_field_sizes[variant_count][field_idx] = fsize + offset: t.CSizeT = variant_count * 16 + field_idx + variant_field_sizes[offset] = t.CSizeT(fsize) + # 直接注册变体字段名别名(避免 CSizeT→str 转换问题) + # 同时解析成员实际类型(对齐 TPC class_members,供 match + # 绑定 bitcast 槽位地址用)。自引用注解(如 + # LLVMType|t.CPtr 引用自身类)此时解析失败返回 None → + # 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset + # 后悬空,注册内部会 strcpy 到 perm_pool。 + if vnm is not None and vnm.id is not None: + mem_ty_l: llvmlite.LLVMType | t.CPtr = None + if trans is not None: + mem_ty_l = HandlesType.resolve_annotation_type( + pool, vaa.annotation, + trans._imported_modules, + trans._from_imports, trans) + self._register_renum_field_alias( + pool, class_name, vnm.id, field_idx + 1, + mem_ty_l, variant_cd.name) + field_idx += 1 + if field_idx > max_field_count: + max_field_count = field_idx + variant_count += 1 + + if variant_count == 0: + fb2: str = VLogger.fmt_buf() + if fb2 is not None: + viperlib.snprintf(fb2, 1024, "%s has no variants", class_name) + VLogger.warning(fb2, "RENUM") + return 0 + + # 计算每个位置的最大字段大小 + # 位置 0 = __tag (i32, 4 字节) + # 位置 1+ = 变体字段 + total_positions: int = max_field_count + 1 # +1 for tag + if total_positions < 2: + total_positions = 2 # 至少 {i32, i32} + + position_max_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * total_positions) + if position_max_sizes is None: + return 0 + string.memset(position_max_sizes, 0, 8 * total_positions) + + # 位置 0 = tag = 4 字节 + position_max_sizes[0] = t.CSizeT(4) + + # 位置 1+ = 每个位置取所有变体的最大字段大小 + for pos in range(1, total_positions): + pos_max: int = 0 + for vi in range(variant_count): + if vi >= 64: + break # variant_field_sizes 64 类槽上限,防读越界 + field_pos: int = pos - 1 # 变体字段从位置 0 开始 + if field_pos >= 16: + continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过 + offset2: t.CSizeT = vi * 16 + field_pos + fsize_val: t.CSizeT = variant_field_sizes[offset2] + if fsize_val > pos_max: + pos_max = fsize_val + position_max_sizes[pos] = t.CSizeT(pos_max) + + # 构建 ParamNode 链表 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + first_node: llvmlite.ParamNode | t.CPtr = None + tail_node: llvmlite.ParamNode | t.CPtr = None + + for pos in range(total_positions): + psize: int = position_max_sizes[pos] + field_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if psize > 4: + field_ty = i64_ty + pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, field_ty) + if pnode is None: + continue + tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) + if first_node is None: + first_node = tail_node + + if first_node is None: + fb3: str = VLogger.fmt_buf() + if fb3 is not None: + viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name) + VLogger.error(fb3, "RENUM") + return 0 + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + renum_type_name: str = class_name + if trans.ModuleSha1 is not None: + renum_name_buf: str = pool.alloc(64) + if renum_name_buf is not None: + viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + renum_type_name = renum_name_buf + + renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( + pool, first_node, total_positions, renum_type_name) + if renum_ty is None: + fb4: str = VLogger.fmt_buf() + if fb4 is not None: + viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name) + VLogger.error(fb4, "RENUM") + return 0 + + # Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活, + # 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效) + # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。 + if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: + renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), renum_ty) + if renum_copy is not None: + renum_ty = renum_copy + + # 注册命名结构体到模块 + llvmlite.module_add_named_type(trans.Module, pool, renum_ty) + + # 注册到 HandlesStruct + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( + pool, class_name, renum_ty, trans.ModuleSha1) + if entry is None: + fb5: str = VLogger.fmt_buf() + if fb5 is not None: + viperlib.snprintf(fb5, 1024, "failed to register %s", class_name) + VLogger.error(fb5, "RENUM") + return 0 + + # 修复 class_name 指针不匹配: + # 别名注册时用 class_name(= cd.name,AST 原始指针), + # 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。 + # 两者是不同指针,CSizeT 指针值比较会失败。 + # 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。 + if entry.Name is not None: + self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name)) + + # 添加 __tag 字段(位置 0,i32) + HandlesStruct.add_field(pool, entry, "__tag", i32_ty, None, None) + + # 添加 payload 字段(位置 1+,i32 或 i64) + for pos in range(1, total_positions): + psize2: int = position_max_sizes[pos] + payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if psize2 > 4: + payload_ty = i64_ty + field_name_buf: str = pool.alloc(16) + if field_name_buf is not None: + viperlib.snprintf(field_name_buf, 16, "_p%d", pos) + HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None) + + # 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造) + self._register_renum_variants(pool, class_name, cd, variant_count) + + # 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题) + + fb6: str = VLogger.fmt_buf() + if fb6 is not None: + viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions", + class_name, variant_count, total_positions) + VLogger.info(fb6, "RENUM") + return 0 + def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + cd: ast.ClassDef | t.CPtr, + variant_count: int): + """注册 REnum 类的变体名和 tag 值到全局变体表""" + if pool is None or class_name is None or cd is None: + return + if variant_count == 0: + return + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return + + # 懒初始化表(首次注册时分配) + # 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配, + # 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在 + # parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。 + if self.RenumClassNames is None: + self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) + self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) + self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + if (self.RenumClassNames is None or self.RenumClassVariantCounts is None + or self.RenumVariantNames is None or self.RenumVariantTags is None): + self.RenumClassNames = None + return + string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX) + string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX) + string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + self.RenumClassCount = 0 + + # 检查是否已注册(避免重复注册) + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is not None and string.strcmp(existing, class_name) == 0: + return + + # 表已满 + if self.RenumClassCount >= RENUM_CLASS_MAX: + return + + # 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空, + # _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存) + idx: int = self.RenumClassCount + cn_len_rv: t.CSizeT = string.strlen(class_name) + cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1) + if cn_buf_rv is None: + return + string.strcpy(cn_buf_rv, class_name) + self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv) + self.RenumClassVariantCounts[idx] = variant_count + + # 遍历 children,提取嵌套变体类名并注册 + cn: t.CSizeT = len(children) + tag: int = 0 + for ci in range(cn): + if tag >= variant_count: + break + if tag >= RENUM_VARIANT_PER_CLASS: + # 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错 + fb_rv: str = VLogger.fmt_buf() + if fb_rv is not None: + viperlib.snprintf(fb_rv, 1024, + "REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name) + VLogger.error(fb_rv, "RENUM") + break + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.ClassDef: + continue + vcd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + if vcd is None or vcd.name is None: + continue + name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag + # 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空) + vn_len_rv: t.CSizeT = string.strlen(vcd.name) + vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1) + if vn_buf_rv is None: + break + string.strcpy(vn_buf_rv, vcd.name) + self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv) + self.RenumVariantTags[name_offset] = tag + tag += 1 + + self.RenumClassCount = idx + 1 + def _lookup_renum_variant(self, variant_name: str) -> str: + """查找变体名所属的 REnum 类名 + + 返回: class_name (str),或 None + """ + if variant_name is None or self.RenumClassNames is None: + return None + + for i in range(self.RenumClassCount): + vcount: int = self.RenumClassVariantCounts[i] + for j in range(vcount): + name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j + vname: str = self.RenumVariantNames[name_offset] + if vname is not None and string.strcmp(vname, variant_name) == 0: + cls_nm: str = self.RenumClassNames[i] + return cls_nm + return None + def _is_renum_class_name(self, class_name: str) -> int: + """检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否""" + if class_name is None or self.RenumClassNames is None: + return 0 + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is not None and string.strcmp(existing, class_name) == 0: + return 1 + return 0 + def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int: + """在指定 REnum 类中查找变体,返回 tag 值或 -1""" + if class_name is None or variant_name is None or self.RenumClassNames is None: + return -1 + for i in range(self.RenumClassCount): + existing: str = self.RenumClassNames[i] + if existing is None or string.strcmp(existing, class_name) != 0: + continue + vcount: int = self.RenumClassVariantCounts[i] + for j in range(vcount): + name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j + vname: str = self.RenumVariantNames[name_offset] + if vname is not None and string.strcmp(vname, variant_name) == 0: + return self.RenumVariantTags[name_offset] + return -1 + return -1 + def _register_renum_field_alias(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str, + field_name: str, + payload_idx: int, + field_ty: llvmlite.LLVMType | t.CPtr = None, + variant_name: str = None): + """注册 REnum 变体字段名别名到全局表 + + field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如 + LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。 + variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员) + """ + if pool is None or class_name is None or field_name is None: + return + if payload_idx < 1: + return + + # 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收) + if self.RenumAliasClass is None: + alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() + self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) + if (self.RenumAliasClass is None or self.RenumAliasField is None + or self.RenumAliasIndex is None or self.RenumAliasTy is None + or self.RenumAliasVariant is None): + self.RenumAliasClass = None + return + string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX) + string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX) + self.RenumAliasCount = 0 + + if self.RenumAliasCount >= RENUM_ALIAS_MAX: + return + + # 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变), + # field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + return + + idx: int = self.RenumAliasCount + self.RenumAliasClass[idx] = cls_key + # field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias + # 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。 + # class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为 + # entry.Name(perm_pool 拷贝),指针值比较契约不变。 + fn_len_rfa: t.CSizeT = string.strlen(field_name) + fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1) + if fn_buf_rfa is None: + return + string.strcpy(fn_buf_rfa, field_name) + self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa) + self.RenumAliasIndex[idx] = t.CSizeT(payload_idx) + # 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空; + # 未解析成功(自引用等)存 0,绑定回退槽位类型) + self.RenumAliasTy[idx] = 0 + if field_ty is not None: + ty_copy_rfa: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), field_ty) + if ty_copy_rfa is not None: + self.RenumAliasTy[idx] = t.CSizeT(ty_copy_rfa) + # 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空) + self.RenumAliasVariant[idx] = 0 + if variant_name is not None: + vn_len_rfa: t.CSizeT = string.strlen(variant_name) + vn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(vn_len_rfa + 1) + if vn_buf_rfa is not None: + string.strcpy(vn_buf_rfa, variant_name) + self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa) + self.RenumAliasCount = idx + 1 + def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT): + """更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr""" + if old_ptr == new_ptr: + return + if self.RenumAliasClass is None: + return + for i in range(self.RenumAliasCount): + if self.RenumAliasClass[i] == old_ptr: + self.RenumAliasClass[i] = new_ptr + def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int: + """查找 REnum 变体字段名的 payload 索引,返回索引或 -1 + + class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针) + field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针) + """ + if class_name is None or field_name is None or self.RenumAliasClass is None: + return -1 + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + # field_name 用 strcmp 内容比较(指针不同但内容相同) + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + return self.RenumAliasIndex[i] + return -1 + def _lookup_renum_field_alias_ty(self, class_name: str, + field_name: str) -> llvmlite.LLVMType | t.CPtr: + """查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None + + 与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。 + 注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。 + """ + if class_name is None or field_name is None or self.RenumAliasTy is None: + return None + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing == cls_key: + fld_existing_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasField[i], t.CPtr)) + if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: + if self.RenumAliasTy[i] == 0: + return None + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.RenumAliasTy[i], t.CPtr)) + return None + def _lookup_renum_member_ty(self, class_name: str, + variant_name: str, + payload_idx: int) -> llvmlite.LLVMType | t.CPtr: + """按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型 + + match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs + Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置 + 内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。 + """ + if class_name is None or variant_name is None or self.RenumAliasVariant is None: + return None + if payload_idx < 1: + return None + cls_key: t.CSizeT = t.CSizeT(class_name) + for i in range(self.RenumAliasCount): + cls_existing: t.CSizeT = self.RenumAliasClass[i] + if cls_existing != cls_key: + continue + if self.RenumAliasVariant[i] == 0: + continue + vnt_ptr: str = (str | t.CPtr)( + t.CVoid(self.RenumAliasVariant[i], t.CPtr)) + if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0: + continue + if self.RenumAliasIndex[i] != payload_idx: + continue + if self.RenumAliasTy[i] == 0: + return None + return (llvmlite.LLVMType | t.CPtr)( + t.CVoid(self.RenumAliasTy[i], t.CPtr)) + return None \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenGeneric.vp b/App/lib/core/Gen/ClassGenGeneric.vp new file mode 100644 index 0000000..aab199a --- /dev/null +++ b/App/lib/core/Gen/ClassGenGeneric.vp @@ -0,0 +1,675 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenGeneric - ClassGenMixin 拆分(阶段 D):泛型模板注册/特化/克隆 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenGeneric(ClassGenBase.ClassGenBase): + """泛型模板注册/特化/克隆""" + + # ============================================================ + # 簇 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) + self.GenericClassFiles = list[str](pool, 8) + if self.GenericClassTpParams is None: + self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8) + if self.GenericClassTpParams is None: + return + string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8) + # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) + names_local: list[str] | t.CPtr = self.GenericClassNames + cn: t.CSizeT = len(names_local) + 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 + # type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的 + tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params) + self.GenericClassNames.append(cd.name) + self.GenericClassNodes.append(cd) + self.GenericClassSha1s.append(module_sha1) + # 同时保存模板来源文件路径(错误定位用,见字段注释) + self.GenericClassFiles.append(HandlesType.get_current_file()) + if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX: + self.GenericClassTpParams[cn] = t.CSizeT(tp_names_buf) + def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str: + """将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区 + + TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params] + (Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool + 分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。 + 返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。 + """ + if tp is None: + return None + tp_n: t.CSizeT = len(tp) + if tp_n == 0: + return None + # 计算总长:各名字长度 + (n-1) 个空格 + NUL + total: t.CSizeT = 1 + ti: t.CSizeT + for ti in range(tp_n): + tp_name: str = tp.get(ti) + if tp_name is not None: + total += string.strlen(tp_name) + 1 + buf: str = CompilerFactory.get_perm_pool().alloc(total) + if buf is None: + return None + buf[0] = '\0' + for ti in range(tp_n): + tp_name = tp.get(ti) + if tp_name is None: + continue + if ti > 0 and buf[0] != '\0': + string.strcat(buf, " ") + string.strcat(buf, tp_name) + return buf + def _find_generic_template_tp_params(self, pool: memhub.MemBuddy | t.CPtr, + class_name: str) -> list[str] | t.CPtr: + """查找泛型类模板的类型参数名列表,未找到返回 None + + 从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str] + (特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。 + """ + if self.GenericClassNames is None or class_name is None \ + or self.GenericClassTpParams is None: + return None + names_local: list[str] | t.CPtr = self.GenericClassNames + cn: t.CSizeT = len(names_local) + 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: + if i >= GENERIC_TEMPLATE_MAX: + return None + buf_addr: t.CSizeT = self.GenericClassTpParams[i] + if buf_addr == 0: + return None + buf_tp: str = (str | t.CPtr)(t.CVoid(buf_addr, t.CPtr)) + # 空格分隔 → list[str] + # 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节), + # 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖 + # (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp + # 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因) + tp_list: list[str] | t.CPtr = list[str](pool, 8) + if tp_list is None: + return None + seg_start: t.CSizeT = 0 + pos: t.CSizeT = 0 + blen: t.CSizeT = string.strlen(buf_tp) + while pos <= blen: + if buf_tp[pos] == ' ' or buf_tp[pos] == '\0': + seg_len: t.CSizeT = pos - seg_start + if seg_len > 0: + seg: str = pool.alloc(seg_len + 1) + if seg is not None: + string.strncpy(seg, buf_tp + seg_start, seg_len) + seg[seg_len] = '\0' + tp_list.append(seg) + seg_start = pos + 1 + pos += 1 + return tp_list + return None + 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 = len(names_local) + 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 = len(names_local) + 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 _find_generic_template_file(self, class_name: str) -> str: + """查找泛型类模板的来源文件路径,未找到返回 None + + 与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时 + 临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。 + """ + if self.GenericClassNames is None or class_name is None: + return None + names_local: list[str] | t.CPtr = self.GenericClassNames + files_local: list[str] | t.CPtr = self.GenericClassFiles + cn: t.CSizeT = len(names_local) + 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: + f_val: str = files_local.get(i) + return f_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 = len(type_args) + 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 = len(tp_names) 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 = len(tup_elts) + 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 = len(old_arg_list) + 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 = len(cd_children) + 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 = len(fd_children) + 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 = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) + self.SpecNames = CompilerFactory.get_perm_pool().alloc(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: str = CompilerFactory.get_perm_pool().alloc(key_len + 1) + name_copy: str = CompilerFactory.get_perm_pool().alloc(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 + # 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded + # 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。 + self.GenericSpecDepth += 1 + if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: + err_spec: str = trans.Pool.alloc(256) + if err_spec is not None: + viperlib.snprintf(err_spec, 256, + "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", + class_name, self.GenericSpecDepth) + HandlesType.fatal_error(None, err_spec, "InternalCompilerError") + HandlesType.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError") + # 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"), + # 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。 + # 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。 + ta_cnt_g: t.CSizeT = len(type_args) + 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 + + # 1. 查找泛型模板 + template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name) + if template_cd is None: + self.GenericSpecDepth -= 1 + return None + + # 2. 生成特化名 + spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args) + if spec_name is None: + self.GenericSpecDepth -= 1 + 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。补译完成后已设置,无需恢复。 + # 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1 + # (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译, + # 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。 + pre_existing.MethodsEmitted = 1 + # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) + tp_names_pre: list[str] | t.CPtr = self._find_generic_template_tp_params( + pool, class_name) + if tp_names_pre is None: + tp_names_pre = 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) + # 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板, + # node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入 + # trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。 + saved_cur_pre: str = HandlesType.get_current_file() + tpl_file_pre: str = self._find_generic_template_file(class_name) + if tpl_file_pre is not None: + HandlesType.set_current_file(tpl_file_pre) + HandlesType.push_trace(tpl_file_pre, template_cd.lineno) + HandlesClassDef._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1) + if tpl_file_pre is not None: + HandlesType.pop_trace() + HandlesType.set_current_file(saved_cur_pre) + 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 = len(type_args) + 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: + self.GenericSpecDepth -= 1 + 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: + self.GenericSpecDepth -= 1 + return cached + + # 4. 检查是否已注册(Phase B 重复特化) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if existing is not None: + self._cache_spec(pool, spec_key, spec_name) + self.GenericSpecDepth -= 1 + return spec_name + + # 预注册缓存(防止递归) + self._cache_spec(pool, spec_key, spec_name) + + # 5. 拷贝 ClassDef 节点 + # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) + tp_names: list[str] | t.CPtr = self._find_generic_template_tp_params( + pool, class_name) + if tp_names is None: + tp_names = 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: + self.GenericSpecDepth -= 1 + 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) + # 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件 + # 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile + # 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。 + saved_cur_full: str = HandlesType.get_current_file() + tpl_file_full: str = self._find_generic_template_file(class_name) + if tpl_file_full is not None: + HandlesType.set_current_file(tpl_file_full) + HandlesType.push_trace(tpl_file_full, template_cd.lineno) + HandlesClassDef.translate_class_def(trans, spec_cd) + if tpl_file_full is not None: + HandlesType.pop_trace() + HandlesType.set_current_file(saved_cur_full) + # 恢复原始 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() + + # 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏, + # 静默继续会让后续 GEP 按错索引访问) + if string.strcmp(class_name, "GSListNode") == 0: + result_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if result_entry is not None: + 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) + if rfn is None: + VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC") + HandlesType.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError") + + self.GenericSpecDepth -= 1 + return spec_name \ No newline at end of file diff --git a/App/lib/core/Gen/ClassGenMixin.vp b/App/lib/core/Gen/ClassGenMixin.vp index e9fa573..3f39cee 100644 --- a/App/lib/core/Gen/ClassGenMixin.vp +++ b/App/lib/core/Gen/ClassGenMixin.vp @@ -15,4754 +15,18 @@ 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 - - -# ============================================================ -# 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.RENUM_ALIAS_MAX 保持一致; -# 本模块 _register_renum_field_alias 用到,必须在此定义——TPV 不跨模块 -# 解析裸常量名,函数体首次被类型检查时 NameError) -RENUM_ALIAS_MAX: t.CDefine = 512 - -# 方法元数据位掩码(与 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_TLS: t.CDefine = 32 - -META_MAX: t.CDefine = 512 -META_KEY_LEN: t.CDefine = 128 - -# 类编译期元数据表容量上限(__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) -# ValueError=1 TypeError=2 RuntimeError=3 ZeroDivisionError=4 IndexError=5 -# 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 - -# 泛型特化缓存容量上限(与 HandlesClassDef.SPEC_CACHE_MAX 一致) -SPEC_CACHE_MAX: t.CDefine = 512 - -# 泛型模板注册容量上限(GenericClassTpParams stdlib 数组槽数, -# 与 GenericClassNames 等 pool 表可容纳的模板数对齐) -GENERIC_TEMPLATE_MAX: t.CDefine = 512 - -# 泛型特化递归深度上限(泛型循环套用防护) -# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环 -GENERIC_SPEC_MAX_DEPTH: t.CDefine = 64 - -# vtable 方法最大数量(与 HandlesClassDef.VTBL_METHOD_MAX 一致) -VTBL_METHOD_MAX: t.CDefine = 32 - +import lib.core.Gen.ClassGenBase as ClassGenBase # ============================================================ # ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum +# +# 500~1500 行/文件架构重构阶段 D:全部方法已拆至 +# ClassGenBase/Enum/Generic/VTable/Def,本文件保留类声明。 +# @t.NoVTable:静态绑定。 # ============================================================ @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 - # 变体成员实际 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 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 = 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 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 = 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 有缓存,重复调用安全) - 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 = 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) - - def _resolve_enum_member_type(self, pool: memhub.MemBuddy | t.CPtr, - ann_node: ast.AST | t.CPtr, - imported_modules: str, - from_imports: str) -> llvmlite.LLVMType | t.CPtr: - """解析枚举成员的类型注解为 LLVM 整数类型""" - if ann_node is None: - return llvmlite.Int32(pool) - - k: int = ann_node.kind() - - # Attribute 节点: t.State / int / t.CInt8T 等 - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node) - if at.attr is None: - return llvmlite.Int32(pool) - # t.State → 默认 i32 - if string.strcmp(at.attr, "State") == 0: - return llvmlite.Int32(pool) - # 其他 t.CXxx 类型 - ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr) - if ty is not None: - return ty - return llvmlite.Int32(pool) - - # Name 节点: from-import 形式(State / CInt) - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node) - if nm.id is None: - return llvmlite.Int32(pool) - if string.strcmp(nm.id, "State") == 0: - return llvmlite.Int32(pool) - ty2: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, nm.id) - if ty2 is not None: - return ty2 - return llvmlite.Int32(pool) - - # BinOp 节点: t.State | t.CInt8T(递归查找实际类型) - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node) - if bop.op == ast.OpKind.BitOr: - left_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, bop.left, imported_modules, from_imports) - # 跳过 t.State(i32 默认),优先返回具体类型 - left_bits: int = HandlesType.get_llvm_type_bits(left_ty) - if left_bits != 0 and not self._is_state_annotation(bop.left): - return left_ty - right_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, bop.right, imported_modules, from_imports) - if right_ty is not None and not self._is_state_annotation(bop.right): - return right_ty - # 两边都是 State 或无法确定,返回较宽的 - right_bits: int = HandlesType.get_llvm_type_bits(right_ty) - if left_bits >= right_bits: - return left_ty - return right_ty - # fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32 - HandlesType.fatal_error( - ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") - return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) - - # fail-fast:未知注解节点 kind,不再静默回退 i32 - HandlesType.fatal_error( - ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError") - return llvmlite.Int32(pool) # 不可达(fatal_error 已退出) - - def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int: - """检查注解节点是否为 t.State,返回 1=是 / 0=否""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is not None and string.strcmp(at.attr, "State") == 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None and string.strcmp(nm.id, "State") == 0: - return 1 - return 0 - return 0 - - def _extract_int_value(self, node: ast.AST | t.CPtr) -> t.CInt64T: - """从 AST 节点提取整数值,失败返回 0""" - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn.const_kind == ast.CONST_INT: - return cn.int_val - return 0 - if k == ast.ASTKind.UnaryOp: - uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uo.op == ast.OpKind.USub: - inner: t.CInt64T = self._extract_int_value(uo.operand) - return -inner - return 0 - return 0 - - def _translate_enum_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译枚举类定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的 - # FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的 - # 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry, - # add_enum_member 成员名去重,重复处理安全合并。 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "ENUM") - return 0 - - cn: t.CSizeT = len(children) - - # 临时数组存储成员信息 - member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) - if member_names_buf is None or member_types_buf is None or member_values_buf is None: - return 0 - string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) - - member_count: int = 0 - next_val: t.CInt64T = 0 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa is None or aa.target is None: - continue - - # 获取成员名 - if aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - - # 解析成员类型 - member_ty: llvmlite.LLVMType | t.CPtr = self._resolve_enum_member_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports) - - # 解析成员值 - has_value: int = 0 - cur_val: t.CInt64T = 0 - if aa.value is not None: - cur_val = self._extract_int_value(aa.value) - has_value = 1 - else: - cur_val = next_val - - # 下一个自动值 - next_val = cur_val + 1 - - # 存储 - if member_count < ENUM_MEMBER_MAX_LOCAL: - member_names_buf[member_count] = t.CSizeT(tgt.id) - member_types_buf[member_count] = t.CSizeT(member_ty) - member_values_buf[member_count] = cur_val - member_count += 1 - - elif sk == ast.ASTKind.Assign: - # 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等 - # CEnum 子类中无类型注释的赋值也视为枚举成员 - ag: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) - if ag is None or ag.targets is None: - continue - tgts: list[ast.AST | t.CPtr] | t.CPtr = ag.targets - tn: t.CSizeT = len(tgts) - if tn == 0: - continue - # 取第一个 target 作为成员名 - t0: ast.AST | t.CPtr = tgts.get(0) - if t0 is None or t0.kind() != ast.ASTKind.Name: - continue - tgt_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) - if tgt_a.id is None: - continue - - # Assign 无类型注释,默认使用 i32 - member_ty_a: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 解析成员值 - cur_val_a: t.CInt64T = 0 - if ag.value is not None: - cur_val_a = self._extract_int_value(ag.value) - else: - cur_val_a = next_val - - # 下一个自动值 - next_val = cur_val_a + 1 - - # 存储 - if member_count < ENUM_MEMBER_MAX_LOCAL: - member_names_buf[member_count] = t.CSizeT(tgt_a.id) - member_types_buf[member_count] = t.CSizeT(member_ty_a) - member_values_buf[member_count] = cur_val_a - member_count += 1 - - if member_count == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no members", class_name) - VLogger.warning(fb, "ENUM") - return 0 - - # 确定基准类型:所有成员类型中 Bits 最大的 - base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - max_bits: int = 0 - for mi in range(member_count): - ty_addr: t.CSizeT = member_types_buf[mi] - if ty_addr == 0: - continue - mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(ty_addr, t.CPtr)) - bits: int = HandlesType.get_llvm_type_bits(mty) - if bits > max_bits: - max_bits = bits - base_ty = mty - - # 注册枚举 - entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum( - pool, class_name, base_ty) - if entry is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to register %s", class_name) - VLogger.error(fb, "ENUM") - return 0 - - # 添加成员 - for mi in range(member_count): - fname_addr: t.CSizeT = member_names_buf[mi] - if fname_addr == 0: - continue - mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) - fty_addr2: t.CSizeT = member_types_buf[mi] - if fty_addr2 == 0: - continue - mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(fty_addr2, t.CPtr)) - mval: t.CInt64T = member_values_buf[mi] - if mname is not None and mty2 is not None: - HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d", - class_name, member_count, max_bits) - VLogger.info(fb, "ENUM") - return 0 - - def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算 LLVM 类型的字节大小(含对齐 padding)""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Int(bits): - return (bits + 7) // 8 - case llvmlite.LLVMType.Float(bits): - return bits // 8 - case llvmlite.LLVMType.Ptr(pointee): - return 8 - case llvmlite.LLVMType.Array(elem_ty, count): - return self._get_type_size(elem_ty) * count - case llvmlite.LLVMType.Struct(fields, fcount, name): - # 计算结构体大小,考虑字段对齐 padding - # 规则: 每个字段的对齐 = 该字段类型的自然对齐 - # 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1 - # 结构体总大小需对齐到最大字段对齐的倍数 - total: int = 0 - max_align: int = 1 - cur: llvmlite.ParamNode | t.CPtr = fields - i: int = 0 - while cur is not None and i < fcount: - if cur.Ty is not None: - fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) - fsize: int = self._get_type_size(fty) - falign: int = self._get_type_align(fty) - # 对齐当前偏移到字段对齐边界 - if falign > 0: - rem: int = total % falign - if rem != 0: - total += falign - rem - total += fsize - if falign > max_align: - max_align = falign - cur = cur.Next - i += 1 - # 结构体总大小对齐到最大字段对齐的倍数 - rem2: int = total % max_align - if rem2 != 0: - total += max_align - rem2 - return total - case _: - return 8 - - def _get_type_align(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """返回类型的自然对齐(字节)""" - if ty is None: - return 1 - match ty: - case llvmlite.LLVMType.Int(bits): - if bits <= 8: - return 1 - elif bits <= 16: - return 2 - elif bits <= 32: - return 4 - else: - return 8 - case llvmlite.LLVMType.Float(bits): - if bits <= 32: - return 4 - else: - return 8 - case llvmlite.LLVMType.Ptr(pointee): - return 8 - case llvmlite.LLVMType.Array(elem_ty, count): - return self._get_type_align(elem_ty) - case llvmlite.LLVMType.Struct(fields, fcount, name): - # 结构体的对齐 = 最大字段对齐 - max_align: int = 1 - cur: llvmlite.ParamNode | t.CPtr = fields - i: int = 0 - while cur is not None and i < fcount: - if cur.Ty is not None: - fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) - fa: int = self._get_type_align(fty) - if fa > max_align: - max_align = fa - cur = cur.Next - i += 1 - return max_align - case _: - return 8 - - def _translate_union_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译联合体定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前) - HandlesStruct.add_visible_struct(pool, class_name) - - # 检查是否已注册(用 SHA1 区分跨模块同名类) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - if existing is not None: - # Phase B: 将已存在的命名结构体注册到当前模块 - if existing.Ty is not None: - llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) - # SHA1 已在 register_struct 时设置,无需再补 - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "UNION") - return 0 - - cn: t.CSizeT = len(children) - - # 临时数组存储字段信息 - field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - if field_names_buf is None or field_types_buf is None: - return 0 - string.memset(field_names_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) - - field_count: int = 0 - max_size: int = 0 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.AnnAssign: - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) - if aa is None or aa.target is None: - continue - - # 获取字段名 - if aa.target.kind() != ast.ASTKind.Name: - continue - tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) - if tgt.id is None: - continue - - # 解析字段类型 - field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) - if field_ty is None: - # Phase A-pre(declare_only=1):依赖的类可能尚未注册, - # 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类) - if trans._declare_only == 1: - return 1 - # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止 - type_name: str = HandlesType.annotation_to_str(aa.annotation) - HandlesType.fatal_error( - aa, - f"'{type_name}' is not defined", - "NameError") - field_ty = llvmlite.Int32(pool) - - # 计算字段大小,更新 max_size - fsize: int = self._get_type_size(field_ty) - if fsize > max_size: - max_size = fsize - - # 存储到数组 - if field_count < HandlesStruct.FIELD_MAX: - field_names_buf[field_count] = t.CSizeT(tgt.id) - field_types_buf[field_count] = t.CSizeT(field_ty) - field_count += 1 - - if field_count == 0: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no fields", class_name) - VLogger.warning(fb, "UNION") - return 0 - - if max_size < 1: - max_size = 1 - - # 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)]) - # 即 { [max_size x i8] } - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size) - - # 构建 ParamNode 链表(单字段:字节数组) - pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) - if pnode is None: - return 0 - string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) - pnode.Ty = array_ty - - # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" - union_type_name: str = class_name - if trans.ModuleSha1 is not None: - union_name_buf: str = pool.alloc(64) - if union_name_buf is not None: - viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) - union_type_name = union_name_buf - - union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) - if union_ty is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name) - VLogger.error(fb, "UNION") - return 0 - - # Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活) - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册 - # includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后 - # entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃 - # (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), union_ty) - if union_copy is not None: - union_ty = union_copy - - # 注册命名结构体到模块 - llvmlite.module_add_named_type(trans.Module, pool, union_ty) - - # 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry) - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( - pool, class_name, union_ty, trans.ModuleSha1) - if entry is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "failed to register %s", class_name) - VLogger.error(fb, "UNION") - return 0 - - # 标记为当前文件可见(命名空间隔离) - HandlesStruct.add_visible_struct(pool, class_name) - - # 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错) - entry.IsUnion = 1 - - # 添加字段信息(所有字段 Index=0,因为共享偏移 0) - for fi in range(field_count): - fname_addr: t.CSizeT = field_names_buf[fi] - if fname_addr == 0: - continue - fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) - fty_addr2: t.CSizeT = field_types_buf[fi] - if fty_addr2 == 0: - continue - fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( - t.CVoid(fty_addr2, t.CPtr)) - if fname is not None and fty2 is not None: - HandlesStruct.add_field(pool, entry, fname, fty2, None, None) - - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d", - class_name, field_count, max_size) - VLogger.info(fb, "UNION") - return 0 - - def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int: - """计算注解类型的字节大小,用于 REnum 布局计算""" - if annotation is None: - return 8 - k: int = annotation.kind() - # 联合类型 A | B → 指针大小 8 - if k == ast.ASTKind.BinOp: - return 8 - # Name(id) 或 Attribute(attr) → 解析类型名 - type_name: str = None - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annotation) - if nm is not None: - type_name = nm.id - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation) - if at is not None: - type_name = at.attr - if type_name is None: - return 8 - # 内置类型 - if string.strcmp(type_name, "int") == 0: - return 4 - if string.strcmp(type_name, "CInt") == 0: - return 4 - if string.strcmp(type_name, "CInt8T") == 0: - return 1 - if string.strcmp(type_name, "CInt16T") == 0: - return 2 - if string.strcmp(type_name, "CInt32T") == 0: - return 4 - if string.strcmp(type_name, "CInt64T") == 0: - return 8 - if string.strcmp(type_name, "CChar") == 0: - return 1 - if string.strcmp(type_name, "CDouble") == 0: - return 8 - if string.strcmp(type_name, "CFloat") == 0: - return 4 - if string.strcmp(type_name, "CPtr") == 0: - return 8 - if string.strcmp(type_name, "CSizeT") == 0: - return 8 - if string.strcmp(type_name, "str") == 0: - return 8 - if string.strcmp(type_name, "bytes") == 0: - return 8 - if string.strcmp(type_name, "bool") == 0: - # bool = t.CBool = i8(1 字节) - return 1 - # 已注册的结构体类型 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(type_name) - if struct_ty is not None: - sz: int = self._get_type_size(struct_ty) - if sz > 0: - return sz - # 未注册类型 → 默认指针大小 8(可能是自引用或前向引用) - return 8 - - def _translate_renum_def(self, trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr) -> int: - """翻译 REnum 类定义,返回 0""" - if cd is None or cd.name is None or trans is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = trans.Pool - class_name: str = cd.name - - # 命名空间隔离:标记为当前文件可见 - HandlesStruct.add_visible_struct(pool, class_name) - - # 检查是否已注册(用 SHA1 区分跨模块同名类) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( - class_name, trans.ModuleSha1) - if existing is not None: - if existing.Ty is not None: - llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) - return 0 - - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - fb: str = VLogger.fmt_buf() - if fb is not None: - viperlib.snprintf(fb, 1024, "%s has no body", class_name) - VLogger.warning(fb, "RENUM") - return 0 - - cn: t.CSizeT = len(children) - - # 变体最多 32 个,每个变体最多 16 个字段 - # variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小 - variant_field_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * 64 * 16) - if variant_field_sizes is None: - return 0 - string.memset(variant_field_sizes, 0, 8 * 64 * 16) - - variant_count: int = 0 - max_field_count: int = 0 # 所有变体中最大字段数 - - for ci in range(cn): - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - sk: int = stmt.kind() - - if sk == ast.ASTKind.ClassDef: - # 嵌套变体类 - variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - if variant_cd is None or variant_cd.children is None: - variant_count += 1 - continue - variant_children: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children - vcn: t.CSizeT = len(variant_children) - field_idx: int = 0 - for vi in range(vcn): - vstmt: ast.AST | t.CPtr = variant_children.get(vi) - if vstmt is None: - continue - vk: int = vstmt.kind() - if vk != ast.ASTKind.AnnAssign: - continue - vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt) - if vaa is None or vaa.target is None or vaa.annotation is None: - continue - if vaa.target.kind() != ast.ASTKind.Name: - continue - # 提取字段名 - vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target) - # 计算字段大小 - fsize: int = self._get_annotation_field_size(vaa.annotation) - if variant_count < 32 and field_idx < 16: - # variant_field_sizes[variant_count][field_idx] = fsize - offset: t.CSizeT = variant_count * 16 + field_idx - variant_field_sizes[offset] = t.CSizeT(fsize) - # 直接注册变体字段名别名(避免 CSizeT→str 转换问题) - # 同时解析成员实际类型(对齐 TPC class_members,供 match - # 绑定 bitcast 槽位地址用)。自引用注解(如 - # LLVMType|t.CPtr 引用自身类)此时解析失败返回 None → - # 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset - # 后悬空,注册内部会 strcpy 到 perm_pool。 - if vnm is not None and vnm.id is not None: - mem_ty_l: llvmlite.LLVMType | t.CPtr = None - if trans is not None: - mem_ty_l = HandlesType.resolve_annotation_type( - pool, vaa.annotation, - trans._imported_modules, - trans._from_imports, trans) - self._register_renum_field_alias( - pool, class_name, vnm.id, field_idx + 1, - mem_ty_l, variant_cd.name) - field_idx += 1 - if field_idx > max_field_count: - max_field_count = field_idx - variant_count += 1 - - if variant_count == 0: - fb2: str = VLogger.fmt_buf() - if fb2 is not None: - viperlib.snprintf(fb2, 1024, "%s has no variants", class_name) - VLogger.warning(fb2, "RENUM") - return 0 - - # 计算每个位置的最大字段大小 - # 位置 0 = __tag (i32, 4 字节) - # 位置 1+ = 变体字段 - total_positions: int = max_field_count + 1 # +1 for tag - if total_positions < 2: - total_positions = 2 # 至少 {i32, i32} - - position_max_sizes: t.CSizeT | t.CPtr = pool.alloc(8 * total_positions) - if position_max_sizes is None: - return 0 - string.memset(position_max_sizes, 0, 8 * total_positions) - - # 位置 0 = tag = 4 字节 - position_max_sizes[0] = t.CSizeT(4) - - # 位置 1+ = 每个位置取所有变体的最大字段大小 - for pos in range(1, total_positions): - pos_max: int = 0 - for vi in range(variant_count): - if vi >= 64: - break # variant_field_sizes 64 类槽上限,防读越界 - field_pos: int = pos - 1 # 变体字段从位置 0 开始 - if field_pos >= 16: - continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过 - offset2: t.CSizeT = vi * 16 + field_pos - fsize_val: t.CSizeT = variant_field_sizes[offset2] - if fsize_val > pos_max: - pos_max = fsize_val - position_max_sizes[pos] = t.CSizeT(pos_max) - - # 构建 ParamNode 链表 - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - first_node: llvmlite.ParamNode | t.CPtr = None - tail_node: llvmlite.ParamNode | t.CPtr = None - - for pos in range(total_positions): - psize: int = position_max_sizes[pos] - field_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if psize > 4: - field_ty = i64_ty - pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, field_ty) - if pnode is None: - continue - tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) - if first_node is None: - first_node = tail_node - - if first_node is None: - fb3: str = VLogger.fmt_buf() - if fb3 is not None: - viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name) - VLogger.error(fb3, "RENUM") - return 0 - - # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" - renum_type_name: str = class_name - if trans.ModuleSha1 is not None: - renum_name_buf: str = pool.alloc(64) - if renum_name_buf is not None: - viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) - renum_type_name = renum_name_buf - - renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( - pool, first_node, total_positions, renum_type_name) - if renum_ty is None: - fb4: str = VLogger.fmt_buf() - if fb4 is not None: - viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name) - VLogger.error(fb4, "RENUM") - return 0 - - # Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活, - # 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效) - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), renum_ty) - if renum_copy is not None: - renum_ty = renum_copy - - # 注册命名结构体到模块 - llvmlite.module_add_named_type(trans.Module, pool, renum_ty) - - # 注册到 HandlesStruct - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( - pool, class_name, renum_ty, trans.ModuleSha1) - if entry is None: - fb5: str = VLogger.fmt_buf() - if fb5 is not None: - viperlib.snprintf(fb5, 1024, "failed to register %s", class_name) - VLogger.error(fb5, "RENUM") - return 0 - - # 修复 class_name 指针不匹配: - # 别名注册时用 class_name(= cd.name,AST 原始指针), - # 但查找时用 entry.Name(register_struct 通过 pool.alloc+strcpy 复制的副本指针)。 - # 两者是不同指针,CSizeT 指针值比较会失败。 - # 调用辅助函数将已注册别名的 class_name 统一更新为 entry.Name。 - if entry.Name is not None: - self._update_renum_alias_class_ptr(t.CSizeT(class_name), t.CSizeT(entry.Name)) - - # 添加 __tag 字段(位置 0,i32) - HandlesStruct.add_field(pool, entry, "__tag", i32_ty, None, None) - - # 添加 payload 字段(位置 1+,i32 或 i64) - for pos in range(1, total_positions): - psize2: int = position_max_sizes[pos] - payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if psize2 > 4: - payload_ty = i64_ty - field_name_buf: str = pool.alloc(16) - if field_name_buf is not None: - viperlib.snprintf(field_name_buf, 16, "_p%d", pos) - HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None) - - # 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造) - self._register_renum_variants(pool, class_name, cd, variant_count) - - # 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题) - - fb6: str = VLogger.fmt_buf() - if fb6 is not None: - viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions", - class_name, variant_count, total_positions) - VLogger.info(fb6, "RENUM") - return 0 - - def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - cd: ast.ClassDef | t.CPtr, - variant_count: int): - """注册 REnum 类的变体名和 tag 值到全局变体表""" - if pool is None or class_name is None or cd is None: - return - if variant_count == 0: - return - children: list[ast.AST | t.CPtr] | t.CPtr = cd.children - if children is None: - return - - # 懒初始化表(首次注册时分配) - # 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配, - # 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在 - # parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。 - if self.RenumClassNames is None: - self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) - self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX) - self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - if (self.RenumClassNames is None or self.RenumClassVariantCounts is None - or self.RenumVariantNames is None or self.RenumVariantTags is None): - self.RenumClassNames = None - return - string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX) - string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX) - string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - self.RenumClassCount = 0 - - # 检查是否已注册(避免重复注册) - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is not None and string.strcmp(existing, class_name) == 0: - return - - # 表已满 - if self.RenumClassCount >= RENUM_CLASS_MAX: - return - - # 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空, - # _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存) - idx: int = self.RenumClassCount - cn_len_rv: t.CSizeT = string.strlen(class_name) - cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1) - if cn_buf_rv is None: - return - string.strcpy(cn_buf_rv, class_name) - self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv) - self.RenumClassVariantCounts[idx] = variant_count - - # 遍历 children,提取嵌套变体类名并注册 - cn: t.CSizeT = len(children) - tag: int = 0 - for ci in range(cn): - if tag >= variant_count: - break - if tag >= RENUM_VARIANT_PER_CLASS: - # 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错 - fb_rv: str = VLogger.fmt_buf() - if fb_rv is not None: - viperlib.snprintf(fb_rv, 1024, - "REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name) - VLogger.error(fb_rv, "RENUM") - break - stmt: ast.AST | t.CPtr = children.get(ci) - if stmt is None: - continue - if stmt.kind() != ast.ASTKind.ClassDef: - continue - vcd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) - if vcd is None or vcd.name is None: - continue - name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag - # 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空) - vn_len_rv: t.CSizeT = string.strlen(vcd.name) - vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1) - if vn_buf_rv is None: - break - string.strcpy(vn_buf_rv, vcd.name) - self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv) - self.RenumVariantTags[name_offset] = tag - tag += 1 - - self.RenumClassCount = idx + 1 - - def _lookup_renum_variant(self, variant_name: str) -> str: - """查找变体名所属的 REnum 类名 - - 返回: class_name (str),或 None - """ - if variant_name is None or self.RenumClassNames is None: - return None - - for i in range(self.RenumClassCount): - vcount: int = self.RenumClassVariantCounts[i] - for j in range(vcount): - name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j - vname: str = self.RenumVariantNames[name_offset] - if vname is not None and string.strcmp(vname, variant_name) == 0: - cls_nm: str = self.RenumClassNames[i] - return cls_nm - return None - - def _is_renum_class_name(self, class_name: str) -> int: - """检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否""" - if class_name is None or self.RenumClassNames is None: - return 0 - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is not None and string.strcmp(existing, class_name) == 0: - return 1 - return 0 - - def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int: - """在指定 REnum 类中查找变体,返回 tag 值或 -1""" - if class_name is None or variant_name is None or self.RenumClassNames is None: - return -1 - for i in range(self.RenumClassCount): - existing: str = self.RenumClassNames[i] - if existing is None or string.strcmp(existing, class_name) != 0: - continue - vcount: int = self.RenumClassVariantCounts[i] - for j in range(vcount): - name_offset: t.CSizeT = i * RENUM_VARIANT_PER_CLASS + j - vname: str = self.RenumVariantNames[name_offset] - if vname is not None and string.strcmp(vname, variant_name) == 0: - return self.RenumVariantTags[name_offset] - return -1 - return -1 - - def _register_renum_field_alias(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str, - field_name: str, - payload_idx: int, - field_ty: llvmlite.LLVMType | t.CPtr = None, - variant_name: str = None): - """注册 REnum 变体字段名别名到全局表 - - field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如 - LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。 - variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员) - """ - if pool is None or class_name is None or field_name is None: - return - if payload_idx < 1: - return - - # 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收) - if self.RenumAliasClass is None: - alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool() - self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX) - if (self.RenumAliasClass is None or self.RenumAliasField is None - or self.RenumAliasIndex is None or self.RenumAliasTy is None - or self.RenumAliasVariant is None): - self.RenumAliasClass = None - return - string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX) - string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX) - self.RenumAliasCount = 0 - - if self.RenumAliasCount >= RENUM_ALIAS_MAX: - return - - # 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变), - # field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - return - - idx: int = self.RenumAliasCount - self.RenumAliasClass[idx] = cls_key - # field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias - # 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。 - # class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为 - # entry.Name(perm_pool 拷贝),指针值比较契约不变。 - fn_len_rfa: t.CSizeT = string.strlen(field_name) - fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1) - if fn_buf_rfa is None: - return - string.strcpy(fn_buf_rfa, field_name) - self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa) - self.RenumAliasIndex[idx] = t.CSizeT(payload_idx) - # 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空; - # 未解析成功(自引用等)存 0,绑定回退槽位类型) - self.RenumAliasTy[idx] = 0 - if field_ty is not None: - ty_copy_rfa: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), field_ty) - if ty_copy_rfa is not None: - self.RenumAliasTy[idx] = t.CSizeT(ty_copy_rfa) - # 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空) - self.RenumAliasVariant[idx] = 0 - if variant_name is not None: - vn_len_rfa: t.CSizeT = string.strlen(variant_name) - vn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(vn_len_rfa + 1) - if vn_buf_rfa is not None: - string.strcpy(vn_buf_rfa, variant_name) - self.RenumAliasVariant[idx] = t.CSizeT(vn_buf_rfa) - self.RenumAliasCount = idx + 1 - - def _update_renum_alias_class_ptr(self, old_ptr: t.CSizeT, new_ptr: t.CSizeT): - """更新别名表中的 class_name 指针,从 old_ptr 更新为 new_ptr""" - if old_ptr == new_ptr: - return - if self.RenumAliasClass is None: - return - for i in range(self.RenumAliasCount): - if self.RenumAliasClass[i] == old_ptr: - self.RenumAliasClass[i] = new_ptr - - def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int: - """查找 REnum 变体字段名的 payload 索引,返回索引或 -1 - - class_name: 用 CSizeT 指针值比较(_update_renum_alias_class_ptr 已统一指针) - field_name: 用 strcmp 内容比较(注册时 vnm.id 与查找时 at.attr 是不同指针) - """ - if class_name is None or field_name is None or self.RenumAliasClass is None: - return -1 - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - # field_name 用 strcmp 内容比较(指针不同但内容相同) - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - return self.RenumAliasIndex[i] - return -1 - - def _lookup_renum_field_alias_ty(self, class_name: str, - field_name: str) -> llvmlite.LLVMType | t.CPtr: - """查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None - - 与 _lookup_renum_field_alias 同表同键(class 指针值比较 + field strcmp)。 - 注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。 - """ - if class_name is None or field_name is None or self.RenumAliasTy is None: - return None - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing == cls_key: - fld_existing_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasField[i], t.CPtr)) - if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0: - if self.RenumAliasTy[i] == 0: - return None - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.RenumAliasTy[i], t.CPtr)) - return None - - def _lookup_renum_member_ty(self, class_name: str, - variant_name: str, - payload_idx: int) -> llvmlite.LLVMType | t.CPtr: - """按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型 - - match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs - Struct.Fields=Ptr),必须带变体名定位。class 指针值比较 + 变体/位置 - 内容比较。返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。 - """ - if class_name is None or variant_name is None or self.RenumAliasVariant is None: - return None - if payload_idx < 1: - return None - cls_key: t.CSizeT = t.CSizeT(class_name) - for i in range(self.RenumAliasCount): - cls_existing: t.CSizeT = self.RenumAliasClass[i] - if cls_existing != cls_key: - continue - if self.RenumAliasVariant[i] == 0: - continue - vnt_ptr: str = (str | t.CPtr)( - t.CVoid(self.RenumAliasVariant[i], t.CPtr)) - if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0: - continue - if self.RenumAliasIndex[i] != payload_idx: - continue - if self.RenumAliasTy[i] == 0: - return None - return (llvmlite.LLVMType | t.CPtr)( - t.CVoid(self.RenumAliasTy[i], t.CPtr)) - return None - - # ============================================================ - # 簇 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) - self.GenericClassFiles = list[str](pool, 8) - if self.GenericClassTpParams is None: - self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8) - if self.GenericClassTpParams is None: - return - string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8) - # 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败) - names_local: list[str] | t.CPtr = self.GenericClassNames - cn: t.CSizeT = len(names_local) - 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 - # type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的 - tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params) - self.GenericClassNames.append(cd.name) - self.GenericClassNodes.append(cd) - self.GenericClassSha1s.append(module_sha1) - # 同时保存模板来源文件路径(错误定位用,见字段注释) - self.GenericClassFiles.append(HandlesType.get_current_file()) - if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX: - self.GenericClassTpParams[cn] = t.CSizeT(tp_names_buf) - - def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str: - """将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区 - - TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params] - (Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool - 分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。 - 返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。 - """ - if tp is None: - return None - tp_n: t.CSizeT = len(tp) - if tp_n == 0: - return None - # 计算总长:各名字长度 + (n-1) 个空格 + NUL - total: t.CSizeT = 1 - ti: t.CSizeT - for ti in range(tp_n): - tp_name: str = tp.get(ti) - if tp_name is not None: - total += string.strlen(tp_name) + 1 - buf: str = CompilerFactory.get_perm_pool().alloc(total) - if buf is None: - return None - buf[0] = '\0' - for ti in range(tp_n): - tp_name = tp.get(ti) - if tp_name is None: - continue - if ti > 0 and buf[0] != '\0': - string.strcat(buf, " ") - string.strcat(buf, tp_name) - return buf - - def _find_generic_template_tp_params(self, pool: memhub.MemBuddy | t.CPtr, - class_name: str) -> list[str] | t.CPtr: - """查找泛型类模板的类型参数名列表,未找到返回 None - - 从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str] - (特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。 - """ - if self.GenericClassNames is None or class_name is None \ - or self.GenericClassTpParams is None: - return None - names_local: list[str] | t.CPtr = self.GenericClassNames - cn: t.CSizeT = len(names_local) - 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: - if i >= GENERIC_TEMPLATE_MAX: - return None - buf_addr: t.CSizeT = self.GenericClassTpParams[i] - if buf_addr == 0: - return None - buf_tp: str = (str | t.CPtr)(t.CVoid(buf_addr, t.CPtr)) - # 空格分隔 → list[str] - # 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节), - # 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖 - # (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp - # 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因) - tp_list: list[str] | t.CPtr = list[str](pool, 8) - if tp_list is None: - return None - seg_start: t.CSizeT = 0 - pos: t.CSizeT = 0 - blen: t.CSizeT = string.strlen(buf_tp) - while pos <= blen: - if buf_tp[pos] == ' ' or buf_tp[pos] == '\0': - seg_len: t.CSizeT = pos - seg_start - if seg_len > 0: - seg: str = pool.alloc(seg_len + 1) - if seg is not None: - string.strncpy(seg, buf_tp + seg_start, seg_len) - seg[seg_len] = '\0' - tp_list.append(seg) - seg_start = pos + 1 - pos += 1 - return tp_list - return None - - 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 = len(names_local) - 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 = len(names_local) - 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 _find_generic_template_file(self, class_name: str) -> str: - """查找泛型类模板的来源文件路径,未找到返回 None - - 与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时 - 临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。 - """ - if self.GenericClassNames is None or class_name is None: - return None - names_local: list[str] | t.CPtr = self.GenericClassNames - files_local: list[str] | t.CPtr = self.GenericClassFiles - cn: t.CSizeT = len(names_local) - 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: - f_val: str = files_local.get(i) - return f_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 = len(type_args) - 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 = len(tp_names) 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 = len(tup_elts) - 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 = len(old_arg_list) - 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 = len(cd_children) - 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 = len(fd_children) - 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 = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8) - self.SpecNames = CompilerFactory.get_perm_pool().alloc(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: str = CompilerFactory.get_perm_pool().alloc(key_len + 1) - name_copy: str = CompilerFactory.get_perm_pool().alloc(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 - # 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded - # 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。 - self.GenericSpecDepth += 1 - if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: - err_spec: str = trans.Pool.alloc(256) - if err_spec is not None: - viperlib.snprintf(err_spec, 256, - "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", - class_name, self.GenericSpecDepth) - HandlesType.fatal_error(None, err_spec, "InternalCompilerError") - HandlesType.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError") - # 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"), - # 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。 - # 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。 - ta_cnt_g: t.CSizeT = len(type_args) - 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 - - # 1. 查找泛型模板 - template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name) - if template_cd is None: - self.GenericSpecDepth -= 1 - return None - - # 2. 生成特化名 - spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args) - if spec_name is None: - self.GenericSpecDepth -= 1 - 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。补译完成后已设置,无需恢复。 - # 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1 - # (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译, - # 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。 - pre_existing.MethodsEmitted = 1 - # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) - tp_names_pre: list[str] | t.CPtr = self._find_generic_template_tp_params( - pool, class_name) - if tp_names_pre is None: - tp_names_pre = 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) - # 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板, - # node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入 - # trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。 - saved_cur_pre: str = HandlesType.get_current_file() - tpl_file_pre: str = self._find_generic_template_file(class_name) - if tpl_file_pre is not None: - HandlesType.set_current_file(tpl_file_pre) - HandlesType.push_trace(tpl_file_pre, template_cd.lineno) - self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1) - if tpl_file_pre is not None: - HandlesType.pop_trace() - HandlesType.set_current_file(saved_cur_pre) - 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 = len(type_args) - 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: - self.GenericSpecDepth -= 1 - 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: - self.GenericSpecDepth -= 1 - return cached - - # 4. 检查是否已注册(Phase B 重复特化) - existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if existing is not None: - self._cache_spec(pool, spec_key, spec_name) - self.GenericSpecDepth -= 1 - return spec_name - - # 预注册缓存(防止递归) - self._cache_spec(pool, spec_key, spec_name) - - # 5. 拷贝 ClassDef 节点 - # 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效) - tp_names: list[str] | t.CPtr = self._find_generic_template_tp_params( - pool, class_name) - if tp_names is None: - tp_names = 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: - self.GenericSpecDepth -= 1 - 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) - # 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件 - # 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile - # 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。 - saved_cur_full: str = HandlesType.get_current_file() - tpl_file_full: str = self._find_generic_template_file(class_name) - if tpl_file_full is not None: - HandlesType.set_current_file(tpl_file_full) - HandlesType.push_trace(tpl_file_full, template_cd.lineno) - self.translate_class_def(trans, spec_cd) - if tpl_file_full is not None: - HandlesType.pop_trace() - HandlesType.set_current_file(saved_cur_full) - # 恢复原始 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() - - # 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏, - # 静默继续会让后续 GEP 按错索引访问) - if string.strcmp(class_name, "GSListNode") == 0: - result_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if result_entry is not None: - 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) - if rfn is None: - VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC") - HandlesType.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError") - - self.GenericSpecDepth -= 1 - 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 - - if trans.ModuleSha1 is None: - # fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)—— - VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS") - HandlesType.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError") - - # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, - # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) - HandlesStruct.add_visible_struct(pool, class_name) - - # 枚举类:交给 HandlesEnum 处理 - if self._is_enum_class(cd, trans) == 1: - return self._translate_enum_def(trans, cd) - - # 联合体类:交给联合体处理 - if self._is_union_class(cd, trans) == 1: - return self._translate_union_def(trans, cd) - - # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) - if self._is_renum_class(cd, trans) == 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 - - # 异常类(try-except):注册编码+继承树,不生成 struct - # (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class → - # _RegisterExceptionClass → return,异常类不编译为结构体) - if self._is_exception_class_def(cd) == 1: - return self._register_exception_class_def(trans, cd) - - # 检查是否已注册(用 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: - # 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空, - # _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表 - # 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType - # 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。 - ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_pool(), existing.Ty) - if ty_deep is not None: - existing.Ty = ty_deep - old_name: str = llvmlite.get_struct_name(existing.Ty) - if old_name is not None: - on_len: t.CSizeT = string.strlen(old_name) - on_copy: str = CompilerFactory.get_perm_pool().alloc(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 * HandlesStruct.FIELD_MAX) - field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * HandlesStruct.FIELD_MAX) - 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 * HandlesStruct.FIELD_MAX) - string.memset(field_types_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_defaults_buf, 0, 8 * HandlesStruct.FIELD_MAX) - string.memset(field_annot_buf, 0, 8 * HandlesStruct.FIELD_MAX) - - 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: - # 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能 - # 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时 - # **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool - # 分配(init_struct_table L136-140),残缺条目跨 pass 存活, - # 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类 - # __init__ 写父类字段(self.TraceFrames)每遍永久失败。 - # 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级 - # 变量/函数参数解析失败静默降级 i32(handle_module_level_var - # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 - if trans is not None: - trans._deps_pending = 1 - return 0 - 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 < HandlesStruct.FIELD_MAX: - 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 = len(children) - 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 - - # 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。 - # 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查 - # CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册 - # 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。 - if HandlesAnnAssign.is_cdefine_annotation(aa.annotation) != 0: - if aa.value is not None: - HandlesAnnAssign._register_cdefine_from_value(pool, tgt.id, aa.value) - # CDefine 字段类型固定 i32,直接收集后跳过通用注解解析: - # resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef - # 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发 - # 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。 - # 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。 - if field_count < HandlesStruct.FIELD_MAX: - cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cdef_ty_l is not None: - field_names_buf[field_count] = t.CSizeT(tgt.id) - field_types_buf[field_count] = t.CSizeT(cdef_ty_l) - if aa.value is not None: - field_defaults_buf[field_count] = t.CSizeT(aa.value) - else: - field_defaults_buf[field_count] = 0 - field_count += 1 - continue - - # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) - # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 - # (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str] - # 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。 - if string.strcmp(tgt.id, "__provides__") == 0: - self._register_class_meta_list(pool, HandlesType.CLASS_META_PROVIDES, class_name, aa.value) - continue - if string.strcmp(tgt.id, "__requires__") == 0: - self._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRES, class_name, aa.value) - continue - if string.strcmp(tgt.id, "__require_must__") == 0: - self._register_class_meta_list(pool, HandlesType.CLASS_META_REQUIRE_MUST, class_name, aa.value) - continue - - # 解析字段类型 - field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, aa.annotation, trans._imported_modules, trans._from_imports, trans) - # 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem] - # (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义): - # 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**), - # for x in self.field 会误走指针迭代(元素非整数 → null 终止符 - # 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。 - if field_ty is not None: - field_ty = HandlesAnnAssign._infer_static_array_ty_from_literal( - pool, aa.annotation, aa.value, field_ty) - 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 A(declare_only=0,Phase2.vp L573 多遍):依赖模块按 - # 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp - # H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记 - # _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。 - # 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成 - # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 - if trans is not None: - trans._deps_pending = 1 - return 0 - # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 - # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) - - # 存储到数组(指针转 CSizeT) - if field_count < HandlesStruct.FIELD_MAX: - 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 指针字段。 - - # ============================================================ - # 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: str = 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: str = 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: str = CompilerFactory.get_perm_pool().alloc(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: str = 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 拷贝(指针匹配不失效)且跨文件永久存活。 - # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1) - # 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 → - # 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields - # 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 - if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0: - st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( - CompilerFactory.get_perm_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: str = 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: - # 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空; - # _translate_oop_methods/_detect_vtable_status 会在后续文件 - # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 - if HandlesStruct.get_stdlib_alloc() != 0: - pn_len: t.CSizeT = string.strlen(parent_name) - pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1) - if pn_buf is not None: - string.strcpy(pn_buf, parent_name) - entry.ParentName = pn_buf - else: - entry.ParentName = parent_name - # 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活) - if parents_count > 0 and parents_buf is not None: - HandlesStruct.set_parent_names(pool, 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: str = None - if fannot_addr != 0: - fannot = (str)(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: str, dst_size: t.CSizeT, - src: str): - """将 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: str, 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: str = 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: str = 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 = len(children) - - # 1. 收集虚方法信息 - # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), - # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 - full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) - # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) - method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(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: str = 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: str = CompilerFactory.get_perm_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: str = CompilerFactory.get_perm_pool().alloc(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" - # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 - # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 - fname_buf: str = CompilerFactory.get_perm_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: str = CompilerFactory.get_perm_pool().alloc(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: str = 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 - # fail-fast:func 无效且全局表 TypeStr 回退也失败, - # 不再写 "i8* null" 静默掩盖缺失实现。 - HandlesType.fatal_error( - cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") - continue - - # 构造函数类型字符串 - func_ty_buf: str = 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: str = 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 - # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 - # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 - # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 - # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, - # 输出 @name = constant {...}(合法外部强定义)。 - - # 添加到模块 - 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, - reemit: int = 0) -> int: - """扫描 class body 中的方法并翻译,生成 __before_init__ - - mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) - reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 - 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, - 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 - 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 - """ - 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 = len(children) - 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: - # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 - # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 - # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 - # VTableMethods=None → _translate_method_call 虚分派条件 - # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 - # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → - # __before_init__ 写 null 崩溃。 - # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), - # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 - mk_has_vt: int = 0 - if oop_entry is not None: - mk_has_vt = oop_entry.HasVTable - if mk_has_vt == 1: - self._collect_vtable_methods(trans, cd, class_name) - return 0 - - # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 - # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 - # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 - # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 - # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 - # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 - # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 - if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 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 @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 - if method_name is None: - # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 - VLogger.error("方法名缺失(fd.name is None)", "OOP") - HandlesType.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") - - # 提取装饰器元数据(@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: str = 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: - # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$set") - elif func_meta & META_PROP_DELETER != 0: - mn_len2: t.CSizeT = string.strlen(method_name_buf) - if mn_len2 + 5 < 128: - string.strcat(method_name_buf, "$del") - method_name = method_name_buf - - is_static_m: int = 0 - is_class_m: int = 0 - is_tls_m: int = 0 - if func_meta & META_STATIC != 0: - is_static_m = 1 - if func_meta & META_CLASS != 0: - is_class_m = 1 - if func_meta & META_TLS != 0: - is_tls_m = 1 - - # 构建方法全名: ClassName.method_name - full_name_buf: str = 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 = len(md_alist) - else: - md_param_count = len(md_alist) - 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 = len(md_dlist) - - # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) - max_funcs: int = 1024 - 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 len(fd_ags.args) > 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: str = 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 = len(alist) - 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 读到垃圾)。 - # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 - match resolved: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty = llvmlite.Ptr(pool, resolved) - case llvmlite.LLVMType.Array(aelem_ty, _): - param_ty = llvmlite.Ptr(pool, aelem_ty) - case _: - param_ty = resolved - pname: str = pool.alloc(32) - if pname is not None: - viperlib.snprintf(pname, 32, "%%%s", arg.arg) - llvmlite.add_param(pool, func, param_ty, pname) - - # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 - # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 - # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_si is not None: - i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) - if i1_ptr_ty_si is not None: - llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") - - # 参数添加完成,补全全局函数表的 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) - - # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; - # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) - if is_tls_m != 0: - tls_m_flag_name: str = pool.alloc(128) - if tls_m_flag_name is not None: - viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) - tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( - pool, mod, tls_m_flag_name, 1, 0) - if tls_m_gv is not None: - i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_m is not None: - # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store - tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) - tls_m_rn: str = pool.alloc(64) - if tls_m_rn is not None: - viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) - tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, tls_m_ptr_ty, tls_m_rn) - if tls_m_ref is not None: - tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( - func_builder, i1_ty_m, tls_m_ref) - lc_m: int = trans._label_counter - trans._label_counter = lc_m + 1 - tls_m_buf: str = pool.alloc(64) - if tls_m_buf is not None: - viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) - tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) - tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, tls_m_buf) - if tls_m_skip is not None and tls_m_cont is not None: - llvmlite.build_cond_br( - func_builder, tls_m_ld, tls_m_skip, tls_m_cont) - llvmlite.position_at_end(func_builder, tls_m_skip) - match ret_ty: - case llvmlite.LLVMType.Void(): - llvmlite.build_ret_void(func_builder) - case llvmlite.LLVMType.Int(_): - tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, ret_ty, 0, "0") - if tlm0 is not None: - llvmlite.build_ret(func_builder, tlm0) - case llvmlite.LLVMType.Float(_): - tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( - pool, ret_ty, 0.0) - if tlmf is not None: - llvmlite.build_ret(func_builder, tlmf) - case _: - tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, ret_ty, "null") - if tlmn is not None: - llvmlite.build_ret(func_builder, tlmn) - llvmlite.position_at_end(func_builder, tls_m_cont) - tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_m, 1, "1") - if tlmo is not None: - llvmlite.build_store(func_builder, tlmo, tls_m_ref) - - # 进入函数作用域 - 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 len(cags.args) > 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: str = 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 = len(alist2) - 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 None: - # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 - HandlesType.fatal_error( - arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", - "NameError") - resolved2 = i32_ty # 不可达(fatal_error 已退出) - if resolved2 is not None: - # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) - # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) - match resolved2: - case llvmlite.LLVMType.Struct(_, _, _): - param_ty2 = llvmlite.Ptr(pool, resolved2) - case llvmlite.LLVMType.Array(aelem_ty2, _): - param_ty2 = llvmlite.Ptr(pool, aelem_ty2) - 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) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) - if arg2.annotation is not None: - cls_nm_oc: str = HandlesType.extract_class_name_from_annotation( - arg2.annotation, imported_modules, pool) - if cls_nm_oc is not None: - HandlesVar.set_var_annot_class_name( - trans.SymTab, arg2.arg, cls_nm_oc) - pname2: str = 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) - - # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 - # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 - # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 - if string.strcmp(method_name, "__next__") == 0: - i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - if i1_ty_sf is not None: - i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) - if i1_ptr_ty_sf is not None: - flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, i1_ptr_ty_sf, "%__stop_iter_flag__") - if flag_ref_sf is not None: - trans._stop_iter_flag_ptr = flag_ref_sf - zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i1_ty_sf, 0, "0") - if zero_i1_sf is not None: - llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) - - # 保存模块级作用域状态 - 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 - old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr - - 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 = len(body) - 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 = len(body) - for bi2 in range(bn2): - stmt2: ast.AST | t.CPtr = body.get(bi2) - if stmt2 is not None: - HandlesBody.translate_stmt(trans, stmt2) - - # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) - # 同语义——编译器不替代码发明返回值,三种合法收尾: - # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) - # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 - # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through - # 视为 UB 同语义) - # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 - # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 - # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 - # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 - # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc - # "value doesn't match function result type 'i64'"(追加88 只修了 - # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) - last_is_return: int = 0 - # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 - bn3: t.CSizeT = 0 - if body is not None: - bn3 = len(body) - if bn3 > 0: - last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: - last_is_return = 1 - if last_is_return == 0: - if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: - last_is_ctrl: int = 0 - if bn3 > 0: - last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) - if last_stmt3_m is not None: - k3m: int = last_stmt3_m.kind() - if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ - k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ - k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: - last_is_ctrl = 1 - _is_void: int = 0 - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - _is_void = 1 - case _: - pass - if _is_void != 0: - llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: - # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 - # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) - # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 - # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 - # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 - # fall-through → 双分支执行崩溃(FuncTest check) - llvmlite.build_unreachable(func_builder) - elif fd.returns is None: - # 无返回类型注解 → 无返回值过程方法,默认零值返回 - if ret_ty is not None: - _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) - if _m_zero_val is not None: - llvmlite.build_ret(func_builder, _m_zero_val) - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) - if ret_ty is not None: - rt_name_m: str = pool.alloc(64) - if rt_name_m is not None: - llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) - if rt_name_m[0] == '\0': - rt_name_m = "?" - err_fn_m: str = pool.alloc(256) - if err_fn_m is not None: - viperlib.snprintf( - err_fn_m, 256, - "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," - "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) - HandlesType.fatal_error(fd, err_fn_m, "TypeError") - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - else: - HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") - - # 恢复模块级作用域 - 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 - trans._stop_iter_flag_ptr = old_stop_iter_flag - - 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: str = 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 = 1024 - 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: str = 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: str = 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 - # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store - # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 - # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 - # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 - # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 - if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ - and fe.DefaultVal.kind() == ast.ASTKind.List: - field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - func_builder, struct_ty, fe.Ty, self_val, fe.Index) - if field_ptr_arr is not None: - zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) - if zero_arr_f is not None: - llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) - # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 - # (AssignGenMixin._init_global_array_from_list)会生成不存在 - # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 - HandlesAnnAssign._init_global_array_from_list( - func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) - 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 +class ClassGenMixin(ClassGenBase.ClassGenBase): + """类定义处理 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)""" diff --git a/App/lib/core/Gen/ClassGenVTable.vp b/App/lib/core/Gen/ClassGenVTable.vp new file mode 100644 index 0000000..46a9f01 --- /dev/null +++ b/App/lib/core/Gen/ClassGenVTable.vp @@ -0,0 +1,1310 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import viperlib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.StubMerger as StubMerger +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.ClassGenBase as ClassGenBase + +# ============================================================ +# ClassGenVTable - ClassGenMixin 拆分(阶段 D):vtable 收集/生成/方法翻译 +# +# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class ClassGenVTable(ClassGenBase.ClassGenBase): + """vtable 收集/生成/方法翻译""" + + # ============================================================ + # _vtable_strcat — 将 src 追加到 dst 末尾 + # ============================================================ + def _vtable_strcat(self, dst: str, dst_size: t.CSizeT, + src: str): + """将 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: str, 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: str = 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: str = 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 = len(children) + + # 1. 收集虚方法信息 + # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), + # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 + full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX) + # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) + method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(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 HandlesClassDef._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 HandlesClassDef._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: str = 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: str = CompilerFactory.get_perm_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: str = CompilerFactory.get_perm_pool().alloc(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 HandlesClassDef._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" + # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 + # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 + fname_buf: str = CompilerFactory.get_perm_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: str = CompilerFactory.get_perm_pool().alloc(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: str = 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 + # fail-fast:func 无效且全局表 TypeStr 回退也失败, + # 不再写 "i8* null" 静默掩盖缺失实现。 + HandlesType.fatal_error( + cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError") + continue + + # 构造函数类型字符串 + func_ty_buf: str = 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: str = 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 + # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 + # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 + # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 + # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, + # 输出 @name = constant {...}(合法外部强定义)。 + + # 添加到模块 + 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, + reemit: int = 0) -> int: + """扫描 class body 中的方法并翻译,生成 __before_init__ + + mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) + reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 + 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, + 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 + 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 + """ + 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 = len(children) + 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 = HandlesClassDef._extract_func_meta(fd_check.decorator_list) + if fd_meta != 0: + HandlesClassDef.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: + # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:Phase 1b 中依赖模块可能先于其依赖类全量翻译(如 tokens.vp 先于 + # memhub 生成 text.ll),此时调用方查到 entry 有 HasVTable=1 但 + # VTableMethods=None → _translate_method_call 虚分派条件 + # (VTableMethods is not None)不成立 → pool.alloc 被静态绑定到 + # MemManager.alloc(默认返回 None)→ KwEntry.__new__ 返回 null → + # __before_init__ 写 null 崩溃。 + # 短名顺序与 Phase 1b 全量收集一致(父类方法在前 + 本类方法,确定性), + # 多遍扫描重复收集时用新缓冲区覆盖(stdlib 泄漏可忽略,Phase 1b 重译幂等)。 + mk_has_vt: int = 0 + if oop_entry is not None: + mk_has_vt = oop_entry.HasVTable + if mk_has_vt == 1: + self._collect_vtable_methods(trans, cd, class_name) + return 0 + + # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 + # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 + # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 + # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 + # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 + # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 + # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 + if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 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 @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 + if method_name is None: + # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 + VLogger.error("方法名缺失(fd.name is None)", "OOP") + HandlesType.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") + + # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) + func_meta: int = HandlesClassDef._extract_func_meta(fd.decorator_list) + # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 + method_name_buf: str = 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: + # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 + mn_len2: t.CSizeT = string.strlen(method_name_buf) + if mn_len2 + 5 < 128: + string.strcat(method_name_buf, "$set") + elif func_meta & META_PROP_DELETER != 0: + mn_len2: t.CSizeT = string.strlen(method_name_buf) + if mn_len2 + 5 < 128: + string.strcat(method_name_buf, "$del") + method_name = method_name_buf + + is_static_m: int = 0 + is_class_m: int = 0 + is_tls_m: int = 0 + if func_meta & META_STATIC != 0: + is_static_m = 1 + if func_meta & META_CLASS != 0: + is_class_m = 1 + if func_meta & META_TLS != 0: + is_tls_m = 1 + + # 构建方法全名: ClassName.method_name + full_name_buf: str = 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 = len(md_alist) + else: + md_param_count = len(md_alist) - 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 = len(md_dlist) + + # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) + max_funcs: int = 1024 + 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 len(fd_ags.args) > 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: str = 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 = len(alist) + 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 读到垃圾)。 + # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 + match resolved: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Ptr(pool, resolved) + case llvmlite.LLVMType.Array(aelem_ty, _): + param_ty = llvmlite.Ptr(pool, aelem_ty) + case _: + param_ty = resolved + pname: str = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 + # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 + # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_si is not None: + i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si) + if i1_ptr_ty_si is not None: + llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") + + # 参数添加完成,补全全局函数表的 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) + + # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; + # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) + if is_tls_m != 0: + tls_m_flag_name: str = pool.alloc(128) + if tls_m_flag_name is not None: + viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) + tls_m_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int( + pool, mod, tls_m_flag_name, 1, 0) + if tls_m_gv is not None: + i1_ty_m: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_m is not None: + # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store + tls_m_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_m) + tls_m_rn: str = pool.alloc(64) + if tls_m_rn is not None: + viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) + tls_m_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, tls_m_ptr_ty, tls_m_rn) + if tls_m_ref is not None: + tls_m_ld: llvmlite.Value | t.CPtr = llvmlite.build_load( + func_builder, i1_ty_m, tls_m_ref) + lc_m: int = trans._label_counter + trans._label_counter = lc_m + 1 + tls_m_buf: str = pool.alloc(64) + if tls_m_buf is not None: + viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) + tls_m_skip: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) + tls_m_cont: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, tls_m_buf) + if tls_m_skip is not None and tls_m_cont is not None: + llvmlite.build_cond_br( + func_builder, tls_m_ld, tls_m_skip, tls_m_cont) + llvmlite.position_at_end(func_builder, tls_m_skip) + match ret_ty: + case llvmlite.LLVMType.Void(): + llvmlite.build_ret_void(func_builder) + case llvmlite.LLVMType.Int(_): + tlm0: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, ret_ty, 0, "0") + if tlm0 is not None: + llvmlite.build_ret(func_builder, tlm0) + case llvmlite.LLVMType.Float(_): + tlmf: llvmlite.Value | t.CPtr = llvmlite.ConstFloat( + pool, ret_ty, 0.0) + if tlmf is not None: + llvmlite.build_ret(func_builder, tlmf) + case _: + tlmn: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, ret_ty, "null") + if tlmn is not None: + llvmlite.build_ret(func_builder, tlmn) + llvmlite.position_at_end(func_builder, tls_m_cont) + tlmo: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_m, 1, "1") + if tlmo is not None: + llvmlite.build_store(func_builder, tlmo, tls_m_ref) + + # 进入函数作用域 + 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 len(cags.args) > 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: str = 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 = len(alist2) + 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 None: + # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 + HandlesType.fatal_error( + arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", + "NameError") + resolved2 = i32_ty # 不可达(fatal_error 已退出) + if resolved2 is not None: + # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) + # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) + match resolved2: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty2 = llvmlite.Ptr(pool, resolved2) + case llvmlite.LLVMType.Array(aelem_ty2, _): + param_ty2 = llvmlite.Ptr(pool, aelem_ty2) + 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) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) + if arg2.annotation is not None: + cls_nm_oc: str = HandlesType.extract_class_name_from_annotation( + arg2.annotation, imported_modules, pool) + if cls_nm_oc is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm_oc) + pname2: str = 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) + + # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 + # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 + # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 + if string.strcmp(method_name, "__next__") == 0: + i1_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + if i1_ty_sf is not None: + i1_ptr_ty_sf: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_sf) + if i1_ptr_ty_sf is not None: + flag_ref_sf: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, i1_ptr_ty_sf, "%__stop_iter_flag__") + if flag_ref_sf is not None: + trans._stop_iter_flag_ptr = flag_ref_sf + zero_i1_sf: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i1_ty_sf, 0, "0") + if zero_i1_sf is not None: + llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) + + # 保存模块级作用域状态 + 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 + old_stop_iter_flag: llvmlite.Value | t.CPtr = trans._stop_iter_flag_ptr + + 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 = len(body) + 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 = len(body) + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 追加89:方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def) + # 同语义——编译器不替代码发明返回值,三种合法收尾: + # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) + # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性 + # 不可达 → build_unreachable(不可能抵达,GCC/Clang fall-through + # 视为 UB 同语义) + # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 + # 有 -> 注解且末句普通语句掉出末尾 → fail-fast。 + # 不做 noreturn 函数名白名单:错误终止路径(fatal_error 等)也必须在 + # 源码层面保证块收尾(如显式 return 样板),每个函数都符合块设计。 + # 原实现 L4529 const_int32 硬编码 ret i32 0,对 i64 返回方法报 llc + # "value doesn't match function result type 'i64'"(追加88 只修了 + # FuncGenMixin 模块级函数路径,方法路径此处追加89 一并同步) + last_is_return: int = 0 + # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 + bn3: t.CSizeT = 0 + if body is not None: + bn3 = len(body) + if bn3 > 0: + last_stmt_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + last_is_ctrl: int = 0 + if bn3 > 0: + last_stmt3_m: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt3_m is not None: + k3m: int = last_stmt3_m.kind() + if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ + k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ + k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: + last_is_ctrl = 1 + _is_void: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + _is_void = 1 + case _: + pass + if _is_void != 0: + llvmlite.build_ret_void(func_builder) + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 追加90(与 FuncGenMixin 同步):非 void 方法末句是控制流 + # 且 merge 块结构性不可达(全分支 return,无 br 到 merge) + # → LLVM 语义 unreachable。merge 可达(分支 br 到 merge)时 + # 不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast)。 + # 原无条件 unreachable 使 llc O2 优化 br-to-unreachable 为 + # fall-through → 双分支执行崩溃(FuncTest check) + llvmlite.build_unreachable(func_builder) + elif fd.returns is None: + # 无返回类型注解 → 无返回值过程方法,默认零值返回 + if ret_ty is not None: + _m_zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty) + if _m_zero_val is not None: + llvmlite.build_ret(func_builder, _m_zero_val) + else: + HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) + if ret_ty is not None: + rt_name_m: str = pool.alloc(64) + if rt_name_m is not None: + llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) + if rt_name_m[0] == '\0': + rt_name_m = "?" + err_fn_m: str = pool.alloc(256) + if err_fn_m is not None: + viperlib.snprintf( + err_fn_m, 256, + "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s)," + "请补显式 return(如 return 0 / return null)", method_name, rt_name_m) + HandlesType.fatal_error(fd, err_fn_m, "TypeError") + HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + else: + HandlesType.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") + + # 恢复模块级作用域 + 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 + trans._stop_iter_flag_ptr = old_stop_iter_flag + + 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: str = 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 = 1024 + 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: str = 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: str = 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 + # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store + # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 + # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 + # 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集 + # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 + if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ + and fe.DefaultVal.kind() == ast.ASTKind.List: + field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr_arr is not None: + zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) + if zero_arr_f is not None: + llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) + # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 + # (AssignGenMixin._init_global_array_from_list)会生成不存在 + # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 + HandlesAnnAssign._init_global_array_from_list( + func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans) + 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 \ No newline at end of file diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index 35a336a..e3ec52d 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -27,6 +27,11 @@ import lib.core.Gen.FuncGenBase as FuncGenBase import lib.core.Gen.FuncGenDef as FuncGenDef import lib.core.Gen.FuncGenMixin as FuncGenMixin import lib.core.Gen.ClassGenMixin as ClassGenMixin +import lib.core.Gen.ClassGenBase as ClassGenBase +import lib.core.Gen.ClassGenEnum as ClassGenEnum +import lib.core.Gen.ClassGenGeneric as ClassGenGeneric +import lib.core.Gen.ClassGenVTable as ClassGenVTable +import lib.core.Gen.ClassGenDef as ClassGenDef import lib.core.Gen.ImportsGenMixin as ImportsGenMixin import lib.core.Gen.StmtGenMixin as StmtGenMixin import lib.core.Gen.AssignGenMixin as AssignGenMixin @@ -62,7 +67,10 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, CallGenLib.CallGenLib, CallGenDispatch.CallGenDispatch, FuncGenBase.FuncGenBase, FuncGenDef.FuncGenDef, FuncGenMixin.FuncGenMixin, - ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin, + ClassGenMixin.ClassGenMixin, ClassGenBase.ClassGenBase, + ClassGenEnum.ClassGenEnum, ClassGenGeneric.ClassGenGeneric, + ClassGenVTable.ClassGenVTable, ClassGenDef.ClassGenDef, + ImportsGenMixin.ImportsGenMixin, StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin, VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin): """生成器:多继承 Mixin 组合(对象化迁移宿主)""" diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index 1f318ef..2b93577 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -1056,6 +1056,39 @@ def translate_class_def(trans: HT.Translator | t.CPtr, return 0 +# ============================================================ +# ClassGenDef 跨 Mixin 委托(阶段 D:ClassGenMixin 拆 Base/Def 后 +# translate_class_def 经此调用这些方法。参数与目标方法一致,去 self) +# ============================================================ +def _is_exception_class_def(cd: ast.ClassDef | t.CPtr) -> int: + """类定义是否是异常类(委托到 gen._is_exception_class_def)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_exception_class_def(cd) + return 0 + + +def _register_exception_class_def(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """注册异常类(分配编码 + 记录父类)(委托到 gen._register_exception_class_def)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._register_exception_class_def(trans, cd) + return 0 + + +def _register_class_meta_list(pool: memhub.MemBuddy | t.CPtr, + kind: int, cls: str, + value_node: ast.AST | t.CPtr) -> None: + """解析类体 __provides__/__requires__ 的 list[str] 字面量并注册(委托到 gen._register_class_meta_list)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + g._register_class_meta_list(pool, kind, cls, value_node) + + # ============================================================ # VTable 生成 #