from __future__ import annotations import vast as ast import re from typing import List import llvmlite.ir as ir from lib.includes import t from lib.includes.t import CTypeRegistry from lib.core.SymbolUtils import ( IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode, IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr, EnumClassIntWidth, ClassHasFuncLevelCVTable) class DeclarationGenerator: """从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)""" # 匹配 LLVM 数组类型:[N x elem_type] _ARRAY_TYPE_RE: re.Pattern = re.compile(r'^\[(\d+)\s+x\s+(.+)\]$') @staticmethod def _decay_array_to_ptr(type_str: str) -> str: """C 语言中数组参数退化为指针:[N x elem_type] → elem_type*""" m = DeclarationGenerator._ARRAY_TYPE_RE.match(type_str) if m: return f'{m.group(2)}*' return type_str def __init__(self, struct_names: set[str] | None = None, enum_names: set[str] | None = None, module_sha1: str | None = None, target_triple: str | None = None, target_datalayout: str | None = None, struct_sha1_map: dict[str, str] | None = None, exception_names: set[str] | None = None, typedef_map: dict[str, ast.AST] | None = None, class_def_map: dict[str, ast.ClassDef] | None = None) -> None: self.ir: ir.Module = ir self.module: ir.Module | None = None self.builder: ir.IRBuilder | None = None self._DefineConstants: dict[str, int | str] = {} self.struct_names: set[str] = struct_names or set() self.enum_names: set[str] = enum_names or set() self.module_sha1: str | None = module_sha1 self.struct_sha1_map: dict[str, str] = struct_sha1_map or {} self.exception_names: set[str] = exception_names or set() self.target_triple: str = target_triple or "x86_64-none-elf" self.target_datalayout: str = target_datalayout or "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" self.typedef_map: dict[str, ast.AST] = typedef_map or {} self._pyi_tree: ast.Module | None = None self._t_alias_map: dict[str, type] = {} # 泛型模板类名(PEP 695 `class Box[T]`):声明端特化判定用,与定义端 # HandlesClassDef._generic_class_templates 同源(ClassDef 的 type_params # 标记),generate() 里从本模块 pyi 与 class_def_map 收集 self._generic_class_names: set[str] = set() # t/c 导入名表(from t import CInt as myint → 'myint' → ('t','CInt')), # 与定义端 Trans._t_c_imported_names 同口径,供泛型实参串解析使用 self._t_c_imported_names: dict[str, tuple[str, str]] = {} # 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members # 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST) self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {} t.configure_platform(self.target_triple) def generate(self, pyi_content: str, src_path: str) -> str: # 传 src_path:解析失败时报错/回退诊断才带得上来源(否则 vast 记为 , # 既无法定位文件,也无法知道是哪份 .pyi 出问题) tree: ast.Module = ast.parse(pyi_content, src_path) self._DefineConstants: dict[str, int | str] = {} self._pyi_tree = tree # 泛型模板类名(PEP 695 `class Box[T]`):class_def_map 覆盖所有已生成 # .vpi 的模块(含本模块),本模块 pyi 直接解析的 ClassDef 优先, # 与定义端 HandlesClassDef 注册 _generic_class_templates 的判据一致 # (都只看 ClassDef.type_params 是否非空,不看类名白名单)。 self._generic_class_names = { node.name for node in ast.iter_child_nodes(tree) if isinstance(node, ast.ClassDef) and getattr(node, 'type_params', None)} for _gc_name, _gc_node in self._cross_module_class_defs.items(): if getattr(_gc_node, 'type_params', None): self._generic_class_names.add(_gc_name) global_typedef_map: dict[str, ast.AST] = self.typedef_map self.typedef_map: dict[str, ast.AST] = {} if global_typedef_map: self.typedef_map.update(global_typedef_map) # 构建 t/c 类型别名映射(from t import CInt as myint) self._t_alias_map: dict[str, type] = {} self._t_c_imported_names: dict[str, tuple[str, str]] = {} for node in ast.iter_child_nodes(tree): if isinstance(node, ast.ImportFrom): if node.module in ('t', 'c'): for alias in node.names: name: str = alias.name asname: str = alias.asname or name self._t_c_imported_names[asname] = (node.module, name) if node.module == 't': t_cls: type | None = getattr(t, name, None) if isinstance(t_cls, type) and issubclass(t_cls, t.CType): self._t_alias_map[asname] = t_cls for node in ast.iter_child_nodes(tree): if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): var_name: str = node.target.id if node.value and isinstance(node.value, ast.Constant): self._DefineConstants[var_name] = node.value.value elif node.value and isinstance(node.value, ast.Name): self._DefineConstants[var_name] = node.value.id is_typedef: bool = False if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': is_typedef = True elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': is_typedef = True elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': is_typedef = True if is_typedef: if node.value: self.typedef_map[var_name] = node.value elif isinstance(node.annotation, ast.BinOp) and node.annotation.right: self.typedef_map[var_name] = node.annotation.right lines: list[str] = [] lines.append('; ModuleID = "transpyc_decl"') lines.append(f'target triple = "{self.target_triple}"') lines.append(f'target datalayout = "{self.target_datalayout}"') lines.append('') for node in ast.iter_child_nodes(tree): if isinstance(node, ast.FunctionDef): if hasattr(node, 'type_params') and node.type_params: continue decl: str | None = self._generate_func_decl(node) if decl: lines.append(decl) elif isinstance(node, ast.AnnAssign): decl: str | None = self._generate_global_decl(node) if decl: lines.append(decl) elif isinstance(node, ast.Assign): decl: str | None = self._generate_global_assign_decl(node) if decl: lines.append(decl) elif isinstance(node, ast.ClassDef): # PEP 695 泛型类不再完全跳过:子类(如 Value(GSListNode[Value]))的 # 继承字段展平需要从泛型基类的 stub 中读取字段(如 GSListNode.Next)。 # _generate_class_decl 内部会跳过泛型类的方法声明(T 参数 → opaque struct)。 decls: list[str] = self._generate_class_decl(node) lines.extend(decls) # 后处理:扫描引用但未定义的结构体类型,自动添加 opaque 声明 # 这解决了泛型类(如 list[T])在 stub 中被跳过导致的 "undefined type" 错误 opaque_decls: list[str] = self._collect_undefined_type_decls(lines) if opaque_decls: # 在 header 之后插入 opaque 声明(ModuleID, triple, datalayout, 空行 = 4 行) insert_idx: int = 4 for i, od in enumerate(opaque_decls): lines.insert(insert_idx + i, od) return '\n'.join(lines) def _collect_undefined_type_decls(self, lines: list[str]) -> list[str]: """扫描所有引用的 %"sha1.TypeName" 类型,返回未定义类型的 opaque 声明列表""" # 收集已定义的类型名 defined_types: set[str] = set() type_def_re: re.Pattern = re.compile(r'^(%".+?")\s*=\s*type\s') for line in lines: m = type_def_re.match(line.strip()) if m: defined_types.add(m.group(1)) # 扫描所有引用的类型名 referenced_types: set[str] = set() type_ref_re: re.Pattern = re.compile(r'%"[a-f0-9]+\.[^"]+"') for line in lines: for m in type_ref_re.finditer(line): ref: str = m.group(0) if ref not in defined_types: referenced_types.add(ref) # 生成 opaque 声明(排序确保确定性) result: list[str] = [] for type_name in sorted(referenced_types): result.append(f'{type_name} = type opaque') return result def _generate_func_decl(self, node: ast.FunctionDef) -> str | None: """生成函数声明""" func_name: str = node.name is_export: bool = self._is_export_func(node) if self.module_sha1 and not is_export: func_name = f"{self.module_sha1}.{func_name}" CReturnTypes: list[ast.AST] = [] if node.decorator_list: for decorator in node.decorator_list: if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): if decorator.func.attr == 'CReturn': for arg in decorator.args: CReturnTypes.append(arg) if node.returns: if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple': slice_node: ast.AST = node.returns.slice if isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: CReturnTypes.append(elt) else: CReturnTypes.append(slice_node) ret_type: str if CReturnTypes: elem_types: list[str] = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes] ret_type = '{ ' + ', '.join(elem_types) + ' }' else: ret_type = self._get_type_str(node.returns) if not ret_type or ret_type == 'void': ret_type = 'void' elif ret_type == 'i8*': if node.returns is None: ret_type = 'void' params: list[str] = [] for arg in node.args.args: arg_type: str if arg.annotation: arg_type = self._get_type_str(arg.annotation) else: arg_type = 'i8*' # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* arg_type = self._decay_array_to_ptr(arg_type) if arg_type and arg_type != 'void': params.append(arg_type) param_str: str = ', '.join(params) if params else '' if node.args.vararg: param_str = param_str + ', ...' if param_str else '...' if func_name[0].isdigit(): return f'declare {ret_type} @"{func_name}"({param_str})' return f'declare {ret_type} @{func_name}({param_str})' def _is_export_func(self, node: ast.FunctionDef) -> bool: """检查函数是否标记为 CExport""" if not node.returns: return False return self._check_annotation_for_export(node.returns) def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool: """递归检查类型注解中是否包含 CExport 或 t.State""" return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')) def _generate_global_decl(self, node: ast.AnnAssign) -> str | None: """生成全局变量声明""" if not isinstance(node.target, ast.Name): return None var_name: str = node.target.id if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': return None if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': return None if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': return None if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': return None if isinstance(node.annotation, ast.List): for elt in node.annotation.elts: if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): return None if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': return None VarType: str = self._get_type_str(node.annotation) if VarType.startswith('[0 x ') and node.value: elem_type: str = VarType[5:-1] actual_count: int = 0 if isinstance(node.value, ast.List): actual_count = len(node.value.elts) elif isinstance(node.value, ast.Constant) and isinstance(node.value.value, str): # 字符串字面量:与 HandlesBase.ParseArrayCount(:731-732) / HandlesAssign # 全局路径同口径(len(str)+1,含结尾 NUL)。此前只修 List 值 → CArray # 字符串全局的 stub 声明停留在 [0 x i8],与定义端 [N x i8] 长度不一致 # (跨模块 type mismatch / llc 拒绝)。 actual_count = len(node.value.value) + 1 if actual_count > 0: VarType = f'[{actual_count} x {elem_type}]' return f'@{var_name} = external global {VarType}' def _generate_global_assign_decl(self, node: ast.Assign) -> str | None: """从无类型标注赋值推断并生成全局变量声明""" if not node.targets or not isinstance(node.targets[0], ast.Name): return None var_name: str = node.targets[0].id VarType: str | None = self._infer_type(node.value) if VarType: return f'@{var_name} = external global {VarType}' return None def _resolve_base_kind(self, base_name: str) -> str | None: """解析基类名称的类型种类(支持别名) Returns: 'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None """ # 1) 查 t 别名映射(from t import CEnum as en) if base_name in self._t_alias_map: t_cls: type = self._t_alias_map[base_name] if issubclass(t_cls, (t.CEnum, t.REnum)): return 'renum' if issubclass(t_cls, t.REnum) else 'enum' if issubclass(t_cls, t.CUnion): return 'union' if issubclass(t_cls, t.CStruct): return 'struct' # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, # 不应被编译为真实结构体,也不应被生成 stub 声明。 if issubclass(t_cls, t.CType): return 'ctype_marker' # 2) 直接查 t 模块属性 t_cls: type | None = getattr(t, base_name, None) if isinstance(t_cls, type) and issubclass(t_cls, t.CType): if issubclass(t_cls, (t.CEnum, t.REnum)): return 'renum' if issubclass(t_cls, t.REnum) else 'enum' if issubclass(t_cls, t.CUnion): return 'union' if issubclass(t_cls, t.CStruct): return 'struct' # CType 及其子类是"类型强转"标记,不编译为结构体。 return 'ctype_marker' return None def _is_marker_base(self, base_name: str) -> bool: """检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)""" if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'): return True if self._resolve_base_kind(base_name) is not None: return True return False def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: """生成结构体/类声明""" decls: list[str] = [] class_name: str = node.name is_enum: bool = False is_renum: bool = False is_union: bool = False is_exception: bool = False if node.bases: for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): base_name = base.attr elif isinstance(base, ast.Name) and hasattr(base, 'id'): base_name = base.id if base_name: if base_name in self.exception_names or base_name == 'Exception': is_exception = True break kind: str | None = self._resolve_base_kind(base_name) if kind == 'enum': is_enum = True break elif kind == 'union': is_union = True elif kind == 'renum': is_renum = True elif kind == 'ctype_marker': # CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是 # "类型强转"标记,不应被编译为真实结构体,也不生成 stub 声明。 return decls if is_exception: return decls if is_enum: enum_values: dict[str, int] = {} next_value: int = 0 # 枚举存储宽度 = 最宽成员类型(与定义端 HandlesClassDef / 跨模块读取端 # 同一规则源 EnumClassIntWidth;此处无 SymbolTable,走 t 类名 / builtins / # 库 typedef 的表)。声明端的全局类型必须与定义端运行时常量同宽(ABI)。 enum_width: int = EnumClassIntWidth(node.body) for item in node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): var_name: str = item.target.id if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): enum_values[var_name] = item.value.value else: enum_values[var_name] = next_value next_value += 1 elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): var_name: str = item.targets[0].id if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): enum_values[var_name] = item.value.value next_value = item.value.value + 1 else: enum_values[var_name] = next_value next_value += 1 for var_name, value in enum_values.items(): decls.append(f'@__config_{class_name}_{var_name} = external global i{enum_width}') return decls if is_renum: # REnum 布局: { i32 __tag, } # 对齐 _EmitREnumLlvm (HandlesClassDef.py) 的 Phase 2 逻辑 # Bug 修复:按每个位置的 max 字段尺寸构建布局,而非选总尺寸最大的变体。 # 不同变体在同一位置可能有不同尺寸的字段(如 Concrete 位置3是 i32, # 但 Var 位置3是 MetaType*),用最大变体的布局会导致指针截断。 variant_fields_list: list[list[str]] = [] for item in node.body: if isinstance(item, ast.ClassDef): variant_fields: list[str] = [] for nested_item in item.body: if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name): ft: str = self._get_type_str(nested_item.annotation, embedded=True) if ft: variant_fields.append(ft) variant_fields_list.append(variant_fields) elif isinstance(item, ast.Assign): # 显式值变体(无 payload) variant_fields_list.append([]) # 计算每个位置的最大尺寸 max_field_count: int = 0 for vf in variant_fields_list: if len(vf) > max_field_count: max_field_count = len(vf) renum_member_types: list[str] = ['i32'] # __tag for pos in range(max_field_count): pos_max_size: int = 0 for vf in variant_fields_list: if pos < len(vf): sz: int = self._llvm_type_size_str(vf[pos]) if sz > pos_max_size: pos_max_size = sz # <=4 用 i32,>4 用 i64(8字节,可容纳指针) if pos_max_size <= 4: renum_member_types.append('i32') else: renum_member_types.append('i64') if len(renum_member_types) < 2: # 无类变体或所有变体无字段时,使用 i32 作为占位(对齐 _EmitREnumLlvm 默认行为) renum_member_types = ['i32', 'i32'] struct_type_name: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' struct_decl: str = f'{struct_type_name} = type {{ {", ".join(renum_member_types)} }}' decls.append(struct_decl) return decls member_types: list[str] = [] has_bitfield: bool = False total_bits: int = 0 has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in node.body) is_cvtable: bool = False is_cpython_object: bool = False is_novtable: bool = False if hasattr(node, 'decorator_list') and node.decorator_list: for decorator in node.decorator_list: if isinstance(decorator, ast.Attribute): if getattr(decorator.value, 'id', None) == 't': if decorator.attr == 'CVTable': is_cvtable = True elif decorator.attr == 'Object': is_cpython_object = True elif decorator.attr == 'NoVTable': is_novtable = True elif isinstance(decorator, ast.Name): if decorator.id == 'CVTable': is_cvtable = True elif decorator.id == 'Object': is_cpython_object = True elif decorator.id == 'NoVTable': is_novtable = True if has_methods and not is_cpython_object: is_cpython_object = True has_parent_class: bool = False parent_is_novtable: bool = False for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id if base_name and not self._is_marker_base(base_name): has_parent_class = True # 检查父类是否为 @t.NoVTable(非多态继承) _p_node: ast.ClassDef | None = None for n in ast.iter_child_nodes(self._pyi_tree): if isinstance(n, ast.ClassDef) and n.name == base_name: _p_node = n break if _p_node is None: _p_node = self._cross_module_class_defs.get(base_name) if _p_node is not None and hasattr(_p_node, 'decorator_list') and _p_node.decorator_list: for dec in _p_node.decorator_list: if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'NoVTable': parent_is_novtable = True elif isinstance(dec, ast.Name) and dec.id == 'NoVTable': parent_is_novtable = True break # 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable # (@t.NoVTable 标记的类及其子类不使用 vtable,字段展平嵌入) if has_parent_class and not is_cvtable and not is_novtable and not parent_is_novtable: is_cvtable = True # 方法级 virtual(`virtual def m(...)` ⇒ 方法装饰器 @t.CVTable)触发类级 vtable: # 与 HandlesClassDef._resolve_class_flags / TPV _detect_vtable_status 的 # `_has_any_func_cvtable` 分支逐条对齐(类级 NoVTable / 无真实父类)。 # 必须在此同步:定义模块按 IsCVTable 在 struct 首部放 vptr,若 stub 不同步, # 跨模块使用该类的 struct 布局会比定义模块少一个字段 ⇒ 字段整体错位。 if not is_cvtable and ClassHasFuncLevelCVTable(node): if is_novtable or not has_parent_class: is_cvtable = True base_has_vtable: bool = False for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id if base_name and not self._is_marker_base(base_name): # 先在当前 .pyi 中查找父类,找不到则查跨模块类定义映射 _base_node: ast.ClassDef | None = None for n in ast.iter_child_nodes(self._pyi_tree): if isinstance(n, ast.ClassDef) and n.name == base_name: _base_node = n break if _base_node is None: _base_node = self._cross_module_class_defs.get(base_name) if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list: for dec in _base_node.decorator_list: if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': base_has_vtable = True elif isinstance(dec, ast.Name) and dec.id == 'CVTable': base_has_vtable = True if base_has_vtable: break # NoVTable 类不添加 vtable 指针(即使有方法和父类) if has_methods and is_cvtable and not base_has_vtable and not is_novtable: member_types.append('i8*') # 多继承字段展平:按继承源去重(2026-08-18)——菱形继承不再重复展平 # 祖先字段(Generator 同时继承 ClassGenMixin/ClassGenEnum/.../ClassGenBase, # 而它们都继承 ClassGenBase → ClassGenBase 字段被展平 6 次,struct 膨胀 # 且 this_adjust/字段 GEP 错位)。每类只展平一次,只取自有字段。 # 与 HandlesClassDef._FlattenInherited 保持同一算法。 _seen_cls: set[str] = set() for base in node.bases: base_name: str | None = None type_args: list[str] = [] if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id slice_node: ast.AST = base.slice if isinstance(slice_node, ast.Name): type_args.append(slice_node.id) elif isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: if isinstance(elt, ast.Name): type_args.append(elt.id) if base_name and not self._is_marker_base(base_name): self._FlattenInheritedDecl(base_name, _seen_cls, member_types, type_args or None) # 自身字段收集(复用 _CollectOwnMemberTypes,与 _FlattenInheritedDecl 一致) _own_types: list[str] _own_types, has_bitfield, total_bits = self._CollectOwnMemberTypes(node) member_types.extend(_own_types) if has_bitfield: if total_bits <= 8: member_types.insert(0, 'i8') elif total_bits <= 16: member_types.insert(0, 'i16') elif total_bits <= 32: member_types.insert(0, 'i32') else: member_types.insert(0, 'i64') struct_type_name: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' struct_decl: str = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' decls.append(struct_decl) if is_cpython_object or is_cvtable: new_func_name: str = f'{class_name}.__before_init__' if self.module_sha1: new_func_name = f"{self.module_sha1}.{new_func_name}" new_func_decl: str if new_func_name[0].isdigit(): new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)' else: new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)' decls.append(new_func_decl) # PEP 695 泛型类跳过方法声明生成:方法参数类型 T 会被解析为 opaque struct, # LLVM 报 "invalid type for function argument"。字段(AnnAssign)仍正常生成, # 确保子类(如 Value(GSListNode[Value]))能从 stub 中读取继承字段(如 Next)。 IsGenericClass: bool = hasattr(node, 'type_params') and bool(node.type_params) if not IsGenericClass: for item in node.body: if isinstance(item, ast.FunctionDef): if hasattr(item, 'type_params') and item.type_params: continue method_name: str = f'{class_name}.{item.name}' if self.module_sha1: method_name = f"{self.module_sha1}.{method_name}" ret_type: str = self._get_type_str(item.returns) if item.returns else 'void' if not ret_type: ret_type = 'void' params: list[str] = [] for arg_idx, arg in enumerate(item.args.args): arg_type: str if arg.annotation: arg_type = self._get_type_str(arg.annotation) elif arg_idx == 0 and arg.arg == 'self': arg_type = f'{struct_type_name}*' else: arg_type = 'i8*' # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* arg_type = self._decay_array_to_ptr(arg_type) params.append(arg_type) param_str: str = ', '.join(params) if params else '' if method_name[0].isdigit(): decls.append(f'declare {ret_type} @"{method_name}"({param_str})') else: decls.append(f'declare {ret_type} @{method_name}({param_str})') # 为继承但未覆写的方法生成包装声明 # 这些声明让跨模块调用能正确解析子类包装函数的签名, # 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断 decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name)) return decls def _generate_inherited_method_decls(self, node: ast.ClassDef, child_class_name: str, child_struct_type: str) -> list[str]: """为继承但未覆写的方法生成包装声明 在 Phase 1 stub 中声明子类继承方法的签名(与父类相同,但 self 参数为子类类型)。 这样测试模块翻译时能从 temp stub 中获取正确的返回类型, 避免 Phase 2 includes 翻译滞后导致跨模块调用使用默认 i32 返回类型。 """ decls: list[str] = [] # 收集子类自身定义的方法名(这些不需要生成包装,子类有自己的实现) seen_method_names: set[str] = set() for item in node.body: if isinstance(item, ast.FunctionDef): seen_method_names.add(item.name) # 沿继承链收集父类方法,近祖先优先 for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id if not base_name or self._is_marker_base(base_name): continue self._CollectInheritedWrapperDecls( base_name, child_class_name, child_struct_type, seen_method_names, decls) return decls def _CollectInheritedWrapperDecls( self, parent_name: str, child_class_name: str, child_struct_type: str, seen_method_names: set[str], decls: list[str]) -> None: """递归收集父类及其祖先的方法,为未覆写的方法生成包装声明""" # 查找父类节点:先在当前 .pyi 中查找,找不到则查跨模块类定义映射 parent_node: ast.ClassDef | None = None for n in ast.iter_child_nodes(self._pyi_tree): if isinstance(n, ast.ClassDef) and n.name == parent_name: parent_node = n break if parent_node is None: parent_node = self._cross_module_class_defs.get(parent_name) if parent_node is None: return # 为父类的每个方法生成包装声明 for item in parent_node.body: if isinstance(item, ast.FunctionDef): if hasattr(item, 'type_params') and item.type_params: continue method_name: str = item.name # __before_init__ 只在自身类生成,不生成继承包装 if method_name == '__before_init__': continue # 跳过子类已覆写的方法,以及已处理的祖先方法 if method_name in seen_method_names: continue seen_method_names.add(method_name) # 构建包装方法名:{module_sha1}.{child_class}.{method_name} wrapper_name: str = f'{child_class_name}.{method_name}' if self.module_sha1: wrapper_name = f"{self.module_sha1}.{wrapper_name}" # 解析返回类型(与父类方法相同) ret_type: str = self._get_type_str(item.returns) if item.returns else 'void' if not ret_type: ret_type = 'void' elif ret_type == 'i8*': if item.returns is None: ret_type = 'void' # 构建参数列表:第一个参数(self)替换为子类类型,其余与父类相同 params: list[str] = [] for arg_idx, arg in enumerate(item.args.args): arg_type: str if arg_idx == 0 and arg.arg == 'self': arg_type = f'{child_struct_type}*' else: if arg.annotation: arg_type = self._get_type_str(arg.annotation) else: arg_type = 'i8*' arg_type = self._decay_array_to_ptr(arg_type) params.append(arg_type) param_str: str = ', '.join(params) if params else '' if wrapper_name[0].isdigit(): decls.append(f'declare {ret_type} @"{wrapper_name}"({param_str})') else: decls.append(f'declare {ret_type} @{wrapper_name}({param_str})') # 递归处理祖先类 for base in parent_node.bases: base_name: str | None = None if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id if base_name and not self._is_marker_base(base_name): self._CollectInheritedWrapperDecls( base_name, child_class_name, child_struct_type, seen_method_names, decls) def _CollectOwnMemberTypes(self, node: ast.ClassDef) -> tuple[list[str], bool, int]: """收集类自身声明的字段类型(不含继承字段)。 与 _generate_class_decl 的字段收集逻辑一致(AnnAssign + __init__/方法内 self.attr 赋值)。返回 (types, has_bitfield, total_bits)。 供 _FlattenInheritedDecl 按"每类只展平一次 + 只取自有字段"使用, 消除菱形继承的重复展平(如 ClassGenBase 41 字段被 ClassGenMixin/ ClassGenEnum/.../ClassGenBase 6 个来源重复展平)。 """ member_types: list[str] = [] has_bitfield: bool = False total_bits: int = 0 seen_member_names: set[str] = set() for item in node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): seen_member_names.add(item.target.id) init_members: list[ast.AnnAssign] = [] for item in node.body: if isinstance(item, ast.FunctionDef) and item.name == '__init__': for stmt in item.body: if (isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self'): init_members.append(stmt) untyped_self_members: list[ast.Assign] = [] for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]: seen_member_names.add(m_name) for item in node.body: if isinstance(item, ast.FunctionDef): if hasattr(item, 'type_params') and item.type_params: continue for stmt in item.body: if (isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self'): attr_name: str = stmt.targets[0].attr if attr_name not in seen_member_names: seen_member_names.add(attr_name) untyped_self_members.append(stmt) for item in list(node.body) + init_members + untyped_self_members: if isinstance(item, ast.AnnAssign): # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) if isinstance(item.target, ast.Name) and item.target.id in ('__provides__', '__requires__', '__require_must__'): continue bit_width: int | None = self._get_bitfield_width(item.annotation) if bit_width is not None: has_bitfield = True total_bits += bit_width else: VarType: str = self._get_type_str(item.annotation, embedded=True) if IsListAnnotation(item.annotation): slice_node: ast.AST = item.annotation.slice is_dynamic: bool = False if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: count_node: ast.AST = slice_node.elts[1] if isinstance(count_node, ast.Constant) and count_node.value is None: is_dynamic = True elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0): if not isinstance(count_node, (ast.Name, ast.BinOp)): is_dynamic = True elif not isinstance(slice_node, ast.Tuple): is_dynamic = True if is_dynamic: elem_type: str = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) init_len: int = 0 if isinstance(item.value, ast.List): init_len = len(item.value.elts) elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): init_len = len(item.value.value) + 1 VarType = f'[{init_len} x {elem_type}]' else: # 固定大小数组: t.CArray[elem_type, count] → [count x elem_type] if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: elem_type = self._get_type_str(slice_node.elts[0], embedded=True) count_val: int = self._get_const_int(slice_node.elts[1]) if count_val > 0: VarType = f'[{count_val} x {elem_type}]' elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): # 单参数 t.CArray[elem_type] → 指针模式 elem_type = self._get_type_str(slice_node, embedded=True) VarType = f'{elem_type}*' member_types.append(VarType) elif isinstance(item, ast.Assign): if (len(item.targets) == 1 and isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self'): attr_name: str = item.targets[0].attr if attr_name in seen_member_names: continue InferredType: str = 'i32' if item.value and isinstance(item.value, ast.Constant): if isinstance(item.value.value, float): InferredType = 'float' elif isinstance(item.value.value, bool): InferredType = 'i8' elif isinstance(item.value.value, str): InferredType = 'i8*' member_types.append(InferredType) else: member_types.append('i32') return member_types, has_bitfield, total_bits def _ShouldEmitOwnVtablePtr(self, node: ast.ClassDef) -> bool: """类自身是否需要 vtable 指针(复刻 _generate_class_decl 的判定)。 仅"有方法 + CVTable 且父类无 vtable + 非 NoVTable"的类在 struct 最前 放 vtable 指针。继承 vtable 父类的子类不重复添加。_FlattenInheritedDecl 递归时用此判定补齐各祖先类的 vtable 指针(原 _get_inherited_members 走 _generate_class_decl 完整 struct 天然包含;改按自有字段后必须补上)。 """ has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in node.body) is_cvtable: bool = False is_cpython_object: bool = False is_novtable: bool = False if hasattr(node, 'decorator_list') and node.decorator_list: for decorator in node.decorator_list: if isinstance(decorator, ast.Attribute): if getattr(decorator.value, 'id', None) == 't': if decorator.attr == 'CVTable': is_cvtable = True elif decorator.attr == 'Object': is_cpython_object = True elif decorator.attr == 'NoVTable': is_novtable = True elif isinstance(decorator, ast.Name): if decorator.id == 'CVTable': is_cvtable = True elif decorator.id == 'Object': is_cpython_object = True elif decorator.id == 'NoVTable': is_novtable = True if has_methods and not is_cpython_object: is_cpython_object = True base_has_vtable: bool = False has_real_parent: bool = False for base in node.bases: base_name: str | None = None if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id if base_name and not self._is_marker_base(base_name): has_real_parent = True _base_node: ast.ClassDef | None = None for n in ast.iter_child_nodes(self._pyi_tree): if isinstance(n, ast.ClassDef) and n.name == base_name: _base_node = n break if _base_node is None: _base_node = self._cross_module_class_defs.get(base_name) if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list: for dec in _base_node.decorator_list: if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': base_has_vtable = True elif isinstance(dec, ast.Name) and dec.id == 'CVTable': base_has_vtable = True if base_has_vtable: break # 方法级 virtual 触发类级 vtable(与上方 _generate_class_decl 同一判据, # 保持在同一个类里两处口径一致;详见该处注释) if not is_cvtable and not base_has_vtable and ClassHasFuncLevelCVTable(node): if is_novtable or not has_real_parent: is_cvtable = True return has_methods and is_cvtable and not base_has_vtable and not is_novtable def _FlattenInheritedDecl(self, cls_name: str, seen_cls: set, member_types: list[str], type_args: list[str] | None = None) -> None: """按继承源去重递归展平:继承树每个类只处理一次,每类只贡献自有字段。 菱形继承(Generator 同时继承 ClassGenMixin/ClassGenEnum/.../ClassGenBase, 而它们都继承 ClassGenBase)会让 ClassGenBase 字段被重复展平,导致 stub struct 与运行时 class_members 布局错位(this_adjust 失效崩溃)。本方法与 HandlesClassDef 的 _FlattenInherited 保持同一算法。 """ if cls_name in seen_cls: return seen_cls.add(cls_name) cls_node: ast.ClassDef | None = None for n in ast.iter_child_nodes(self._pyi_tree): if isinstance(n, ast.ClassDef) and n.name == cls_name: cls_node = n break if cls_node is None: cls_node = self._cross_module_class_defs.get(cls_name) if cls_node is None: # 跨模块未知类:回退到完整展平(_get_inherited_members 递归) mts, _ = self._get_inherited_members(cls_name) if type_args: mts = self._specialize_member_types(mts, type_args) member_types.extend(mts) return for base in cls_node.bases: base_name: str | None = None base_type_args: list[str] = [] if isinstance(base, ast.Attribute): base_name = base.attr elif isinstance(base, ast.Name): base_name = base.id elif isinstance(base, ast.Subscript): if isinstance(base.value, ast.Attribute): base_name = base.value.attr elif isinstance(base.value, ast.Name): base_name = base.value.id slice_node: ast.AST = base.slice if isinstance(slice_node, ast.Name): base_type_args.append(slice_node.id) elif isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: if isinstance(elt, ast.Name): base_type_args.append(elt.id) if base_name and not self._is_marker_base(base_name): self._FlattenInheritedDecl(base_name, seen_cls, member_types, base_type_args or None) own, _hbf, _tbits = self._CollectOwnMemberTypes(cls_node) if type_args: own = self._specialize_member_types(own, type_args) # 该类的 vtable 指针(若有)放在自有字段最前(与 _generate_class_decl # L485 一致;递归时各祖先类的 vtable 也按此补齐) if self._ShouldEmitOwnVtablePtr(cls_node): member_types.append('i8*') member_types.extend(own) def _get_inherited_members(self, base_name: str) -> tuple[list[str], set[str]]: member_types: list[str] = [] seen_names: set[str] = set() if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: return member_types, seen_names base_node: ast.ClassDef | None = None for node in ast.iter_child_nodes(self._pyi_tree): if isinstance(node, ast.ClassDef) and node.name == base_name: base_node = node break if base_node is None: # 跨模块父类查找:当前 .pyi 中没有父类定义时,从跨模块类定义映射中查找 # (如 exprs.py 的 Name(AST),AST 定义在 base.py) base_node = self._cross_module_class_defs.get(base_name) if base_node is None: return member_types, seen_names base_decls: list[str] = self._generate_class_decl(base_node) for decl in base_decls: if '= type {' in decl: type_body: str = decl.split('= type {')[1].rstrip('}').strip() if type_body: for t in type_body.split(','): t = t.strip() if t: member_types.append(t) break for item in base_node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): seen_names.add(item.target.id) elif isinstance(item, ast.Assign) and len(item.targets) == 1: if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self': seen_names.add(item.targets[0].attr) for item in base_node.body: if isinstance(item, ast.FunctionDef) and item.name == '__init__': for stmt in item.body: if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self': seen_names.add(stmt.target.attr) elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self': seen_names.add(stmt.targets[0].attr) return member_types, seen_names def _specialize_member_types(self, member_types: list[str], type_args: list[str]) -> list[str]: """将基类成员类型中的泛型参数 T 替换为具体类型参数 处理泛型基类继承(如 GSListNode[BasicBlock])时,基类 _get_inherited_members 返回的成员类型中会包含未特化的 T 引用(形式为 %"SHA1.T"*)。 替换策略:使用 i8*(不透明指针)代替 T*,而非具体类型指针。 原因:跨模块场景中,具体类型指针的 SHA1 前缀可能与导入模块不一致, 导致 TransPyC 类型转换失败。i8* 作为通用指针类型,可安全赋值给 任何 Class | t.CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。 Args: member_types: 基类成员类型字符串列表 type_args: 类型参数名列表(如 ['BasicBlock']) Returns: 特化后的成员类型字符串列表 """ if not type_args: return member_types result: list[str] = [] for mt in member_types: new_mt: str = mt # 将 %"SHA1.T"* 替换为 i8*(不透明指针) new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt) # 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8* new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt) result.append(new_mt) return result def _llvm_type_size_str(self, type_str: str) -> int: """估算 LLVM 类型字符串的大小(字节),用于 REnum 变体大小比较 对齐 _EmitREnumLlvm 中的大小计算逻辑: - i1=1, i8=1, i16=2, i32=4, i64=8, float=4, double=8, ptr=8 - [N x T] = N * size(T) - 其他结构体类型按指针大小 8 估算(保守值) """ s: str = type_str.strip() if not s: return 0 # 指针类型 if s.endswith('*'): return 8 # 数组类型 [N x T] m = self._ARR_TYPE_RE.match(s) if hasattr(self, '_ARR_TYPE_RE') else None if m: try: n: int = int(m.group(1)) return n * self._llvm_type_size_str(m.group(2)) except ValueError: return 8 # 基本整数/浮点类型 size_map: dict[str, int] = { 'i1': 1, 'i8': 1, 'i16': 2, 'i32': 4, 'i64': 8, 'float': 4, 'double': 8, 'half': 2, 'fp128': 16, 'void': 0, } if s in size_map: return size_map[s] # %{...} 结构体类型 - 保守估算为指针大小 if s.startswith('%') or s.startswith('{'): return 8 # 其他未知类型保守估算 return 8 @staticmethod def _ptr_level_of(type_str: str) -> int: """统计类型字符串尾部的指针层数('i8***' → 3,'i32' → 0)""" return len(type_str) - len(type_str.rstrip('*')) def _merge_cptr_subscript(self, base_type: str, cptr_sub_type: str) -> str: """base | t.CPtr[T] → Ptr^N(base_type),N = t.CPtr[T] 段自身指针层数。 与定义侧 TPV TypeGenResolve.vp:2610-2639 同口径:数 CPtr 侧已解析类型的 外层 Ptr 嵌套层 N(TypeGenResolve.vp:2616-2632),再给另一侧**纯外包** N 层 Ptr(TypeGenResolve.vp:2633-2639,对 struct 基类型亦不吸收)。 与 LLVMTypeMapper._resolve_bitor 的 IsCPtrSubscriptNode 分支(_add_pointer_levels 逐层追加)同口径,对同一批形态两处结果一致。 注:裸 | t.CPtr(非下标标记)仍走上方的 %"..."* 吸收分支,与本节无关。 """ return base_type + '*' * self._ptr_level_of(cptr_sub_type) def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str: """指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],判据见 SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。 与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价 联合写法 `T | t.CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由 _MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用 的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果 就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 / 联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 t.CPtr[...] 共用本条 规则(此前 t.CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得 list[X]*,同一指针语义两种结果)。 """ inner: ast.AST = annotation.slice inner_type: str = self._get_type_str(inner) if self._is_bare_class_ref_annotation(inner, inner_type): return inner_type if inner_type in ('', 'void', 'void*'): return 'i8*' return f'{inner_type}*' def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool: """节点是否为"裸类引用"(本身即指针 → 吸收一层 t.CPtr)。 与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是 指针('%"sha1.X"*'),所以 `AST | t.CPtr` 合并后仍是该指针(定义端 _MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针 下标(rawptr[...] / t.CPtr[...])不是裸类引用——它们已自带指针层数, 须逐层外包(rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr → AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。 """ if not inner_type: return False if isinstance(inner, ast.BinOp): return False if isinstance(inner, ast.Subscript): return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner)) return inner_type.startswith('%') and inner_type.endswith('*') def _get_type_str(self, annotation: ast.AST | None, embedded: bool = False) -> str: if annotation is None: return 'i8*' non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray', 'rawarray'} if isinstance(annotation, ast.Name): if annotation.id == 'None': return 'void' if annotation.id in ('str', 'bytes'): return 'i8*' llvm_type: str | None = CTypeRegistry.NameToLLVM(annotation.id) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(annotation.id) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if ptr_level > 0: if base == 'void': return 'i8*' if '*' in base: return base return f'{base}*' return base if annotation.id in self.struct_names: sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' if embedded: return sname else: return f'{sname}*' if annotation.id in non_struct_types: return 'i32' if annotation.id in self.enum_names: return 'i32' if annotation.id in self.typedef_map: resolved_str: str = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) return resolved_str # 检查 t 类型别名(from t import CInt as myint) if annotation.id in self._t_alias_map: t_cls: type = self._t_alias_map[annotation.id] llvm: str | None = CTypeRegistry.CTypeToLLVM(t_cls) if llvm: return llvm # builtins 隐式 CTypedef(int64/uint64/size_t 等:builtins.vp 声明、 # 用户文件无需 import 即用):常规路径 miss 后若落下方 fallback 会按 # "本模块结构体"建 %"{mod}.int64" opaque(ClassGenGeneric._clone_annotation # 的 "i64 != %int64*" 根因)。按 builtins.vp 权威定义展开。 from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _DG_TAR _dg_bv: str | None = _DG_TAR.builtins_typedef_value(annotation.id) if _dg_bv: if _dg_bv.startswith('t.'): _dg_llvm: str | None = CTypeRegistry.NameToLLVM(_dg_bv[2:]) if _dg_llvm: return _dg_llvm _dg_node: ast.AST | None = None try: _dg_node = ast.parse(_dg_bv, '', mode='eval').body except Exception: _dg_node = None if _dg_node is not None: _dg_ret: str = self._get_type_str(_dg_node, embedded=embedded) if _dg_ret and _dg_ret != 'i32': return _dg_ret sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' return f'{sname}*' elif isinstance(annotation, ast.Attribute): attr_name: str = annotation.attr if hasattr(annotation, 'attr') else '' module_name: str = '' if hasattr(annotation, 'value'): if isinstance(annotation.value, ast.Name): module_name = annotation.value.id elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'): module_name = annotation.value.attr if (module_name == 't' and attr_name == 'State') or attr_name == 'State': return '' if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable': return 'i8*' llvm_type: str | None = CTypeRegistry.NameToLLVM(attr_name) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(attr_name) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if ptr_level > 0: if base == 'void': return 'i8*' if '*' in base: return base return f'{base}*' return base if attr_name in self.typedef_map: return self._get_type_str(self.typedef_map[attr_name], embedded=embedded) if attr_name in self.enum_names: return 'i32' if attr_name in self.struct_names: sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' if embedded: return sname else: return f'{sname}*' if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types: sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' return f'{sname}*' if attr_name and attr_name not in non_struct_types: sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' return f'{sname}*' return 'i32' elif isinstance(annotation, ast.BinOp): left_type: str = self._get_type_str(annotation.left, embedded=embedded) right_type: str = self._get_type_str(annotation.right, embedded=embedded) if left_type in ('', 'void'): return right_type if right_type not in ('', 'void') else (left_type or right_type) if right_type in ('', 'void'): return left_type # t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的 # "first CPtr absorption" 语义:struct | t.CPtr → struct*(吸收,struct 变量默认是指针)。 # 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | t.CPtr → i8**(不吸收)。 # 例外:LLVM 聚合数组([N x T],字符串以 '[' 开头)不可再外包指针层 → i8*。 # 注:具名泛型特化(%"mod.list[X]"*)**不**走此回退——stub 已由 # _collect_undefined_type_decls 为其补 opaque 声明,保留名字才能与 define 端 # 的 %"mod.list[ast.ASTptr]"* 逐字一致(原 `'[' in left_type` 会把 # list[X] | t.CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。 if right_type == 'i8*': if left_type[:1] == '[': return 'i8*' if left_type in ('', 'void'): return 'i8*' # 吸收仅对"裸类引用"成立(其非 embedded 形式本身即指针): # ast.AST | t.CPtr → %"sha1.AST"*。已自带指针层数的左值 # (rawptr[...] / t.CPtr[...] 下标 / 联合写法)须逐层外包: # rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr → AST** # ——与定义端 _CollectAllOperandTypes 整体拉平、只吸收一次 CPtr # (_MergeAllComponentTypes 的 base_ptr_count>0 分支)一致。 if self._is_bare_class_ref_annotation(annotation.left, left_type): return left_type if '*' in left_type: return f'{left_type}*' return f'{left_type}*' # X | t.CPtr[T](T 为下标段,非裸标记):CPtr 侧贡献自身指针层数 N, # 另一侧外包 N 层(Ptr^N(X));左右两侧写法对称(定义侧 TPV # TypeGenResolve.vp:2604-2609 亦两侧皆判)。必须先于下方 # "'*' in left_type → 直接返回左值":否则左值本身已是指针 # (BYTEPTR⇒i8*)时会吞掉右段层数(BYTEPTR | t.CPtr[t.CPtr] 改前得 i8*)。 # LLVM 聚合([N x T] / { ... })不可再外包指针层,保持既有行为(只报不改)。 if IsCPtrSubscriptNode(annotation.right) and left_type[:1] not in ('[', '{'): return self._merge_cptr_subscript(left_type, right_type) if IsCPtrSubscriptNode(annotation.left) and right_type[:1] not in ('[', '{'): return self._merge_cptr_subscript(right_type, left_type) # t.CPtr 裸标记在左侧(t.CPtr | X):与右侧写法(X | t.CPtr,见上) # 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数: # t.CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。 # 仅对裸标记 t.CPtr 生效(left 为 t.CPtr[T] 下标走上一条分支; # str/bytes 等其它 i8* 左值不受影响)。 if IsCPtrNode(annotation.left) and right_type[:1] not in ('[', '{'): if self._is_bare_class_ref_annotation(annotation.right, right_type): return right_type return f'{right_type}*' if '*' in left_type: return left_type if '*' in right_type: return right_type return left_type elif isinstance(annotation, ast.Subscript): # 指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带 # 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | t.CPtr`:与定义端 # **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的 # _t_c_imported_names 表解析 X→CPtr)+ 同一层数规则 # (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T # 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T] # 在此退化成 i8*,t.CPtr[T] 走的是"embedded + 追加一层"的独立分支: # 非同一规则,且对泛型容器特化多出一层(t.CPtr[list[X]] 得 list[X]**, # 而 rawptr[list[X]] 得 list[X]*)。 ValueIsCPtr: bool = ( (isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr') or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr') ) if (IsPtrSubscriptNode(annotation, TCAliasMap=self._t_c_imported_names) or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))): return self._ptr_subscript_type_str(annotation) base: str = self._get_type_str(annotation.value) if base == 'i8*' and isinstance(annotation.slice, ast.Constant): return f'[{self._get_const_int(annotation.slice)} x i8]' if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): return f'[{annotation.slice.value} x {base}]' # 处理 t.CArray[elem_type, count] / rawarray[elem_type, count] / array[elem_type, count] # 注解 → [count x elem_type] # 支持 t.CArray (ast.Attribute)、CArray/rawarray/array (ast.Name) 三种写法 # (array 为本轮新增的内建软关键字,与 t.CArray 逐点等价) ValueIsCArray: bool = ( (isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CArray') or (isinstance(annotation.value, ast.Name) and annotation.value.id in ('CArray', 'rawarray', 'array')) ) if ValueIsCArray: SliceNode: ast.AST = annotation.slice if isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2: ElemType: str = self._get_type_str(SliceNode.elts[0], embedded=True) CountVal: int = self._get_const_int(SliceNode.elts[1]) if CountVal > 0: return f'[{CountVal} x {ElemType}]' # count 为 None 或 0 → 零长度数组(外部符号) return f'[0 x {ElemType}]' elif isinstance(SliceNode, (ast.Attribute, ast.Name, ast.Subscript)): # 单参数 t.CArray[elem_type]:与 t.CArray[elem_type, None] 语义统一为 # "长度自动推导数组"。此处无初始化字面量可推导 → 与 ,None 分支同用 # [0 x elem] 占位,真实长度由 _generate_global_decl 按初始化字面量 # (List 长度 / str 长度+1) 修正。 # 参数位置经 _decay_array_to_ptr(:23-28) 退化为 elem*,与旧指针行为一致。 ElemType: str = self._get_type_str(SliceNode, embedded=True) return f'[0 x {ElemType}]' if isinstance(annotation.value, ast.Name) and annotation.value.id == 'tuple': slice_node: ast.AST = annotation.slice elem_types: list[str] if isinstance(slice_node, ast.Tuple): elem_types = [self._get_type_str(e, embedded=True) for e in slice_node.elts] else: elem_types = [self._get_type_str(slice_node, embedded=True)] return '{ ' + ', '.join(elem_types) + ' }' # 处理泛型类类型注解(如 list[str] / list[rawptr[ast.AST]] / # 用户泛型类 Box[Node]) # 实参串走 SymbolUtils.ResolveGenericTypeArgStr(与定义端 # _mangle_generic_class_name 同一规则源):此前只认 Name / Name-Tuple # 实参,Attribute(ast.AST)/ Subscript(rawptr[...])/ BinOp # (X | t.CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*, # 与 define 端发射的 %".list[ast.ASTptr]" 不一致 # (Undefined method / 签名错位)。 # 内建容器(non_struct_types)之外,**用户泛型类**同样特化:判据 # _generic_class_names(ClassDef.type_params,与定义端 # HandlesClassDef._generic_class_templates 同源),此前只有内建容器名 # 会特化 → Box[Node] 字段在 stub 端是 %".Box"*、定义端是 # %".Box[<已解析实参>]"*(Holder 字段布局两侧不一致)。 if isinstance(annotation.value, ast.Name): gc_name: str = annotation.value.id if (gc_name in non_struct_types or gc_name in self._generic_class_names) \ and gc_name != 'tuple': gc_slice: ast.AST = annotation.slice # 多参数泛型(dict[K, V]):'][' 分隔,与 # _mangle_generic_class_name 一致 gc_nodes: list[ast.AST] = ( list(gc_slice.elts) if isinstance(gc_slice, ast.Tuple) else [gc_slice]) gc_mangled: list[str] = [ ResolveGenericTypeArgStr( gc_node, TCAliasMap=self._t_c_imported_names, StructSha1Map=self.struct_sha1_map) for gc_node in gc_nodes] gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']' # 特化名前缀取**泛型模板类定义模块**的 SHA1(list → includes/_list.vp、 # Box → 定义 Box 的模块,查 struct_sha1_map 即"类名 → 定义模块"表), # 与定义端 HandlesClassDef._specialize_generic_class 的 # Gen.module_sha1 = template['sha1']、调用点 # Gen._struct_sha1_map[spec_name] 同一条规则源。 # 此前用 self.module_sha1(使用方模块):同一特化在 declare(使用方前缀) # 与 define/call(模板模块前缀)两侧不一致 → 跨模块 undefined symbol。 gc_sha1: str | None = self.struct_sha1_map.get(gc_name, self.module_sha1) gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}' # 一律以指针引用(不区分 embedded):定义端对嵌入式泛型容器 # (字段 / t.CArray 元素)用不透明指针(实测字段 i8*,见 # FieldForms/FieldBox/FieldOrder),嵌入 unsized opaque # 结构体值会让字段/元素偏移错位;非 embedded(参数/返回) # 亦与定义端同为指针 return f'{gc_sname}*' return f'{base}' elif isinstance(annotation, ast.Constant): if annotation.value is None: return 'void' if isinstance(annotation.value, int): return 'i32' if isinstance(annotation.value, str): type_name: str = annotation.value if type_name in self.enum_names: return 'i32' if type_name in self.struct_names: sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) sname: str = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' if embedded: return sname else: return f'{sname}*' llvm_type: str | None = CTypeRegistry.NameToLLVM(type_name) if llvm_type is not None: return llvm_type resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(type_name) if resolved is not None: ctype_cls: type ptr_level: int ctype_cls, ptr_level = resolved base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if ptr_level > 0: if base == 'void': return 'i8*' if '*' in base: return base return f'{base}*' return base sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) sname: str = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' return f'{sname}*' return 'i8*' elif isinstance(annotation, ast.Call): if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable': return 'i8*' if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable': return 'i8*' return 'i32' def _infer_type(self, value: ast.AST) -> str: """从值推断类型""" if isinstance(value, ast.Constant): if isinstance(value.value, int): return 'i32' elif isinstance(value.value, float): return 'double' elif isinstance(value.value, str): return 'i8*' elif isinstance(value.value, bool): return 'i8' elif isinstance(value, ast.List): return 'i8*' elif isinstance(value, ast.Dict): return 'i8*' elif isinstance(value, ast.Name): return 'i32' elif isinstance(value, ast.BinOp): return self._infer_type(value.left) elif isinstance(value, ast.Call): return 'i8*' return 'i32' def _get_bitfield_width(self, annotation: ast.AST) -> int | None: if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): right_width: int | None = self._get_bitfield_width(annotation.right) if right_width is not None: return right_width return self._get_bitfield_width(annotation.left) if isinstance(annotation, ast.Call): if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit': if annotation.args: arg: ast.AST = annotation.args[0] if isinstance(arg, ast.Constant) and isinstance(arg.value, int): return arg.value if isinstance(annotation, ast.Subscript): if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit': if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): return annotation.slice.value return None def _get_const_int(self, node: ast.AST) -> int: """获取常量整数值,支持符号常量和简单表达式""" if isinstance(node, ast.Constant) and isinstance(node.value, int): return node.value if isinstance(node, ast.Name): if node.id in self._DefineConstants: val: int | str = self._DefineConstants[node.id] if isinstance(val, int): return val if isinstance(node, ast.BinOp): left_val: int = self._get_const_int(node.left) right_val: int = self._get_const_int(node.right) if left_val and right_val: if isinstance(node.op, ast.Add): return left_val + right_val if isinstance(node.op, ast.Sub): return left_val - right_val if isinstance(node.op, ast.Mult): return left_val * right_val if isinstance(node.op, ast.Div): return left_val // right_val if isinstance(node.op, ast.FloorDiv): return left_val // right_val return 0