refactor(gen): ClassGenMixin 拆 5 组(Base/Enum/Generic/VTable/Def,4768→空壳)

This commit is contained in:
TermiNexus committed 2026-08-17 07:23:40 +08:00
1 parent 81d4ff3ac4
commit 47ac2dd57c
8 files changed
+4807 -4745

No files matched your search

File diff suppressed because it is too large. Load diff
+577
View File
@@ -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 无法完成
# 翻译: <file>,请检查依赖模块是否已编译/注册"),不静默掩盖。
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
File diff suppressed because it is too large. Load diff
+675
View File
@@ -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
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+9 -1
View File
@@ -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 组合(对象化迁移宿主)"""
+33
View File
@@ -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 生成
#