from __future__ import annotations import vast as ast import copy import re from typing import List import llvmlite.ir as ir from lib.core import TypeSystem from lib.core.TypeSystem import CTypeRegistry from lib.core.SymbolUtils import ( IsListAnnotation, IsCPtrSubscriptNode, IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr, EnumClassIntWidth, ClassHasFuncLevelCVTable) # 泛型特化(`_SubstituteTypeArgs`)把 `%"SHA1.T"` / `%"SHA1.T"*` 替换为 i8* 用的 # **预编译**正则(性能:字面量正则预编译避免 re 缓存查找与编译开销)。 _RE_T_TYPE_PTR: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"\*') _RE_T_TYPE: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"') 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() # 内建类型导入名表(CInt as myint → 'myint' → CInt), # 与定义端 Trans._from_import_aliases 同口径,供泛型实参串解析使用 self._from_import_aliases: 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 {} TypeSystem.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) # 类型标记按裸名直接识别、不依赖导入:别名映射表保持为空。 self._t_alias_map: dict[str, type] = {} self._from_import_aliases: dict[str, tuple[str, str]] = {} 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 Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple( getattr(node.annotation, 'Markers', None) or ()) is_typedef: bool = 'typedef' in Markers if is_typedef and node.value: self.typedef_map[var_name] = node.value 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}" MultiRetTypes: list[ast.AST] = [] if node.decorator_list: for decorator in node.decorator_list: # fail-fast:`CReturn` 不是内建标记;多返回值请改用 `-> tuple[ty1, ty2, ...]`。 _DecName: str = '' if isinstance(decorator, ast.Call): if isinstance(decorator.func, ast.Name): _DecName = decorator.func.id elif isinstance(decorator.func, ast.Attribute): _DecName = decorator.func.attr if _DecName == 'CReturn': raise SyntaxError( f"函数 '{node.name}':`CReturn` 不是内建标记;请改用返回注解 " f"`-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)" ) 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: MultiRetTypes.append(elt) else: MultiRetTypes.append(slice_node) ret_type: str if MultiRetTypes: elem_types: list[str] = [self._get_type_str(rt, embedded=True) for rt in MultiRetTypes] 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: """检查函数是否导出/外部可见(export / extern / state)。 新语法的 `export def` / `extern def` 由解析器写入 FunctionDef.Export / Extern。 """ if bool(getattr(node, 'Export', False)) or bool(getattr(node, 'Extern', False)): return True Markers: tuple[str, ...] = getattr(node, 'Markers', None) or () if 'export' in Markers or 'extern' in Markers or 'state' in Markers: return True 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: """检查类型注解是否带 export / extern / state 标记(只读 Markers)。""" if annotation is None: return False Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or () return 'export' in Markers or 'extern' in Markers or 'state' in Markers 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 # define 是编译期常量,不是变量:stub 里**不得**生成 external global, # 否则其他模块引用它时变成未定义符号(链接失败)。标记由 Markers 字段承载。 Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple( getattr(node.annotation, 'Markers', None) or ()) if 'define' in Markers: return None if 'typedef' in Markers: 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 == 'Callable': return None if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Name) and elt.value.id == '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) 查内建类型别名映射 if base_name in self._t_alias_map: t_cls: type = self._t_alias_map[base_name] if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)): return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum' if issubclass(t_cls, TypeSystem.CUnion): return 'union' if issubclass(t_cls, TypeSystem.CStruct): return 'struct' # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, # 不应被编译为真实结构体,也不应被生成 stub 声明。 if issubclass(t_cls, TypeSystem.CType): return 'ctype_marker' # 2) 直接查内建类型类 t_cls: type | None = getattr(TypeSystem, base_name, None) if isinstance(t_cls, type) and issubclass(t_cls, TypeSystem.CType): if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)): return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum' if issubclass(t_cls, TypeSystem.CUnion): return 'union' if issubclass(t_cls, TypeSystem.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.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 # 检查父类是否为 @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.Name) and dec.id == 'NoVTable': parent_is_novtable = True break # 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable # (@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(...)` ⇒ 方法装饰器 @CVTable)触发类级 vtable: # 与 HandlesClassDef._resolve_class_flags / VPC _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.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) # 嵌套类 / 嵌套 struct:定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef. # _EmitNestedClassDefs),此处同步产出同名完整类型声明 —— 否则跨模块引用 # `外类.内类` 只会得到一个 opaque 前向声明(指针可用、字段偏移全失效)。 # deepcopy 后改名再递归:本函数所有名字都派生自 node.name,改名即全链路一致; # 判断/枚举/联合等分支在递归时会各自按内层类自身的基类重新分派。 for _nested_item in getattr(node, 'body', None) or []: if not isinstance(_nested_item, ast.ClassDef): continue _nested_inner: str | None = getattr(_nested_item, 'name', None) if not _nested_inner: continue _nested_node: ast.ClassDef = copy.deepcopy(_nested_item) _nested_node.name = f'{class_name}_{_nested_inner}' decls.extend(self._generate_class_decl(_nested_node)) 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: # 固定大小数组: 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)): # 单参数 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 # 不再兜底 i32:只认**能唯一确定**的取值形态,推不出即响亮失败。 # 规则表必须与定义端 HandlesClassDef._scan_node_for_self_assign 的 # Assign 分支**逐条一致**(stub 与定义端 struct 布局必须同源, # 少/多一个槽 ⇒ 跨模块字段偏移整体错位): # 整型/布尔字面量 → 'i32'(定义端 bool 走 int 分支); # 浮点字面量 → 'double'(定义端 DoubleType;此前这里写 'float' # = f32,与定义端 8 字节不一致);字符串字面量 → 'i8*'。 # 注:`self.X = <带注解形参>` / 白名单调用(float()/double()/char()/ # int()…/len())在定义端可定型,本函数**拿不到**符号表故不在此推 # (这些形态一旦出现会被定义端接受,而 stub 这里判不了); # 另外方法体内的裸 `self.X = ...` 已被上方 seen_member_names 过滤 # (只对**本类自有声明**判重,不含继承字段)——若贸然放行, # 继承字段(如 G4Node.Next)会被当成自有字段重复加一个槽, # 反而制造布局分叉。要放行必须先在此补"祖先字段名"判定。 InferredType: str | None = None if item.value is not None and isinstance(item.value, ast.Constant): _v: object = item.value.value if isinstance(_v, bool): InferredType = 'i32' elif isinstance(_v, int): InferredType = 'i32' elif isinstance(_v, float): InferredType = 'double' elif isinstance(_v, str): InferredType = 'i8*' if InferredType is None: _vt: str = '' try: _vt = ast.unparse(item.value) if item.value is not None else '<无值>' except Exception: _vt = '<无法反解析>' raise ValueError( f"[FATAL] 类 '{node.name}' 的字段 '{attr_name}' 在 stub 声明里" f"推不出类型(`self.{attr_name} = {_vt}`,行 " f"{getattr(item, 'lineno', 0)})——拒绝静默写成 i32。" f"请在类体声明该字段并给注解。") 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.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.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 | 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_T_TYPE_PTR.sub('i8*', new_mt) # 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8* new_mt = _RE_T_TYPE.sub('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] # 注:此处原写作 `self._ARR_TYPE_RE`(少一个 A)并用 `hasattr` 守卫 —— 该属性 # **全仓从未定义** ⇒ 守卫恒假 ⇒ 本分支恒不执行:数组字段一律落到下方"未知类型 → 8" # 的保守值,与 docstring 声明的"_EmitREnumLlvm 尺寸口径对齐"不符(静默降级)。 # 现改用本类已定义的 `_ARRAY_TYPE_RE`(见文件顶部),并去掉守卫: # 属性若再丢失应当响亮失败,而不是静默退回 8。 m = self._ARRAY_TYPE_RE.match(s) 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 def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str: """指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T],判据见 SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。 裸类引用的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被 吸收 → 结果就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 / 嵌套指针下标)逐层外包。 """ 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: """节点是否为"裸类引用"(本身即指针 → 吸收一层 CPtr)。 类引用的**非** embedded 形式本身就是指针('%"sha1.X"*'),再包一层 指针会被吸收;指针下标(rawptr[...] / CPtr[...])已自带指针层数, 须逐层外包(CPtr[Node] → Node**)。 """ if not inner_type: 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*' if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): Line: int = getattr(annotation, 'lineno', 0) or 0 raise TypeError( f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);" f"类型注解只能是单一类型:指针请写 `T*` 或 `rawptr[T]`," f"修饰符请用关键字(const/volatile/static/export/extern)") 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*' # 裸指针标记(rawptr = void*,CPtr 亦为裸指针):一律 i8*。 # 不得落入下方"未知类型 → %"{sha}.rawptr"*" 的伪结构体分支。 if annotation.id in ('rawptr', 'CPtr'): return 'i8*' # 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 # CPtr 同形的一层指针(i8*)参与联合合并(`T | CRef` → T*)。 if annotation.id in ('CRef', 'CTempRef'): 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 # 检查内建类型别名 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: _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 '' # 裸指针标记(t.rawptr / t.CPtr):i8*,不做结构体回落。 if attr_name in ('rawptr', 'CPtr'): return 'i8*' # 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 CPtr # 同形的「一层指针 = i8*」参与联合合并(`T | CRef` → T*),保证跨模块 # .vpi 声明端类型与定义端 _ctype_to_llvm 一致。 if attr_name in ('CRef', 'CTempRef'): return 'i8*' 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 # 嵌套类 / 嵌套 struct:限定名 `外类.内类`(module_name 是**类名**而非模块名)。 # 定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef._EmitNestedClassDefs), # 故此处按扁平名拼类型;命中与否由 struct_names 里是否存在该扁平名裁决 # (不存在即维持下方既有路径,不改变任何既有类型名)。 if module_name: NestedName: str = f'{module_name}_{attr_name}' if NestedName in self.struct_names: NestedSha1: str | None = self.struct_sha1_map.get(NestedName, self.module_sha1) NestedStr: str = f'%"{NestedSha1}.{NestedName}"' if NestedSha1 else f'%struct.{NestedName}' return NestedStr if embedded else f'{NestedStr}*' if attr_name == 'State': return '' if 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.Subscript): # 指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T]): # 裸类引用吸收一层、其余逐层外包,内层 T 照常解析 # (跨模块类由 struct_sha1_map 补 SHA1 前缀)。 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._from_import_aliases) or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))): return self._ptr_subscript_type_str(annotation) MarkerName: str | None = None if isinstance(annotation.value, ast.Name): MarkerName = annotation.value.id elif isinstance(annotation.value, ast.Attribute): MarkerName = annotation.value.attr if MarkerName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'): InnerType: str = self._get_type_str(annotation.slice, embedded=embedded) if self._is_bare_class_ref_annotation(annotation.slice, InnerType): return InnerType if InnerType in ('', 'void', 'void*'): return 'i8*' return f'{InnerType}*' # 内建裸名函数指针构造子 callable[...] / Callable[...]:与 Attribute 分支的 # Callable[...] 逐点等价(同为 i8*)。缺此分支时落到下方 Name 泛型特化 / # 兜底返回 'i32'(现场 Repl.vp:307 `ReplFragFn: callable[[rawptr], int]` # 声明成 i32 全局 ⇒ 赋 i8* 触发「指针隐式转整数」)。 if isinstance(annotation.value, ast.Name) and (annotation.value.id == 'callable' or annotation.value.id == 'Callable'): return 'i8*' 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}]' # 处理 CArray[elem_type, count] / rawarray[elem_type, count] / array[elem_type, count] # 注解 → [count x elem_type] # 支持 CArray (ast.Attribute)、CArray/rawarray/array (ast.Name) 三种写法 # (array 为本轮新增的内建软关键字,与 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)): # 单参数 CArray[elem_type]:与 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 | 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._from_import_aliases, 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):定义端对嵌入式泛型容器 # (字段 / 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 in ('callable', '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: BitWidth: int | None = getattr(annotation, 'BitWidth', None) if BitWidth: return BitWidth 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