from __future__ import annotations from typing import Any import ast import os import llvmlite.ir as ir from lib.includes import t as _t from lib.includes.t import CTypeRegistry from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap class VaArgInstruction(ir.Instruction): def descr(self, buf: list[str]) -> None: ptr: ir.Value = self.operands[0] buf.append("va_arg {0} {1}, {2}\n".format( ptr.type, ptr.get_reference(), self.type)) class BaseGenMixin: @staticmethod def _parse_triple(triple: str | None) -> dict[str, bool | int]: """解析目标三元组,返回平台信息字典""" info: dict[str, bool | int] = { 'is_windows': False, 'is_linux': False, 'is_macos': False, 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, } if not triple: return info triple_lower: str = triple.lower() # 检测操作系统 if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: info['is_windows'] = True # Windows LLP64: long = 32 位, wchar_t = 16 位 info['long_size'] = 32 info['wchar_t_size'] = 16 elif 'linux' in triple_lower: info['is_linux'] = True elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: info['is_macos'] = True # 检测架构 if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: info['is_x86_64'] = True elif 'aarch64' in triple_lower or 'arm64' in triple_lower: info['is_arm64'] = True elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: info['is_32bit'] = True info['ptr_size'] = 4 info['long_size'] = 32 if info['is_windows']: info['wchar_t_size'] = 16 else: info['wchar_t_size'] = 32 return info def __init__(self, triple: str | None = None, datalayout: str | None = None) -> None: self.module: ir.Module = ir.Module(name="transpyc_module") if triple: self.module.triple = triple else: self.module.triple = "x86_64-none-elf" if datalayout: self.module.data_layout = datalayout else: self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" # 解析目标平台信息 self._platform_info: dict[str, bool | int] = self._parse_triple(self.module.triple) self.ptr_size: int = self._platform_info['ptr_size'] # 根据目标平台配置 t 模块中的平台相关类型大小 _t.configure_platform(self.module.triple) self.builder: ir.IRBuilder | None = None self.func: ir.Function | None = None self.functions: dict[str, ir.Function] = {} self.variables: dict[str, ir.Value | None] = {} self._direct_values: dict[str, ir.Value] = {} self._reg_values: dict[str, ir.Value] = {} self.var_signedness: dict[str, bool] = {} self._unsigned_results: set[int] = {} self.string_const_counter: int = 0 self.Vtables: dict[str, ir.GlobalVariable] = {} self.class_methods: dict[str, list[str]] = {} self.class_members: dict[str, list[tuple[str, ir.Type]]] = {} self.class_member_defaults: dict[str, dict[str, Any]] = {} self.class_member_signeds: dict[str, dict[str, bool]] = {} self.class_member_bitfields: dict[str, dict[str, int]] = {} self.class_member_byteorders: dict[str, dict[str, str]] = {} self.local_var_byteorders: dict[str, str] = {} self.class_member_element_class: dict[str, dict[str, str]] = {} self.class_member_bitoffsets: dict[str, dict[str, int]] = {} self.structs: dict[str, ir.IdentifiedStructType] = {} self.typedef_int_widths: dict[str, int] = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8) self._cross_module_vtable_classes: set[str] = set() self._cross_module_novtable: set[str] = set() self.class_vtable: set[str] = set() self._class_graph: dict[str, Any] = {} self.class_parent: dict[str, str] = {} # Store member annotations for deferred type resolution (cross-module class references) self.class_member_annotations: dict[str, dict[str, Any]] = {} self.loop_break_targets: list[ir.Block] = [] self.loop_continue_targets: list[ir.Block] = [] self.eh_jmp_buf_stack: list[ir.Value] = [] self.eh_except_block_stack: list[ir.Block] = [] self.eh_finally_stack: list[Any] = [] self.global_vars: set[str] = set() self.nonlocal_params: dict[str, Any] = {} self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup self.var_struct_class: dict[str, str] = {} self.var_ptr_element: dict[str, bool] = {} # 全局变量的指针元素标志(持久,不受函数重置影响) # 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长 self.global_var_ptr_element: dict[str, bool] = {} self.class_provides: dict[str, list[str]] = {} self.class_requires: dict[str, list[str]] = {} self.class_require_must: dict[str, list[str]] = {} # 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名 # 用于 __require_must__ 的纯编译期静态可达性检查 self._with_provides_stack: list[list[str]] = [] # 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...] # 'need': t.CNeedPtr — 仅对非指针值取地址 # 'always': t.CAutoPtr — 无条件取地址 self._auto_addr_params: dict[str, list[str | None]] = {} self.global_struct_class: dict[str, str] = {} self.var_type_info: dict[str, Any] = {} self.var_const_flags: dict[str, bool] = {} self._current_source_file: str | None = None self._current_source_lines: list[str] = [] self._ns_cache: dict[str, str] = {} self._type_cache: dict[tuple[str, bool], ir.Type] = {} self._typedef_cache: dict[str, Any] = {} self._func_sig_cache: dict[str, Any] = {} self.var_type_assignments: dict[str, Any] = {} self._temp_struct_ptrs: list[ir.Value] = [] self._stop_iter_flag_param: ir.Value | None = None self._local_heap_ptrs: list[tuple[ir.Value, str, str | None]] = [] self._var_to_heap_ptr: dict[str, ir.Value] = {} self.known_return_types: dict[str, ir.Type] = {} self._current_lineno: int = 0 self._current_node_info: str = "" self.module_sha1: str | None = None self.ModuleSha1Map: dict[str, str] = {} self._temp_dir: str | None = None self._export_funcs: set[str] = set() self._export_extern_funcs: dict[str, str] = {} self._current_module_func_names: set[str] = set() # __doc__ 魔法字符串注册表:symbol_name -> docstring 文本(None 表示空/优化剥离) self._doc_strings: dict[str, str | None] = {} self.class_packed: set[str] = set() self._define_constants: dict[str, int] = {} # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 self._struct_sha1_map: dict[str, str] = {} self.SymbolTable: Any = None self._Trans: Any = None self.class_sha1_map: dict[str, str] = {} # 以下属性原先懒注入,此处显式初始化以消除 hasattr/getattr 动态反射 self._import_handler_ref: Any = None self._classes_in_progress: set[str] = set() # 字段收集期间添加当前类名,阻止 CollectAnnAssignMember 触发的嵌套 # _generate_structs 用不完整 class_members 调用 set_body(set_body 只能调用一次) # 用集合而非单值,因为嵌套特化类 _EmitClassLlvm 会清除单值,导致外层类被错误设置 body self._collecting_members_set: set[str] = set() self._last_var_name: str | None = None self._variadic_info: dict | None = None self._vtable_copy_counter: int = 0 self._decorated_funcs: dict = {} self._current_tree: Any = None self._DefineConstants: dict = {} self._all_define_constants: dict = {} # 闭包追踪:记录返回闭包的函数和变量 # _closure_return_types: func_name -> (fn_return_type, nonlocal_arg_types) self._closure_return_types: dict[str, tuple[Any, list[Any]]] = {} # _closure_var_types: var_name -> (fn_return_type, nonlocal_arg_types) self._closure_var_types: dict[str, tuple[Any, list[Any]]] = {} pi: dict[str, bool | int] = self._platform_info # 根据目标平台设置宏(声明式,从三元组推导) if pi['is_windows']: self._define_constants['_WIN32'] = 1 if not pi['is_32bit']: self._define_constants['_WIN64'] = 1 self._define_constants['WIN64'] = 1 self._define_constants['WIN32'] = 1 if pi['is_linux']: self._define_constants['__linux__'] = 1 if pi['is_macos']: self._define_constants['__APPLE__'] = 1 self._define_constants['__MACH__'] = 1 if pi['is_x86_64']: self._define_constants['__x86_64__'] = 1 self._define_constants['__x86_64'] = 1 self._define_constants['_M_X64'] = 1 elif pi['is_arm64']: self._define_constants['__aarch64__'] = 1 self._define_constants['_M_ARM64'] = 1 if not pi['is_32bit'] and pi['is_linux']: self._define_constants['__LP64__'] = 1 elif pi['is_32bit']: self._define_constants['_ILP32'] = 1 self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] def find_struct_by_pointee(self, pointee: ir.Type) -> tuple[str, ir.IdentifiedStructType] | None: """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" for class_name, struct_type in self.structs.items(): if pointee == struct_type: return (class_name, struct_type) return None @staticmethod def _extract_short_name(name: str) -> str: """从结构体类型名中提取短名(去掉 sha1 前缀)。 如 "6bc91356c652f8ca.Function" → "Function" 如 "Function" → "Function"(无 sha1 前缀时原样返回) """ if '.' in name: prefix: str = name.split('.', 1)[0] if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): return name.split('.', 1)[1] return name @staticmethod def _extract_struct_sha1(st: ir.IdentifiedStructType) -> str: """从 IdentifiedStructType 的 name 中提取 sha1 前缀(16 位十六进制)。 返回空字符串表示无 sha1 前缀。用于同名类冲突检测。 """ if not isinstance(st, ir.IdentifiedStructType): return '' try: name: str = st.name except (AssertionError, AttributeError): return '' if '.' in name: prefix: str = name.split('.', 1)[0] if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): return prefix return '' def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType: clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') # 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"), # 先尝试用短名称(如 "zbit_writer")查找已注册的 struct, # 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致 if '.' in clean_name and clean_name not in self.structs: parts: list[str] = clean_name.split('.', 1) if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]): short_name: str = parts[1] if short_name in self.structs: existing_short: ir.IdentifiedStructType = self.structs[short_name] # 治本修复:同名类 sha1 冲突检测。 # 当请求的 sha1 前缀与现有 struct 的 sha1 前缀不一致时 # (如 stmts.py:Module 与 __module.py:Module 同名冲突), # 不能复用已有 struct(set_body 已锁定为错误布局), # 需创建独立 struct 并以 sha1 前缀全名存储。 _existing_sha1: str = self._extract_struct_sha1(existing_short) if _existing_sha1 and _existing_sha1 != parts[0]: if clean_name in self.structs: return self.structs[clean_name] st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=clean_name, packed=packed) self.structs[clean_name] = st_new return st_new return existing_short # 优先解析 typedef 整数类型(如 INT/UINT/BYTE),避免将其注册为 opaque struct。 # 必须在 `if clean_name in self.structs` 缓存检查之前执行, # 否则首次调用(SymbolTable 未就绪时)会将 typedef 名缓存为 opaque struct, # 后续调用即使 SymbolTable 就绪也只会返回缓存的错误类型。 # 此修复同时解决两个问题: # 1. alloca unsized type:变量声明 `argc: INT = 6` 不再生成 `alloca %"...INT"` # 2. 下标访问:FindStructNameInAnnotation 不再匹配 typedef 名(因不在 Gen.structs) td_width: int | None = self._resolve_typedef_int_width(clean_name) if td_width is not None: if td_width > 0: self.typedef_int_widths[clean_name] = td_width return ir.IntType(td_width) # td_width == 0: 特殊 typedef 名称(str/bytes/list 等),返回 i8 self.typedef_int_widths[clean_name] = 0 return ir.IntType(8) if clean_name in self.structs: existing: ir.IdentifiedStructType = self.structs[clean_name] # 治本修复:同名类 sha1 冲突检测(短名调用路径)。 # 当 source_sha1 与现有 struct 的 sha1 前缀不一致时(跨模块同名类冲突), # 不能复用已有 struct(set_body 已锁定为错误布局), # 需创建独立 struct 并以 sha1 前缀全名存储,不覆盖短名条目。 if source_sha1: _existing_sha1: str = self._extract_struct_sha1(existing) if _existing_sha1 and _existing_sha1 != source_sha1: full_key: str = f"{source_sha1}.{clean_name}" if full_key in self.structs: st_full: ir.IdentifiedStructType = self.structs[full_key] if packed and isinstance(st_full, ir.IdentifiedStructType) and not st_full.packed: st_full.packed = True return st_full ns_name: str = f"{source_sha1}.{clean_name}" st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) self.structs[full_key] = st_new return st_new if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed: existing.packed = True return existing if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}: return ir.IntType(8) # typing.Any 是"任意类型"标记,应解析为 i8*(通用指针), # 而非创建为 opaque 结构体(否则包含 Any 字段的结构体会变成 unsized)。 if clean_name == 'Any': return ir.IntType(8).as_pointer() # t.CType 的基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/CDouble 等, # position 含 BASE 且 Size>0)有具体 LLVM 类型,应直接返回对应的 # ir.IntType/ir.FloatType/ir.DoubleType,而非创建结构体。 # _is_ctype_marker_name 对这些类型返回 False(不跳过),需要在此处拦截。 _basic_llvm_type: ir.Type | None = self._try_resolve_ctype_basic(clean_name) if _basic_llvm_type is not None: return _basic_llvm_type # t.CType 及其子类是"类型强转"标记,不应被编译为真实结构体。 # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类, # 因为用户定义的结构体类继承自它们,需要被创建为结构体)。 if self._is_ctype_marker_name(clean_name): return ir.IntType(8) if self.SymbolTable: Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name) if Entry and Entry.IsTypedef: resolved_str: str = self._resolve_typedef(clean_name) if resolved_str != clean_name: return self._type_str_to_llvm(resolved_str) if Entry.BaseType: if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: resolved: str = self._resolve_ctype_to_str(Entry) if resolved: return self._type_str_to_llvm(resolved) if Entry and Entry.IsRenum: if clean_name in self.structs: return self.structs[clean_name] # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), # 需要继续到下方正常结构体创建路径,创建 opaque 结构体。 # 这对自引用 REnum(如 LLVMType 包含 LLVMType*)至关重要: # _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。 elif Entry and Entry.IsEnum and clean_name not in self.class_methods: return ir.IntType(32) # 治本修复:当 clean_name 是已注册的类(在 class_methods 或 class_members 中)时, # 不应走 IsExceptionClass/IsFunction/IsVariable 分支返回非结构体类型。 # 否则 _get_or_create_struct 返回指针类型(如 _TypedPointerType)而非 IdentifiedStructType, # 导致 _TryLoadStructFromStub 的 set_body 被跳过(isinstance 检查失败), # struct 保持不完整字段数,引发跨模块 GEP 越界崩溃。 _is_class_name: bool = clean_name in self.class_methods or clean_name in self.class_members if Entry and Entry.IsExceptionClass and not _is_class_name: return ir.IntType(32) if Entry and Entry.IsFunction and not _is_class_name: return ir.PointerType(ir.IntType(8)) if Entry and Entry.IsVariable and not _is_class_name: return ir.PointerType(ir.IntType(8)) if Entry and Entry.BaseType: if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): return ir.IntType(32) if Entry.BaseType is _t.CEnum: return ir.IntType(32) ns_name: str if source_sha1: ns_name = f"{source_sha1}.{clean_name}" elif clean_name in self._struct_sha1_map: ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" else: ns_name = self._mangle_name(clean_name) st: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) self.structs[clean_name] = st # 尝试解析 typedef 的底层整数位宽 width: int | None = self._resolve_typedef_int_width(clean_name) if width is not None: self.typedef_int_widths[clean_name] = width return st def _resolve_typedef_int_width(self, name: str) -> int | None: """解析 typedef 名称的底层整数位宽 通过 CTypeRegistry 和 BuiltinTypeMap 动态解析, 替代硬编码的 TYPEDEF_NAMES 映射表。 返回 int 位宽或 None(无法解析)。 """ # 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名) bm: Any = BuiltinTypeMap.Get(name) if bm: ctype_cls: Any ptr_count: int ctype_cls, ptr_count = bm if ptr_count > 0: return None # 指针类型,不是整数 typedef llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) # 2. 再查 SymbolTable(用户定义的 typedef) if self.SymbolTable: Entry: _CTypeInfo | None = self.SymbolTable.lookup(name) if Entry and Entry.IsTypedef: if Entry.BaseType: if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0: llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) if Entry.OriginalType: if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0: llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) elif isinstance(Entry.OriginalType, str): # OriginalType 是类型名字符串(如 'CInt', 'CUnsignedInt'), # 通过 CTypeRegistry 解析为整数位宽 cls: Any = CTypeRegistry.GetClassByName(Entry.OriginalType) if cls: llvm_str: str = CTypeRegistry.CTypeToLLVM(cls) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) # 3. 尝试 CTypeRegistry 直接按名称查找 ctype_cls: Any = CTypeRegistry.GetClassByName(name) if ctype_cls: llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) # 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义) # 注意:如果 name 已注册为 struct(用户定义了同名 class,如 includes/_dict.py 中的 dict), # 则不应视为 typedef,应返回 None 让调用方走 struct 创建路径。 # 解决时序问题:_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs, # 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。 _SPECIAL_TYPEDEFS: set[str] = { 'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray', } if name in _SPECIAL_TYPEDEFS: if name in self.structs: return None # 已注册为 struct,不视为 typedef if self.SymbolTable is not None: try: if self.SymbolTable.is_struct(name): return None # SymbolTable 中标记为 struct,不视为 typedef except Exception: pass return 0 # 标记为 typedef,但位宽为 0(非整数) # t.CType 及其子类是"类型强转"标记,不应被创建为结构体。 # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类)。 # 返回 0 标记为 typedef,使 _get_or_create_struct 走 typedef 路径返回 i8。 if self._is_ctype_marker_name(name): return 0 return None @staticmethod def _is_ctype_marker_name(name: str) -> bool: """检查名称是否是 t.CType 的"类型强转"标记子类名。 只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/ CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等) 才应该跳过结构体创建。有 BASE position 的基本类型(CInt/CChar/CSizeT/ CLong/CFloat/CDouble 等)有具体大小,应被正常解析为对应宽度的整数/浮点。 CStruct/CEnum/CUnion/REnum 的用户子类是合法结构体,需要被创建。 注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault, 所以这里直接用 getattr(t, name) 检查 t 模块属性。 Returns: True 如果 name 是 CType 标记子类名(应跳过结构体创建) """ if not name: return False # 去除可能的 SHA1 前缀(如 "abc123.CPtr" -> "CPtr") short_name: str = name.split('.')[-1] if '.' in name else name # 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian) t_cls: Any = getattr(_t, short_name, None) if not isinstance(t_cls, type) or not issubclass(t_cls, _t.CType): return False # 排除 CStruct/CEnum/CUnion/REnum 子类(它们是命名类型的基类, # 用户定义的结构体继承自它们,需要被创建为结构体) if issubclass(t_cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): return False # 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过 # (CInt→i32, CChar→i8, CSizeT→i64, CLong→i64, CFloat→f32 等) # CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过 if _t.CType.BASE in t_cls.position: # 检查实例的 Size(类属性可能未设置,用实例获取) try: inst = t_cls() size_val = getattr(inst, 'Size', None) if size_val is not None and size_val > 0: return False except Exception: pass return True def _try_resolve_ctype_basic(self, name: str) -> ir.Type | None: """尝试将 t.CType 的基本类型子类名解析为对应的 LLVM 基本类型。 仅对 t 模块内的 CType 基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/ CDouble 等,即 position 含 BASE 且 Size>0)生效,返回对应的 ir.IntType/ir.FloatType/ir.DoubleType。 CStruct/CEnum/CUnion/REnum 子类不在此处理(用户自定义结构体需要被 创建为结构体)。CVoid/CType/CPtr 等无 Size 或 Size=0 的类型也不在此 处理(应通过 _is_ctype_marker_name 跳过结构体创建)。 Returns: 对应的 ir.Type,或 None 表示不是基本类型,需要继续走结构体创建路径。 """ if not name: return None short_name: str = name.split('.')[-1] if '.' in name else name cls: Any = getattr(_t, short_name, None) if not isinstance(cls, type) or not issubclass(cls, _t.CType): return None if issubclass(cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): return None if _t.CType.BASE not in getattr(cls, 'position', frozenset()): return None try: inst = cls() size_val = getattr(inst, 'Size', None) if size_val is None or size_val <= 0: return None except Exception: return None llvm_str: str | None = CTypeRegistry.NameToLLVM(short_name) if not llvm_str: return None return self._type_str_to_llvm(llvm_str) def _set_node_info(self, node: ast.AST, extra_info: str = "") -> None: if hasattr(node, 'lineno'): self._current_lineno = node.lineno else: self._current_lineno = 0 if hasattr(node, 'col_offset'): self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" else: self._current_node_info = f"line {self._current_lineno}" if extra_info: self._current_node_info += f" ({extra_info})" def _set_source_info(self, filepath: str) -> None: self._current_source_file = filepath try: with open(filepath, 'r', encoding='utf-8') as f: self._current_source_lines = f.readlines() except Exception: # 文件读取失败时回退为空行列表 self._current_source_lines = [] def _skip_mangle(self, name: str) -> bool: skip_prefixes: tuple[str, ...] = ('llvm.', 'str_const_', 'printf', 'memset_pattern') if any(name.startswith(p) for p in skip_prefixes): return True if '.' in name: parts: list[str] = name.split('.', 1) if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): return True return False def _mangle_name(self, name: str) -> str: if self._skip_mangle(name): return name if name in self._export_funcs: return name if self.module_sha1: return f"{self.module_sha1}.{name}" return name def _find_function(self, name: str) -> ir.Function | None: if name in self.functions: return self.functions[name] g: Any = self.module.globals.get(name) if g and isinstance(g, ir.Function): self.functions[name] = g return g mangled: str = self._mangle_func_name(name) if mangled != name: if mangled in self.functions: self.functions[name] = self.functions[mangled] return self.functions[mangled] g = self.module.globals.get(mangled) if g and isinstance(g, ir.Function): self.functions[mangled] = g self.functions[name] = g return g for sha1 in self.ModuleSha1Map.values(): prefixed: str = f"{sha1}.{name}" if prefixed in self.functions: self.functions[name] = self.functions[prefixed] return self.functions[prefixed] g = self.module.globals.get(prefixed) if g and isinstance(g, ir.Function): self.functions[prefixed] = g self.functions[name] = g return g return None def _has_function(self, name: str) -> bool: return self._find_function(name) is not None def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function: g = self.module.globals.get(mangled_name) if g and isinstance(g, ir.Function): return g return ir.Function(self.module, func_type, name=mangled_name) def _get_function(self, name: str) -> ir.Function | None: func: ir.Function | None = self._find_function(name) return func def _mangle_func_name(self, name: str, module_name: str | None = None) -> str: if name in self._export_funcs and not module_name: return name if name in self._export_extern_funcs: target_sha1: str = self._export_extern_funcs[name] if module_name: # 显式带 module_name 调用(如 stdlib.system):即使当前模块定义了同名函数, # 也应按模块匹配 extern,返回裸名。snprintf 之所以工作而 system 不工作, # 就是因为 os._win32 定义了自己的 system 包装,导致旧逻辑跳过了 extern 匹配。 if module_name == target_sha1: return name if module_name in self.ModuleSha1Map and self.ModuleSha1Map[module_name] == target_sha1: return name init_name: str = f"{module_name}.__init__" if init_name in self.ModuleSha1Map and self.ModuleSha1Map[init_name] == target_sha1: return name # 兜底:module_name 不在 ModuleSha1Map 中或 sha1 不匹配, # 但函数在 _export_extern_funcs 中(C extern 不应混淆), # 仅当当前模块未定义同名函数时才返回裸名。 if name not in self._current_module_func_names: return name elif name not in self._current_module_func_names: # 无 module_name 调用(如 from stdlib import system; system()): # 仅当当前模块未定义同名函数时才返回 extern 裸名, # 否则让本地定义走正常 mangle 路径(本地 def 遮蔽 import 语义)。 return name # main 函数作为程序入口点,永远不混淆 if name == 'main': return name # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') class_sha1_map: dict[str, str] = self.class_sha1_map if class_sha1_map: if '.' in name: base_class: str = name.split('.')[0] if base_class in class_sha1_map: sha1: str = class_sha1_map[base_class] return f"{sha1}.{name}" elif name in class_sha1_map: sha1: str = class_sha1_map[name] return f"{sha1}.{name}" # If module_name is already a SHA1 hash (16 hex chars), use it directly if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): return f"{module_name}.{name}" if module_name and module_name in self.ModuleSha1Map: sha1: str = self.ModuleSha1Map[module_name] return f"{sha1}.{name}" # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') if module_name: init_name: str = f"{module_name}.__init__" if init_name in self.ModuleSha1Map: sha1: str = self.ModuleSha1Map[init_name] return f"{sha1}.{name}" if self._skip_mangle(name): return name if self.module_sha1: return f"{self.module_sha1}.{name}" return name def _get_source_line(self, lineno: int) -> str | None: if 0 < lineno <= len(self._current_source_lines): return self._current_source_lines[lineno - 1].rstrip('\r\n') return None def _get_node_info(self) -> str: info: str = "" if self._current_node_info: info = f" [{self._current_node_info}]" if self._current_source_file: info += f" in {self._current_source_file}" lineno: int = self._current_lineno if lineno > 0: info += f", line {lineno}:" source_line: str | None = self._get_source_line(lineno) if source_line: info += f"\n → {source_line}" return info # ========== 统一工具方法 ========== def _create_string_global(self, s: str, name: str | None = None) -> ir.Constant: """创建字符串全局变量并返回 i8* 指针。 统一字符串全局变量创建模式:编码为 utf-8 + '\\x00' 终止符, 创建 internal linkage 的 GlobalVariable,返回 i8* 指针常量。 """ str_val: str = s + '\x00' str_bytes: bytes = str_val.encode('utf-8') arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) gv_name: str = name or f"str_const_{self.string_const_counter}" self.string_const_counter += 1 gv: ir.GlobalVariable = ir.GlobalVariable(self.module, arr_type, name=gv_name) gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) gv.linkage = 'internal' return ir.Constant(ir.PointerType(ir.IntType(8)), gv.get_reference()) def _create_doc_global(self, symbol_name: str, docstring: str | None) -> None: """为符号创建 __doc__ 全局常量。 - docstring 为 None 或空字符串时,不创建常量(访问时内联空指针) - slice_level != 0(优化开启)时,内容视为空 - 非空时创建 internal linkage、global_constant=True 的只读字符串常量 - 常量名格式:{module_sha1}.{symbol_name}.__doc__ """ slice_level: int = getattr(self._Trans, 'SliceLevel', 3) if slice_level != 0: docstring = None if docstring is None or docstring == '': self._doc_strings[symbol_name] = None return self._doc_strings[symbol_name] = docstring mangled: str = self._mangle_name(f"{symbol_name}.__doc__") self._create_string_global(docstring, name=mangled) gv: ir.GlobalVariable | None = self.module.globals.get(mangled) if gv is not None: gv.global_constant = True def _get_doc_ptr(self, symbol_name: str) -> ir.Value | None: """获取符号 __doc__ 的 i8* 指针。 - 若符号未注册 __doc__,返回 None(调用方回退到其他解析) - 若 __doc__ 为空(无 docstring 或优化剥离),返回 i8* null 内联空指针 - 若 __doc__ 非空,返回指向字符串全局常量的 i8* 指针 - 跨模块 docstring(在 _doc_strings 中有文本但 module.globals 无对应常量)首次访问时创建本地 internal linkage 只读副本 """ if symbol_name not in self._doc_strings: return None docstring: str | None = self._doc_strings[symbol_name] if docstring is None or docstring == '': return ir.Constant(ir.PointerType(ir.IntType(8)), None) mangled: str = self._mangle_name(f"{symbol_name}.__doc__") gv: ir.GlobalVariable | None = self.module.globals.get(mangled) if gv is None: # 跨模块 docstring:创建本地 internal linkage 只读字符串常量副本 self._create_string_global(docstring, name=mangled) gv = self.module.globals.get(mangled) if gv is None: return ir.Constant(ir.PointerType(ir.IntType(8)), None) gv.global_constant = True zero: ir.Constant = ir.Constant(ir.IntType(32), 0) return self.builder.gep(gv, [zero, zero], name=f"{symbol_name}_doc_ptr") def _apply_bswap_if_big(self, val: ir.Value, byte_order: str, name: str) -> ir.Value: """大端字节序时对整数应用 bswap,否则原值返回。 仅对 16/32/64 位整数生效,统一 bswap 逻辑。 """ if byte_order == 'big' and isinstance(val.type, ir.IntType) and val.type.width in (16, 32, 64): return self.builder.bswap(val, name=name) return val def _zero_value_for_type(self, llvm_type: ir.Type) -> ir.Constant | None: """为指定 LLVM 类型生成零值常量。 合并原 HandlesAssign._zero_value 与 StructGen._zero_value_for_type 的逻辑。 返回 ir.Constant 或 None(无法生成零值的类型,如 opaque struct)。 """ if isinstance(llvm_type, ir.IntType): return ir.Constant(llvm_type, 0) elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): return ir.Constant(llvm_type, 0.0) elif isinstance(llvm_type, ir.PointerType): return ir.Constant(llvm_type, None) elif isinstance(llvm_type, ir.ArrayType): elem_zv: ir.Constant | None = self._zero_value_for_type(llvm_type.element) if elem_zv is None: return None return ir.Constant(llvm_type, [elem_zv] * llvm_type.count) elif isinstance(llvm_type, ir.BaseStructType): if llvm_type.elements is not None and len(llvm_type.elements) > 0: elem_zvs: list[ir.Constant | None] = [self._zero_value_for_type(m) for m in llvm_type.elements] if any(zv is None for zv in elem_zvs): return None return ir.Constant(llvm_type, elem_zvs) return None return None