from __future__ import annotations import re import ast import os import hashlib import llvmlite.ir as ir from llvmlite.ir.values import _Undefined class VaArgInstruction(ir.Instruction): def descr(self, buf): ptr = 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): """解析目标三元组,返回平台信息字典""" info = { '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 = 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=None, datalayout=None): self.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 = self._parse_triple(self.module.triple) self.ptr_size = self._platform_info['ptr_size'] # 根据目标平台配置 t 模块中的平台相关类型大小 import t as _t _t.configure_platform(self.module.triple) self.builder = None self.func = None self.functions = {} self.variables = {} self._direct_values = {} self._reg_values = {} self.var_signedness = {} self._unsigned_results = {} self.string_const_counter = 0 self.Vtables = {} self.class_methods = {} self.class_members = {} self.class_member_defaults = {} self.class_member_signeds = {} self.class_member_bitfields = {} self.class_member_byteorders = {} self.class_member_element_class = {} self.class_member_bitoffsets = {} self.structs = {} self.typedef_int_widths = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8) self._cross_module_vtable_classes = set() self.class_vtable = set() self.class_parent = {} # Store member annotations for deferred type resolution (cross-module class references) self.class_member_annotations = {} self.loop_break_targets = [] self.loop_continue_targets = [] self.eh_jmp_buf_stack = [] self.eh_except_block_stack = [] self.eh_finally_stack = [] self.global_vars = set() self.nonlocal_params = {} self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup self.var_struct_class = {} self.global_struct_class = {} self.var_type_info = {} self.var_const_flags = {} self._current_source_file = None self._current_source_lines = [] self._ns_cache = {} self._type_cache = {} self._typedef_cache = {} self._func_sig_cache = {} self.var_type_assignments = {} self._temp_struct_ptrs = [] self._stop_iter_flag_param = None self._local_heap_ptrs = [] self._var_to_heap_ptr = {} self.known_return_types = {} self._current_lineno = 0 self._current_node_info = "" self.module_sha1 = None self.ModuleSha1Map = {} self._temp_dir = None self._export_funcs = set() self._export_extern_funcs = set() self._current_module_func_names = set() self.class_packed = set() self._define_constants = {} pi = 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): """根据 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, source_sha1=None, packed=False): clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') if clean_name in self.structs: existing = 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 and clean_name in self.SymbolTable: Entry = self.SymbolTable[clean_name] if Entry.IsTypedef: resolved_str = self._resolve_typedef(clean_name) if resolved_str != clean_name: return self._type_str_to_llvm(resolved_str) if Entry.BaseType: from lib.includes import t as _t if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: resolved = self._resolve_ctype_to_str(Entry) if resolved: return self._type_str_to_llvm(resolved) if Entry.IsRenum: if clean_name in self.structs: return self.structs[clean_name] if Entry.IsEnum: return ir.IntType(32) if Entry.IsExceptionClass: return ir.IntType(32) if Entry.IsFunction: return ir.PointerType(ir.IntType(8)) if Entry.IsVariable: return ir.PointerType(ir.IntType(8)) if Entry.BaseType: from lib.includes import t as _t 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) 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(self.module, name=ns_name, packed=packed) self.structs[clean_name] = st # 尝试解析 typedef 的底层整数位宽 width = 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): """解析 typedef 名称的底层整数位宽 通过 CTypeRegistry 和 BuiltinTypeMap 动态解析, 替代硬编码的 TYPEDEF_NAMES 映射表。 返回 int 位宽或 None(无法解析)。 """ from lib.includes.t import CTypeRegistry from lib.core.Handles.HandlesBase import BuiltinTypeMap # 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名) bm = BuiltinTypeMap.Get(name) if bm: ctype_cls, ptr_count = bm if ptr_count > 0: return None # 指针类型,不是整数 typedef llvm_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 and name in self.SymbolTable: Entry = self.SymbolTable[name] if Entry.IsTypedef: if Entry.BaseType: from lib.includes import t as _t if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0: llvm_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: from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0: llvm_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 = CTypeRegistry.GetClassByName(name) if ctype_cls: llvm_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 = { 'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', } if name in _SPECIAL_TYPEDEFS: return 0 # 标记为 typedef,但位宽为 0(非整数) return None def _set_node_info(self, node, extra_info=""): 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): 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): if 'workspace' in self._ns_cache: return self._ns_cache['workspace'] cwd = os.getcwd().replace('\\', '/').lower() digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12] self._ns_cache['workspace'] = digest return digest def _skip_mangle(self, name): skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern') if any(name.startswith(p) for p in skip_prefixes): return True if '.' in name: parts = 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): 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): if name in self.functions: return self.functions[name] g = self.module.globals.get(name) if g and isinstance(g, ir.Function): self.functions[name] = g return g mangled = 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 = 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): return self._find_function(name) is not None def _get_or_declare_function(self, mangled_name, func_type): 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): func = self._find_function(name) return func def _mangle_func_name(self, name, module_name=None): 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 = getattr(self, 'class_sha1_map', {}) if class_sha1_map: if '.' in name: base_class = name.split('.')[0] if base_class in class_sha1_map: sha1 = class_sha1_map[base_class] return f"{sha1}.{name}" elif name in class_sha1_map: sha1 = 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 = self.ModuleSha1Map[module_name] return f"{sha1}.{name}" # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') if module_name: init_name = f"{module_name}.__init__" if init_name in self.ModuleSha1Map: sha1 = 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): 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): info = "" if self._current_node_info: info = f" [{self._current_node_info}]" if self._current_source_file: info += f" in {self._current_source_file}" lineno = self._current_lineno if lineno > 0: info += f", line {lineno}:" source_line = self._get_source_line(lineno) if source_line: info += f"\n → {source_line}" return info