from __future__ import annotations from typing import Any import re import ast import os import hashlib import llvmlite.ir as ir from llvmlite.ir.values import _Undefined from lib.includes import t as _t from lib.includes.t import CTypeRegistry from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap from lib.constants.config import mode as _config_mode 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.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] = {} 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: set[str] = set() self._current_module_func_names: set[str] = set() self.class_packed: set[str] = set() self._define_constants: dict[str, int] = {} 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 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: return self.structs[short_name] if clean_name in self.structs: existing: ir.IdentifiedStructType = self.structs[clean_name] 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) if hasattr(self, 'SymbolTable') and 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] if Entry and Entry.IsEnum: return ir.IntType(32) if Entry and Entry.IsExceptionClass: return ir.IntType(32) if Entry and Entry.IsFunction: return ir.PointerType(ir.IntType(8)) if Entry and Entry.IsVariable: 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 hasattr(self, '_struct_sha1_map') and 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 hasattr(self, 'SymbolTable') and 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:]) # 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 定义) _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: return 0 # 标记为 typedef,但位宽为 0(非整数) return None 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 _ns_hash(self) -> str: if 'workspace' in self._ns_cache: return self._ns_cache['workspace'] cwd: str = os.getcwd().replace('\\', '/').lower() digest: str = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12] self._ns_cache['workspace'] = digest return digest 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: for g in self.module.globals: if isinstance(g, ir.Function) and g.name == mangled_name: 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: return name if name in self._export_extern_funcs and name not in self._current_module_func_names: 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] = getattr(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 _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