diff --git a/App/lib/Projectrans/Config.py b/App/lib/Projectrans/Config.py index 962aebe..95f495e 100644 --- a/App/lib/Projectrans/Config.py +++ b/App/lib/Projectrans/Config.py @@ -18,8 +18,9 @@ _mbuddy: memhub.MemManager | t.CPtr # 配置值(从 project.vpj 加载) SourceDir: str -TempDir: str -OutputDir: str +BuildDir: str +TempDir: str # = {BuildDir}/temp(自动计算) +OutputDir: str # = {BuildDir}/output(自动计算) ProjectName: str ProjectVersion: str CompilerCmd: str @@ -29,7 +30,7 @@ LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags LinkerOutput: str TargetTriple: str TargetDataLayout: str -SliceLevel: t.CInt +Sha1SliceLevel: t.CInt # SHA1 切片层数(目录分散等级) StrictMode: t.CInt IncludesDir: str # includes 目录路径(从 includes 数组首元素) @@ -43,9 +44,9 @@ def Load_project_config(path: str) -> int: Returns: 0 表示成功,非 0 表示失败 """ - global SourceDir, TempDir, OutputDir, ProjectName, ProjectVersion + global SourceDir, BuildDir, TempDir, OutputDir, ProjectName, ProjectVersion global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput - global TargetTriple, TargetDataLayout, SliceLevel, StrictMode + global TargetTriple, TargetDataLayout, Sha1SliceLevel, StrictMode global IncludesDir if path is None: @@ -79,8 +80,12 @@ def Load_project_config(path: str) -> int: # 读取顶层字段 SourceDir = root["source_dir"].as_string() if root["source_dir"] is not None else None - TempDir = root["temp_dir"].as_string() if root["temp_dir"] is not None else None - OutputDir = root["output_dir"].as_string() if root["output_dir"] is not None else None + # build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录 + bd_val: JsonValue | t.CPtr = root["build_dir"] + if bd_val is not None and bd_val.is_string(): + BuildDir = bd_val.as_string() + else: + BuildDir = "./.tpv_build" ProjectName = root["name"].as_string() if root["name"] is not None else None ProjectVersion = root["version"].as_string() if root["version"] is not None else None @@ -108,11 +113,17 @@ def Load_project_config(path: str) -> int: TargetDataLayout = target["datalayout"].as_string() if target["datalayout"] is not None else None # 读取 options 子对象 + # Sha1SliceLevel: SHA1 切片层数(默认 1,每层取 SHA1 前 2 字符作为子目录) + # level=0 → 不切片,文件直接放 base_dir + # level=1 → b7/{sha1}.ext + # level=2 → b7/90/{sha1}.ext options: JsonValue | t.CPtr = root["options"] + Sha1SliceLevel = 1 + StrictMode = 1 if options is not None and options.is_object(): - sl: JsonValue | t.CPtr = options["slice_level"] + sl: JsonValue | t.CPtr = options["sha1_slice_level"] if sl is not None and sl.is_int(): - SliceLevel = sl.as_int() + Sha1SliceLevel = sl.as_int() sm: JsonValue | t.CPtr = options["strict_mode"] if sm is not None and sm.is_bool(): StrictMode = 1 if sm.as_bool() else 0 @@ -241,9 +252,10 @@ def _join_path(rel: str, project_dir: str) -> str: def resolve_paths(project_dir: str) -> int: - """解析并规范化工程路径(src/temp/output/includes) + """解析并规范化工程路径(src/build/includes) 将 project.vpj 中的相对路径(以 ./ 开头)转换为基于 project_dir 的路径。 + BuildDir 解析后,TempDir = {BuildDir}/temp,OutputDir = {BuildDir}/output。 Args: project_dir: 工程根目录(project.vpj 所在目录) @@ -251,15 +263,28 @@ def resolve_paths(project_dir: str) -> int: Returns: 0 表示成功,非 0 表示失败 """ - global SourceDir, TempDir, OutputDir, IncludesDir + global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir if project_dir is None: return 1 if _mbuddy is None: return 1 SourceDir = _join_path(SourceDir, project_dir) - TempDir = _join_path(TempDir, project_dir) - OutputDir = _join_path(OutputDir, project_dir) + BuildDir = _join_path(BuildDir, project_dir) + + # TempDir = {BuildDir}/temp + if BuildDir is not None: + bd_len: t.CSizeT = string.strlen(BuildDir) + temp_buf: str = _mbuddy.alloc(bd_len + 8) + if temp_buf is not None: + viperlib.snprintf(temp_buf, bd_len + 8, "%s/temp", BuildDir) + TempDir = temp_buf + # OutputDir = {BuildDir}/output + output_buf: str = _mbuddy.alloc(bd_len + 8) + if output_buf is not None: + viperlib.snprintf(output_buf, bd_len + 8, "%s/output", BuildDir) + OutputDir = output_buf + # includes 路径可能是 ../includes 形式,需要基于 project_dir 解析 if IncludesDir is not None: IncludesDir = _join_path(IncludesDir, project_dir) @@ -287,6 +312,8 @@ def print_config(): stdio.printf(" project: %s v%s\n", ProjectName, ProjectVersion if ProjectVersion is not None else "?") if SourceDir is not None: stdio.printf(" source_dir: %s\n", SourceDir) + if BuildDir is not None: + stdio.printf(" build_dir: %s\n", BuildDir) if TempDir is not None: stdio.printf(" temp_dir: %s\n", TempDir) if OutputDir is not None: @@ -296,4 +323,48 @@ def print_config(): if LinkerCmd is not None: stdio.printf(" linker: %s -> %s\n", LinkerCmd, LinkerOutput if LinkerOutput is not None else "?") if IncludesDir is not None: - stdio.printf(" includes: %s\n", IncludesDir) \ No newline at end of file + stdio.printf(" includes: %s\n", IncludesDir) + stdio.printf(" sha1_slice_level: %d\n", Sha1SliceLevel) + + +# ============================================================ +# slice_subdir - 根据 SHA1 和切片层数返回子目录路径 +# +# 每层取 SHA1 的 2 个字符作为子目录名: +# level=0 → None(不切片) +# level=1 → "b7" +# level=2 → "b7/90" +# level=3 → "b7/90/23" +# +# Args: +# sha1: SHA1 字符串(至少 2*level 字符) +# level: 切片层数 +# +# Returns: +# 子目录路径字符串(mbuddy 分配,无需释放),level<=0 时返回 None +# ============================================================ +def slice_subdir(sha1: str, level: int) -> str: + """根据 SHA1 和切片层数返回子目录路径""" + if level <= 0 or sha1 is None: + return None + if _mbuddy is None: + return None + # 每层 2 字符 + 分隔符,最后无分隔符 + null + # buf 大小: level * 2 + (level - 1) + 1 = level * 3 + buf_len: t.CSizeT = t.CSizeT(level * 3) + buf: str = _mbuddy.alloc(buf_len) + if buf is None: + return None + pos: int = 0 + i: int = 0 + while i < level: + if i > 0: + buf[pos] = '/' + pos += 1 + idx: int = i * 2 + buf[pos] = sha1[idx] + buf[pos + 1] = sha1[idx + 1] + pos += 2 + i += 1 + buf[pos] = '\0' + return buf \ No newline at end of file diff --git a/App/lib/Projectrans/DeclarationGenerator.py b/App/lib/Projectrans/DeclarationGenerator.py deleted file mode 100644 index be1917a..0000000 --- a/App/lib/Projectrans/DeclarationGenerator.py +++ /dev/null @@ -1,1188 +0,0 @@ -from __future__ import annotations - -import ast -import re -from typing import List - -from lib.includes import t -from lib.includes.t import CTypeRegistry -from lib.core.SymbolUtils import IsListAnnotation, AnnotationContainsName - - -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 = None - self.module = None - self.builder = 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] = {} - # 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members - # 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST) - self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {} - t.configure_platform(self.target_triple) - - def generate(self, pyi_content: str, src_path: str) -> str: - tree: ast.Module = ast.parse(pyi_content) - - self._DefineConstants: dict[str, int | str] = {} - self._pyi_tree = tree - global_typedef_map: dict[str, ast.AST] = self.typedef_map - self.typedef_map: dict[str, ast.AST] = {} - if global_typedef_map: - self.typedef_map.update(global_typedef_map) - - # 构建 t/c 类型别名映射(from t import CInt as myint) - self._t_alias_map: dict[str, type] = {} - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.ImportFrom): - if node.module in ('t', 'c'): - for alias in node.names: - name: str = alias.name - asname: str = alias.asname or name - if node.module == 't': - t_cls: type | None = getattr(t, name, None) - if isinstance(t_cls, type) and issubclass(t_cls, t.CType): - self._t_alias_map[asname] = t_cls - - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - var_name: str = node.target.id - if node.value and isinstance(node.value, ast.Constant): - self._DefineConstants[var_name] = node.value.value - elif node.value and isinstance(node.value, ast.Name): - self._DefineConstants[var_name] = node.value.id - is_typedef: bool = False - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - is_typedef = True - if is_typedef: - if node.value: - self.typedef_map[var_name] = node.value - elif isinstance(node.annotation, ast.BinOp) and node.annotation.right: - self.typedef_map[var_name] = node.annotation.right - - lines: list[str] = [] - lines.append('; ModuleID = "transpyc_decl"') - lines.append(f'target triple = "{self.target_triple}"') - lines.append(f'target datalayout = "{self.target_datalayout}"') - lines.append('') - - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.FunctionDef): - if hasattr(node, 'type_params') and node.type_params: - continue - decl: str | None = self._generate_func_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.AnnAssign): - decl: str | None = self._generate_global_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.Assign): - decl: str | None = self._generate_global_assign_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.ClassDef): - # PEP 695 泛型类不再完全跳过:子类(如 Value(GSListNode[Value]))的 - # 继承字段展平需要从泛型基类的 stub 中读取字段(如 GSListNode.Next)。 - # _generate_class_decl 内部会跳过泛型类的方法声明(T 参数 → opaque struct)。 - decls: list[str] = self._generate_class_decl(node) - lines.extend(decls) - - # 后处理:扫描引用但未定义的结构体类型,自动添加 opaque 声明 - # 这解决了泛型类(如 list[T])在 stub 中被跳过导致的 "undefined type" 错误 - opaque_decls: list[str] = self._collect_undefined_type_decls(lines) - if opaque_decls: - # 在 header 之后插入 opaque 声明(ModuleID, triple, datalayout, 空行 = 4 行) - insert_idx: int = 4 - for i, od in enumerate(opaque_decls): - lines.insert(insert_idx + i, od) - - return '\n'.join(lines) - - def _collect_undefined_type_decls(self, lines: list[str]) -> list[str]: - """扫描所有引用的 %"sha1.TypeName" 类型,返回未定义类型的 opaque 声明列表""" - # 收集已定义的类型名 - defined_types: set[str] = set() - type_def_re: re.Pattern = re.compile(r'^(%".+?")\s*=\s*type\s') - for line in lines: - m = type_def_re.match(line.strip()) - if m: - defined_types.add(m.group(1)) - - # 扫描所有引用的类型名 - referenced_types: set[str] = set() - type_ref_re: re.Pattern = re.compile(r'%"[a-f0-9]+\.[^"]+"') - for line in lines: - for m in type_ref_re.finditer(line): - ref: str = m.group(0) - if ref not in defined_types: - referenced_types.add(ref) - - # 生成 opaque 声明(排序确保确定性) - result: list[str] = [] - for type_name in sorted(referenced_types): - result.append(f'{type_name} = type opaque') - return result - - def _generate_func_decl(self, node: ast.FunctionDef) -> str | None: - """生成函数声明""" - func_name: str = node.name - is_export: bool = self._is_export_func(node) - if self.module_sha1 and not is_export: - func_name = f"{self.module_sha1}.{func_name}" - CReturnTypes: list[ast.AST] = [] - if node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): - if decorator.func.attr == 'CReturn': - for arg in decorator.args: - CReturnTypes.append(arg) - if node.returns: - if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple': - slice_node: ast.AST = node.returns.slice - if isinstance(slice_node, ast.Tuple): - for elt in slice_node.elts: - CReturnTypes.append(elt) - else: - CReturnTypes.append(slice_node) - ret_type: str - if CReturnTypes: - elem_types: list[str] = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes] - ret_type = '{ ' + ', '.join(elem_types) + ' }' - else: - ret_type = self._get_type_str(node.returns) - if not ret_type or ret_type == 'void': - ret_type = 'void' - elif ret_type == 'i8*': - if node.returns is None: - ret_type = 'void' - - params: list[str] = [] - for arg in node.args.args: - arg_type: str - if arg.annotation: - arg_type = self._get_type_str(arg.annotation) - else: - arg_type = 'i8*' - # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* - arg_type = self._decay_array_to_ptr(arg_type) - if arg_type and arg_type != 'void': - params.append(arg_type) - - param_str: str = ', '.join(params) if params else '' - if node.args.vararg: - param_str = param_str + ', ...' if param_str else '...' - if func_name[0].isdigit(): - return f'declare {ret_type} @"{func_name}"({param_str})' - return f'declare {ret_type} @{func_name}({param_str})' - - def _is_export_func(self, node: ast.FunctionDef) -> bool: - """检查函数是否标记为 CExport""" - if not node.returns: - return False - return self._check_annotation_for_export(node.returns) - - def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool: - """递归检查类型注解中是否包含 CExport 或 t.State""" - return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')) - - def _generate_global_decl(self, node: ast.AnnAssign) -> str | None: - """生成全局变量声明""" - if not isinstance(node.target, ast.Name): - return None - var_name: str = node.target.id - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': - return None - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - return None - if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.List): - for elt in node.annotation.elts: - if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): - return None - if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': - return None - VarType: str = self._get_type_str(node.annotation) - if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): - elem_type: str = VarType[5:-1] - actual_count: int = len(node.value.elts) - 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' | None - """ - # 1) 查 t 别名映射(from t import CEnum as en) - if base_name in self._t_alias_map: - t_cls: type = self._t_alias_map[base_name] - if issubclass(t_cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(t_cls, t.REnum) else 'enum' - if issubclass(t_cls, t.CUnion): - return 'union' - if issubclass(t_cls, t.CStruct): - return 'struct' - - # 2) 直接查 t 模块属性 - t_cls: type | None = getattr(t, base_name, None) - if isinstance(t_cls, type) and issubclass(t_cls, t.CType): - if issubclass(t_cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(t_cls, t.REnum) else 'enum' - if issubclass(t_cls, t.CUnion): - return 'union' - if issubclass(t_cls, t.CStruct): - return 'struct' - - 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 - if is_exception: - return decls - if is_enum: - enum_values: dict[str, int] = {} - next_value: int = 0 - 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 i32') - return decls - if is_renum: - # REnum 布局: { i32 __tag, } - # 对齐 _EmitREnumLlvm (HandlesClassDef.py) 的 Phase 2 逻辑 - # Bug 修复:按每个位置的 max 字段尺寸构建布局,而非选总尺寸最大的变体。 - # 不同变体在同一位置可能有不同尺寸的字段(如 Concrete 位置3是 i32, - # 但 Var 位置3是 MetaType*),用最大变体的布局会导致指针截断。 - variant_fields_list: list[list[str]] = [] - for item in node.body: - if isinstance(item, ast.ClassDef): - variant_fields: list[str] = [] - for nested_item in item.body: - if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name): - ft: str = self._get_type_str(nested_item.annotation, embedded=True) - if ft: - variant_fields.append(ft) - variant_fields_list.append(variant_fields) - elif isinstance(item, ast.Assign): - # 显式值变体(无 payload) - variant_fields_list.append([]) - # 计算每个位置的最大尺寸 - max_field_count: int = 0 - for vf in variant_fields_list: - if len(vf) > max_field_count: - max_field_count = len(vf) - renum_member_types: list[str] = ['i32'] # __tag - for pos in range(max_field_count): - pos_max_size: int = 0 - for vf in variant_fields_list: - if pos < len(vf): - sz: int = self._llvm_type_size_str(vf[pos]) - if sz > pos_max_size: - pos_max_size = sz - # <=4 用 i32,>4 用 i64(8字节,可容纳指针) - if pos_max_size <= 4: - renum_member_types.append('i32') - else: - renum_member_types.append('i64') - if len(renum_member_types) < 2: - # 无类变体或所有变体无字段时,使用 i32 作为占位(对齐 _EmitREnumLlvm 默认行为) - renum_member_types = ['i32', 'i32'] - struct_type_name: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' - struct_decl: str = f'{struct_type_name} = type {{ {", ".join(renum_member_types)} }}' - decls.append(struct_decl) - return decls - member_types: list[str] = [] - has_bitfield: bool = False - total_bits: int = 0 - has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in node.body) - is_cvtable: bool = False - is_cpython_object: bool = False - is_novtable: bool = False - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if getattr(decorator.value, 'id', None) == 't': - if decorator.attr == 'CVTable': - is_cvtable = True - elif decorator.attr == 'Object': - is_cpython_object = True - elif decorator.attr == 'NoVTable': - is_novtable = True - elif isinstance(decorator, ast.Name): - if decorator.id == 'CVTable': - is_cvtable = True - elif decorator.id == 'Object': - is_cpython_object = True - elif decorator.id == 'NoVTable': - is_novtable = True - if has_methods and not is_cpython_object: - is_cpython_object = True - has_parent_class: bool = False - parent_is_novtable: bool = False - for base in node.bases: - base_name: str | None = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and not self._is_marker_base(base_name): - has_parent_class = True - # 检查父类是否为 @t.NoVTable(非多态继承) - _p_node: ast.ClassDef | None = None - for n in ast.iter_child_nodes(self._pyi_tree): - if isinstance(n, ast.ClassDef) and n.name == base_name: - _p_node = n - break - if _p_node is None: - _p_node = self._cross_module_class_defs.get(base_name) - if _p_node is not None and hasattr(_p_node, 'decorator_list') and _p_node.decorator_list: - for dec in _p_node.decorator_list: - if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'NoVTable': - parent_is_novtable = True - elif isinstance(dec, ast.Name) and dec.id == 'NoVTable': - parent_is_novtable = True - break - # 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable - # (@t.NoVTable 标记的类及其子类不使用 vtable,字段展平嵌入) - if has_parent_class and not is_cvtable and not is_novtable and not parent_is_novtable: - is_cvtable = True - base_has_vtable: bool = False - for base in node.bases: - base_name: str | None = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and not self._is_marker_base(base_name): - # 先在当前 .pyi 中查找父类,找不到则查跨模块类定义映射 - _base_node: ast.ClassDef | None = None - for n in ast.iter_child_nodes(self._pyi_tree): - if isinstance(n, ast.ClassDef) and n.name == base_name: - _base_node = n - break - if _base_node is None: - _base_node = self._cross_module_class_defs.get(base_name) - if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list: - for dec in _base_node.decorator_list: - if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': - base_has_vtable = True - elif isinstance(dec, ast.Name) and dec.id == 'CVTable': - base_has_vtable = True - if base_has_vtable: - break - # NoVTable 类不添加 vtable 指针(即使有方法和父类) - if has_methods and is_cvtable and not base_has_vtable and not is_novtable: - member_types.append('i8*') - seen_member_names: 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): - base_member_types: list[str] - base_seen: set[str] - base_member_types, base_seen = self._get_inherited_members(base_name) - if type_args: - base_member_types = self._specialize_member_types(base_member_types, type_args) - for mt in base_member_types: - member_types.append(mt) - seen_member_names.update(base_seen) - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_member_names.add(item.target.id) - init_members: list[ast.AnnAssign] = [] - for item in node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if (isinstance(stmt, ast.AnnAssign) - and isinstance(stmt.target, ast.Attribute) - and isinstance(stmt.target.value, ast.Name) - and stmt.target.value.id == 'self'): - init_members.append(stmt) - untyped_self_members: list[ast.Assign] = [] - for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]: - seen_member_names.add(m_name) - for item in node.body: - if isinstance(item, ast.FunctionDef): - if hasattr(item, 'type_params') and item.type_params: - continue - for stmt in item.body: - if (isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - and isinstance(stmt.targets[0], ast.Attribute) - and isinstance(stmt.targets[0].value, ast.Name) - and stmt.targets[0].value.id == 'self'): - attr_name: str = stmt.targets[0].attr - if attr_name not in seen_member_names: - seen_member_names.add(attr_name) - untyped_self_members.append(stmt) - for item in list(node.body) + init_members + untyped_self_members: - if isinstance(item, ast.AnnAssign): - # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) - if isinstance(item.target, ast.Name) and item.target.id in ('__provides__', '__requires__', '__require_must__'): - continue - bit_width: int | None = self._get_bitfield_width(item.annotation) - if bit_width is not None: - has_bitfield = True - total_bits += bit_width - else: - VarType: str = self._get_type_str(item.annotation, embedded=True) - if IsListAnnotation(item.annotation): - slice_node: ast.AST = item.annotation.slice - is_dynamic: bool = False - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - count_node: ast.AST = slice_node.elts[1] - if isinstance(count_node, ast.Constant) and count_node.value is None: - is_dynamic = True - elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0): - if not isinstance(count_node, (ast.Name, ast.BinOp)): - is_dynamic = True - elif not isinstance(slice_node, ast.Tuple): - is_dynamic = True - if is_dynamic: - elem_type: str = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) - init_len: int = 0 - if isinstance(item.value, ast.List): - init_len = len(item.value.elts) - elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): - init_len = len(item.value.value) + 1 - VarType = f'[{init_len} x {elem_type}]' - else: - # 固定大小数组: t.CArray[elem_type, count] → [count x elem_type] - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - elem_type: str = self._get_type_str(slice_node.elts[0], embedded=True) - count_val: int = self._get_const_int(slice_node.elts[1]) - if count_val > 0: - VarType = f'[{count_val} x {elem_type}]' - elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): - # 单参数 t.CArray[elem_type] → 指针模式 - elem_type: str = self._get_type_str(slice_node, embedded=True) - VarType = f'{elem_type}*' - member_types.append(VarType) - elif isinstance(item, ast.Assign): - if (len(item.targets) == 1 - and isinstance(item.targets[0], ast.Attribute) - and isinstance(item.targets[0].value, ast.Name) - and item.targets[0].value.id == 'self'): - attr_name: str = item.targets[0].attr - if attr_name in seen_member_names: - continue - InferredType: str = 'i32' - if item.value and isinstance(item.value, ast.Constant): - if isinstance(item.value.value, float): - InferredType = 'float' - elif isinstance(item.value.value, bool): - InferredType = 'i8' - elif isinstance(item.value.value, str): - InferredType = 'i8*' - member_types.append(InferredType) - else: - member_types.append('i32') - if has_bitfield: - if total_bits <= 8: - member_types.insert(0, 'i8') - elif total_bits <= 16: - member_types.insert(0, 'i16') - elif total_bits <= 32: - member_types.insert(0, 'i32') - else: - member_types.insert(0, 'i64') - struct_type_name: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' - struct_decl: str = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' - decls.append(struct_decl) - if is_cpython_object or is_cvtable: - new_func_name: str = f'{class_name}.__before_init__' - if self.module_sha1: - new_func_name = f"{self.module_sha1}.{new_func_name}" - new_func_decl: str - if new_func_name[0].isdigit(): - new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)' - else: - new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)' - decls.append(new_func_decl) - # PEP 695 泛型类跳过方法声明生成:方法参数类型 T 会被解析为 opaque struct, - # LLVM 报 "invalid type for function argument"。字段(AnnAssign)仍正常生成, - # 确保子类(如 Value(GSListNode[Value]))能从 stub 中读取继承字段(如 Next)。 - IsGenericClass: bool = hasattr(node, 'type_params') and bool(node.type_params) - if not IsGenericClass: - for item in node.body: - if isinstance(item, ast.FunctionDef): - if hasattr(item, 'type_params') and item.type_params: - continue - method_name: str = f'{class_name}.{item.name}' - if self.module_sha1: - method_name = f"{self.module_sha1}.{method_name}" - ret_type: str = self._get_type_str(item.returns) if item.returns else 'void' - if not ret_type: - ret_type = 'void' - params: list[str] = [] - for arg_idx, arg in enumerate(item.args.args): - arg_type: str - if arg.annotation: - arg_type = self._get_type_str(arg.annotation) - elif arg_idx == 0 and arg.arg == 'self': - arg_type = f'{struct_type_name}*' - else: - arg_type = 'i8*' - # C 语言中数组参数退化为指针:[N x elem_type] → elem_type* - arg_type = self._decay_array_to_ptr(arg_type) - params.append(arg_type) - param_str: str = ', '.join(params) if params else '' - if method_name[0].isdigit(): - decls.append(f'declare {ret_type} @"{method_name}"({param_str})') - else: - decls.append(f'declare {ret_type} @{method_name}({param_str})') - # 为继承但未覆写的方法生成包装声明 - # 这些声明让跨模块调用能正确解析子类包装函数的签名, - # 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断 - decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name)) - return decls - - def _generate_inherited_method_decls(self, node: ast.ClassDef, child_class_name: str, child_struct_type: str) -> list[str]: - """为继承但未覆写的方法生成包装声明 - - 在 Phase 1 stub 中声明子类继承方法的签名(与父类相同,但 self 参数为子类类型)。 - 这样测试模块翻译时能从 temp stub 中获取正确的返回类型, - 避免 Phase 2 includes 翻译滞后导致跨模块调用使用默认 i32 返回类型。 - """ - decls: list[str] = [] - # 收集子类自身定义的方法名(这些不需要生成包装,子类有自己的实现) - seen_method_names: set[str] = set() - for item in node.body: - if isinstance(item, ast.FunctionDef): - seen_method_names.add(item.name) - - # 沿继承链收集父类方法,近祖先优先 - for base in node.bases: - base_name: str | None = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if not base_name or self._is_marker_base(base_name): - continue - self._CollectInheritedWrapperDecls( - base_name, child_class_name, child_struct_type, - seen_method_names, decls) - return decls - - def _CollectInheritedWrapperDecls( - self, parent_name: str, child_class_name: str, child_struct_type: str, - seen_method_names: set[str], decls: list[str]) -> None: - """递归收集父类及其祖先的方法,为未覆写的方法生成包装声明""" - # 查找父类节点:先在当前 .pyi 中查找,找不到则查跨模块类定义映射 - parent_node: ast.ClassDef | None = None - for n in ast.iter_child_nodes(self._pyi_tree): - if isinstance(n, ast.ClassDef) and n.name == parent_name: - parent_node = n - break - if parent_node is None: - parent_node = self._cross_module_class_defs.get(parent_name) - if parent_node is None: - return - - # 为父类的每个方法生成包装声明 - for item in parent_node.body: - if isinstance(item, ast.FunctionDef): - if hasattr(item, 'type_params') and item.type_params: - continue - method_name: str = item.name - # __before_init__ 只在自身类生成,不生成继承包装 - if method_name == '__before_init__': - continue - # 跳过子类已覆写的方法,以及已处理的祖先方法 - if method_name in seen_method_names: - continue - seen_method_names.add(method_name) - - # 构建包装方法名:{module_sha1}.{child_class}.{method_name} - wrapper_name: str = f'{child_class_name}.{method_name}' - if self.module_sha1: - wrapper_name = f"{self.module_sha1}.{wrapper_name}" - - # 解析返回类型(与父类方法相同) - ret_type: str = self._get_type_str(item.returns) if item.returns else 'void' - if not ret_type: - ret_type = 'void' - elif ret_type == 'i8*': - if item.returns is None: - ret_type = 'void' - - # 构建参数列表:第一个参数(self)替换为子类类型,其余与父类相同 - params: list[str] = [] - for arg_idx, arg in enumerate(item.args.args): - arg_type: str - if arg_idx == 0 and arg.arg == 'self': - arg_type = f'{child_struct_type}*' - else: - if arg.annotation: - arg_type = self._get_type_str(arg.annotation) - else: - arg_type = 'i8*' - arg_type = self._decay_array_to_ptr(arg_type) - params.append(arg_type) - - param_str: str = ', '.join(params) if params else '' - if wrapper_name[0].isdigit(): - decls.append(f'declare {ret_type} @"{wrapper_name}"({param_str})') - else: - decls.append(f'declare {ret_type} @{wrapper_name}({param_str})') - - # 递归处理祖先类 - for base in parent_node.bases: - base_name: str | None = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and not self._is_marker_base(base_name): - self._CollectInheritedWrapperDecls( - base_name, child_class_name, child_struct_type, - seen_method_names, decls) - - def _get_inherited_members(self, base_name: str) -> tuple[list[str], set[str]]: - member_types: list[str] = [] - seen_names: set[str] = set() - if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: - return member_types, seen_names - base_node: ast.ClassDef | None = None - for node in ast.iter_child_nodes(self._pyi_tree): - if isinstance(node, ast.ClassDef) and node.name == base_name: - base_node = node - break - if base_node is None: - # 跨模块父类查找:当前 .pyi 中没有父类定义时,从跨模块类定义映射中查找 - # (如 exprs.py 的 Name(AST),AST 定义在 base.py) - base_node = self._cross_module_class_defs.get(base_name) - if base_node is None: - return member_types, seen_names - base_decls: list[str] = self._generate_class_decl(base_node) - for decl in base_decls: - if '= type {' in decl: - type_body: str = decl.split('= type {')[1].rstrip('}').strip() - if type_body: - for t in type_body.split(','): - t = t.strip() - if t: - member_types.append(t) - break - for item in base_node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_names.add(item.target.id) - elif isinstance(item, ast.Assign) and len(item.targets) == 1: - if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self': - seen_names.add(item.targets[0].attr) - for item in base_node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self': - seen_names.add(stmt.target.attr) - elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self': - seen_names.add(stmt.targets[0].attr) - return member_types, seen_names - - def _specialize_member_types(self, member_types: list[str], type_args: list[str]) -> list[str]: - """将基类成员类型中的泛型参数 T 替换为具体类型参数 - - 处理泛型基类继承(如 GSListNode[BasicBlock])时,基类 _get_inherited_members - 返回的成员类型中会包含未特化的 T 引用(形式为 %"SHA1.T"*)。 - - 替换策略:使用 i8*(不透明指针)代替 T*,而非具体类型指针。 - 原因:跨模块场景中,具体类型指针的 SHA1 前缀可能与导入模块不一致, - 导致 TransPyC 类型转换失败。i8* 作为通用指针类型,可安全赋值给 - 任何 Class | t.CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。 - - Args: - member_types: 基类成员类型字符串列表 - type_args: 类型参数名列表(如 ['BasicBlock']) - - Returns: - 特化后的成员类型字符串列表 - """ - if not type_args: - return member_types - result: list[str] = [] - for mt in member_types: - new_mt: str = mt - # 将 %"SHA1.T"* 替换为 i8*(不透明指针) - new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt) - # 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8* - new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt) - result.append(new_mt) - return result - - def _llvm_type_size_str(self, type_str: str) -> int: - """估算 LLVM 类型字符串的大小(字节),用于 REnum 变体大小比较 - - 对齐 _EmitREnumLlvm 中的大小计算逻辑: - - i1=1, i8=1, i16=2, i32=4, i64=8, float=4, double=8, ptr=8 - - [N x T] = N * size(T) - - 其他结构体类型按指针大小 8 估算(保守值) - """ - s: str = type_str.strip() - if not s: - return 0 - # 指针类型 - if s.endswith('*'): - return 8 - # 数组类型 [N x T] - m = self._ARR_TYPE_RE.match(s) if hasattr(self, '_ARR_TYPE_RE') else None - if m: - try: - n: int = int(m.group(1)) - return n * self._llvm_type_size_str(m.group(2)) - except ValueError: - return 8 - # 基本整数/浮点类型 - size_map: dict[str, int] = { - 'i1': 1, 'i8': 1, 'i16': 2, 'i32': 4, 'i64': 8, - 'float': 4, 'double': 8, 'half': 2, 'fp128': 16, - 'void': 0, - } - if s in size_map: - return size_map[s] - # %{...} 结构体类型 - 保守估算为指针大小 - if s.startswith('%') or s.startswith('{'): - return 8 - # 其他未知类型保守估算 - return 8 - - def _get_type_str(self, annotation: ast.AST | None, embedded: bool = False) -> str: - if annotation is None: - return 'i8*' - - non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray'} - - if isinstance(annotation, ast.Name): - if annotation.id == 'None': - return 'void' - if annotation.id in ('str', 'bytes'): - return 'i8*' - llvm_type: str | None = CTypeRegistry.NameToLLVM(annotation.id) - if llvm_type is not None: - return llvm_type - resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(annotation.id) - if resolved is not None: - ctype_cls: type - ptr_level: int - ctype_cls, ptr_level = resolved - base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - if annotation.id in self.struct_names: - sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) - sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' - if embedded: - return sname - else: - return f'{sname}*' - if annotation.id in non_struct_types: - return 'i32' - if annotation.id in self.enum_names: - return 'i32' - if annotation.id in self.typedef_map: - resolved_str: str = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) - return resolved_str - # 检查 t 类型别名(from t import CInt as myint) - if annotation.id in self._t_alias_map: - t_cls: type = self._t_alias_map[annotation.id] - llvm: str | None = CTypeRegistry.CTypeToLLVM(t_cls) - if llvm: - return llvm - sha1: str | None = self.struct_sha1_map.get(annotation.id, self.module_sha1) - sname: str = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' - return f'{sname}*' - elif isinstance(annotation, ast.Attribute): - attr_name: str = annotation.attr if hasattr(annotation, 'attr') else '' - module_name: str = '' - if hasattr(annotation, 'value'): - if isinstance(annotation.value, ast.Name): - module_name = annotation.value.id - elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'): - module_name = annotation.value.attr - if (module_name == 't' and attr_name == 'State') or attr_name == 'State': - return '' - if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable': - return 'i8*' - llvm_type: str | None = CTypeRegistry.NameToLLVM(attr_name) - if llvm_type is not None: - return llvm_type - resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(attr_name) - if resolved is not None: - ctype_cls: type - ptr_level: int - ctype_cls, ptr_level = resolved - base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - if attr_name in self.typedef_map: - return self._get_type_str(self.typedef_map[attr_name], embedded=embedded) - if attr_name in self.enum_names: - return 'i32' - if attr_name in self.struct_names: - sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - if embedded: - return sname - else: - return f'{sname}*' - if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types: - sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - return f'{sname}*' - if attr_name and attr_name not in non_struct_types: - sha1: str | None = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - return f'{sname}*' - return 'i32' - elif isinstance(annotation, ast.BinOp): - left_type: str = self._get_type_str(annotation.left, embedded=embedded) - right_type: str = self._get_type_str(annotation.right, embedded=embedded) - if left_type in ('', 'void'): - return right_type if right_type not in ('', 'void') else (left_type or right_type) - if right_type in ('', 'void'): - return left_type - # t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的 - # "first CPtr absorption" 语义:struct | t.CPtr → struct*(吸收,struct 变量默认是指针)。 - # 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | t.CPtr → i8**(不吸收)。 - # 例外:泛型特化类型(含 '[')回退为 i8*,避免引用未定义的特化结构体。 - if right_type == 'i8*': - if '[' in left_type: - return 'i8*' - if left_type in ('', 'void'): - return 'i8*' - if left_type.startswith('%"') and left_type.endswith('*'): - return left_type - if '*' in left_type: - return f'{left_type}*' - return f'{left_type}*' - if '*' in left_type: - return left_type - if '*' in right_type: - return right_type - return left_type - elif isinstance(annotation, ast.Subscript): - 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]' - # 处理 t.CPtr[Type] 语法(指向 Type 的指针) - # 例如: t.CPtr[t.CPtr] -> i8** (void**), t.CPtr[t.CInt] -> i32* (int*) - # t.CPtr[t.CPtr[t.CInt]] -> i32** (int**) - ValueIsCPtr: bool = ( - (isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr') - or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr') - ) - if ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)): - slice_type: str = self._get_type_str(annotation.slice, embedded=True) - if slice_type and slice_type != 'void': - return f'{slice_type}*' - return 'i8*' - if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): - return f'[{annotation.slice.value} x {base}]' - # 处理 t.CArray[elem_type, count] 注解 → [count x elem_type] - # 支持 t.CArray (ast.Attribute) 和 CArray (ast.Name) 两种写法 - ValueIsCArray: bool = ( - (isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CArray') - or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CArray') - ) - if ValueIsCArray: - SliceNode: ast.AST = annotation.slice - if isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2: - ElemType: str = self._get_type_str(SliceNode.elts[0], embedded=True) - CountVal: int = self._get_const_int(SliceNode.elts[1]) - if CountVal > 0: - return f'[{CountVal} x {ElemType}]' - # count 为 None 或 0 → 零长度数组(外部符号) - return f'[0 x {ElemType}]' - elif isinstance(SliceNode, (ast.Attribute, ast.Name, ast.Subscript)): - # 单参数 t.CArray[elem_type] → 指针模式 - ElemType: str = self._get_type_str(SliceNode, embedded=True) - return f'{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]) - if isinstance(annotation.value, ast.Name): - gc_name: str = annotation.value.id - if gc_name in non_struct_types and gc_name != 'tuple': - gc_slice: ast.AST = annotation.slice - gc_args: list[str] = [] - if isinstance(gc_slice, ast.Name): - gc_args.append(gc_slice.id) - elif isinstance(gc_slice, ast.Tuple): - gc_valid: bool = True - for gc_elt in gc_slice.elts: - if isinstance(gc_elt, ast.Name): - gc_args.append(gc_elt.id) - else: - gc_valid = False - break - if not gc_valid: - gc_args = [] - if gc_args: - gc_mangled: list[str] = [] - for gc_ta in gc_args: - gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta) - if gc_llvm: - if gc_llvm in ('float', 'double', 'half', 'fp128'): - gc_cls: type | None = CTypeRegistry.GetClassByName(gc_ta) - gc_sz: int = gc_cls().Size if gc_cls else 0 - gc_mangled.append('f' + str(gc_sz)) - else: - gc_mangled.append(gc_llvm) - else: - gc_mangled.append(gc_ta) - gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']' - gc_sha1: str | None = self.module_sha1 - gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}' - if embedded: - return gc_sname - return f'{gc_sname}*' - return f'{base}' - elif isinstance(annotation, ast.Constant): - if annotation.value is None: - return 'void' - if isinstance(annotation.value, int): - return 'i32' - if isinstance(annotation.value, str): - type_name: str = annotation.value - if type_name in self.enum_names: - return 'i32' - if type_name in self.struct_names: - sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) - sname: str = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' - if embedded: - return sname - else: - return f'{sname}*' - llvm_type: str | None = CTypeRegistry.NameToLLVM(type_name) - if llvm_type is not None: - return llvm_type - resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(type_name) - if resolved is not None: - ctype_cls: type - ptr_level: int - ctype_cls, ptr_level = resolved - base: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - sha1: str | None = self.struct_sha1_map.get(type_name, self.module_sha1) - sname: str = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' - return f'{sname}*' - return 'i8*' - elif isinstance(annotation, ast.Call): - if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable': - return 'i8*' - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable': - return 'i8*' - return 'i32' - - def _infer_type(self, value: ast.AST) -> str: - """从值推断类型""" - if isinstance(value, ast.Constant): - if isinstance(value.value, int): - return 'i32' - elif isinstance(value.value, float): - return 'double' - elif isinstance(value.value, str): - return 'i8*' - elif isinstance(value.value, bool): - return 'i8' - elif isinstance(value, ast.List): - return 'i8*' - elif isinstance(value, ast.Dict): - return 'i8*' - elif isinstance(value, ast.Name): - return 'i32' - elif isinstance(value, ast.BinOp): - return self._infer_type(value.left) - elif isinstance(value, ast.Call): - return 'i8*' - return 'i32' - - def _get_bitfield_width(self, annotation: ast.AST) -> int | None: - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - right_width: int | None = self._get_bitfield_width(annotation.right) - if right_width is not None: - return right_width - return self._get_bitfield_width(annotation.left) - if isinstance(annotation, ast.Call): - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit': - if annotation.args: - arg: ast.AST = annotation.args[0] - if isinstance(arg, ast.Constant) and isinstance(arg.value, int): - return arg.value - if isinstance(annotation, ast.Subscript): - if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit': - if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): - return annotation.slice.value - return None - - def _get_const_int(self, node: ast.AST) -> int: - """获取常量整数值,支持符号常量和简单表达式""" - if isinstance(node, ast.Constant) and isinstance(node.value, int): - return node.value - if isinstance(node, ast.Name): - if node.id in self._DefineConstants: - val: int | str = self._DefineConstants[node.id] - if isinstance(val, int): - return val - if isinstance(node, ast.BinOp): - left_val: int = self._get_const_int(node.left) - right_val: int = self._get_const_int(node.right) - if left_val and right_val: - if isinstance(node.op, ast.Add): - return left_val + right_val - if isinstance(node.op, ast.Sub): - return left_val - right_val - if isinstance(node.op, ast.Mult): - return left_val * right_val - if isinstance(node.op, ast.Div): - return left_val // right_val - if isinstance(node.op, ast.FloorDiv): - return left_val // right_val - return 0 diff --git a/App/lib/Projectrans/Phase1Generator.py b/App/lib/Projectrans/Phase1Generator.py deleted file mode 100644 index c30ed83..0000000 --- a/App/lib/Projectrans/Phase1Generator.py +++ /dev/null @@ -1,595 +0,0 @@ -from __future__ import annotations - -import os -import ast -import json -import shutil -import traceback - -from lib.Projectrans.Utils import compute_sha1, get_file_dependencies, find_reachable_files_from_entries, parse_python_file -from lib.Projectrans.DeclarationGenerator import DeclarationGenerator -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _ConfigMode -from StubGen import PythonToStubConverter - -# 全局缓存目录(不被 --clean 清除),用于缓存库文件的 .pyi / .stub.ll / .doc.json -_COMPILER_ROOT: str = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -_GLOBAL_CACHE_DIR: str = os.path.join(_COMPILER_ROOT, '.transpyc_cache') - - -def _TryGlobalCache(Sha1: str, Ext: str, TempPath: str) -> bool: - """检查全局缓存中是否存在指定文件,若存在则复制到 temp_dir 并返回 True。""" - GlobalPath: str = os.path.join(_GLOBAL_CACHE_DIR, f"{Sha1}.{Ext}") - if os.path.isfile(GlobalPath): - try: - os.makedirs(os.path.dirname(TempPath), exist_ok=True) - shutil.copy2(GlobalPath, TempPath) - return True - except Exception: - pass - return False - - -def _SaveToGlobalCache(Sha1: str, Ext: str, TempPath: str) -> None: - """将文件保存到全局缓存供后续使用。""" - GlobalPath: str = os.path.join(_GLOBAL_CACHE_DIR, f"{Sha1}.{Ext}") - try: - os.makedirs(_GLOBAL_CACHE_DIR, exist_ok=True) - shutil.copy2(TempPath, GlobalPath) - except Exception: - pass - - -class Phase1Generator: - """阶段一:从源文件生成声明接口""" - - def __init__(self, src_root: str, temp_dir: str, include_dirs: list[str] | None = None, entry_files: list[str] | None = None, target_triple: str | None = None, target_datalayout: str | None = None) -> None: - self.src_root: str = os.path.abspath(src_root) - self.temp_dir: str = os.path.abspath(temp_dir) - self.include_dirs: list[str] = include_dirs or [] - self.sha1_map: dict[str, str] = {} - self.include_py_map: dict[str, str] = {} - self.entry_files: list[str] | None = entry_files - self.target_triple: str | None = target_triple - self.target_datalayout: str | None = target_datalayout - os.makedirs(self.temp_dir, exist_ok=True) - # 增量编译 manifest:{abs_path: {sha1, mtime, size}} - # 未变更文件(mtime+size 匹配)跳过 open+read+sha1,仅需 stat - self._manifest: dict[str, dict] = {} - self._typedef_map_cache: dict[str, ast.AST] | None = None - self._manifest_path: str = os.path.join(self.temp_dir, '_phase1_manifest.json') - self._load_manifest() - - def _load_manifest(self) -> None: - """加载上次运行的 manifest(mtime+size → sha1 缓存)""" - try: - if os.path.isfile(self._manifest_path): - with open(self._manifest_path, 'r', encoding='utf-8') as f: - self._manifest = json.load(f) - except Exception: - self._manifest = {} - - def _save_manifest(self) -> None: - """保存 manifest 供下次增量编译使用""" - try: - with open(self._manifest_path, 'w', encoding='utf-8') as f: - json.dump(self._manifest, f) - except Exception: - pass - - def _get_sha1(self, src_path: str) -> str: - """用 mtime+size 缓存加速 sha1 计算。 - - 未变更文件(mtime+size 匹配 manifest)直接返回缓存的 sha1, - 跳过 open+read+compute_sha1,仅需一次 stat 调用。 - """ - abs_path: str = os.path.abspath(src_path) - try: - st: os.stat_result = os.stat(abs_path) - except OSError: - return '' - mtime: float = st.st_mtime - size: int = st.st_size - entry: dict = self._manifest.get(abs_path, {}) - if entry.get('mtime') == mtime and entry.get('size') == size: - sha1: str = entry.get('sha1', '') - if sha1: - return sha1 - # mtime/size 不匹配,需读取内容重新计算 - try: - with open(abs_path, 'r', encoding='utf-8') as f: - content: str = f.read() - except Exception: - return '' - sha1 = compute_sha1(content) - self._manifest[abs_path] = {'sha1': sha1, 'mtime': mtime, 'size': size} - return sha1 - - def _get_needed_include_files(self, reachable_source_files: set[str]) -> list[tuple[str, str, str]]: - """从可达源文件收集所有被引用(含传递依赖)的 include 文件""" - include_file_map: dict[str, tuple[str, str, str]] = {} - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py') or fname.endswith('.pyi'): - src_path: str = os.path.join(root, fname) - rel_from_inc: str = os.path.relpath(src_path, includes_dir) - ModulePath: str = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name: str = os.path.splitext(ModulePath)[0] - info: tuple[str, str, str] = (src_path, rel_from_inc, includes_dir) - include_file_map[module_name] = info - top_pkg: str = module_name.split('.')[0] - # __init__.py 是包入口,应优先作为 top_pkg 的代表 - # (参考 find_reachable_files_from_entries 的优先级逻辑), - # 否则若 os/path.py 先被遍历,'os' 会错误指向 path.py - # 而非 os/__init__.py,导致包入口 SHA1 未注册到 sha1_map - if module_name == f"{top_pkg}.__init__": - include_file_map[top_pkg] = info - elif top_pkg not in include_file_map: - include_file_map[top_pkg] = info - - imported_from_src: set[str] = set() - for src_path in reachable_source_files: - deps: set[str] = get_file_dependencies(src_path, self.src_root) - imported_from_src.update(deps) - - # 检测 dict/list 容器使用,自动添加 _dict/_list/json 依赖 - for src_path in reachable_source_files: - try: - # 复用 parse_python_file 的 AST 缓存(get_file_dependencies 已解析过同一文件) - content, tree = parse_python_file(src_path) - if tree is None: - continue - for node in ast.walk(tree): - if isinstance(node, ast.Subscript) and isinstance(node.value, ast.Name): - if node.value.id == 'dict': - imported_from_src.add('_dict') - imported_from_src.add('json') - break - elif node.value.id == 'list': - imported_from_src.add('_list') - break - if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): - if node.func.id == 'dict': - imported_from_src.add('_dict') - imported_from_src.add('json') - break - elif node.func.id == 'list': - imported_from_src.add('_list') - break - # 检测类型注解 d: dict / l: list (非泛型形式) - if isinstance(node, ast.AnnAssign) and isinstance(node.annotation, ast.Name): - if node.annotation.id == 'dict': - imported_from_src.add('_dict') - imported_from_src.add('json') - break - elif node.annotation.id == 'list': - imported_from_src.add('_list') - break - except Exception: - pass - - needed: set[str] = set() - queue: list[str] = list(imported_from_src) - while queue: - mod_name: str = queue.pop(0) - if mod_name in needed: - continue - if mod_name in include_file_map: - needed.add(mod_name) - src_path: str = include_file_map[mod_name][0] - includes_dir: str = include_file_map[mod_name][2] - deps: set[str] = get_file_dependencies(src_path, includes_dir) - for dep in deps: - if dep in include_file_map and dep not in needed: - queue.append(dep) - - needed_infos: list[tuple[str, str, str]] = [] - for mod_name in sorted(needed): - if mod_name in include_file_map: - info: tuple[str, str, str] = include_file_map[mod_name] - if info not in needed_infos: - needed_infos.append(info) - - return needed_infos - - def run(self) -> None: - """扫描源目录,只处理入口文件可达的 .py 文件(导入遍历)""" - py_files: list[str] - if self.entry_files: - py_files = list(self.entry_files) - else: - main_py: str = os.path.join(self.src_root, 'main.py') - if os.path.exists(main_py): - py_files = [main_py] - else: - py_files = [] - for root, dirs, files in os.walk(self.src_root): - dirs[:] = [d for d in dirs if d not in ('__pycache__',)] - for file in files: - if file.endswith('.py'): - py_files.append(os.path.join(root, file)) - - if not py_files: - _vlog().warning("未找到入口文件或源文件") - return - - reachable: set[str] - if self.entry_files: - reachable = find_reachable_files_from_entries(self.src_root, py_files) - else: - reachable = find_reachable_files_from_entries(self.src_root, py_files) - - _vlog().info(f"找到 {len(reachable)} 个可达源文件(从入口遍历)") - - for i, src_path in enumerate(sorted(reachable), 1): - rel: str = os.path.relpath(src_path, self.src_root) - _vlog().info(f"[{i}/{len(reachable)}] 生成签名: {rel}") - try: - self._process_file_pyi(src_path, rel) - except Exception as e: - _vlog().error(f"生成签名失败: {e}") - traceback.print_exc() - - needed_includes: list[tuple[str, str, str]] = self._get_needed_include_files(reachable) - self._process_include_py_files_pyi(needed_includes) - - struct_names: set[str] - enum_names: set[str] - struct_sha1_map: dict[str, str] - exception_names: set[str] - struct_names, enum_names, struct_sha1_map, exception_names, class_def_map = self._build_struct_registry() - _vlog().info(f"结构体注册表: {len(struct_names)} 个类型, {len(enum_names)} 个枚举") - for name in sorted(struct_names): - _vlog().debug(f" {name}") - - # 预先收集 typedef 映射,避免在 _process_file_stub 中对每个源文件重复扫描所有 .pyi - self._typedef_map_cache: dict[str, ast.AST] = self._collect_typedef_map() - - for i, src_path in enumerate(sorted(reachable), 1): - rel: str = os.path.relpath(src_path, self.src_root) - try: - self._process_file_stub(src_path, rel, struct_names, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names, class_def_map=class_def_map) - except Exception as e: - _vlog().error(f"生成声明失败: {e}") - traceback.print_exc() - - self._process_include_py_files_stub(struct_names, needed_includes, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names, class_def_map=class_def_map) - - # 保存 manifest 供下次增量编译使用 - self._save_manifest() - - _vlog().success(f"声明接口生成到: {self.temp_dir}") - _vlog().info(f"SHA1 映射表 ({len(self.sha1_map)} 个文件):") - for sha1, rel in sorted(self.sha1_map.items()): - _vlog().debug(f" {sha1} -> {rel}") - - def _collect_include_py_files(self) -> list[tuple[str, str, str]]: - include_py_files: list[tuple[str, str, str]] = [] - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py') or fname.endswith('.pyi'): - src_path: str = os.path.join(root, fname) - rel_from_inc: str = os.path.relpath(src_path, includes_dir) - include_py_files.append((src_path, rel_from_inc, includes_dir)) - return include_py_files - - def _process_include_py_files_pyi(self, needed_includes: list[tuple[str, str, str]] | None = None) -> None: - include_py_files: list[tuple[str, str, str]] - if needed_includes is not None: - include_py_files = needed_includes - else: - include_py_files = self._collect_include_py_files() - if not include_py_files: - return - _vlog().info(f"处理 {len(include_py_files)} 个被引用的 Python 库文件") - for src_path, rel_from_inc, includes_dir in include_py_files: - ModulePath: str = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name: str = os.path.splitext(ModulePath)[0] - try: - # 增量优化:用 mtime+size 获取 sha1,未变更文件跳过 open+read - sha1: str = self._get_sha1(src_path) - if not sha1: - continue - self.sha1_map[sha1] = f"includes/{rel_from_inc}" - top_module: str = rel_from_inc.split(os.sep)[0].split('/')[0] - if top_module not in self.include_py_map: - self.include_py_map[top_module] = sha1 - self.include_py_map[module_name] = sha1 - - sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi") - if os.path.isfile(sig_path): - _vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.pyi") - continue - - # 全局缓存检查(不被 --clean 清除) - if _TryGlobalCache(sha1, 'pyi', sig_path): - _vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.pyi") - continue - - # 缓存未命中,需读取 content 生成 .pyi - with open(src_path, 'r', encoding='utf-8') as f: - content: str = f.read() - sig_content: str = PythonToStubConverter.convert(content, module_name) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - _SaveToGlobalCache(sha1, 'pyi', sig_path) - _vlog().info(f" 生成签名: {rel_from_inc} -> {sha1}.pyi") - except Exception as e: - _vlog().error(f"处理 include 文件失败 {rel_from_inc}: {e}") - - def _collect_typedef_map(self) -> dict[str, ast.AST]: - typedef_map: dict[str, ast.AST] = {} - if not os.path.isdir(self.temp_dir): - return typedef_map - for fname in os.listdir(self.temp_dir): - if not fname.endswith('.pyi'): - continue - pyi_path: str = os.path.join(self.temp_dir, fname) - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - content: str = f.read() - tree: ast.Module = ast.parse(content) - 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 - is_typedef: bool = False - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - is_typedef = True - if is_typedef and node.value and var_name not in typedef_map: - typedef_map[var_name] = node.value - except Exception as _e: - if _ConfigMode == "strict": - raise - _vlog().warning(f"收集 typedef 映射失败: {_e}", "Exception") - return typedef_map - - def _process_include_py_files_stub(self, struct_names: set[str], needed_includes: list[tuple[str, str, str]] | None = None, enum_names: set[str] | None = None, struct_sha1_map: dict[str, str] | None = None, exception_names: set[str] | None = None, class_def_map: dict[str, ast.ClassDef] | None = None) -> None: - include_py_files: list[tuple[str, str, str]] - if needed_includes is not None: - include_py_files = needed_includes - else: - include_py_files = self._collect_include_py_files() - if not include_py_files: - return - typedef_map: dict[str, ast.AST] = self._collect_typedef_map() - for src_path, rel_from_inc, includes_dir in include_py_files: - ModulePath: str = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name: str = os.path.splitext(ModulePath)[0] - try: - # 增量优化:用 mtime+size 获取 sha1,未变更文件跳过 open+read - sha1: str = self._get_sha1(src_path) - if not sha1: - continue - - stub_path: str = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(stub_path): - _vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll") - continue - - # 全局缓存检查(不被 --clean 清除) - if _TryGlobalCache(sha1, 'stub.ll', stub_path): - _vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.stub.ll") - continue - - sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi") - if not os.path.isfile(sig_path): - _TryGlobalCache(sha1, 'pyi', sig_path) - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content: str = f.read() - - self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map, class_def_map=class_def_map) - _SaveToGlobalCache(sha1, 'stub.ll', stub_path) - _vlog().info(f" 生成声明: {rel_from_inc} -> {sha1}.stub.ll") - except Exception as e: - _vlog().error(f"处理 include 文件失败 {rel_from_inc}: {e}") - - def _extract_docstrings(self, content: str) -> dict[str, str]: - """从源码 AST 提取所有函数/结构体/方法的首条裸字符串字面量 docstring。 - - - 顶层 FunctionDef: key = 函数名 - - 顶层 ClassDef: key = 类名;同时遍历方法,key = "ClassName.method" - - docstring 必须是 body[0] 为 ast.Expr + ast.Constant(str) - - 空字符串不计入 - """ - result: dict[str, str] = {} - try: - tree = ast.parse(content) - except SyntaxError: - return result - for node in tree.body: - if isinstance(node, ast.FunctionDef): - doc = self._get_first_docstring(node.body) - if doc is not None and doc != '': - result[node.name] = doc - elif isinstance(node, ast.ClassDef): - doc = self._get_first_docstring(node.body) - if doc is not None and doc != '': - result[node.name] = doc - for sub in node.body: - if isinstance(sub, ast.FunctionDef): - m_doc = self._get_first_docstring(sub.body) - if m_doc is not None and m_doc != '': - result[f"{node.name}.{sub.name}"] = m_doc - return result - - def _get_first_docstring(self, body: list[ast.stmt]) -> str | None: - """返回 body 首条裸字符串字面量,否则 None""" - if body and isinstance(body[0], ast.Expr) and isinstance(body[0].value, ast.Constant) and isinstance(body[0].value.value, str): - return body[0].value.value - return None - - def _process_file_pyi(self, src_path: str, rel_path: str) -> None: - # 增量优化:先用 mtime+size 获取 sha1,未变更文件跳过 open+read - sha1: str = self._get_sha1(src_path) - if not sha1: - return - self.sha1_map[sha1] = rel_path - - sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi") - if os.path.isfile(sig_path): - _vlog().info(f" -> {sha1}.pyi (缓存)") - # 缓存命中时补全缺失的 .doc.json - doc_path: str = os.path.join(self.temp_dir, f"{sha1}.doc.json") - if not os.path.isfile(doc_path): - if not _TryGlobalCache(sha1, 'doc.json', doc_path): - # doc.json 缺失时需读 content 提取 docstring - with open(src_path, 'r', encoding='utf-8') as f: - content: str = f.read() - docs: dict[str, str] = self._extract_docstrings(content) - try: - with open(doc_path, 'w', encoding='utf-8', newline='\n') as f: - json.dump(docs, f, ensure_ascii=False) - _SaveToGlobalCache(sha1, 'doc.json', doc_path) - except Exception as e: - _vlog().warning(f"补写 {sha1}.doc.json 失败: {e}") - return - - # 全局缓存检查 - if _TryGlobalCache(sha1, 'pyi', sig_path): - _vlog().info(f" -> {sha1}.pyi (全局缓存)") - doc_path: str = os.path.join(self.temp_dir, f"{sha1}.doc.json") - if not os.path.isfile(doc_path): - _TryGlobalCache(sha1, 'doc.json', doc_path) - return - - # 缓存未命中,需读取 content 生成 .pyi - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - - module_name: str = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - sig_content: str = PythonToStubConverter.convert(content, module_name) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - _SaveToGlobalCache(sha1, 'pyi', sig_path) - _vlog().info(f" -> {sha1}.pyi (签名)") - - # 提取 docstring 写入 {sha1}.doc.json,供 Phase2 跨模块 __doc__ 加载 - docs: dict[str, str] = self._extract_docstrings(content) - doc_path: str = os.path.join(self.temp_dir, f"{sha1}.doc.json") - try: - with open(doc_path, 'w', encoding='utf-8', newline='\n') as f: - json.dump(docs, f, ensure_ascii=False) - _SaveToGlobalCache(sha1, 'doc.json', doc_path) - except Exception as e: - _vlog().warning(f"写入 {sha1}.doc.json 失败: {e}") - - def _process_file_stub(self, src_path: str, rel_path: str, struct_names: set[str], enum_names: set[str] | None = None, struct_sha1_map: dict[str, str] | None = None, exception_names: set[str] | None = None, class_def_map: dict[str, ast.ClassDef] | None = None) -> None: - # 增量优化:用 mtime+size 获取 sha1,未变更文件跳过 open+read - sha1: str = self._get_sha1(src_path) - if not sha1: - return - stub_path: str = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(stub_path): - _vlog().info(f" -> {sha1}.stub.ll (缓存)") - return - - sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi") - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content: str = f.read() - - typedef_map: dict[str, ast.AST] = self._typedef_map_cache or self._collect_typedef_map() - self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map, class_def_map=class_def_map) - _vlog().info(f" -> {sha1}.stub.ll (声明)") - - def _build_struct_registry(self) -> tuple[set[str], set[str], dict[str, str], set[str], dict[str, ast.ClassDef]]: - struct_names: set[str] = set() - enum_names: set[str] = set() - exception_names: set[str] = set() - struct_sha1_map: dict[str, str] = {} - class_def_map: dict[str, ast.ClassDef] = {} - valid_sha1_keys: set[str] = set(self.sha1_map.keys()) - for fname in os.listdir(self.temp_dir): - if not fname.endswith('.pyi'): - continue - sha1_key: str = fname.replace('.pyi', '') - if sha1_key not in valid_sha1_keys: - continue - pyi_path: str = os.path.join(self.temp_dir, fname) - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - content: str = f.read() - tree: ast.Module = ast.parse(content) - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.ClassDef): - is_enum: bool = False - is_renum: bool = False - is_exception: bool = False - if node.bases: - for base in node.bases: - if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): - if base.attr == 'REnum': - is_renum = True - break - elif base.attr in ('CEnum', 'Enum'): - is_enum = True - break - elif base.attr == 'Exception' or base.attr in exception_names: - is_exception = True - break - elif isinstance(base, ast.Name) and hasattr(base, 'id'): - if base.id == 'REnum': - is_renum = True - break - elif base.id in ('CEnum', 'Enum'): - is_enum = True - break - elif base.id == 'Exception' or base.id in exception_names: - is_exception = True - break - # 也检查装饰器形式 @t.CEnum / @t.REnum - if not is_enum and not is_renum and not is_exception and hasattr(node, 'decorator_list') and node.decorator_list: - for deco in node.decorator_list: - deco_attr: str | None = None - if isinstance(deco, ast.Attribute) and hasattr(deco, 'attr'): - deco_attr = deco.attr - elif isinstance(deco, ast.Name) and hasattr(deco, 'id'): - deco_attr = deco.id - if deco_attr == 'REnum': - is_renum = True - break - elif deco_attr in ('CEnum', 'Enum'): - is_enum = True - break - # REnum 是结构体类型(带 __tag + payload),需加入 struct_names 以便 - # DeclarationGenerator._get_type_str 返回 %Name* 而非 i32 - if is_renum: - struct_names.add(node.name) - struct_sha1_map[node.name] = sha1_key - elif is_enum: - enum_names.add(node.name) - elif is_exception: - exception_names.add(node.name) - else: - struct_names.add(node.name) - struct_sha1_map[node.name] = sha1_key - # 收集所有类(含枚举/异常)的 ClassDef 节点,供 DeclarationGenerator - # 跨模块字段展平使用(如 exprs.py 的 Name(AST) 需查找 base.py 的 AST) - class_def_map[node.name] = node - except Exception as _e: - if _ConfigMode == "strict": - raise - _vlog().warning(f"构建结构体/枚举注册表失败: {_e}", "Exception") - return struct_names, enum_names, struct_sha1_map, exception_names, class_def_map - - def _generate_decl_ll(self, pyi_content: str, ll_path: str, src_path: str, struct_names: set[str] | None = None, enum_names: set[str] | None = None, module_sha1: 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: - try: - decl_gen: DeclarationGenerator = DeclarationGenerator(struct_names=struct_names, enum_names=enum_names, module_sha1=module_sha1, target_triple=self.target_triple, target_datalayout=self.target_datalayout, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map, class_def_map=class_def_map) - decl_ll: str = decl_gen.generate(pyi_content, src_path) - with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(decl_ll) - except Exception as e: - _vlog().warning(f".ll 声明生成失败: {e}") - with open(ll_path, 'w', encoding='utf-8') as f: - f.write(f"; declaration for {os.path.basename(src_path)}\n; error: {e}\n") diff --git a/App/lib/Projectrans/Phase2Translator.py b/App/lib/Projectrans/Phase2Translator.py deleted file mode 100644 index 5c1e300..0000000 --- a/App/lib/Projectrans/Phase2Translator.py +++ /dev/null @@ -1,3056 +0,0 @@ -from __future__ import annotations - -import sys -import os -import re -import shutil -import subprocess -import ast -import traceback -import json -import pickle -import time -from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, as_completed, wait, FIRST_COMPLETED -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode -from lib.core.CTypeInfo import CTypeInfo -from lib.includes import t -from lib.core.SymbolUtils import AnnotationContainsName -from lib.Projectrans.Utils import compute_sha1, _check_annotation_for_export, find_reachable_files_from_entries, topological_sort_files, parse_python_file -from lib.Projectrans.Phase1Generator import _TryGlobalCache, _SaveToGlobalCache, _GLOBAL_CACHE_DIR -from StubGen import PythonToStubConverter - - -def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object]) -> None: - """从 .pyi 文件中提取 CDefine 常量到 all_dc。文件不存在时静默跳过。""" - if not os.path.exists(pyi_path): - return - try: - # 复用 parse_python_file 的 AST 缓存(.pyi 文件被多处解析) - _, tree = parse_python_file(pyi_path) - if tree is None: - return - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - if AnnotationContainsName(node.annotation, 'CDefine') and node.value: - val = None - if isinstance(node.value, ast.Constant): - val = node.value.value - elif isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], ast.Constant): - val = node.value.args[0].value - if val is not None: - all_dc[f"{node.target.id}"] = val - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - - -def _parallel_translate_worker(src_path: str, out_path: str, src_root: str, temp_dir: str, output_dir: str, - include_dirs: list[str], triple: str | None, datalayout: str | None, - sha1_map: dict[str, str], sig_files: dict[str, str], - stub_files: dict[str, str], include_py_map: dict[str, str], slice_level: int, - shared_sym_pickle_path: str, struct_sha1_map: dict[str, str], - prebuilt_ModuleSha1Map: dict[str, str] | None = None) -> tuple[str, str, str]: - try: - trans = Phase2Translator(src_root, temp_dir, output_dir, - compile_cmd='llc', include_dirs=include_dirs, - target_triple=triple, target_datalayout=datalayout) - trans.sha1_map = sha1_map - trans.sig_files = sig_files - trans.stub_files = stub_files - trans.include_py_map = include_py_map - trans.slice_level = slice_level - trans.struct_sha1_map = struct_sha1_map - - if shared_sym_pickle_path and os.path.exists(shared_sym_pickle_path): - # 使用 pickle.load(f) 流式加载,避免 pickle.loads(f.read()) 一次性 - # 将整个 pickle 文件读入内存(磁盘副本 + 反序列化对象同时占用内存)导致 MemoryError。 - # 同时提高递归限制,防止深层嵌套对象反序列化失败。 - sys.setrecursionlimit(max(sys.getrecursionlimit(), 100000)) - with open(shared_sym_pickle_path, 'rb') as f: - shared_data = pickle.load(f) - trans._shared_symbol_table = shared_data['symbol_table'] - trans._shared_source_module_sig_files = shared_data['source_module_sig_files'] - trans._shared_all_dc = shared_data['all_dc'] - trans._shared_export_extern_funcs = shared_data['export_extern_funcs'] - trans.inline_func_symbols = shared_data['inline_func_symbols'] - trans.function_default_args = shared_data['function_default_args'] - trans.function_param_names = shared_data.get('function_param_names', {}) - trans._shared_generic_class_templates = shared_data.get('generic_class_templates', {}) - trans._shared_doc_meta = shared_data.get('shared_doc_meta', {}) - trans._shared_class_vtable = shared_data.get('class_vtable', set()) - trans._shared_cross_module_vtable = shared_data.get('cross_module_vtable', set()) - trans._shared_class_methods = shared_data.get('class_methods', {}) - trans._shared_cross_module_novtable = shared_data.get('cross_module_novtable', set()) - else: - trans._precollect_inline_symbols() - trans._build_shared_symbol_data() - - trans._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=prebuilt_ModuleSha1Map) - return ('ok', src_path, '') - except Exception as e: - return ('error', src_path, f'{e}\n{traceback.format_exc()}') - - -def _count_braces_outside_strings(text: str) -> int: - """统计花括号差值,跳过 c"..." 字符串字面量内部的括号""" - count = 0 - i = 0 - while i < len(text): - if text[i:i+2] == 'c"' and (i == 0 or text[i-1] != '\\'): - # 跳过 c"..." 字面量 - i += 2 - while i < len(text): - if text[i] == '"' and (i == 0 or text[i-1] != '\\'): - i += 1 - break - i += 1 - continue - if text[i] == '{': - count += 1 - elif text[i] == '}': - count -= 1 - i += 1 - return count - - -class Phase2Translator: - """阶段二:使用声明接口翻译源文件""" - - INCLUDE_LIB_EXTENSIONS: tuple[str, ...] = ('.dll', '.ll', '.so', '.o', '.a', '.lib') - INCLUDE_SRC_EXTENSIONS: tuple[str, ...] = ('.c', '.cpp', '.cc', '.cxx', '.m', '.mm') - INCLUDE_DIRS: list[str] = [ - os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'includes'), - ] - - def __init__(self, src_root: str, temp_dir: str, output_dir: str, compile_cmd: str = 'llc', compile_flags: list[str] | None = None, linker_cmd: str | None = None, linker_flags: list[str] | None = None, linker_output: str | None = None, include_dirs: list[str] | None = None, entry_files: list[str] | None = None, target_triple: str | None = None, target_datalayout: str | None = None, force_recompile_includes: bool = False) -> None: - self.src_root = os.path.abspath(src_root) - self.temp_dir = os.path.abspath(temp_dir) - self.output_dir = os.path.abspath(output_dir) - self.compile_cmd = compile_cmd - self.compile_flags = compile_flags or ['-filetype=obj'] - self.triple = target_triple - self.datalayout = target_datalayout - if not self.triple: - for i, flag in enumerate(self.compile_flags): - if flag.startswith('-mtriple='): - self.triple = flag[len('-mtriple='):] - elif flag == '-mtriple' and i + 1 < len(self.compile_flags): - self.triple = self.compile_flags[i + 1] - self.linker_cmd = linker_cmd - self.linker_flags = linker_flags or [] - self.linker_output = linker_output - self.slice_level = 3 - self.sha1_map: dict[str, str] = {} - self.sig_files: dict[str, str] = {} - self.stub_files: dict[str, str] = {} - self.include_py_map: dict[str, str] = {} - self.used_includes: set[str] = set() - self._last_ErrorStack: list | None = None - self.function_default_args: dict[str, list] = {} - self.function_param_names: dict[str, list] = {} - self.inline_func_symbols: dict[str, CTypeInfo] = {} - self.extra_link_files: list[str] = [] - self.extra_compile_files: list[str] = [] - self.extra_py_files: list[str] = [] - self._include_sha1s: set[str] = set() - # 持有 ProcessPoolExecutor 引用,避免局部变量 GC 时 finalizer 阻塞 ~99s - # (join_executor_internals 在 GC 时同步等待 worker 退出队列) - self._executor_pool: ProcessPoolExecutor | None = None - self.entry_files: list[str] | None = entry_files - self.force_recompile_includes: bool = force_recompile_includes - self._shared_symbol_table: object | None = None - self._shared_source_module_sig_files: dict[str, str] = {} - self._shared_all_dc: dict[str, dict] = {} - self._shared_export_extern_funcs: dict[str, str] = {} - self.include_dirs: list[str] = [] - self.struct_sha1_map: dict[str, str] = {} - self._shared_generic_class_templates: dict[str, dict] = {} - self._shared_doc_meta: dict[str, dict[str, str]] = {} - # 共享 vtable 状态跨模块(修复 pool.alloc(48) 虚表分派失败导致段错误) - self._shared_class_vtable: set[str] = set() - self._shared_cross_module_vtable: set[str] = set() - self._shared_class_methods: dict[str, list[str]] = {} - self._shared_cross_module_novtable: set[str] = set() - default_dirs = [d for d in self.INCLUDE_DIRS if os.path.isdir(d)] - if include_dirs: - seen = set() - self.include_dirs = [] - for d in list(include_dirs) + default_dirs: - d = os.path.abspath(d) - if d not in seen and os.path.isdir(d): - self.include_dirs.append(d) - seen.add(d) - else: - self.include_dirs = default_dirs - self._LoadSha1Map() - - def _LoadSha1Map(self) -> None: - """从 temp_dir 加载 SHA1 映射、签名文件和 stub 声明文件列表。 - temp_dir 中缺失的文件会从全局缓存补充。 - """ - if not os.path.exists(self.temp_dir): - _vlog().error(f"声明目录不存在: {self.temp_dir}") - return - - for fname in os.listdir(self.temp_dir): - fpath = os.path.join(self.temp_dir, fname) - if fname.startswith('_'): - continue - if fname.endswith('.pyi'): - sha1 = fname[:-4] - self.sig_files[sha1] = fpath - elif fname.endswith('.stub.ll'): - sha1 = fname[:-8] - self.stub_files[sha1] = fpath - - # 从全局缓存补充 temp_dir 中缺失的 .pyi / .stub.ll - if os.path.isdir(_GLOBAL_CACHE_DIR): - for fname in os.listdir(_GLOBAL_CACHE_DIR): - if fname.startswith('_'): - continue - if fname.endswith('.pyi'): - sha1 = fname[:-4] - if sha1 not in self.sig_files: - self.sig_files[sha1] = os.path.join(_GLOBAL_CACHE_DIR, fname) - elif fname.endswith('.stub.ll'): - sha1 = fname[:-8] - if sha1 not in self.stub_files: - self.stub_files[sha1] = os.path.join(_GLOBAL_CACHE_DIR, fname) - - sha1_file_path = os.path.join(self.temp_dir, '_sha1_map.txt') - if os.path.exists(sha1_file_path): - with open(sha1_file_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if ':' in line: - sha1, rel = line.split(':', 1) - self.sha1_map[sha1] = rel - if rel.startswith('includes/'): - module_name = os.path.splitext(os.path.basename(rel))[0] - self.include_py_map[module_name] = sha1 - else: - for sha1, stub_path in self.stub_files.items(): - self.sha1_map[sha1] = sha1 - - def _build_struct_sha1_map(self) -> dict[str, str]: - struct_sha1_map = {} - valid_sha1_keys = set(self.sha1_map.keys()) - # 收集 temp_dir 和全局缓存中的 .pyi 文件 - pyi_dirs: list[str] = [self.temp_dir] - if os.path.isdir(_GLOBAL_CACHE_DIR): - pyi_dirs.append(_GLOBAL_CACHE_DIR) - for scan_dir in pyi_dirs: - if not os.path.isdir(scan_dir): - continue - for fname in os.listdir(scan_dir): - if not fname.endswith('.pyi'): - continue - sha1_key = fname.replace('.pyi', '') - if sha1_key not in valid_sha1_keys: - continue - if sha1_key in struct_sha1_map: - continue - pyi_path = os.path.join(scan_dir, fname) - # 复用 parse_python_file 的 AST 缓存(.pyi 文件可能被多处解析) - _, tree = parse_python_file(pyi_path) - if tree is None: - continue - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - struct_sha1_map[node.name] = sha1_key - return struct_sha1_map - - def run(self) -> None: - """扫描源目录,翻译并生成 .ll 含代码文件(导入遍历)""" - import sys as _sys - if self.entry_files: - py_files = list(self.entry_files) - else: - main_py = os.path.join(self.src_root, 'main.py') - if os.path.exists(main_py): - py_files = [main_py] - else: - py_files = [] - for root, dirs, files in os.walk(self.src_root): - dirs[:] = [d for d in dirs if d not in ('__pycache__',)] - for file in files: - if file.endswith('.py'): - py_files.append(os.path.join(root, file)) - - if not py_files: - _vlog().info("未找到入口文件或源文件") - return - - reachable = find_reachable_files_from_entries(self.src_root, py_files) - py_files = list(reachable) - - py_files = topological_sort_files(py_files, self.src_root) - - _vlog().info(f"找到 {len(py_files)} 个可达源文件(已按依赖排序)") - _vlog().info("处理顺序:") - for i, f in enumerate(py_files[:10], 1): - rel = os.path.relpath(f, self.src_root) - _vlog().info(f" {i}. {rel}") - os.makedirs(self.output_dir, exist_ok=True) - - valid_sha1s = set(self.sha1_map.keys()) - old_stub_count = len(self.stub_files) - old_sig_count = len(self.sig_files) - self.stub_files = {k: v for k, v in self.stub_files.items() if k in valid_sha1s} - self.sig_files = {k: v for k, v in self.sig_files.items() if k in valid_sha1s} - if old_stub_count != len(self.stub_files) or old_sig_count != len(self.sig_files): - _vlog().info(f"过滤旧文件: stub {old_stub_count}->{len(self.stub_files)}, sig {old_sig_count}->{len(self.sig_files)}") - - active_sha1s = set() - self._precollect_inline_symbols() - self._build_shared_symbol_data() - self._precollect_vtable_state() - self.struct_sha1_map = self._build_struct_sha1_map() - - need_translate = [] - for i, src_path in enumerate(py_files, 1): - rel = os.path.relpath(src_path, self.src_root) - # 复用 parse_python_file 的 AST 缓存(get_file_dependencies 已 parse 过) - content, tree = parse_python_file(src_path) - sha1 = compute_sha1(content) - active_sha1s.add(sha1) - out_path = os.path.join(self.output_dir, f"{sha1}.ll") - - current_ModuleSha1Map = self._build_current_ModuleSha1Map(sha1) - - if tree is not None: - try: - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - self.used_includes.add(alias.name.split('.')[0]) - elif isinstance(node, ast.ImportFrom): - if node.module: - self.used_includes.add(node.module.split('.')[0]) - # 检测 list/dict 容器使用,自动添加 _list/_dict/json 到 used_includes - # 以便 _scan_include_libraries 能发现并编译这些库文件 - if isinstance(node, ast.Subscript) and isinstance(node.value, ast.Name): - if node.value.id == 'dict': - self.used_includes.add('_dict') - self.used_includes.add('json') - elif node.value.id == 'list': - self.used_includes.add('_list') - if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): - if node.func.id == 'dict': - self.used_includes.add('_dict') - self.used_includes.add('json') - elif node.func.id == 'list': - self.used_includes.add('_list') - # 检测类型注解 d: dict / l: list (非泛型形式) - if isinstance(node, ast.AnnAssign) and isinstance(node.annotation, ast.Name): - if node.annotation.id == 'dict': - self.used_includes.add('_dict') - self.used_includes.add('json') - elif node.annotation.id == 'list': - self.used_includes.add('_list') - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"收集源文件导入的 include 模块失败: {_e}", "Exception") - - if os.path.isfile(out_path): - deps_changed = self._check_deps_changed(sha1, current_ModuleSha1Map) - if not deps_changed: - _vlog().info(f"[{i}/{len(py_files)}] 跳过(缓存): {rel} -> {sha1}.ll") - continue - else: - if self._recombine_ll(sha1, current_ModuleSha1Map): - _vlog().info(f"[{i}/{len(py_files)}] 重组(依赖变化): {rel} -> {sha1}.ll") - continue - _vlog().info(f"[{i}/{len(py_files)}] 重译(依赖变化): {rel} -> {sha1}.ll") - - else: - stub_cache = os.path.join(self.output_dir, f"{sha1}.stub.ll") - text_cache = os.path.join(self.output_dir, f"{sha1}.text.ll") - if os.path.isfile(stub_cache) and os.path.isfile(text_cache): - if self._recombine_ll(sha1, current_ModuleSha1Map): - _vlog().info(f"[{i}/{len(py_files)}] 重组(缓存恢复): {rel} -> {sha1}.ll") - continue - - need_translate.append((i, src_path, out_path, sha1, current_ModuleSha1Map)) - - if need_translate: - # 提前从 include 文件源码中提取函数参数名,供主项目编译时 keyword 参数匹配使用 - self._extract_include_param_names_from_dirs() - # 提前从 App 源文件中提取函数默认参数,供跨模块调用参数检查使用 - # (避免并行编译时,被调用函数的文件尚未编译完,导致默认参数信息缺失) - self._extract_app_default_args(need_translate) - - _vlog().info(f"\n需要翻译 {len(need_translate)} 个文件") - t_start = time.time() - - n_workers = min(8, len(need_translate)) - - if n_workers > 1 and len(need_translate) > 1: - _vlog().info(f" 并行翻译 (workers={n_workers})") - - shared_pickle_path = os.path.join(self.temp_dir, '_shared_sym.json') - try: - shared_data = { - 'symbol_table': self._shared_symbol_table, - 'source_module_sig_files': self._shared_source_module_sig_files, - 'all_dc': self._shared_all_dc, - 'export_extern_funcs': self._shared_export_extern_funcs, - 'inline_func_symbols': self.inline_func_symbols, - 'function_default_args': self.function_default_args, - 'function_param_names': self.function_param_names, - 'generic_class_templates': self._shared_generic_class_templates, - 'shared_doc_meta': self._shared_doc_meta, - 'class_vtable': self._shared_class_vtable, - 'cross_module_vtable': self._shared_cross_module_vtable, - 'class_methods': self._shared_class_methods, - 'cross_module_novtable': self._shared_cross_module_novtable, - } - with open(shared_pickle_path, 'wb') as f: - f.write(pickle.dumps(shared_data)) - _vlog().info(f" 共享符号表已序列化 ({os.path.getsize(shared_pickle_path)//1024}KB)") - except Exception as e: - _vlog().warning(f"符号表序列化失败({e}),worker将自行构建") - shared_pickle_path = '' - - errors = [] - # 复用 self._executor_pool:避免局部变量 GC 时 finalizer 阻塞 ~99s - # (join_executor_internals 在 GC 时同步等待 worker 退出队列) - if self._executor_pool is None: - self._executor_pool = ProcessPoolExecutor(max_workers=n_workers) - executor = self._executor_pool - try: - futures = {} - for i, src_path, out_path, sha1, msm in need_translate: - rel = os.path.relpath(src_path, self.src_root) - future = executor.submit( - _parallel_translate_worker, - src_path, out_path, - self.src_root, self.temp_dir, self.output_dir, - self.include_dirs, self.triple, self.datalayout, - self.sha1_map, self.sig_files, self.stub_files, - self.include_py_map, self.slice_level, - shared_pickle_path, self.struct_sha1_map, - prebuilt_ModuleSha1Map=msm - ) - futures[future] = (i, rel) - - done_count = 0 - for future in as_completed(futures): - i, rel = futures[future] - done_count += 1 - try: - status, _, err = future.result() - if status == 'ok': - _vlog().info(f" [{done_count}/{len(need_translate)}] 完成: {rel}") - else: - _vlog().error(f" {rel}: {err}") - errors.append((rel, err)) - except Exception as e: - _vlog().error(f" {rel}: {e}") - errors.append((rel, str(e))) - except Exception: - # 异常时立即清理,正常流程不 shutdown(留给 includes 阶段复用) - if self._executor_pool is not None: - self._executor_pool.shutdown(wait=False, cancel_futures=True) - self._executor_pool = None - raise - - if errors: - _vlog().error(f"\n{len(errors)} 个文件翻译失败,继续编译 includes") - else: - for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate): - rel = os.path.relpath(src_path, self.src_root) - t0 = time.time() - try: - self._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=msm) - t1 = time.time() - _vlog().info(f" [{idx+1}/{len(need_translate)}] {rel} ({t1-t0:.1f}s)") - except Exception as e: - _vlog().error(f" {rel}: {e}") - traceback.print_exc() - t_end = time.time() - _vlog().info(f" 翻译总耗时: {t_end-t_start:.1f}s") - - _vlog().info(f"\n[阶段二完成] .ll 文件生成到: {self.output_dir}") - self._scan_include_libraries() - self._compile_include_py_files(active_sha1s) - self._compile_ll_files(active_sha1s) - self._compile_include_sources() - if self.linker_cmd: - self._link_obj_files(active_sha1s) - # 清理 ProcessPoolExecutor:所有翻译已完成,shutdown(wait=False) 让 worker - # 后台退出。避免 GC finalizer 在程序末尾阻塞 ~99s(join_executor_internals) - if self._executor_pool is not None: - self._executor_pool.shutdown(wait=False, cancel_futures=True) - self._executor_pool = None - - def _build_current_ModuleSha1Map(self, self_sha1: str | None) -> dict[str, str]: - """构建当前模块的依赖 SHA1 映射(与 _translate_file 中逻辑一致)""" - ModuleSha1Map = {} - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == self_sha1: - continue - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - inc_mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - inc_mod_name = inc_mod_name[len('includes/'):] - inc_short_name = inc_mod_name.split('.')[-1] if '.' in inc_mod_name else inc_mod_name - actual_sha1 = sha1_key - for inc_dir in self.include_dirs: - if os.path.isdir(inc_dir): - py_path = os.path.join(inc_dir, rel_path[len('includes/'):].replace(os.sep, '/')) - py_path = os.path.splitext(py_path)[0] + '.py' - if os.path.isfile(py_path): - with open(py_path, 'r', encoding='utf-8') as f: - py_sha1 = compute_sha1(f.read()) - actual_sha1 = py_sha1 - break - ModuleSha1Map[inc_mod_name] = actual_sha1 - ModuleSha1Map[inc_short_name] = actual_sha1 - # Also add parent package name (e.g., 'hashlib' for 'hashlib.__init__') - if inc_short_name == '__init__' and '.' in inc_mod_name: - parent_pkg = inc_mod_name.rsplit('.', 1)[0] - ModuleSha1Map[parent_pkg] = actual_sha1 - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - ModuleSha1Map[module_name] = sha1_key - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - ModuleSha1Map[short_name] = sha1_key - # 包入口文件:注册父包名(如 'os.__init__' -> 'os'),使 import os 能解析到包级符号 - if short_name == '__init__' and '.' in module_name: - parent_pkg = module_name.rsplit('.', 1)[0] - ModuleSha1Map[parent_pkg] = sha1_key - return ModuleSha1Map - - @staticmethod - def _extract_llvm_type_name(line: str) -> str | None: - """从 LLVM IR 类型定义行提取类型名(字符串操作,不使用正则) - - 支持 list[str]、dict[str, int] 等含特殊字符的类型名。 - 例如: - %"18e6990aa81cc5b6.list[str]" = type { ... } → "18e6990aa81cc5b6.list[str]" - %struct.foo = type { ... } → "struct.foo" - """ - stripped = line.strip() - if not stripped.startswith('%'): - return None - # 处理带引号的情况: %"name" = type ... - if stripped.startswith('%"'): - end_quote = stripped.find('"', 2) - if end_quote > 0: - return stripped[2:end_quote] - return None - # 处理不带引号的情况: %name = type ... - eq_pos = stripped.find('=') - if eq_pos > 1: - return stripped[1:eq_pos].strip() - return None - - @staticmethod - def _find_all_type_refs(text: str) -> set[str]: - """查找文本中所有 %"..."/%name 类型引用(字符串操作,不使用正则) - - 支持 list[str]、dict[str, int] 等含特殊字符的类型名。 - """ - refs: set[str] = set() - i: int = 0 - n: int = len(text) - while i < n: - if text[i] == '%': - if i + 1 < n and text[i + 1] == '"': - # 带引号: %"name" - end: int = text.find('"', i + 2) - if end > 0: - name: str = text[i + 2:end] - if name: - refs.add(name) - i = end + 1 - continue - else: - # 不带引号: %name (仅匹配字母、数字、下划线、点) - j: int = i + 1 - while j < n and (text[j].isalnum() or text[j] in '._'): - j += 1 - if j > i + 1: - refs.add(text[i + 1:j]) - i = j - continue - i += 1 - return refs - - @staticmethod - def _split_ll(ll_content: str) -> tuple[str, str]: - """将 .ll 内容拆分为 stub(声明)和 text(代码)两部分 - - stub: target, 注释, %type = type, declare, @xxx = external global - text: define ... { ... }, @xxx = global/constant (带初始化器) - """ - stub_lines = [] - text_lines = [] - in_define = False - brace_depth = 0 - module_sha1 = None - defined_names = set() - - for line in ll_content.splitlines(True): - stripped = line.strip() - - if stripped.startswith('define '): - dm = re.match(r'define\s+[^@]*@"?([a-f0-9]+)\.', stripped) - if dm and module_sha1 is None: - module_sha1 = dm.group(1) - dm2 = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm2: - defined_names.add(dm2.group(1)) - - in_global_def = False - global_var_name = None - global_type_parts = [] - global_brace_depth = 0 - - for line in ll_content.splitlines(True): - stripped = line.strip() - - if in_global_def: - text_lines.append(line) - global_type_parts.append(stripped) - global_brace_depth += _count_braces_outside_strings(stripped) - if global_brace_depth <= 0: - full_type = ' '.join(global_type_parts).strip() - depth = 0 - type_end = len(full_type) - for ci, cc in enumerate(full_type): - if cc in ('{', '['): - depth += 1 - elif cc in ('}', ']'): - depth -= 1 - elif depth == 0 and cc == ' ': - type_end = ci - break - var_type = full_type[:type_end].strip() - if var_type: - stub_lines.append(f'{global_var_name} = external global {var_type}\n') - in_global_def = False - global_var_name = None - global_type_parts = [] - global_brace_depth = 0 - continue - - if in_define: - text_lines.append(line) - brace_depth += _count_braces_outside_strings(stripped) - if brace_depth <= 0: - in_define = False - continue - - if stripped.startswith('define '): - text_lines.append(line) - in_define = True - brace_depth = _count_braces_outside_strings(stripped) - decl_line = re.sub(r'^define\s+', 'declare ', stripped) - decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) - decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) - paren_pos = decl_line.rfind(')') - if paren_pos >= 0: - decl_line = decl_line[:paren_pos + 1] - stub_lines.append(decl_line + '\n') - continue - - if stripped == '{' and text_lines and not in_define: - prev_stripped = text_lines[-1].strip() if text_lines else '' - if prev_stripped.startswith('define ') or prev_stripped.endswith('noredzone') or prev_stripped.endswith(')'): - text_lines.append(line) - brace_depth = 1 - in_define = True - if prev_stripped.startswith('define '): - decl_line = re.sub(r'^define\s+', 'declare ', prev_stripped) - decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) - decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) - paren_pos = decl_line.rfind(')') - if paren_pos >= 0: - decl_line = decl_line[:paren_pos + 1] - stub_lines.append(decl_line + '\n') - continue - - if stripped.startswith('@') and ' global ' in stripped and 'external global' not in stripped: - text_lines.append(line) - if ' internal ' not in stripped and ' private ' not in stripped: - name_match = re.match(r'(@\S+)', stripped) - if name_match: - var_name = name_match.group(1) - global_pos = stripped.find(' global ') - after_global = stripped[global_pos + 8:] - depth = 0 - type_end = len(after_global) - for ci, cc in enumerate(after_global): - if cc in ('{', '['): - depth += 1 - elif cc in ('}', ']'): - depth -= 1 - elif depth == 0 and cc == ' ': - type_end = ci - break - var_type = after_global[:type_end].strip() - brace_depth_gv = 0 - for cc in var_type: - if cc == '{': - brace_depth_gv += 1 - elif cc == '}': - brace_depth_gv -= 1 - if brace_depth_gv > 0: - in_global_def = True - global_var_name = var_name - global_type_parts = [var_type] - global_brace_depth = brace_depth_gv - elif var_type: - stub_lines.append(f'{var_name} = external global {var_type}\n') - continue - if stripped.startswith('@') and ' constant ' in stripped: - text_lines.append(line) - continue - - if stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - if fname in defined_names: - stub_lines.append(line) - continue - dot_pos = fname.find('.') - if dot_pos > 0: - fname_sha1 = fname[:dot_pos] - if module_sha1 and fname_sha1 != module_sha1 and len(fname_sha1) >= 16: - continue - if re.match(r'^[a-f0-9]{16}\.', fname): - continue - stub_lines.append(line) - continue - - stub_lines.append(line) - - return ''.join(stub_lines), ''.join(text_lines) - - def _save_deps(self, sha1: str, ModuleSha1Map: dict[str, str]) -> None: - """保存依赖指纹到 .deps.json""" - deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") - deps = {} - for mod_name, dep_sha1 in ModuleSha1Map.items(): - deps[mod_name] = dep_sha1 - with open(deps_path, 'w', encoding='utf-8') as f: - json.dump(deps, f) - - def _LoadDeps(self, sha1: str) -> dict[str, str] | None: - """加载依赖指纹""" - deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") - if os.path.isfile(deps_path): - try: - with open(deps_path, 'r', encoding='utf-8') as f: - return json.load(f) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"加载依赖指纹 JSON 失败: {_e}", "Exception") - return None - - def _check_deps_changed(self, sha1: str, current_ModuleSha1Map: dict[str, str]) -> bool: - """检查依赖指纹是否变化""" - saved_deps = self._LoadDeps(sha1) - if saved_deps is None: - return True - for mod_name, dep_sha1 in current_ModuleSha1Map.items(): - if saved_deps.get(mod_name) != dep_sha1: - return True - for mod_name, dep_sha1 in saved_deps.items(): - if current_ModuleSha1Map.get(mod_name) != dep_sha1: - return True - return False - - def _recombine_ll(self, sha1: str, current_ModuleSha1Map: dict[str, str]) -> bool: - """依赖变化时重新组合 .ll:更新 .stub.ll 中的 SHA1 前缀,拼接 .stub.ll + .text.ll""" - saved_deps = self._LoadDeps(sha1) - if saved_deps is None: - return False - - stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") - text_path = os.path.join(self.output_dir, f"{sha1}.text.ll") - ll_path = os.path.join(self.output_dir, f"{sha1}.ll") - - if not os.path.isfile(stub_path) or not os.path.isfile(text_path): - return False - - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - with open(text_path, 'r', encoding='utf-8') as f: - text_content = f.read() - - sha1_replacements = {} - for mod_name, old_sha1 in saved_deps.items(): - new_sha1 = current_ModuleSha1Map.get(mod_name) - if new_sha1 and old_sha1 != new_sha1: - sha1_replacements[old_sha1] = new_sha1 - - if sha1_replacements: - for old_sha1, new_sha1 in sha1_replacements.items(): - stub_content = stub_content.replace(old_sha1, new_sha1) - text_content = text_content.replace(old_sha1, new_sha1) - - combined = stub_content - if not combined.endswith('\n'): - combined += '\n' - combined += text_content - - with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(combined) - with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - with open(text_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(text_content) - - self._save_deps(sha1, current_ModuleSha1Map) - - obj_path = os.path.join(self.output_dir, f"{sha1}.obj") - if os.path.isfile(obj_path): - os.remove(obj_path) - - return True - - def _inject_auto_imports(self, code: str, src_path: str) -> str: - """检测源码中对 list/dict 容器的使用,自动注入 import _list / import _dict。 - 当使用 dict 时,同时注入 import json (用于 dict 的 JSON 处理功能)。 - - 检测模式: - - list[T] / dict[V] 作为类型注解 (ast.Subscript, value=Name(id='list'/'dict')) - - list[T](...) / dict[V](...) 作为构造函数调用 (ast.Call, func=Subscript) - - list(...) / dict(...) 作为构造函数调用 (ast.Call, func=Name) - """ - try: - tree = ast.parse(code) - except SyntaxError: - return code - - # 检查是否已经导入了 _list / _dict / json - has_list_import: bool = False - has_dict_import: bool = False - has_json_import: bool = False - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.Import): - for alias in node.names: - if alias.name == '_list': - has_list_import = True - elif alias.name == '_dict': - has_dict_import = True - elif alias.name == 'json': - has_json_import = True - elif isinstance(node, ast.ImportFrom): - if node.module == '_list': - has_list_import = True - elif node.module == '_dict': - has_dict_import = True - elif node.module == 'json': - has_json_import = True - if has_list_import and has_dict_import and has_json_import: - break - - # 检查是否使用了 list / dict 容器 - uses_list: bool = False - uses_dict: bool = False - for node in ast.walk(tree): - if isinstance(node, ast.Subscript): - if isinstance(node.value, ast.Name): - if node.value.id == 'list': - uses_list = True - elif node.value.id == 'dict': - uses_dict = True - if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): - if node.func.id == 'list': - uses_list = True - elif node.func.id == 'dict': - uses_dict = True - # 检测类型注解 d: dict / l: list (非泛型形式) - if isinstance(node, ast.AnnAssign) and isinstance(node.annotation, ast.Name): - if node.annotation.id == 'dict': - uses_dict = True - elif node.annotation.id == 'list': - uses_list = True - - # 注入 import 到源码开头 - prefix: str = '' - if uses_list and not has_list_import: - prefix += 'import _list\n' - if uses_dict and not has_dict_import: - prefix += 'import _dict\n' - if uses_dict and not has_json_import: - prefix += 'import json\n' - if prefix: - return prefix + code - return code - - def _translate_file(self, src_path: str, out_path: str, prebuilt_ModuleSha1Map: dict[str, str] | None = None) -> None: - """翻译单个源文件,嵌入相关 .stub.ll 声明""" - with open(src_path, 'r', encoding='utf-8') as f: - code = f.read() - - # SHA1 必须在自动导入注入之前计算,以保持与 Phase1 生成的文件名/函数名前缀一致 - sha1 = compute_sha1(code) - - # 自动导入: 检测 list 容器使用,自动注入 import _list - code = self._inject_auto_imports(code, src_path) - - if prebuilt_ModuleSha1Map is not None: - ModuleSha1Map = prebuilt_ModuleSha1Map - else: - ModuleSha1Map = self._build_current_ModuleSha1Map(sha1) - - import TransPyC as _TransPyC - trans = _TransPyC.TransPyC(code=code, triple=self.triple, datalayout=self.datalayout) - trans.translator.CurrentFile = src_path - trans.SliceLevel = self.slice_level - trans.translator.SliceLevel = self.slice_level - trans.translator.SliceCount = 0 - trans.translator.SliceInfos = [] - trans.translator.LlvmGen = None - trans.translator._module_sha1 = sha1 - trans.translator._ModuleSha1Map = ModuleSha1Map - trans.translator._struct_sha1_map = self.struct_sha1_map - trans.translator._global_function_default_args = self.function_default_args - trans.translator._global_function_param_names = self.function_param_names - trans.translator._temp_dir = self.temp_dir - trans.translator._shared_doc_meta = self._shared_doc_meta - # 传递共享 vtable 状态 - trans.translator._shared_class_vtable = self._shared_class_vtable - trans.translator._shared_cross_module_vtable = self._shared_cross_module_vtable - trans.translator._shared_class_methods = self._shared_class_methods - trans.translator._shared_cross_module_novtable = self._shared_cross_module_novtable - - if self._shared_symbol_table is not None: - trans.translator.SymbolTable = self._shared_symbol_table - # 确保共享符号表的 translator 指向当前 translator,以便 import 别名解析正确 - if hasattr(self._shared_symbol_table, 'translator'): - self._shared_symbol_table.translator = trans.translator - trans.translator._source_module_sig_files = self._shared_source_module_sig_files - trans.translator._all_define_constants = self._shared_all_dc - trans.translator._export_extern_funcs = self._shared_export_extern_funcs - if self._shared_generic_class_templates: - if not hasattr(trans.translator.ClassHandler, '_generic_class_templates'): - trans.translator.ClassHandler._generic_class_templates = {} - trans.translator.ClassHandler._generic_class_templates.update(self._shared_generic_class_templates) - else: - export_extern_funcs = {} - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == sha1: - continue - try: - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content = f.read() - sig_tree = ast.parse(sig_content) - for node in ast.iter_child_nodes(sig_tree): - if isinstance(node, ast.FunctionDef): - if _check_annotation_for_export(node.returns): - export_extern_funcs[node.name] = sha1_key - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"收集导出外部函数声明失败: {_e}", "Exception") - if export_extern_funcs: - trans.translator._export_extern_funcs = export_extern_funcs - - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - for pyi_file in os.listdir(includes_dir): - if pyi_file.endswith('.pyi'): - pyi_path = os.path.join(includes_dir, pyi_file) - module_name = os.path.splitext(pyi_file)[0] - trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) - for py_file in os.listdir(includes_dir): - if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'): - module_name = os.path.splitext(py_file)[0] - sha1_key = self.include_py_map.get(module_name) - if sha1_key and sha1_key in self.sig_files: - sig_path = self.sig_files[sha1_key] - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - # 收集需要重导出的包,等所有模块符号加载完后再处理 - _pending_reexports = [] - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - mod_name = mod_name[len('includes/'):] - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) - if mod_name.endswith('.__init__'): - package_name = mod_name[:-len('.__init__')] - _pending_reexports.append((sig_path, package_name)) - - # 所有 includes 模块符号已加载,现在处理包重导出 - for sig_path, package_name in _pending_reexports: - self._register_package_reexports(trans, sig_path, package_name) - - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == sha1: - continue - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - trans.translator._source_module_sig_files[module_name] = sig_path - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - if short_name != module_name: - trans.translator._source_module_sig_files[short_name] = sig_path - - all_dc = {} - for sha1_key, stub_path in self.stub_files.items(): - if sha1_key == sha1: - continue - if os.path.exists(stub_path): - try: - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - for line in stub_content.splitlines(): - line = line.strip() - if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): - var_name = line.split('=')[0].strip().lstrip('@') - val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') - try: - val = int(val_part) - all_dc[var_name] = val - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - for sha1_key, pyi_path in self.sig_files.items(): - if sha1_key == sha1: - continue - _ExtractCDefineConstantsFromPyi(pyi_path, all_dc) - if all_dc: - trans.translator._all_define_constants = all_dc - - for sym_name, sym_info in self.inline_func_symbols.items(): - if sym_name not in trans.translator.SymbolTable: - trans.translator.SymbolTable[sym_name] = sym_info - else: - existing = trans.translator.SymbolTable[sym_name] - if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): - existing.IsInline = sym_info.IsInline - existing.InlineBody = sym_info.InlineBody - existing.InlineParams = sym_info.InlineParams - - try: - result = trans.Convert( - OutputFilename=out_path, - SourceFilename=src_path, - target='llvm' - ) - except Exception as e: - error_stack = getattr(trans.translator, '_ErrorStack', []) - if error_stack: - self._last_ErrorStack = error_stack - chain_lines = [] - for entry in reversed(error_stack): - if len(entry) >= 3: - exc_msg, line_info = entry[1], entry[2] - chain_lines.append(" %s\n %s" % (line_info, exc_msg)) - if chain_lines: - enriched = str(e) + "\n" + "\n".join(chain_lines) - raise type(e)(enriched) from e - node_info = "" - if hasattr(trans.translator, 'LlvmGen') and trans.translator.LlvmGen: - node_info = trans.translator.LlvmGen._get_node_info() - if node_info: - enriched = "%s\n %s" % (str(e), node_info.strip()) - raise type(e)(enriched) from e - raise - - if result and isinstance(result, str): - for func_name, func_def in trans.translator.FunctionDefCache.items(): - if hasattr(func_def, 'args'): - mangled = trans.translator.LlvmGen._mangle_func_name(func_name) if trans.translator.LlvmGen else func_name - # 提取参数名 - if hasattr(func_def.args, 'args'): - param_names = [arg.arg for arg in func_def.args.args] - self.function_param_names[mangled] = param_names - self.function_param_names[func_name] = param_names - # 提取默认值 - if hasattr(func_def.args, 'defaults') and func_def.args.defaults: - defaults = [] - for d in func_def.args.defaults: - if isinstance(d, ast.Constant): - defaults.append(d.value) - else: - defaults.append(None) - self.function_default_args[mangled] = defaults - self.function_default_args[func_name] = defaults - for sym_name, sym_info in trans.translator.SymbolTable.items(): - if isinstance(sym_info, CTypeInfo) and getattr(sym_info, 'IsInline', False) and getattr(sym_info, 'InlineBody', None): - self.inline_func_symbols[sym_name] = sym_info - - out_dir = os.path.dirname(out_path) - if out_dir: - os.makedirs(out_dir, exist_ok=True) - # 修复 LLVM 22+: external global 不能有初值,改为 linkonce - result = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', result, flags=re.MULTILINE) - # 后处理:添加 llvmlite 不支持的 LLVM 属性(如 willreturn, mustprogress) - pending_str_attrs = getattr(trans.translator.LlvmGen, '_pending_str_attrs', None) - if pending_str_attrs: - for func_name, attrs in pending_str_attrs.items(): - attrs_str = ' '.join(attrs) - # 匹配 define ... @func_name(...) ... { 并在 { 之前添加属性 - pattern = rf'(define\s+[^@]*@{re.escape(func_name)}\s*\([^)]*\))([^{{]*)(\{{)' - result, n = re.subn(pattern, rf'\1\2 {attrs_str}\3', result, count=1) - if n == 0: - _vlog().warning(f"后处理添加属性失败: 未找到函数 {func_name} 的定义") - with open(out_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(result) - - stub_content, text_content = self._split_ll(result) - base = os.path.splitext(out_path)[0] - with open(base + '.stub.ll', 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - with open(base + '.text.ll', 'w', encoding='utf-8', newline='\n') as f: - f.write(text_content) - self._save_deps(sha1, ModuleSha1Map) - - _vlog().info(f" -> {os.path.basename(out_path)}") - else: - stub_path = self.stub_files.get(sha1) - if stub_path and os.path.exists(stub_path): - out_dir = os.path.dirname(out_path) - if out_dir: - os.makedirs(out_dir, exist_ok=True) - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - with open(out_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - _vlog().info(f" -> {os.path.basename(out_path)} (仅声明)") - - def _register_package_reexports(self, trans, init_pyi_path: str, package_name: str) -> None: - """解析 __init__.pyi 中的 from .xxx import yyy 或 from __xxx import yyy,在包级别注册导出符号""" - try: - # 复用 parse_python_file 的 AST 缓存 - _, tree = parse_python_file(init_pyi_path) - if tree is None: - return - for node in ast.walk(tree): - if isinstance(node, ast.ImportFrom) and node.module: - sub_module = node.module.lstrip('.') - for alias in node.names: - symbol_name = alias.name - exported_name = alias.asname if alias.asname else symbol_name - source_keys = [ - f"{package_name}.{sub_module}.{symbol_name}", - f"{package_name}.__{sub_module}.{symbol_name}" if not sub_module.startswith('__') else None, - symbol_name, - ] - target_key = f"{package_name}.{exported_name}" - if target_key not in trans.translator.SymbolTable: - for source_key in source_keys: - if source_key and source_key in trans.translator.SymbolTable: - trans.translator.SymbolTable[target_key] = trans.translator.SymbolTable[source_key] - break - if exported_name not in trans.translator.SymbolTable: - for source_key in source_keys: - if source_key and source_key in trans.translator.SymbolTable: - trans.translator.SymbolTable[exported_name] = trans.translator.SymbolTable[source_key] - break - except Exception as e: - _vlog().warning(f" [警告] 解析包重导出失败 {init_pyi_path}: {e}") - - def _compile_ll_files(self, active_sha1s: set[str]) -> None: - """将 output_dir 中属于 active_sha1s 的 .ll 文件编译为 .obj(跳过已编译过的 include 文件)""" - # 第一次 walk:清理 stale 文件(.obj/.deps.json/纯 .ll,排除 .stub.ll/.text.ll) - stale_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.obj'): - sha1 = file[:-4] - if sha1 not in active_sha1s: - stale_files.append(os.path.join(root, file)) - elif file.endswith('.deps.json'): - sha1 = file[:-10] - if sha1 not in active_sha1s: - stale_files.append(os.path.join(root, file)) - elif file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): - sha1 = file[:-3] - if sha1 not in active_sha1s: - stale_files.append(os.path.join(root, file)) - if stale_files: - for fpath in stale_files: - try: - os.remove(fpath) - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - _vlog().info(f"[清理] 删除 {len(stale_files)} 个过时文件") - - # 第二次 walk:收集需要编译的 .ll 文件(排除 .stub.ll/.text.ll) - ll_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): - sha1 = file[:-3] - if sha1 in active_sha1s: - fpath = os.path.join(root, file) - obj_path = os.path.join(root, file[:-3] + '.obj') - if not os.path.isfile(obj_path): - ll_files.append(fpath) - if not ll_files: - _vlog().info("[编译] 无 .ll 文件需要重新编译") - else: - _vlog().info(f"\n[编译] 找到 {len(ll_files)} 个 .ll 文件需要编译") - - # 第三次 walk:收集 all_ll_files(用于 alwaysinline 检测,排除 include sha1s) - all_ll_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): - sha1 = file[:-3] - if sha1 in active_sha1s and sha1 not in self._include_sha1s: - all_ll_files.append(os.path.join(root, file)) - - has_inline = False - for ll_path in all_ll_files: - try: - with open(ll_path, 'r', encoding='utf-8') as f: - content = f.read() - if 'alwaysinline' in content: - has_inline = True - break - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - - if has_inline: - llvm_link = shutil.which('llvm-link') or shutil.which('llvm-link.exe') - opt_cmd = shutil.which('opt') or shutil.which('opt.exe') - if llvm_link and opt_cmd: - _vlog().info(" [内联] 检测到 alwaysinline 函数,执行跨模块内联优化...") - for ll_path in all_ll_files: - try: - with open(ll_path, 'r', encoding='utf-8') as f: - content = f.read() - type_defs = [] - type_def_indices = set() - for i, line in enumerate(content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_defs.append(line) - type_def_indices.add(i) - if type_def_indices: - lines = content.splitlines(True) - content_no_types = ''.join(line for i, line in enumerate(lines) if i not in type_def_indices) - header_end = 0 - for i, line in enumerate(content_no_types.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - lines2 = content_no_types.splitlines(True) - fixed = ''.join(lines2[:header_end]) + '\n'.join(type_defs) + '\n' + ''.join(lines2[header_end:]) - with open(ll_path, 'w', encoding='utf-8') as f: - f.write(fixed) - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - merged_ll = os.path.join(self.output_dir, '_merged.ll') - optimized_ll = os.path.join(self.output_dir, '_merged_opt.ll') - try: - link_cmd = [llvm_link] + all_ll_files + ['-o', merged_ll] - result = subprocess.run(link_cmd, capture_output=True, text=True) - if result.returncode != 0: - _vlog().warning(f" llvm-link 失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - else: - opt_result_cmd = [opt_cmd, '-passes=always-inline', merged_ll, '-S', '-o', optimized_ll] - result = subprocess.run(opt_result_cmd, capture_output=True, text=True) - if result.returncode != 0: - _vlog().warning(f" opt 失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - else: - _vlog().info(" [内联] 跨模块内联优化完成") - with open(optimized_ll, 'r', encoding='utf-8') as f: - opt_content = f.read() - opt_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content, flags=re.MULTILINE) - opt_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content, flags=re.MULTILINE) - # LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义 - opt_content = re.sub(r'(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', opt_content, flags=re.MULTILINE) - opt_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content) - opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', opt_content) - with open(optimized_ll, 'w', encoding='utf-8') as f: - f.write(opt_content) - merged_obj = os.path.join(self.output_dir, '_merged.obj') - try: - cmd = [self.compile_cmd] + self.compile_flags + ['-o', merged_obj, optimized_ll] - result = subprocess.run(cmd, capture_output=True, text=True, - cwd=self.output_dir) - if result.returncode == 0: - _vlog().success(f" 合并模块编译完成") - for ll_path in ll_files: - obj_path = ll_path[:-3] + '.obj' - sha1_obj = os.path.join(self.output_dir, os.path.basename(ll_path)[:-3] + '.obj') - if os.path.isfile(sha1_obj): - os.remove(sha1_obj) - return - else: - _vlog().warning(f" 合并模块编译失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - except Exception as e: - _vlog().warning(f" 合并模块编译异常: {e},回退到单独编译") - has_inline = False - except FileNotFoundError: - _vlog().warning(f" 找不到 llvm-link 或 opt,回退到单独编译") - has_inline = False - else: - _vlog().warning(" 未找到 llvm-link/opt 工具,回退到单独编译(alwaysinline 可能不生效)") - - def _compile_one(ll_path: str) -> tuple[str, str, str]: - rel = os.path.relpath(ll_path, self.output_dir) - obj_path = ll_path[:-3] + '.obj' - if os.path.isfile(obj_path): - return (rel, 'cached', '') - try: - with open(ll_path, 'r', encoding='utf-8') as f: - ll_content = f.read() - sha1 = os.path.basename(ll_path)[:-3] - deps = self._LoadDeps(sha1) - stub_prefix = '' - if deps: - # 去重:同一个全局变量如果同时有 external 声明和实际定义, - # 移除 external 声明,避免 "redefinition of global" 错误 - # 注意:此去重必须在收集现有符号之前执行,否则行号偏移会导致 - # lines_to_remove 误删其他行(如全局变量定义) - ll_lines_for_dedup = ll_content.splitlines() - external_globals: dict[str, int] = {} - non_external_globals: dict[str, int] = {} - for i, line in enumerate(ll_lines_for_dedup): - stripped = line.strip() - if stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): - gm = re.match(r'(@\S+)', stripped) - if gm: - gname = gm.group(1) - is_external = re.match(r'@\S+\s*=\s*external\s+', stripped) is not None - if is_external: - external_globals[gname] = i - else: - non_external_globals[gname] = i - lines_to_remove_global_dedup: set[int] = set() - for gname in external_globals: - if gname in non_external_globals: - lines_to_remove_global_dedup.add(external_globals[gname]) - if lines_to_remove_global_dedup: - ll_content = '\n'.join( - line for i, line in enumerate(ll_lines_for_dedup) - if i not in lines_to_remove_global_dedup - ) + '\n' - existing_symbols: dict[str, str] = {} - opaque_line_indices: dict[str, int] = {} - existing_declares: set[str] = set() - existing_declare_lines: dict[str, set[int]] = {} - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - name = Phase2Translator._extract_llvm_type_name(stripped) - if name: - if '= type opaque' in stripped: - existing_symbols[name] = 'opaque' - opaque_line_indices[name] = i - else: - existing_symbols[name] = 'full' - elif stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - existing_declares.add(fname) - existing_declare_lines.setdefault(fname, set()).add(i) - seen_stub_sha1: set[str] = set() - replaced_opaque_names: set[str] = set() - replaced_declare_names: set[str] = set() - all_stub_lines: list[str | None] = [] - stub_type_map: dict[str, tuple[bool, int]] = {} - stub_declare_names: set[str] = set() - stub_declare_lines: dict[str, str] = {} - existing_defines: set[str] = set() - existing_global_defs: set[str] = set() - stub_global_defs: set[str] = set() - for line in ll_content.splitlines(): - stripped = line.strip() - if stripped.startswith('define'): - dm = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - existing_defines.add(dm.group(1)) - elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): - gm = re.match(r'(@\S+)', stripped) - if gm: - existing_global_defs.add(gm.group(1)) - for dep_name, dep_sha1 in deps.items(): - if dep_sha1 in seen_stub_sha1: - continue - seen_stub_sha1.add(dep_sha1) - stub_path = os.path.join(self.output_dir, f"{dep_sha1}.stub.ll") - if not os.path.isfile(stub_path): - stub_path = os.path.join(self.temp_dir, f"{dep_sha1}.stub.ll") - if os.path.isfile(stub_path): - with open(stub_path, 'r', encoding='utf-8') as sf: - stub_content = sf.read() - for line in stub_content.splitlines(): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - continue - if stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - if 'zdef_alloc' in fname: - _vlog().debug(f"[DEBUG] stub declare for {fname}: existing_declares={fname in existing_declares}, stub_declare_names={fname in stub_declare_names}, has_struct={'%' in stripped}, existing={existing_declare_lines.get(fname)}") - if fname in existing_defines: - continue - if fname in existing_declares or fname in stub_declare_names: - existing_decl_line = stub_declare_lines.get(fname) - if existing_decl_line is not None: - has_struct = '%' in stripped - existing_has_struct = '%' in existing_decl_line if existing_decl_line else False - if has_struct and not existing_has_struct: - for i, l in enumerate(all_stub_lines): - if l is not None and l.strip().startswith('declare'): - em = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', l.strip()) - if em and em.group(1) == fname: - all_stub_lines[i] = line - break - continue - elif fname in existing_declares: - has_struct = '%' in stripped - if has_struct: - replaced_declare_names.add(fname) - stub_declare_names.add(fname) - stub_declare_lines[fname] = line - all_stub_lines.append(line) - continue - continue - stub_declare_names.add(fname) - stub_declare_lines[fname] = line - all_stub_lines.append(line) - continue - if stripped.startswith('%') and '= type' in stripped: - name = Phase2Translator._extract_llvm_type_name(stripped) - if name: - is_opaque = '= type opaque' in stripped - if name in existing_symbols: - if existing_symbols[name] == 'opaque' and not is_opaque: - replaced_opaque_names.add(name) - existing_symbols[name] = 'full' - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - continue - if name in stub_type_map: - prev_opaque, prev_idx = stub_type_map[name] - if prev_opaque and not is_opaque: - all_stub_lines[prev_idx] = None - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - continue - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - else: - all_stub_lines.append(line) - elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): - gm = re.match(r'(@\S+)', stripped) - if gm and (gm.group(1) in existing_global_defs or gm.group(1) in stub_global_defs): - continue - if gm: - stub_global_defs.add(gm.group(1)) - all_stub_lines.append(line) - else: - all_stub_lines.append(line) - filtered = [l for l in all_stub_lines if l is not None] - if filtered: - stub_prefix = '\n'.join(filtered) + '\n' - lines_to_remove = set() - if replaced_opaque_names: - for name in replaced_opaque_names: - if name in opaque_line_indices: - lines_to_remove.add(opaque_line_indices[name]) - if replaced_declare_names: - _vlog().debug(f"[DEBUG] replaced_declare_names: {replaced_declare_names}") - for fname in replaced_declare_names: - if fname in existing_declare_lines: - lines_to_remove.update(existing_declare_lines[fname]) - _vlog().debug(f"[DEBUG] removing lines {existing_declare_lines[fname]} for {fname}") - else: - _vlog().debug(f"[DEBUG] fname {fname} not in existing_declare_lines: {list(existing_declare_lines.keys())}") - if lines_to_remove: - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in lines_to_remove) - type_defs_in_ll = [] - type_def_line_indices = set() - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_defs_in_ll.append(line) - type_def_line_indices.add(i) - if type_def_line_indices: - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in type_def_line_indices) - if type_defs_in_ll: - stub_prefix += '\n'.join(type_defs_in_ll) + '\n' - if stub_prefix: - header_end = 0 - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:]) - ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content, flags=re.MULTILINE) - # LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义 - ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE) - # LLVM 22+: 移除同一模块中已有 define 的 declare 语句(LLVM 22 将 declare+define 视为重复定义) - defined_funcs: set[str] = set() - for m in re.finditer(r'^define\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', ll_content, re.MULTILINE): - defined_funcs.add(m.group(1)) - if defined_funcs: - lines: list[str] = ll_content.splitlines(True) - kept_lines: list[str] = [] - for line in lines: - m = re.match(r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', line) - if m and m.group(1) in defined_funcs: - continue - kept_lines.append(line) - ll_content = ''.join(kept_lines) - # 移除重复的 declare 语句(同一函数多次 declare 但没有 define) - seen_declares: set[str] = set() - dedup_lines: list[str] = ll_content.splitlines(True) - dedup_kept: list[str] = [] - for line in dedup_lines: - dm = re.match(r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', line) - if dm: - fname = dm.group(1) - if fname in seen_declares: - continue - seen_declares.add(fname) - dedup_kept.append(line) - ll_content = ''.join(dedup_kept) - final_type_defs = [] - final_type_def_indices = set() - seen_type_names_main = set() - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_name_main = stripped.split('=')[0].strip() - final_type_def_indices.add(i) - if type_name_main in seen_type_names_main: - continue - seen_type_names_main.add(type_name_main) - final_type_defs.append(line) - if final_type_def_indices: - final_lines = ll_content.splitlines(True) - ll_content_no_types = ''.join(line for i, line in enumerate(final_lines) if i not in final_type_def_indices) - header_end = 0 - for i, line in enumerate(ll_content_no_types.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - final_lines2 = ll_content_no_types.splitlines(True) - ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:]) - dso_ll_path = ll_path[:-3] + '_dso.ll' - with open(dso_ll_path, 'w', encoding='utf-8') as f: - f.write(ll_content) - cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] - result = subprocess.run(cmd, capture_output=True, text=True, - cwd=os.path.dirname(ll_path) or '.') - if result.returncode == 0: - return (rel, 'ok', '') - else: - return (rel, 'error', result.stderr.strip()) - except FileNotFoundError: - return (rel, 'error', f'找不到编译器: {self.compile_cmd}') - except Exception as e: - return (rel, 'error', str(e)) - - need_compile = [] - for ll_path in ll_files: - obj_path = ll_path[:-3] + '.obj' - if not os.path.isfile(obj_path): - need_compile.append(ll_path) - - if need_compile: - n_workers = min(os.cpu_count() or 4, len(need_compile), 8) - _vlog().info(f" 并行编译 {len(need_compile)} 个文件 (workers={n_workers})") - errors = [] - with ThreadPoolExecutor(max_workers=n_workers) as executor: - futures = {executor.submit(_compile_one, ll_path): ll_path for ll_path in need_compile} - for future in as_completed(futures): - rel, status, err = future.result() - if status == 'ok': - _vlog().success(f" {rel}") - elif status == 'error': - _vlog().error(f" {rel}: {err}") - errors.append((rel, err)) - elif status == 'cached': - pass - if errors: - _vlog().error(f"\n{len(errors)} 个文件编译失败") - sys.exit(1) - - def _precollect_vtable_state(self) -> None: - """预扫描 includes .py 文件,收集 @t.CVTable 类的虚表信息。 - - 并行编译(ProcessPoolExecutor)创建独立内存的 worker 进程, - vtable 状态必须预收集并通过 pickle 共享。 - 复用 parse_python_file 的 AST 缓存。 - """ - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if not fname.endswith('.py'): - continue - py_path: str = os.path.join(root, fname) - code, tree = parse_python_file(py_path) - # 字符串预过滤:不含 CVTable 的文件跳过 AST 遍历 - if tree is None or 'CVTable' not in code: - continue - try: - for node in ast.iter_child_nodes(tree): - if not isinstance(node, ast.ClassDef): - continue - has_cvtable: bool = False - for dec in node.decorator_list: - if isinstance(dec, ast.Attribute): - if getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': - has_cvtable = True - elif isinstance(dec, ast.Name): - if dec.id == 'CVTable': - has_cvtable = True - if not has_cvtable: - continue - class_name: str = node.name - has_methods: bool = False - if class_name not in self._shared_class_methods: - self._shared_class_methods[class_name] = [] - for item in node.body: - if isinstance(item, ast.FunctionDef): - has_methods = True - method_name: str = item.name - # 构造函数不放入 vtable(避免子类与基类 vtable 大小不一致破坏多态分派) - if method_name in ('__new__', '__init__', '__before_init__'): - continue - if method_name == '__init__': - func_full_name: str = f"{class_name}.__init__" - elif method_name == '__call__': - func_full_name = f"{class_name}.__call__" - else: - func_full_name = f"{class_name}.{method_name}" - if func_full_name not in self._shared_class_methods[class_name]: - self._shared_class_methods[class_name].append(func_full_name) - if has_methods: - self._shared_class_vtable.add(class_name) - self._shared_cross_module_vtable.add(class_name) - except Exception: - pass - - def _build_include_py_index(self, includes_dir: str) -> set[str]: - """预扫描 includes 目录,构建所有 .py 文件路径集合 - - 用 set 查询替代 os.path.isfile,避免 3490 次磁盘 stat(83s→<0.1s)。 - 同时规范化路径为小写(Windows 不区分大小写)以加速查找。 - """ - py_index: set[str] = set() - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py'): - py_index.add(os.path.normcase(os.path.join(root, fname))) - return py_index - - def _scan_include_libraries(self) -> None: - """扫描 includes 目录,检测被使用的模块对应的库文件和源文件""" - if not self.used_includes: - return - - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - - # 预构建 .py 文件索引,避免递归发现时反复 os.path.isfile - py_index = self._build_include_py_index(includes_dir) - - for module_name in self.used_includes: - module_dir = os.path.join(includes_dir, module_name) - if os.path.isdir(module_dir): - self._scan_dir_for_libs(module_dir, module_name) - for root, dirs, files in os.walk(module_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py'): - py_path = os.path.join(root, fname) - if py_path not in self.extra_py_files: - self.extra_py_files.append(py_path) - _vlog().info(f" [includes] 发现 Python 包文件: {os.path.relpath(py_path, includes_dir)}") - - for ext in self.INCLUDE_LIB_EXTENSIONS: - lib_path = os.path.join(includes_dir, module_name + ext) - if os.path.isfile(lib_path): - self.extra_link_files.append(lib_path) - _vlog().info(f" [includes] 发现库文件: {os.path.relpath(lib_path, includes_dir)}") - - for ext in self.INCLUDE_SRC_EXTENSIONS: - src_path = os.path.join(includes_dir, module_name + ext) - if os.path.isfile(src_path): - self.extra_compile_files.append(src_path) - _vlog().info(f" [includes] 发现源文件: {os.path.relpath(src_path, includes_dir)}") - - py_path = os.path.join(includes_dir, module_name + '.py') - if os.path.normcase(py_path) in py_index: - self.extra_py_files.append(py_path) - _vlog().info(f" [includes] 发现 Python 源文件: {os.path.relpath(py_path, includes_dir)}") - - discovered = set() - for ef in list(self.extra_py_files): - self._discover_transitive_deps(ef, includes_dir, discovered, py_index) - - if self.extra_link_files: - _vlog().info(f"\n[includes] 需要链接的库文件: {len(self.extra_link_files)} 个") - if self.extra_compile_files: - _vlog().info(f"[includes] 需要编译的源文件: {len(self.extra_compile_files)} 个") - - def _scan_dir_for_libs(self, directory: str, module_name: str) -> None: - """递归扫描目录中的库文件和源文件""" - for root, dirs, files in os.walk(directory): - for fname in files: - fpath = os.path.join(root, fname) - _, ext = os.path.splitext(fname) - ext = ext.lower() - if ext in self.INCLUDE_LIB_EXTENSIONS: - self.extra_link_files.append(fpath) - _vlog().info(f" [includes] 发现库文件: {os.path.relpath(fpath, directory)}") - elif ext in self.INCLUDE_SRC_EXTENSIONS: - self.extra_compile_files.append(fpath) - _vlog().info(f" [includes] 发现源文件: {os.path.relpath(fpath, directory)}") - - def _discover_transitive_deps(self, py_path: str, includes_dir: str, discovered: set[str], py_index: set[str] | None = None) -> None: - """递归发现 Python 文件的间接依赖 - - 复用 parse_python_file 的 AST 缓存,避免重复 open+read+ast.parse。 - py_index 为预构建的 .py 文件路径集合,避免 os.path.isfile 磁盘 stat。 - """ - if py_path in discovered: - return - discovered.add(py_path) - _, tree = parse_python_file(py_path) - if tree is None: - return - try: - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - self._try_add_include_dep(alias.name, includes_dir, discovered, py_index) - elif isinstance(node, ast.ImportFrom): - if node.module and node.level == 0: - self._try_add_include_dep(node.module, includes_dir, discovered, py_index) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"发现 include 传递依赖失败: {_e}", "Exception") - - def _try_add_include_dep(self, module_name: str, includes_dir: str, discovered: set, py_index: set[str] | None = None): - """尝试将模块添加为 include 依赖(支持子包,如 w32.win32base) - - py_index 非空时用 set 查询替代 os.path.isfile(O(1) vs 24ms/次)。 - """ - # 候选路径:子包路径(w32/win32base.py)、顶层模块(w32.py)、子包 __init__.py - candidates: list[str] = [] - # 子包路径:w32.win32base → w32/win32base.py - candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep) + '.py')) - # 子包 __init__.py:w32.win32base → w32/win32base/__init__.py - candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep), '__init__.py')) - # 顶层模块:取第一个组件 → w32.py - top_module = module_name.split('.')[0] - if top_module != module_name: - candidates.append(os.path.join(includes_dir, top_module + '.py')) - - for py_path in candidates: - exists: bool - if py_index is not None: - exists = os.path.normcase(py_path) in py_index - else: - exists = os.path.isfile(py_path) - if exists and py_path not in self.extra_py_files: - self.extra_py_files.append(py_path) - _vlog().info(f" [includes] 发现间接依赖: {os.path.relpath(py_path, includes_dir)}") - self._discover_transitive_deps(py_path, includes_dir, discovered, py_index) - return # 找到第一个匹配即可 - - def _is_decl_only_file(self, src_path: str) -> bool: - """复用 parse_python_file 的 AST 缓存""" - _, tree = parse_python_file(src_path) - if tree is None: - return False - try: - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - return False - if isinstance(node, ast.FunctionDef): - body = node.body - if len(body) == 1: - stmt = body[0] - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Constant) and stmt.value.value is ...: - continue - if isinstance(stmt, ast.Pass): - continue - return False - return True - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"判断是否为声明文件失败: {_e}", "Exception") - return False - - def _sort_include_files_by_deps(self, file_list: list[str]) -> tuple[list[str], dict[str, set[str]]]: - """按依赖关系对 include 文件进行拓扑排序,确保被依赖的文件先编译。 - - 返回 (排序后的文件列表, 依赖字典)。 - 依赖字典: {fpath: set(依赖的fpath)},仅包含 file_list 中的依赖。 - """ - # 构建文件名到路径的映射 - name_to_path = {} - for fpath in file_list: - basename = os.path.splitext(os.path.basename(fpath))[0] - name_to_path[basename] = fpath - - # 也支持包内模块: vpsdk/window -> path - for fpath in file_list: - # 尝试从 includes 目录推断模块全名 - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(fpath, includes_dir) - mod_name = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - name_to_path[mod_name] = fpath - except ValueError: - pass - - # 分析每个文件的 import 依赖(复用 parse_python_file 的 AST 缓存) - deps = {} # path -> set of paths it depends on - for fpath in file_list: - deps[fpath] = set() - try: - _, tree = parse_python_file(fpath) - if tree is None: - continue - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.Import): - for alias in node.names: - # 尝试完整路径和各级前缀,确保同包内子模块依赖能被正确解析 - # 例如 import zlib.zhuff -> 应先匹配 zlib.zhuff,再回退到 zlib - parts = alias.name.split('.') - for i in range(len(parts), 0, -1): - mod = '.'.join(parts[:i]) - if mod in name_to_path and name_to_path[mod] != fpath: - deps[fpath].add(name_to_path[mod]) - break - elif isinstance(node, ast.ImportFrom): - if node.module and node.level == 0: - # 绝对导入:同样尝试完整路径和各级前缀 - parts = node.module.split('.') - for i in range(len(parts), 0, -1): - mod = '.'.join(parts[:i]) - if mod in name_to_path and name_to_path[mod] != fpath: - deps[fpath].add(name_to_path[mod]) - break - elif node.level > 0: - # 相对导入:from .xxx import yyy 或 from ..xxx import yyy - # 根据当前文件位置推断目标模块的完整路径 - current_dir = os.path.dirname(fpath) - # node.level == 1 表示当前包,node.level == 2 表示上一级包 - package_dir = current_dir - for _ in range(node.level - 1): - package_dir = os.path.dirname(package_dir) - # 推断当前包名(从 includes 目录的相对路径) - package_name: str | None = None - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(package_dir, includes_dir) - if rel and rel != '.': - package_name = rel.replace(os.sep, '.').replace('/', '.') - break - except ValueError: - pass - # 构建目标模块名并查找 - target_mod: str | None = None - if node.module: - target_mod = f"{package_name}.{node.module}" if package_name else node.module - else: - # from . import yyy:yyy 是子模块,在 names 中 - target_mod = package_name - if target_mod: - parts = target_mod.split('.') - for i in range(len(parts), 0, -1): - mod = '.'.join(parts[:i]) - if mod in name_to_path and name_to_path[mod] != fpath: - deps[fpath].add(name_to_path[mod]) - break - # from . import yyy:yyy 可能是子模块 - if node.level > 0 and not node.module: - for alias in node.names: - sub_mod = f"{package_name}.{alias.name}" if package_name else alias.name - if sub_mod in name_to_path and name_to_path[sub_mod] != fpath: - deps[fpath].add(name_to_path[sub_mod]) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"分析 include 文件导入依赖失败: {_e}", "Exception") - - # 拓扑排序 (Kahn's algorithm) - # in_degree 只计入 file_list 中的依赖——decl-only 文件(如 stdint.py) - # 不在 file_list 中,不应计入入度,否则依赖它们的文件入度永远不为 0, - # 被误判为循环依赖通过 fallback 添加,导致编译顺序错误。 - file_set = set(file_list) - in_degree = {fpath: sum(1 for dep in deps[fpath] if dep in file_set) for fpath in file_list} - # 反向邻接表:如果 A 依赖 B,则 B -> A - reverse_adj = {fpath: [] for fpath in file_list} - for fpath in file_list: - for dep in deps[fpath]: - if dep in reverse_adj: - reverse_adj[dep].append(fpath) - - result = [] - queue = [fpath for fpath in file_list if in_degree[fpath] == 0] - # 对队列排序以保持确定性 - queue.sort(key=lambda x: x) - - while queue: - current = queue.pop(0) - result.append(current) - for neighbor in reverse_adj[current]: - in_degree[neighbor] -= 1 - if in_degree[neighbor] == 0: - queue.append(neighbor) - queue.sort(key=lambda x: x) - - # 如果有循环依赖,把剩余文件也加入 - for fpath in file_list: - if fpath not in result: - result.append(fpath) - - # 仅保留 file_list 内的依赖(用于波次并行翻译) - file_set_result = set(file_list) - deps_in_set = {fpath: (deps[fpath] & file_set_result) for fpath in file_list} - return result, deps_in_set - - def _get_precompiled_obj_path(self, src_path: str, sha1: str) -> str | None: - """计算 include 文件在 includes.binary/ 中的预编译 .obj 路径。 - - 预编译目录位于 include 目录同级,命名为 {basename}.binary/。 - 文件命名为 {sha1}.{triple_safe}.{rel_model}.obj,区分目标平台和重定位模型。 - """ - AbsSrcPath: str = os.path.abspath(src_path) - RelModel: str = 'static' - for _flag in self.compile_flags: - if _flag.startswith('-relocation-model='): - RelModel = _flag[len('-relocation-model='):] - break - for inc_dir in self.include_dirs: - abs_inc: str = os.path.abspath(inc_dir) - try: - rel: str = os.path.relpath(AbsSrcPath, abs_inc) - if rel.startswith('..'): - continue - inc_parent: str = os.path.dirname(abs_inc) - inc_base: str = os.path.basename(abs_inc) - precompiled_dir: str = os.path.join(inc_parent, inc_base + '.binary') - triple_safe: str = (self.triple or 'default').replace(os.sep, '_').replace('/', '_').replace('\\', '_').replace(':', '_') - return os.path.join(precompiled_dir, f"{sha1}.{triple_safe}.{RelModel}.obj") - except ValueError: - continue - return None - - def _compile_include_py_files(self, active_sha1s: set[str]) -> None: - """通过 TransPyC 翻译器编译 includes 目录中发现的 .py 文件 - - 优化流程:预注册符号 → 并行翻译 → 串行后处理 → 并行编译 → 注册+缓存 - """ - if not self.extra_py_files: - return - - # 按依赖关系排序 include 文件,确保被依赖的文件先编译 - sorted_files, file_deps = self._sort_include_files_by_deps(self.extra_py_files) - _vlog().info(f"\n[includes 编译] 找到 {len(sorted_files)} 个 Python 源文件") - - # 构建 include 文件的模块 SHA1 映射(预计算所有文件,构建完整映射) - include_ModuleSha1Map = self._build_current_ModuleSha1Map(None) - need_translate = [] # [(src_path, sha1, module_name, ll_path, obj_path, precompiled_obj)] - for src_path in sorted_files: - module_name = os.path.splitext(os.path.basename(src_path))[0] - # 复用 parse_python_file 缓存的 content,避免重复 open+read - py_content, _ = parse_python_file(src_path) - sha1 = compute_sha1(py_content) - self.include_py_map[module_name] = sha1 - active_sha1s.add(sha1) - self._include_sha1s.add(sha1) - - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(src_path, includes_dir) - mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - include_ModuleSha1Map[mod_full] = sha1 - include_ModuleSha1Map[module_name] = sha1 - # 包入口文件:注册父包名(如 'os.__init__' -> 'os') - if module_name == '__init__' and '.' in mod_full: - parent_pkg = mod_full.rsplit('.', 1)[0] - include_ModuleSha1Map[parent_pkg] = sha1 - except ValueError: - pass - include_ModuleSha1Map[module_name] = sha1 - ll_path = os.path.join(self.output_dir, f"{sha1}.ll") - obj_path = os.path.join(self.output_dir, f"{sha1}.obj") - precompiled_obj = self._get_precompiled_obj_path(src_path, sha1) - - if self._is_decl_only_file(src_path): - _vlog().info(f" 跳过(声明文件): {module_name}.py") - # 声明文件(如 stdint.py)虽不编译为 .obj,但其 typedef/类型别名 - # 必须注册到共享符号表,否则依赖它的 include 文件编译时 - # 类型解析失败(如 UINT32PTR 被当作命名结构体而非 i32*) - self._register_compiled_include(src_path, sha1, None, include_ModuleSha1Map) - self._collect_inline_symbols(src_path) - continue - - # 优先检查 includes.binary 预编译缓存(跨项目共享) - if not self.force_recompile_includes and precompiled_obj and os.path.isfile(precompiled_obj): - _vlog().info(f" 跳过(预编译): {module_name}.py -> {os.path.basename(precompiled_obj)}") - # 预编译跳过的文件仍需注册 .pyi/.stub.ll 声明和符号, - # 否则依赖它的 include 文件(如 vpui.py import vpsdk.window) - # 在 _EmitModuleDeclarationsLlvm 中找不到声明,导致 Undefined symbol - self._register_compiled_include(src_path, sha1, None, include_ModuleSha1Map) - self._collect_inline_symbols(src_path) - self.extra_link_files.append(precompiled_obj) - continue - - if not self.force_recompile_includes and os.path.isfile(obj_path): - _vlog().info(f" 跳过(缓存): {module_name}.py -> {sha1}.obj") - self._register_compiled_include(src_path, sha1, None, include_ModuleSha1Map) - self._collect_inline_symbols(src_path) - self.extra_link_files.append(obj_path) - continue - - need_translate.append((src_path, sha1, module_name, ll_path, obj_path, precompiled_obj)) - - if not need_translate: - return - - # 预注册所有待翻译文件的符号(从 Phase1 缓存加载 .pyi / .stub.ll) - # 这样并行翻译时所有跨模块符号都已可用 - for src_path, sha1, module_name, ll_path, obj_path, precompiled_obj in need_translate: - self._register_compiled_include(src_path, sha1, None, include_ModuleSha1Map) - - # 预收集 stub_decls(所有文件共用,避免重复扫描 .stub.ll) - stub_decls = [] - for other_sha1, other_stub in self.stub_files.items(): - if os.path.exists(other_stub): - try: - with open(other_stub, 'r', encoding='utf-8') as sf: - for sline in sf: - sl = sline.strip() - if sl.startswith('%') and '= type' in sl and 'opaque' not in sl: - struct_name = Phase2Translator._extract_llvm_type_name(sl) - if struct_name: - stub_decls.append(sl) - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - all_type_defs = {} - for sdecl in stub_decls: - tname = Phase2Translator._extract_llvm_type_name(sdecl) - if tname: - all_type_defs[tname] = sdecl - - # ========== 阶段1:并行翻译 ========== - _vlog().info(f" 翻译 {len(need_translate)} 个文件") - if len(need_translate) > 1: - # 序列化共享符号表供 worker 使用 - shared_pickle_path = os.path.join(self.output_dir, '_shared_sym_includes.pickle') - try: - shared_data = { - 'symbol_table': self._shared_symbol_table, - 'source_module_sig_files': self._shared_source_module_sig_files, - 'all_dc': self._shared_all_dc, - 'export_extern_funcs': self._shared_export_extern_funcs, - 'inline_func_symbols': self.inline_func_symbols, - 'function_default_args': self.function_default_args, - 'function_param_names': self.function_param_names, - 'generic_class_templates': self._shared_generic_class_templates, - 'shared_doc_meta': self._shared_doc_meta, - 'class_vtable': self._shared_class_vtable, - 'cross_module_vtable': self._shared_cross_module_vtable, - 'class_methods': self._shared_class_methods, - 'cross_module_novtable': self._shared_cross_module_novtable, - } - with open(shared_pickle_path, 'wb') as f: - f.write(pickle.dumps(shared_data)) - except Exception as e: - _vlog().warning(f"符号表序列化失败({e}),include将串行翻译") - shared_pickle_path = '' - - if shared_pickle_path and os.path.exists(shared_pickle_path): - n_workers = min(8, len(need_translate)) - errors = [] - # 波次并行翻译:按依赖关系分批提交,确保被依赖的文件先翻译完成。 - # 根因:_TryLoadStructFromStub 扫描 output 目录加载跨模块 struct 定义, - # 若依赖文件尚未完成翻译(output stub 未写入),只能取到 Phase1 temp - # 中的不完整 stub(缺少跨模块继承字段),导致运行时崩溃。 - item_by_path = {item[0]: item for item in need_translate} - translate_paths = set(item_by_path.keys()) - # 每个文件的依赖(仅限本轮待翻译集合内) - translate_deps = { - p: (file_deps.get(p, set()) & translate_paths) - for p in translate_paths - } - # 复用 self._executor_pool(与 App 源文件阶段共享),避免 GC 阻塞 - if self._executor_pool is None: - self._executor_pool = ProcessPoolExecutor(max_workers=n_workers) - executor = self._executor_pool - try: - completed_paths: set[str] = set() - remaining = list(need_translate) # 保持拓扑序 - in_progress: dict = {} # future -> item - done_count = 0 - - while remaining or in_progress: - # 提交所有依赖已完成的文件 - ready = [ - item for item in remaining - if translate_deps[item[0]] <= completed_paths - ] - for item in ready: - remaining.remove(item) - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - future = executor.submit( - _parallel_translate_worker, - src_path, ll_path, - self.src_root, self.temp_dir, self.output_dir, - self.include_dirs, self.triple, self.datalayout, - self.sha1_map, self.sig_files, self.stub_files, - self.include_py_map, self.slice_level, - shared_pickle_path, self.struct_sha1_map, - include_ModuleSha1Map - ) - in_progress[future] = item - - if not in_progress: - # 无可提交且无进行中:循环依赖 fallback - for item in remaining: - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - future = executor.submit( - _parallel_translate_worker, - src_path, ll_path, - self.src_root, self.temp_dir, self.output_dir, - self.include_dirs, self.triple, self.datalayout, - self.sha1_map, self.sig_files, self.stub_files, - self.include_py_map, self.slice_level, - shared_pickle_path, self.struct_sha1_map, - include_ModuleSha1Map - ) - in_progress[future] = item - remaining.clear() - - # 等待至少一个完成 - done_set, _ = wait(in_progress, return_when=FIRST_COMPLETED) - for future in done_set: - item = in_progress.pop(future) - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - completed_paths.add(src_path) - done_count += 1 - try: - status, _, err = future.result() - if status == 'ok': - _vlog().info(f" [{done_count}/{len(need_translate)}] 翻译完成: {module_name}.py") - else: - _vlog().error(f" {module_name}.py: {err}") - errors.append((module_name, err)) - except Exception as e: - _vlog().error(f" {module_name}.py: {e}") - errors.append((module_name, str(e))) - except Exception: - if self._executor_pool is not None: - self._executor_pool.shutdown(wait=False, cancel_futures=True) - self._executor_pool = None - raise - - if errors: - _vlog().error(f"\n{len(errors)} 个 include 文件翻译失败") - sys.exit(1) - else: - # 串行回退 - for item in need_translate: - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - _vlog().info(f" 翻译: {module_name}.py -> {sha1}.ll") - self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map) - else: - item = need_translate[0] - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - _vlog().info(f" 翻译: {module_name}.py -> {sha1}.ll") - self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map) - - # ========== 阶段2:串行后处理(dso_local + stub_decls 注入)========== - compile_tasks = [] # [(dso_ll_path, obj_path, src_path, sha1, module_name, ll_path, precompiled_obj, ll_content)] - for item in need_translate: - src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item - if not os.path.isfile(ll_path): - _vlog().error(f" 翻译未生成 .ll 文件: {module_name}.py") - continue - - with open(ll_path, 'r', encoding='utf-8') as f: - ll_content = f.read() - - # dso_local 正则标注(使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare) - ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content, flags=re.MULTILINE) - # LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义 - ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE) - ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE) - - # stub_decls 注入(复用预收集的 stub_decls) - if stub_decls: - for sdecl in stub_decls: - sname = Phase2Translator._extract_llvm_type_name(sdecl) - if sname: - short = sname.split('.')[-1] if '.' in sname else sname - ll_content = re.sub( - r'%"?' + re.escape(sname) + r'"?\s*=\s*type\s*opaque', - sdecl, ll_content) - if short != sname: - ll_content = re.sub( - r'%"?' + re.escape(short) + r'"?\s*=\s*type\s*opaque', - sdecl, ll_content) - - max_iterations = 10 - for _ in range(max_iterations): - defined_types = set() - for line in ll_content.splitlines(): - sl = line.strip() - if sl.startswith('%') and '= type' in sl: - tname = Phase2Translator._extract_llvm_type_name(sl) - if tname: - defined_types.add(tname) - # 同时添加短名,防止 missing 循环因全名/短名不匹配而重复添加 - if '.' in tname: - parts = tname.split('.', 1) - if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]): - defined_types.add(parts[1]) - - referenced_types = Phase2Translator._find_all_type_refs(ll_content) - missing = referenced_types - defined_types - new_defs = [] - for tname in sorted(missing): - if tname in all_type_defs: - new_defs.append(all_type_defs[tname]) - else: - short_key = tname.split('.')[-1] if '.' in tname else tname - for full_name, defn in all_type_defs.items(): - if full_name.split('.')[-1] == short_key: - if short_key not in defined_types: - new_defs.append(defn) - break - else: - # 未在 stub 中找到定义(如泛型类 list[T]), - # 声明为 opaque 以满足 llc 的类型前向声明要求 - new_defs.append(f'%"{tname}" = type opaque') - - if not new_defs: - break - - inject_block = '\n'.join(new_defs) + '\n' - lines = ll_content.splitlines(True) - insert_pos = 0 - for i, line in enumerate(lines): - stripped = line.strip() - if stripped and not stripped.startswith(';') and not stripped.startswith('target ') and not stripped.startswith('source_filename') and not stripped.startswith('declare ') and not stripped.startswith('@') and not stripped.startswith('define ') and not stripped.startswith('attributes ') and not stripped.startswith('!') and not stripped.startswith('module '): - insert_pos = i - break - if insert_pos == 0: - insert_pos = len(lines) - ll_content = ''.join(lines[:insert_pos]) + inject_block + ''.join(lines[insert_pos:]) - - # 将所有类型定义移到 declares 之前 - # (llc 要求 by-value struct 参数的类型在 declare 前定义,否则报 invalid type for function argument) - lines = ll_content.splitlines(True) - type_def_lines = [] - other_lines = [] - seen_type_names_inc = set() - for line in lines: - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_name_inc = stripped.split('=')[0].strip() - if type_name_inc in seen_type_names_inc: - continue - seen_type_names_inc.add(type_name_inc) - type_def_lines.append(line) - else: - other_lines.append(line) - if type_def_lines: - insert_pos = 0 - for i, line in enumerate(other_lines): - stripped = line.strip() - if stripped and not stripped.startswith(';') and not stripped.startswith('target ') and not stripped.startswith('source_filename') and not stripped.startswith('!'): - insert_pos = i - break - if insert_pos == 0: - insert_pos = len(other_lines) - ll_content = ''.join(other_lines[:insert_pos]) + ''.join(type_def_lines) + ''.join(other_lines[insert_pos:]) - - dso_ll_path = ll_path[:-3] + '_dso.ll' - with open(dso_ll_path, 'w', encoding='utf-8') as f: - f.write(ll_content) - compile_tasks.append((dso_ll_path, obj_path, src_path, sha1, module_name, ll_path, precompiled_obj, ll_content)) - - if not compile_tasks: - return - - # ========== 阶段3:并行编译(llc)========== - _vlog().info(f" 编译 {len(compile_tasks)} 个 .ll 文件") - compile_results = {} # task -> result - - def _compile_one_include(task): - dso_ll_path, obj_path = task[0], task[1] - cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] - result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.output_dir) - return (task, result) - - if len(compile_tasks) > 1: - n_workers = min(8, len(compile_tasks)) - with ThreadPoolExecutor(max_workers=n_workers) as executor: - futures = {executor.submit(_compile_one_include, task): task for task in compile_tasks} - done_count = 0 - for future in as_completed(futures): - done_count += 1 - try: - task, result = future.result() - module_name = task[4] - if result.returncode == 0: - _vlog().success(f" [{done_count}/{len(compile_tasks)}] 编译成功: {module_name}.py") - else: - _vlog().warning(f" [{done_count}/{len(compile_tasks)}] 编译失败: {module_name}.py: {result.stderr.strip()}") - compile_results[task] = result - except Exception as e: - task = futures[future] - module_name = task[4] - _vlog().error(f" [{done_count}/{len(compile_tasks)}] 编译异常: {module_name}.py: {e}") - compile_results[task] = None - else: - task = compile_tasks[0] - task_result, result = _compile_one_include(task) - module_name = task[4] - if result.returncode == 0: - _vlog().success(f" 编译成功: {module_name}.py") - else: - _vlog().warning(f" 编译失败: {module_name}.py: {result.stderr.strip()}") - compile_results[task] = result - - # ========== 阶段4:注册 + 缓存 ========== - has_error = False - for task in compile_tasks: - dso_ll_path, obj_path, src_path, sha1, module_name, ll_path, precompiled_obj, ll_content = task - result = compile_results.get(task) - if result and result.returncode == 0: - self.extra_link_files.append(obj_path) - # 复制到 includes.binary 预编译目录 - if precompiled_obj: - precompiled_dir = os.path.dirname(precompiled_obj) - try: - if not os.path.exists(precompiled_dir): - os.makedirs(precompiled_dir, exist_ok=True) - shutil.copy2(obj_path, precompiled_obj) - except Exception as _e: - if _config_mode == "strict": - _vlog().warning(f"预编译缓存写入失败: {_e}") - # 注册符号 - self._register_compiled_include(src_path, sha1, ll_content, include_ModuleSha1Map) - # 清理临时文件(仅成功时清理,失败时保留以便调试) - # DEBUG: 保留 .ll 文件以便静态分析 - # for ext in ['.ll', '_dso.ll']: - # p = ll_path[:-3] + ext - # if os.path.isfile(p): - # os.remove(p) - else: - has_error = True - _vlog().warning(f" 保留失败文件以便调试: {ll_path}") - - if has_error: - _vlog().error(f"\nincludes 文件编译失败") - sys.exit(1) - - # 从 include 文件源码中提取函数参数名,供主项目编译时 keyword 参数匹配使用 - self._extract_include_param_names(sorted_files) - - def _extract_include_param_names_from_dirs(self) -> None: - """从 include 目录的 Python 源码中提取函数参数名,存入 function_param_names - - 优化:单次递归遍历 AST,维护当前类上下文,O(N) 复杂度。 - 复用 parse_python_file 的 AST 缓存。 - """ - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for filename in os.listdir(includes_dir): - if not filename.endswith('.py'): - continue - src_path = os.path.join(includes_dir, filename) - try: - source, tree = parse_python_file(src_path) - if tree is None: - continue - sha1 = compute_sha1(source) - self._collect_function_params(tree, sha1) - except Exception as e: - _vlog().warning(f" 提取参数名失败 {src_path}: {e}") - - def _collect_function_params(self, tree: ast.AST, sha1: str | None) -> None: - """单次递归遍历 AST 收集函数参数名(含类方法),O(N) 复杂度 - - 遍历时维护 current_class 上下文:遇到 ClassDef 进入类作用域, - 遇到 FunctionDef 记录参数名并标注所属类,函数内部的嵌套定义 - 不再属于外层类。 - """ - def visit(node: ast.AST, current_class: str | None) -> None: - for child in ast.iter_child_nodes(node): - if isinstance(child, ast.ClassDef): - # 进入类作用域,递归处理类体 - visit(child, child.name) - elif isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)): - func_name = child.name - param_names = [arg.arg for arg in child.args.args] - self.function_param_names[func_name] = param_names - if sha1: - self.function_param_names[f'{sha1}.{func_name}'] = param_names - if current_class: - self.function_param_names[f'{current_class}.{func_name}'] = param_names - if sha1: - self.function_param_names[f'{sha1}.{current_class}.{func_name}'] = param_names - # 函数内部的嵌套定义不属于外层类 - visit(child, None) - else: - visit(child, current_class) - visit(tree, None) - - def _extract_app_default_args(self, need_translate: list) -> None: - """从 App 源文件中提取函数默认参数,存入 function_default_args - - 在 Phase 2 并行编译开始前调用,确保跨模块调用参数检查能正确识别默认参数。 - need_translate 中每个元素是 (i, src_path, out_path, sha1, current_ModuleSha1Map) - 复用 parse_python_file 的 AST 缓存(run() 循环已 parse 过)。 - """ - for entry in need_translate: - src_path = entry[1] - sha1 = entry[3] - _, tree = parse_python_file(src_path) - if tree is None: - continue - try: - for node in ast.walk(tree): - if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): - func_name = node.name - defaults = getattr(node.args, 'defaults', []) - if defaults: - default_vals = [] - for d in defaults: - if isinstance(d, ast.Constant): - default_vals.append(d.value) - else: - default_vals.append(None) - # 存储多种键格式,确保跨模块调用检查能找到 - self.function_default_args[func_name] = default_vals - self.function_default_args[f'{sha1}.{func_name}'] = default_vals - # 也更新参数名(预扫描时补充) - param_names = [arg.arg for arg in node.args.args] - if func_name not in self.function_param_names: - self.function_param_names[func_name] = param_names - if f'{sha1}.{func_name}' not in self.function_param_names: - self.function_param_names[f'{sha1}.{func_name}'] = param_names - except Exception as e: - _vlog().warning(f" 提取默认参数失败 {src_path}: {e}") - - def _extract_include_param_names(self, sorted_files: list[str]) -> None: - """从 include 文件的 Python 源码中提取函数参数名,存入 function_param_names - - 优化:复用 _collect_function_params 的 O(N) 单次遍历 + parse_python_file 缓存。 - """ - for src_path in sorted_files: - if self._is_decl_only_file(src_path): - continue - try: - _, tree = parse_python_file(src_path) - if tree is None: - continue - module_name = os.path.splitext(os.path.basename(src_path))[0] - sha1 = self.include_py_map.get(module_name) - self._collect_function_params(tree, sha1) - except Exception as e: - _vlog().warning(f" 提取参数名失败 {src_path}: {e}") - - def _register_compiled_include(self, src_path: str, sha1: str, ll_content: str, include_ModuleSha1Map: dict[str, str]) -> None: - """编译 include 文件成功后,生成签名和 stub 文件并注册到符号表中""" - module_name = os.path.splitext(os.path.basename(src_path))[0] - - # 确定完整模块名(如 vpsdk.window) - mod_full = module_name - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(src_path, includes_dir) - mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - break - except ValueError: - pass - - # 1. 生成 .pyi 签名文件(如果还没有的话) - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - if not os.path.isfile(sig_path): - # 全局缓存检查(不被 --clean 清除) - _TryGlobalCache(sha1, 'pyi', sig_path) - if not os.path.isfile(sig_path): - try: - with open(src_path, 'r', encoding='utf-8') as f: - py_content = f.read() - sig_content = PythonToStubConverter.convert(py_content, mod_full) - os.makedirs(self.temp_dir, exist_ok=True) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - _SaveToGlobalCache(sha1, 'pyi', sig_path) - except Exception as e: - if _config_mode == "strict": - raise - _vlog().warning(f"签名生成失败不阻塞编译: {e}", "Exception") - - # 注册到 sig_files 和 _source_module_sig_files - if os.path.isfile(sig_path): - self.sig_files[sha1] = sig_path - self.sha1_map[sha1] = f"includes/{mod_full.replace('.', os.sep)}.py" - if self._shared_source_module_sig_files is not None: - self._shared_source_module_sig_files[mod_full] = sig_path - self._shared_source_module_sig_files[module_name] = sig_path - - # 将签名信息加载到共享符号表中 - if self._shared_symbol_table is not None: - try: - self._shared_symbol_table.LoadModuleSymbols(sig_path, mod_full, lineno=0) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"加载模块签名到共享符号表失败: {_e}", "Exception") - - # 2. 生成 .stub.ll 文件 - stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") - if not os.path.isfile(stub_path): - # 全局缓存检查(不被 --clean 清除) - _TryGlobalCache(sha1, 'stub.ll', stub_path) - if not os.path.isfile(stub_path) and ll_content: - try: - stub_content, _ = self._split_ll(ll_content) - with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - _SaveToGlobalCache(sha1, 'stub.ll', stub_path) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"生成 .stub.ll 文件失败: {_e}", "Exception") - - # 注册到 stub_files - if os.path.isfile(stub_path): - self.stub_files[sha1] = stub_path - elif os.path.isfile(sig_path): - # 如果 stub 文件不存在,也尝试从 temp 目录查找 - temp_stub = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(temp_stub): - self.stub_files[sha1] = temp_stub - else: - # 最后尝试从全局缓存直接读取 - _TryGlobalCache(sha1, 'stub.ll', temp_stub) - if os.path.isfile(temp_stub): - self.stub_files[sha1] = temp_stub - - def _precollect_inline_symbols(self) -> None: - """在主翻译循环之前,扫描includes目录中used_includes相关的模块收集内联函数AST""" - if not self.used_includes: - return - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for module_name in self.used_includes: - module_dir = os.path.join(includes_dir, module_name) - if os.path.isdir(module_dir): - for root, dirs, files in os.walk(module_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py'): - src_path = os.path.join(root, fname) - self._collect_inline_symbols(src_path) - py_path = os.path.join(includes_dir, module_name + '.py') - if os.path.isfile(py_path): - self._collect_inline_symbols(py_path) - for ef in self.extra_py_files: - self._collect_inline_symbols(ef) - - def _collect_inline_symbols(self, src_path: str): - """解析源文件,收集内联函数的AST信息到inline_func_symbols - - 复用 parse_python_file 的 AST 缓存,避免重复 open+read+ast.parse。 - """ - try: - _, tree = parse_python_file(src_path) - if tree is None: - return - module_name = os.path.splitext(os.path.basename(src_path))[0] - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.FunctionDef) and node.returns: - is_inline = False - if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr): - for part in [node.returns.left, node.returns.right]: - if isinstance(part, ast.Attribute) and part.attr == 'CInline': - is_inline = True - break - if isinstance(part, ast.Name) and part.id == 'CInline': - is_inline = True - break - elif isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline': - is_inline = True - elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline': - is_inline = True - if is_inline: - func_name = node.name - sym_key = f"{module_name}.{func_name}" - info = CTypeInfo() - info.Name = func_name - info.IsFunction = True - info.IsInline = True - info.InlineBody = node.body - info.InlineParams = [arg.arg for arg in node.args.args] - info.Storage = t.CInline() - self.inline_func_symbols[func_name] = info - self.inline_func_symbols[sym_key] = info - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"预收集内联函数符号失败: {_e}", "Exception") - - def _build_shared_symbol_data(self) -> None: - """一次性构建所有文件共享的符号表数据,避免每个文件重复加载""" - t0 = time.time() - - _vlog().info("[缓存] 构建共享符号表数据...") - - import TransPyC as _TransPyC - base_trans = _TransPyC.TransPyC(code="pass", triple=self.triple, datalayout=self.datalayout) - base_trans.translator.LlvmGen = None - base_trans.translator._ModuleSha1Map = {} - base_trans.translator._global_function_default_args = self.function_default_args - base_trans.translator._global_function_param_names = self.function_param_names - - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - for pyi_file in os.listdir(includes_dir): - if pyi_file.endswith('.pyi'): - pyi_path = os.path.join(includes_dir, pyi_file) - module_name = os.path.splitext(pyi_file)[0] - base_trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) - for py_file in os.listdir(includes_dir): - if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'): - module_name = os.path.splitext(py_file)[0] - sha1_key = self.include_py_map.get(module_name) - if sha1_key and sha1_key in self.sig_files: - sig_path = self.sig_files[sha1_key] - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - # 收集需要重导出的包,等所有模块符号加载完后再处理 - _pending_reexports = [] - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - mod_name = mod_name[len('includes/'):] - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) - if mod_name.endswith('.__init__'): - package_name = mod_name[:-len('.__init__')] - _pending_reexports.append((sig_path, package_name)) - - # 所有 includes 模块符号已加载,现在处理包重导出 - for sig_path, package_name in _pending_reexports: - self._register_package_reexports(base_trans, sig_path, package_name) - - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - base_trans.translator._source_module_sig_files[module_name] = sig_path - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - if short_name != module_name: - base_trans.translator._source_module_sig_files[short_name] = sig_path - - all_dc = {} - for sha1_key, stub_path in self.stub_files.items(): - if os.path.exists(stub_path): - try: - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - for line in stub_content.splitlines(): - line = line.strip() - if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): - var_name = line.split('=')[0].strip().lstrip('@') - val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') - try: - val = int(val_part) - all_dc[var_name] = val - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - except Exception as e: - _vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e) - - for sha1_key, pyi_path in self.sig_files.items(): - _ExtractCDefineConstantsFromPyi(pyi_path, all_dc) - - export_extern_funcs = {} - for sha1_key, sig_path in self.sig_files.items(): - try: - # 复用 parse_python_file 的 AST 缓存(sig 文件被多处解析) - _, sig_tree = parse_python_file(sig_path) - if sig_tree is None: - continue - for node in ast.iter_child_nodes(sig_tree): - if isinstance(node, ast.FunctionDef): - if _check_annotation_for_export(node.returns): - export_extern_funcs[node.name] = sha1_key - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"收集共享导出外部函数失败: {_e}", "Exception") - - for sym_name, sym_info in self.inline_func_symbols.items(): - if sym_name not in base_trans.translator.SymbolTable: - base_trans.translator.SymbolTable[sym_name] = sym_info - else: - existing = base_trans.translator.SymbolTable[sym_name] - if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): - existing.IsInline = sym_info.IsInline - existing.InlineBody = sym_info.InlineBody - existing.InlineParams = sym_info.InlineParams - - self._shared_symbol_table = base_trans.translator.SymbolTable - self._shared_source_module_sig_files = dict(base_trans.translator._source_module_sig_files) - self._shared_all_dc = all_dc - self._shared_export_extern_funcs = export_extern_funcs - - generic_class_templates = {} - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - abs_includes = os.path.join(self.src_root, includes_dir) if not os.path.isabs(includes_dir) else includes_dir - if not os.path.isdir(abs_includes): - abs_includes = includes_dir - for py_file in os.listdir(abs_includes): - if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'): - py_path = os.path.join(abs_includes, py_file) - try: - # 复用 parse_python_file 的 AST 缓存 - _, py_tree = parse_python_file(py_path) - if py_tree is None: - continue - for node in py_tree.body: - if isinstance(node, ast.ClassDef) and hasattr(node, 'type_params') and node.type_params: - type_params = [tp.name for tp in node.type_params] - generic_class_templates[node.name] = { - 'node': node, - 'type_params': type_params, - } - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"收集泛型类模板失败: {_e}", "Exception") - self._shared_generic_class_templates = generic_class_templates - - # 加载所有 {sha1}.doc.json 到 _shared_doc_meta,供跨模块 __doc__ 查询 - shared_doc_meta: dict[str, dict[str, str]] = {} - if os.path.isdir(self.temp_dir): - for fname in os.listdir(self.temp_dir): - if fname.endswith('.doc.json'): - sha1_key = fname[:-len('.doc.json')] - try: - with open(os.path.join(self.temp_dir, fname), 'r', encoding='utf-8') as f: - data = json.load(f) - if isinstance(data, dict): - shared_doc_meta[sha1_key] = {str(k): str(v) for k, v in data.items()} - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"加载 {fname} 失败: {_e}", "Exception") - # 也从全局缓存加载 .doc.json(temp_dir 被 --clean 清空时补充) - if os.path.isdir(_GLOBAL_CACHE_DIR): - for fname in os.listdir(_GLOBAL_CACHE_DIR): - if fname.endswith('.doc.json'): - sha1_key = fname[:-len('.doc.json')] - if sha1_key in shared_doc_meta: - continue - try: - with open(os.path.join(_GLOBAL_CACHE_DIR, fname), 'r', encoding='utf-8') as f: - data = json.load(f) - if isinstance(data, dict): - shared_doc_meta[sha1_key] = {str(k): str(v) for k, v in data.items()} - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"加载全局缓存 {fname} 失败: {_e}", "Exception") - self._shared_doc_meta = shared_doc_meta - - t1 = time.time() - _vlog().info(f"[缓存] 共享符号表构建完成 ({t1-t0:.2f}s, {len(self._shared_symbol_table)} 符号, {len(generic_class_templates)} 泛型模板, {len(shared_doc_meta)} doc 元数据)") - - def _compile_include_sources(self): - """扫描项目目录中的汇编存根,编译 includes 目录中发现的 C/C++ 源文件""" - extra_sources = list(self.extra_compile_files) - scan_dirs = [] - if self.src_root and os.path.isdir(self.src_root): - scan_dirs.append(self.src_root) - project_dir = os.path.dirname(self.output_dir) - if project_dir and os.path.isdir(project_dir) and project_dir not in scan_dirs: - scan_dirs.append(project_dir) - for scan_dir in scan_dirs: - for root, dirs, files in os.walk(scan_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith(('.S', '.s', '.c', '.cpp')): - if fname.startswith('test_'): - continue - fpath = os.path.join(root, fname) - if fpath not in extra_sources: - extra_sources.append(fpath) - if not extra_sources: - return - - cc_map = { - '.c': 'gcc', - '.cpp': 'g++', '.cc': 'g++', '.cxx': 'g++', - '.m': 'clang', '.mm': 'clang++', - '.s': 'gcc', '.S': 'gcc', - } - - _vlog().info(f"\n[includes 编译] 找到 {len(extra_sources)} 个源文件") - - for src_path in extra_sources: - _, ext = os.path.splitext(src_path) - ext = ext.lower() - obj_path = os.path.join(self.output_dir, os.path.splitext(os.path.basename(src_path))[0] + '.obj') - if ext in ('.s', '.S') and any('oformat' in f for f in self.linker_flags): - cc = 'clang' - compile_src = src_path - extra_flags = ['-c', '-target', 'x86_64-none-elf', '-o', obj_path, compile_src] - else: - cc = cc_map.get(ext, 'gcc') - extra_flags = ['-c', '-o', obj_path, src_path] - - _vlog().info(f" 编译: {os.path.basename(src_path)} -> {os.path.basename(obj_path)}") - - try: - cmd = [cc] + extra_flags - result = subprocess.run(cmd, capture_output=True, text=True) - if result.returncode == 0: - _vlog().success(" 编译成功") - self.extra_link_files.append(obj_path) - else: - _vlog().error(f" 编译失败: {result.stderr.strip()}") - _vlog().error(f"\nC/C++ 源文件编译失败,立即终止编译。") - sys.exit(1) - except FileNotFoundError: - _vlog().error(f" 找不到编译器: {cc}") - _vlog().error(f"\n找不到编译器,立即终止编译。") - sys.exit(1) - except Exception as e: - _vlog().error(f" {e}") - _vlog().error(f"\n编译异常,立即终止编译。") - sys.exit(1) - - def _strip_debug_sections(self, exe_path: str) -> None: - """剥离 .exe 中的调试段(跳过裸机二进制)""" - if not os.path.exists(exe_path): - return - ext = os.path.splitext(exe_path)[1].lower() - if ext not in ('.exe', '.dll', '.obj', '.o', '.elf'): - _vlog().info(f" [剥离] 跳过({ext} 格式无需剥离)") - return - for tool in ['llvm-strip', 'strip']: - strip_cmd = shutil.which(tool) - if strip_cmd: - try: - result = subprocess.run( - [strip_cmd, '--strip-debug', exe_path], - capture_output=True, text=True - ) - if result.returncode == 0: - _vlog().info(f" [剥离] 调试段已移除 ({tool})") - else: - _vlog().warning(f" [剥离] 警告: {result.stderr.strip()}") - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"剥离可执行文件调试段失败: {_e}", "Exception") - break - - def _link_obj_files(self, active_sha1s: set[str]) -> None: - """将 active_sha1s 对应的 .obj 文件和 includes 库文件链接为可执行文件""" - obj_files = [] - merged_obj = os.path.join(self.output_dir, '_merged.obj') - if os.path.isfile(merged_obj): - obj_files.append(merged_obj) - else: - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.obj'): - sha1 = file[:-4] - if sha1 in active_sha1s and sha1 not in self._include_sha1s: - obj_files.append(os.path.join(root, file)) - - if not obj_files and not self.extra_link_files: - _vlog().info("[链接] 无文件可链接") - return - - _vlog().info(f"\n[链接] 找到 {len(obj_files)} 个 .obj 文件") - - all_link_files = obj_files + self.extra_link_files - seen = set() - all_link_files = [f for f in all_link_files if not (f in seen or seen.add(f))] - if self.extra_link_files: - _vlog().info(f"[链接] 额外库文件: {len(self.extra_link_files)} 个") - for lib in self.extra_link_files: - _vlog().info(f" - {os.path.basename(lib)}") - - if not self.linker_cmd: - _vlog().info("[链接] 未配置链接器") - return - - exe_path = os.path.join(self.output_dir, self.linker_output) if self.linker_output else os.path.join(self.output_dir, 'a.exe') - is_binary = self.linker_output and self.linker_output.endswith('.bin') - - # 检查是否直接输出二进制(使用 --oformat binary / -oformat binary 标志) - is_direct_binary = is_binary and any('oformat' in f for f in self.linker_flags) - - if is_binary and not is_direct_binary: - link_output = exe_path[:-4] + '_pe.exe' - else: - link_output = exe_path - - # 自动复制或生成 linker.ld 到输出目录 - linker_ld_src = os.path.join(os.path.dirname(self.output_dir), 'linker.ld') - linker_ld_dst = os.path.join(self.output_dir, 'linker.ld') - if os.path.isfile(linker_ld_src) and not os.path.isfile(linker_ld_dst): - shutil.copy2(linker_ld_src, linker_ld_dst) - _vlog().info(f" [链接] 使用链接脚本: linker.ld") - elif not os.path.isfile(linker_ld_dst) and any('-T' in f or '-T' in f.replace(',', ' ') for f in self.linker_flags): - default_ld = """ENTRY(_start) - -SECTIONS { - . = 0x100000; - - .text : { - *(.text) - *(.text.*) - } - - .rodata : { - *(.rodata) - *(.rodata.*) - } - - .data : { - *(.data) - *(.data.*) - } - - .bss : { - *(.bss) - *(.bss.*) - } - - /DISCARD/ : { - *(.comment) - *(.note) - *(.eh_frame) - *(.eh_frame_hdr) - *(.reloc) - *(.rela) - *(.debug*) - } -} -""" - with open(linker_ld_dst, 'w', encoding='utf-8', newline='\n') as f: - f.write(default_ld) - _vlog().info(f" [链接] 自动创建默认链接脚本: linker.ld") - - try: - # 将 linker_flags 拆分为非库标志和库标志(-l/-L),库标志放在目标文件之后 - # 这样 Unix 风格链接器才能正确解析库中的符号 - # -Wl, 选项是链接器全局选项,放在目标文件之前 - non_lib_flags = [] - lib_flags = [] - i = 0 - while i < len(self.linker_flags): - flag = self.linker_flags[i] - if flag in ('-l', '-L') and i + 1 < len(self.linker_flags): - # -l xxx / -L xxx 分开的形式 - lib_flags.extend([flag, self.linker_flags[i + 1]]) - i += 2 - elif flag.startswith('-l') or flag.startswith('-L'): - # -lxxx / -Lxxx 合并的形式 - lib_flags.append(flag) - i += 1 - else: - # 其他所有标志(包括 -Wl, 选项)放在目标文件之前 - non_lib_flags.append(flag) - i += 1 - cmd = [self.linker_cmd] + non_lib_flags + ['-o', link_output] + all_link_files + lib_flags - _vlog().info(f" 执行: {' '.join(cmd)}") - result = subprocess.run( - cmd, - capture_output=True, - text=True, - cwd=self.output_dir or '.' - ) - if result.returncode == 0: - if is_binary and not is_direct_binary: - objcopy = shutil.which('llvm-objcopy') or shutil.which('objcopy') - if objcopy: - conv = subprocess.run( - [objcopy, '-O', 'binary', link_output, exe_path], - capture_output=True, text=True - ) - if conv.returncode == 0: - os.remove(link_output) - _vlog().success(f" 生成裸机二进制: {exe_path}") - file_size = os.path.getsize(exe_path) - _vlog().info(f" [大小] {file_size} 字节") - else: - _vlog().error(f" 二进制转换失败: {conv.stderr.strip()}") - sys.exit(1) - else: - _vlog().error(" 找不到 llvm-objcopy,无法生成裸机二进制") - sys.exit(1) - else: - _vlog().success(f" 生成: {exe_path}") - file_size = os.path.getsize(exe_path) - _vlog().info(f" [大小] {file_size} 字节") - if not is_binary: - self._strip_debug_sections(exe_path) - else: - _vlog().error(f" 链接失败: {result.stderr.strip()}") - _vlog().error(f"\n链接失败,立即终止编译。") - sys.exit(1) - except FileNotFoundError: - _vlog().error(f" 找不到链接器: {self.linker_cmd}") - _vlog().error(f"\n找不到链接器,立即终止编译。") - sys.exit(1) - except Exception as e: - _vlog().error(f" {e}") - _vlog().error(f"\n链接异常,立即终止编译。") - sys.exit(1) diff --git a/App/lib/Shell/Config.py b/App/lib/Shell/Config.py deleted file mode 100644 index 5bfcfc7..0000000 --- a/App/lib/Shell/Config.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import annotations - - -class Config: - """配置类""" - def __init__(self) -> None: - self.debug: bool = False - self.mode: str = 'relaxed' # 'relaxed' 或 'strict' diff --git a/App/lib/Shell/Serializer.py b/App/lib/Shell/Serializer.py deleted file mode 100644 index f87409e..0000000 --- a/App/lib/Shell/Serializer.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import json -import struct -from typing import Any - - -def SerializeSymbolTable(SymbolTable: dict[str, Any]) -> bytes: - """将符号表序列化为二进制格式 - - 格式: - - 4字节: JSON数据长度(小端序) - - N字节: JSON数据(UTF-8编码) - - Args: - SymbolTable: 符号表字典 - - Returns: - 二进制字节数据 - """ - JsonData: bytes = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8') - length: int = len(JsonData) - # 使用4字节小端序整数表示长度 - header: bytes = struct.pack(' dict[str, Any]: - """从二进制数据反序列化符号表 - - Args: - data: 二进制字节数据 - - Returns: - 符号表字典 - """ - if len(data) < 4: - raise ValueError("Invalid symbin file: data too short") - # 解析4字节长度头(小端序) - length: int = struct.unpack(' None: - """初始化SymbolFile对象 - - Args: - file: 文件路径 - string: 代码字符串 - type: 文件类型,支持"c"或"py" - encoding: 文件编码 - """ - self.FilePath: str | None = file - self.CodeString: str | None = string - self.FileType: str | None = type - self.encoding: str = encoding - self.symbols: dict[str, Any] = {} diff --git a/App/lib/Shell/TransPyC.py b/App/lib/Shell/TransPyC.py deleted file mode 100644 index 2aa92e7..0000000 --- a/App/lib/Shell/TransPyC.py +++ /dev/null @@ -1,645 +0,0 @@ -from __future__ import annotations - -import sys -import os -import ast -import shlex -import datetime -import tempfile -import subprocess -from typing import Any -from lib.includes import c -from lib.includes import t -from lib.constants.config import ( - DEFAULT_INPUT_FILE, DEFAULT_OUTPUT_FILE, - DEFAULT_COMPILE_COMMAND, - DEFAULT_COMPILE_FLAGS, - HELP_MESSAGE, DEFAULT_METADATA -) -from lib.utils.helpers import ( - DetectFileType, ExecuteCommand, - AppendFileContent -) -from lib.core.VLogger import info, warning, error, success, debug -from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.Shell.Serializer import SerializeSymbolTable, SymbolFile -from lib.Shell.Config import Config - - -class TransPyC: - """TransPyC 主类""" - - def __init__(self, code: str | None = None, debug: bool = False, triple: str | None = None, datalayout: str | None = None) -> None: - """初始化TransPyC对象 - - Args: - code: 代码字符串 - debug: 调试模式 - triple: LLVM target triple (e.g. "x86_64-pc-linux-gnu") - datalayout: LLVM data layout string - """ - self.Args: dict[str, Any] = {} - self.HeaderFiles: list[str] = [] - self.HelperFiles: list[str] = [] - self.AnnotationFiles: list[str] = [] - self.translator: Translator = Translator() - self.code: str | None = code - self.translator.Content = code - self.config: Config = Config() - self.translator.config = self.config - self.config.debug = debug - self.SymbolFiles: list[SymbolFile] = [] - self.SliceLevel: int | str = 3 - self.SliceCount: int = 0 - self.SliceInfos: list[Any] = [] - self.metadata: dict[str, Any] = DEFAULT_METADATA.copy() - self.triple: str | None = triple - self.datalayout: str | None = datalayout - self._source_module_sig_files: dict[str, Any] = {} - - @staticmethod - def PreProcessSymbol(SymbolFile: SymbolFile, debug: bool = False) -> bytes | tuple[bytes, str]: - """预处理符号文件,提取符号表并返回二进制数据 - - Args: - SymbolFile: SymbolFile对象,包含文件路径和类型信息 - debug: 是否启用调试模式,如果为True,返回 (bytes, DebugInfo) - 对于Python文件,DebugInfo包含p2c日志 - 对于C文件,DebugInfo包含基本处理信息 - - Returns: - 如果debug为False: bytes - 序列化后的符号表二进制数据 - 如果debug为True: (bytes, str) - (二进制数据, 调试日志) - """ - translator: Translator = Translator() - DebugLogs: list[str] | str = [] - - try: - # 读取文件内容 - if SymbolFile.FilePath: - with open(SymbolFile.FilePath, 'r', encoding=SymbolFile.encoding) as f: - content: str = f.read() - elif SymbolFile.CodeString: - content = SymbolFile.CodeString - else: - raise ValueError("SymbolFile must have either FilePath or CodeString") - - # 根据文件类型处理 - FileType: str | None = SymbolFile.FileType - if not FileType and SymbolFile.FilePath: - # 从文件路径推断类型 - if SymbolFile.FilePath.endswith('.py'): - FileType = 'py' - elif SymbolFile.FilePath.endswith('.c') or SymbolFile.FilePath.endswith('.h'): - FileType = 'c' - - if FileType == 'py': - # Python文件处理 - translator.OriginalLines = content.split('\n') - translator.Content = content - - # 设置调试文件(如果需要) - if debug: - DebugFile: str = SymbolFile.FilePath.replace('.py', '.p2c') if SymbolFile.FilePath else 'debug.p2c' - translator.SetDebugFile(DebugFile) - # 清空调试文件 - with open(DebugFile, 'w', encoding=SymbolFile.encoding) as f: - f.write('') - - # 解析AST并提取符号 - tree: ast.Module = ast.parse(content) - - if debug: - with open(DebugFile, 'a', encoding=SymbolFile.encoding) as f: - f.write('=== AST Tree (Compact) ===\n') - f.write(ast.dump(tree)) - f.write('\n\n') - - # 遍历AST提取符号 - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.ClassDef): - translator.SymbolTable[node.name] = {'type': 'struct', 'members': {}} - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - VarName: str = item.target.id - TypeInfo: CTypeInfo | None = translator.TypeMergeHandler.GetCTypeInfo(item.annotation) if item.annotation else None - VarType: str = TypeInfo.ToString() if TypeInfo else 'unknown' - IsPtr: bool = TypeInfo.IsPtr if TypeInfo else False - translator.SymbolTable[node.name]['members'][VarName] = { - 'type': VarType, - 'IsPtr': IsPtr - } - elif isinstance(node, ast.FunctionDef): - translator.SymbolTable[node.name] = {'type': 'function'} - elif isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name): - VarName: str = node.target.id - VarType: str = 'unknown' - IsPtr: bool = False - if node.annotation: - try: - TypeInfo: CTypeInfo | None = translator.TypeMergeHandler.GetCTypeInfo(node.annotation) - VarType = TypeInfo.ToString() if TypeInfo else 'unknown' - IsPtr = TypeInfo.IsPtr if TypeInfo else False - except: - pass - translator.SymbolTable[VarName] = { - 'type': 'variable', - 'declared_type': VarType, - 'IsPtr': IsPtr - } - - if debug: - with open(DebugFile, 'a', encoding=SymbolFile.encoding) as f: - f.write('=== Symbol Table ===\n') - f.write(str(translator.SymbolTable)) - f.write('\n\n') - # 读取调试日志 - with open(DebugFile, 'r', encoding=SymbolFile.encoding) as f: - DebugLogs = f.read() - - elif FileType == 'c': - # C文件处理 - 使用现有的ParseHelperFiles逻辑 - translator.ParseHelperFiles([SymbolFile.FilePath], SymbolFile.encoding) - - if debug: - DebugLogs = f"=== C File Symbol Extraction ===\n" - DebugLogs += f"File: {SymbolFile.FilePath}\n" - DebugLogs += f"=== Symbol Table ===\n" - DebugLogs += str(translator.SymbolTable) - DebugLogs += "\n\n" - else: - raise ValueError(f"Unsupported file type: {FileType}") - - # 序列化符号表 - BinaryData: bytes = SerializeSymbolTable(translator.SymbolTable) - - if debug: - return BinaryData, DebugLogs - return BinaryData - - except Exception as e: - error_msg: str = f"Error processing symbol file: {e}" - if debug: - return b'', error_msg - raise RuntimeError(error_msg) - - def ParseArgs(self) -> None: - """解析命令行参数""" - I: int = 1 - while I < len(sys.argv): - if sys.argv[I] == '-f': - if I + 1 < len(sys.argv): - self.Args['Input'] = sys.argv[I + 1] - I += 2 - else: - error('-f requires an argument') - sys.exit(1) - elif sys.argv[I] == '-o': - if I + 1 < len(sys.argv): - self.Args['Output'] = sys.argv[I + 1] - I += 2 - else: - error('-o requires an argument') - sys.exit(1) - elif sys.argv[I] == '-wh': - if I + 1 < len(sys.argv): - self.HeaderFiles = sys.argv[I + 1:] - break - else: - error('-wh requires arguments') - sys.exit(1) - elif sys.argv[I] == '-debug': - if I + 1 < len(sys.argv): - self.Args['Debug'] = sys.argv[I + 1] - I += 2 - else: - error('-debug requires an argument') - sys.exit(1) - elif sys.argv[I] == '-cc': - # 编译命令 - if I + 1 < len(sys.argv): - self.Args['CompileCommand'] = sys.argv[I + 1] - I += 2 - else: - error('-cc requires an argument') - sys.exit(1) - elif sys.argv[I] == '-cflags': - # 编译标志 - if I + 1 < len(sys.argv): - self.Args['CompileFlags'] = sys.argv[I + 1] - I += 2 - else: - error('-cflags requires an argument') - sys.exit(1) - elif sys.argv[I] == '-run': - # 是否运行生成的程序 - self.Args['Run'] = True - I += 1 - elif sys.argv[I] == '-args': - # 运行时参数 - if I + 1 < len(sys.argv): - self.Args['RunArgs'] = sys.argv[I + 1] - I += 2 - else: - error('-args requires an argument') - sys.exit(1) - elif sys.argv[I] == '-level' or sys.argv[I] == '-l': - if I + 1 < len(sys.argv): - LevelArg: str = sys.argv[I + 1] - if LevelArg.isdigit(): - self.Args['SliceLevel'] = int(LevelArg) - elif LevelArg == 's': - self.Args['SliceLevel'] = 's' - else: - self.Args['SliceLevel'] = 3 - I += 1 - else: - self.Args['SliceLevel'] = 3 - elif sys.argv[I] == '-h': - # 辅助文件,用于解析符号信息 - if I + 1 < len(sys.argv): - # 收集所有后续参数作为辅助文件,直到遇到下一个以-开头的参数 - while I + 1 < len(sys.argv) and not sys.argv[I + 1].startswith('-'): - self.HelperFiles.append(sys.argv[I + 1]) - I += 1 - I += 1 - else: - error('-h requires arguments') - sys.exit(1) - elif sys.argv[I] == '-presym': - # 预处理符号文件,生成.symbin文件 - # 格式: -presym -o [-debug ] - if I + 1 < len(sys.argv): - InputFile: str = sys.argv[I + 1] - I += 2 - - # 解析可选参数 - OutputFile: str | None = None - DebugFile: str | None = None - while I < len(sys.argv) and sys.argv[I].startswith('-'): - if sys.argv[I] == '-o': - if I + 1 < len(sys.argv): - OutputFile = sys.argv[I + 1] - I += 2 - else: - error('-o requires an argument') - sys.exit(1) - elif sys.argv[I] == '-debug': - if I + 1 < len(sys.argv): - DebugFile = sys.argv[I + 1] - I += 2 - else: - error('-debug requires an argument') - sys.exit(1) - else: - break - - # 如果没有指定输出文件,使用默认名称 - if not OutputFile: - OutputFile = InputFile.replace('.py', '.symbin').replace('.c', '.symbin') - - # 执行预处理 - self.Args['PreSym'] = { - 'input': InputFile, - 'output': OutputFile, - 'debug': DebugFile - } - else: - error('-presym requires an argument') - sys.exit(1) - elif sys.argv[I] == '-e' or sys.argv[I] == '--encoding': - if I + 1 < len(sys.argv): - self.Args['Encoding'] = sys.argv[I + 1] - I += 2 - else: - error('-e/--encoding requires an argument') - sys.exit(1) - elif sys.argv[I] == '--triple': - if I + 1 < len(sys.argv): - self.triple = sys.argv[I + 1] - I += 2 - else: - error('--triple requires an argument') - sys.exit(1) - elif sys.argv[I] == '--datalayout': - if I + 1 < len(sys.argv): - self.datalayout = sys.argv[I + 1] - I += 2 - else: - error('--datalayout requires an argument') - sys.exit(1) - else: - error(f'Unknown argument {sys.argv[I]}') - sys.exit(1) - - # 检查是否有预处理符号文件的请求,如果有则跳过输入输出检查 - if 'PreSym' not in self.Args and ('Input' not in self.Args or 'Output' not in self.Args): - error('缺少参数') - info(HELP_MESSAGE) - sys.exit(1) - - def CompileAndRun(self, OutputFile: str) -> None: - """编译并运行生成的C代码""" - # 获取编译命令 - CompileCmd: str = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND) - CompileFlags: str = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS) - - # 构建编译命令(使用列表形式,避免 shell 注入) - FullCompileCmd: list[str] = shlex.split(CompileCmd) + shlex.split(CompileFlags) + [OutputFile, '-o', f'{OutputFile}.exe'] - info(f'编译命令: {" ".join(FullCompileCmd)}') - - # 执行编译命令 - try: - CompileResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(FullCompileCmd) - if CompileResult: - success('编译成功!') - - # 检查是否需要运行 - if self.Args.get('Run', False): - RunArgs: str = self.Args.get('RunArgs', '') - RunCmd: list[str] = [f'{OutputFile}.exe'] + (shlex.split(RunArgs) if RunArgs else []) - info(f'运行: {" ".join(RunCmd)}') - - # 执行运行命令 - RunResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(RunCmd) - if RunResult: - info('执行输出:') - info(RunResult.stdout) - if RunResult.stderr: - warning('执行错误:') - warning(RunResult.stderr) - except Exception as e: - error(f'编译失败: {e}') - - def WriteDebugInfo(self, content: str) -> None: - """写入调试信息到指定文件""" - # 获取调试文件路径 - if 'Debug' in self.Args: - DebugFile: str = self.Args['Debug'] - else: - DebugFile: str = self.Args.get('Output', '').replace('.c', '.p2c') - - if DebugFile: - AppendFileContent(DebugFile, content) - - def PythonToC(self, InputFile: str, OutputFile: str) -> None: - """Python到C的转换""" - # 获取编码参数 - encoding: str = self.Args.get('Encoding', 'utf-8') - - # 设置调试文件路径(使用 .p2c 扩展名) - if 'Debug' in self.Args: - DebugFile: str = self.Args['Debug'] - else: - # 默认使用 .p2c 文件 - DebugFile: str = OutputFile.replace('.c', '.p2c') - - # 设置翻译器的调试文件 - self.translator.SetDebugFile(DebugFile) - - # 先清空调试文件 - with open(DebugFile, 'w', encoding=encoding) as f: - f.write('') - - # 解析辅助文件,提取符号信息 - if self.HelperFiles: - self.translator.ParseHelperFiles(self.HelperFiles, encoding) - - # 加载注解文件,提取类型定义 - if self.AnnotationFiles: - self.translator.LoadAnnotationFiles(self.AnnotationFiles) - - # 获取编码参数 - encoding = self.Args.get('Encoding', 'utf-8') - with open(InputFile, 'r', encoding=encoding) as F: - Content: str = F.read() - - # 保存原始代码行 - self.translator.OriginalLines = Content.split('\n') - self.translator.Content = Content - - # 解析Python代码为AST - Tree: ast.Module = ast.parse(Content) - - # 解析文件以提取类型信息(用于 EmbeddedAssignments) - self.translator.ParsePythonFile(InputFile, encoding) - - # 写入AST树信息(压缩格式) - with open(DebugFile, 'a', encoding=encoding) as f: - f.write('=== AST Tree (Compact) ===\n') - f.write(ast.dump(Tree)) - f.write('\n\n') - - Target: str = 'llvm' - CCode: str = self.translator.GenerateCCode(Tree, target=Target) - - timestamp: str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - filename: str = os.path.basename(OutputFile) - - encoding = self.Args.get('Encoding', 'utf-8') - with open(OutputFile, 'w', encoding=encoding) as F: - F.write(CCode) - F.write('\n') - - def CToPython(self, InputFile: str, OutputFile: str, HeaderFiles: list[str]) -> None: - """C到Python的转换(暂时禁用)""" - warning("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。") - - def AddSymbol(self, SymbolFiles: SymbolFile | list[SymbolFile]) -> None: - """添加符号文件 - - Args: - SymbolFiles: 符号文件或符号文件列表 - """ - if isinstance(SymbolFiles, list): - self.SymbolFiles.extend(SymbolFiles) - else: - self.SymbolFiles.append(SymbolFiles) - - # 收集文件路径和编码 - HelperFiles: list[str] = [] - encodings: list[str] = [] - for SymbolFile in self.SymbolFiles: - FilePath: str | None = SymbolFile.FilePath - encoding: str = SymbolFile.encoding - if FilePath: - HelperFiles.append(FilePath) - encodings.append(encoding) - - # 解析辅助文件 - if HelperFiles: - # 暂时使用第一个文件的编码 - encoding = encodings[0] if encodings else 'utf-8' - self.translator.ParseHelperFiles(HelperFiles, encoding) - - def Convert(self, OutputFilename: str | None = None, SourceFilename: str | None = None, target: str = 'llvm') -> str | tuple[str, dict[str, Any]] | None: - """转换代码 - - Args: - OutputFilename: 输出文件名(用于模板渲染) - SourceFilename: 源文件路径(用于设置CurrentFile,影响导入模块的查找) - target: 目标代码类型,仅支持 'llvm' - - Returns: - 如果debug是字符串,则返回生成的代码 - 如果debug是True,则返回生成的代码和调试信息 - """ - if not self.code: - error('未提供代码') - return None - - from lib.core.Handles.HandlesImports import ImportHandle - ImportHandle._struct_Load_cache.clear() - - # 如果提供了 SourceFilename,先设置 CurrentFile - # 这样导入模块时会相对于源文件所在目录查找 - if SourceFilename: - self.translator.CurrentFile = SourceFilename - - # 加载注解文件,提取类型定义 - if self.AnnotationFiles: - self.translator.LoadAnnotationFiles(self.AnnotationFiles) - - # 保存原始代码行 - self.translator.OriginalLines = self.code.split('\n') - - # 解析Python代码为AST - Tree: ast.Module = ast.parse(self.code) - - # 从源代码直接预扫描 import 语句,注册别名 - # 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST - if not getattr(self.translator, '_ImportedModules', None): - self.translator._ImportedModules = set() - _prescan_tree: ast.Module = ast.parse(self.code) - for _node in ast.iter_child_nodes(_prescan_tree): - if isinstance(_node, ast.Import): - for _alias in _node.names: - _name: str = _alias.name - if _name in ('c', 't'): - continue - self.translator._ImportedModules.add(_name) - if _alias.asname: - self.translator.SymbolTable.import_aliases[_alias.asname] = _name - elif isinstance(_node, ast.ImportFrom): - _module_name: str | None = _node.module - if _module_name and _module_name not in ('c', 't'): - self.translator._ImportedModules.add(_module_name) - for _alias in _node.names: - if _alias.asname: - self.translator.SymbolTable.import_aliases[_alias.asname] = f"{_module_name}.{_alias.name}" - - # 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments) - # 创建临时文件路径用于解析 - with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f: - f.write(self.code) - TempFile: str = f.name - try: - # UpdateCurrentFile=False 表示不修改 CurrentFile - if SourceFilename: - self.translator.ParsePythonFile(TempFile, UpdateCurrentFile=False) - else: - self.translator.ParsePythonFile(TempFile) - finally: - os.unlink(TempFile) - - timestamp: str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - if self.triple: - self.translator.triple = self.triple - if self.datalayout: - self.translator.datalayout = self.datalayout - - # 生成代码 - code: str = self.translator.GenerateCCode(Tree, target='llvm') - filename: str = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll' - - # 处理调试信息 - if isinstance(self.config.debug, str): - # 如果debug是字符串,写入调试信息到文件 - with open(self.config.debug, 'w', encoding='utf-8') as f: - f.write('=== Symbol Table ===\n') - f.write(str(self.translator.SymbolTable) + '\n\n') - f.write('=== AST Tree ===\n') - f.write(ast.dump(Tree, indent=2) + '\n\n') - f.write('=== Export Table ===\n') - f.write(self.translator.Exportable.to_json() + '\n\n') - f.write('=== Generated Code ===\n') - f.write(code + '\n') - return code - elif self.config.debug: - # 如果debug是True,返回生成的代码和调试信息 - DebugInfo: dict[str, Any] = { - 'SymbolTable': self.translator.SymbolTable, - 'ast_tree': ast.dump(Tree, indent=2), - 'Exportable': self.translator.Exportable.to_dict(), - 'generated_code': code - } - return code, DebugInfo - else: - # 如果debug是False,只返回生成的代码 - return code - - def Run(self) -> None: - """主运行函数""" - # 检查是否有命令行参数 - if len(sys.argv) > 1: - # 有命令行参数,使用 ParseArgs 方法解析 - self.ParseArgs() - - # 检查是否有预处理符号文件的请求 - if 'PreSym' in self.Args: - PresymConfig: dict[str, Any] = self.Args['PreSym'] - InputFile: str = PresymConfig['input'] - OutputFile: str = PresymConfig['output'] - DebugFile: str | None = PresymConfig['debug'] - - # 获取编码参数 - encoding: str = self.Args.get('Encoding', 'utf-8') - - # 推断文件类型 - FileType: str | None = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None - - # 创建 SymbolFile 对象,传入编码参数 - SymbolFile: SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding) - - # 调用 PreProcessSymbol - if DebugFile: - BinaryData: bytes - DebugInfo: str - BinaryData, DebugInfo = TransPyC.PreProcessSymbol(SymbolFile, debug=True) - # 写入调试文件 - with open(DebugFile, 'w', encoding=encoding) as f: - f.write(DebugInfo) - info(f"调试信息写入: {DebugFile}") - else: - BinaryData: bytes = TransPyC.PreProcessSymbol(SymbolFile, debug=False) - - # 写入二进制符号文件 - with open(OutputFile, 'wb') as f: - f.write(BinaryData) - - success(f"符号文件生成: {OutputFile}") - return - - InputFile: str = self.Args['Input'] - OutputFile: str = self.Args['Output'] - else: - # 没有命令行参数,使用默认的测试文件名称 - InputFile: str = DEFAULT_INPUT_FILE - OutputFile: str = DEFAULT_OUTPUT_FILE - info('使用默认测试文件: test.py -> test.c') - - FileType: str = DetectFileType(InputFile) - - if FileType == '.py': - self.PythonToC(InputFile, OutputFile) - # 检查是否需要编译和运行 - if 'CompileCommand' in self.Args or self.Args.get('Run', False): - self.CompileAndRun(OutputFile) - elif FileType == '.c': - self.CToPython(InputFile, OutputFile, self.HeaderFiles) - else: - error(f'不支持的文件类型: {FileType}') - sys.exit(1) diff --git a/App/lib/Shell/__init__.py b/App/lib/Shell/__init__.py deleted file mode 100644 index ffec9e5..0000000 --- a/App/lib/Shell/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Shell 包 - TransPyC 命令行入口""" -from lib.Shell.Serializer import SerializeSymbolTable, deSerializeSymbolTable, SymbolFile -from lib.Shell.Config import Config -from lib.Shell.TransPyC import TransPyC - -__all__ = ['SerializeSymbolTable', 'deSerializeSymbolTable', 'SymbolFile', 'Config', 'TransPyC'] diff --git a/App/lib/StubGen/Config.py b/App/lib/StubGen/Config.py deleted file mode 100644 index 4e3b135..0000000 --- a/App/lib/StubGen/Config.py +++ /dev/null @@ -1,43 +0,0 @@ -"""StubGen 配置模块""" -from __future__ import annotations -import json -from dataclasses import dataclass, field -from typing import List, Dict, Optional - - -@dataclass -class StubGenConfig: - """存根生成器配置""" - InputDir: Optional[str] = None - OutputDir: str = "./stubs" - InputFiles: List[str] = field(default_factory=list) - IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.py"]) - ExcludePatterns: List[str] = field(default_factory=list) - TypeMappings: Dict[str, str] = field(default_factory=dict) - PreserveStructure: bool = True # 保持目录结构 - GenerateGuards: bool = True # 生成宏守卫 - verbose: bool = False - DryRun: bool = False - - @classmethod - def from_dict(cls, data: dict) -> StubGenConfig: - """从字典创建配置""" - return cls( - InputDir=data.get('InputDir'), - OutputDir=data.get('OutputDir', './stubs'), - InputFiles=data.get('InputFiles', []), - IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.py']), - ExcludePatterns=data.get('ExcludePatterns', []), - TypeMappings=data.get('TypeMappings', {}), - PreserveStructure=data.get('PreserveStructure', True), - GenerateGuards=data.get('GenerateGuards', True), - verbose=data.get('verbose', False), - DryRun=data.get('DryRun', False), - ) - - @classmethod - def from_file(cls, FilePath: str) -> StubGenConfig: - """从 JSON 文件加载配置""" - with open(FilePath, 'r', encoding='utf-8') as f: - data: dict = json.load(f) - return cls.from_dict(data) \ No newline at end of file diff --git a/App/lib/StubGen/Converter.py b/App/lib/StubGen/Converter.py index 6dee267..7b18c69 100644 --- a/App/lib/StubGen/Converter.py +++ b/App/lib/StubGen/Converter.py @@ -127,6 +127,23 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, ti += 1 return pos + # Call: 函数调用表达式 (用于装饰器如 @t.NoVTable()) + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(annot) + pos = _PyiTypeStr(buf, buf_size, pos, cl.func) + pos = _PyiEmit(buf, buf_size, pos, "(") + if cl.args is not None: + can: t.CSizeT = cl.args.__len__() + cai: t.CSizeT = 0 + while cai < can: + if cai > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + ca: ast.AST | t.CPtr = cl.args.get(cai) + pos = _PyiTypeStr(buf, buf_size, pos, ca) + cai += 1 + pos = _PyiEmit(buf, buf_size, pos, ")") + return pos + # 未知类型,回退到 t.CInt return _PyiEmit(buf, buf_size, pos, "t.CInt") @@ -140,6 +157,19 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, fn: ast.FunctionDef | t.CPtr, indent_level: int, class_name: str) -> t.CSizeT: """生成函数签名到 buf,返回新的 pos""" + # 装饰器 + if fn.decorator_list is not None: + dn: t.CSizeT = fn.decorator_list.__len__() + di: t.CSizeT = 0 + while di < dn: + dec: ast.AST | t.CPtr = fn.decorator_list.get(di) + if dec is not None: + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "@") + pos = _PyiTypeStr(buf, buf_size, pos, dec) + pos = _PyiEmit(buf, buf_size, pos, "\n") + di += 1 + pos = _PyiIndent(buf, buf_size, pos, indent_level) pos = _PyiEmit(buf, buf_size, pos, "def ") if fn.name is not None: @@ -210,11 +240,39 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, cls: ast.ClassDef | t.CPtr, indent_level: int) -> t.CSizeT: """生成类定义到 buf,返回新的 pos""" + # 装饰器 + if cls.decorator_list is not None: + dcn: t.CSizeT = cls.decorator_list.__len__() + dci: t.CSizeT = 0 + while dci < dcn: + ddec: ast.AST | t.CPtr = cls.decorator_list.get(dci) + if ddec is not None: + pos = _PyiIndent(buf, buf_size, pos, indent_level) + pos = _PyiEmit(buf, buf_size, pos, "@") + pos = _PyiTypeStr(buf, buf_size, pos, ddec) + pos = _PyiEmit(buf, buf_size, pos, "\n") + dci += 1 + pos = _PyiIndent(buf, buf_size, pos, indent_level) pos = _PyiEmit(buf, buf_size, pos, "class ") if cls.name is not None: pos = _PyiEmit(buf, buf_size, pos, cls.name) + # PEP 695 类型参数 (class Foo[T]:) + if cls.type_params is not None: + tpn: t.CSizeT = cls.type_params.__len__() + if tpn > 0: + pos = _PyiEmit(buf, buf_size, pos, "[") + tpi: t.CSizeT = 0 + while tpi < tpn: + if tpi > 0: + pos = _PyiEmit(buf, buf_size, pos, ", ") + tpname: str = cls.type_params.get(tpi) + if tpname is not None: + pos = _PyiEmit(buf, buf_size, pos, tpname) + tpi += 1 + pos = _PyiEmit(buf, buf_size, pos, "]") + # 基类 if cls.bases is not None: bn: t.CSizeT = cls.bases.__len__() @@ -245,6 +303,29 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, # 方法 if sk == ast.ASTKind.FunctionDef: mfn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + # __init__ 方法:先提取 self.x: Type 属性 + if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0: + if mfn.children is not None: + icn: t.CSizeT = mfn.children.__len__() + ici: t.CSizeT = 0 + while ici < icn: + ibody: ast.AST | t.CPtr = mfn.children.get(ici) + if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign: + iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody) + if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute: + iat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(iaa.target) + # 检查 target.value 是否为 Name("self") + if iat.value is not None and iat.value.kind() == ast.ASTKind.Name: + iavn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iat.value) + if iavn.id is not None and string.strcmp(iavn.id, "self") == 0: + pos = _PyiIndent(buf, buf_size, pos, indent_level + 1) + if iat.attr is not None: + pos = _PyiEmit(buf, buf_size, pos, iat.attr) + pos = _PyiEmit(buf, buf_size, pos, ": ") + pos = _PyiTypeStr(buf, buf_size, pos, iaa.annotation) + pos = _PyiEmit(buf, buf_size, pos, "\n") + has_member = 1 + ici += 1 pos = _PyiFunction(buf, buf_size, pos, mfn, indent_level + 1, cls.name) has_member = 1 @@ -260,6 +341,12 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT, pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) pos = _PyiEmit(buf, buf_size, pos, "\n") has_member = 1 + + # 嵌套类 + elif sk == ast.ASTKind.ClassDef: + ncls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt) + pos = _PyiClass(buf, buf_size, pos, ncls, indent_level + 1) + has_member = 1 ci += 1 # 空类补 pass @@ -411,6 +498,45 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation) pos = _PyiEmit(buf, buf_size, pos, "\n") + # 全局赋值(无注解)— 从 Constant value 推断类型 + elif k == ast.ASTKind.Assign: + asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt) + if asg.targets is not None and asg.value is not None: + atn: t.CSizeT = asg.targets.__len__() + if atn == 1: + atg: ast.AST | t.CPtr = asg.targets.get(0) + if atg is not None and atg.kind() == ast.ASTKind.Name: + agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg) + aval: ast.AST | t.CPtr = asg.value + avk: int = aval.kind() + inferred: int = 0 + if avk == ast.ASTKind.Constant: + acv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aval) + if acv.const_kind == ast.CONST_INT: + inferred = 1 + elif acv.const_kind == ast.CONST_FLOAT: + inferred = 2 + elif acv.const_kind == ast.CONST_STR: + inferred = 3 + elif acv.const_kind == ast.CONST_BOOL: + inferred = 4 + elif acv.const_kind == ast.CONST_NONE: + inferred = 5 + if inferred > 0 and agn.id is not None: + pos = _PyiEmit(buf, buf_size, pos, agn.id) + pos = _PyiEmit(buf, buf_size, pos, ": ") + if inferred == 1: + pos = _PyiEmit(buf, buf_size, pos, "t.CInt") + elif inferred == 2: + pos = _PyiEmit(buf, buf_size, pos, "t.CDouble") + elif inferred == 3: + pos = _PyiEmit(buf, buf_size, pos, "str") + elif inferred == 4: + pos = _PyiEmit(buf, buf_size, pos, "bool") + elif inferred == 5: + pos = _PyiEmit(buf, buf_size, pos, "None") + pos = _PyiEmit(buf, buf_size, pos, "\n") + i += 1 # NUL 终止 diff --git a/App/lib/StubGen/Generator.py b/App/lib/StubGen/Generator.py deleted file mode 100644 index 526071f..0000000 --- a/App/lib/StubGen/Generator.py +++ /dev/null @@ -1,313 +0,0 @@ -"""StubGen 生成器模块 - 存根生成器主类和命令行入口""" -from __future__ import annotations -import sys -import os -import re -import argparse -import logging -import traceback -from pathlib import Path -from typing import List - -from lib.core.VLogger import get_logger as _vlog -from lib.core.stub_generator import CHeaderParser, PythonStubGenerator, CTypeMapper -from lib.StubGen.Config import StubGenConfig -from lib.StubGen.Converter import PythonToStubConverter - - -class StubGen: - """存根生成器主类""" - - def __init__(self, config: StubGenConfig) -> None: - self.config: StubGenConfig = config - self.logger: logging.Logger = self._SetupLogger() - self.GeneratedFiles: List[str] = [] - self.FailedFiles: List[str] = [] - - # 应用自定义类型映射 - if config.TypeMappings: - CTypeMapper.BASIC_TYPE_MAP.update(config.TypeMappings) - - def _SetupLogger(self) -> logging.Logger: - """设置日志""" - logger: logging.Logger = logging.getLogger('StubGen') - logger.setLevel(logging.DEBUG if self.config.verbose else logging.INFO) - - if not logger.handlers: - handler: logging.StreamHandler = logging.StreamHandler(sys.stdout) - formatter: logging.Formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%H:%M:%S' - ) - handler.setFormatter(formatter) - logger.addHandler(handler) - - return logger - - def FindInputFiles(self) -> list[tuple[str, str]]: - """查找输入文件,返回 (文件路径, 相对路径) 列表""" - files: list[tuple[str, str]] = [] - - # 添加显式指定的文件 - for FilePath in self.config.InputFiles: - if os.path.exists(FilePath): - RelPath: str = os.path.relpath(FilePath, self.config.InputDir or '.') - files.append((FilePath, RelPath)) - else: - self.logger.warning(f"Input file not found: {FilePath}") - - # 从输入目录查找 - if self.config.InputDir and os.path.exists(self.config.InputDir): - InputPath: Path = Path(self.config.InputDir) - for pattern in self.config.IncludePatterns: - for FilePath in InputPath.rglob(pattern): - # 检查是否在排除列表中 - excluded: bool = False - RelPath: str = os.path.relpath(str(FilePath), self.config.InputDir) - - for exclude_pattern in self.config.ExcludePatterns: - if FilePath.match(exclude_pattern) or RelPath == exclude_pattern: - excluded = True - break - - if not excluded: - files.append((str(FilePath), RelPath)) - - # 去重并保持顺序 - seen: set[str] = set() - UniqueFiles: list[tuple[str, str]] = [] - for FilePath, RelPath in files: - key: str = FilePath - if key not in seen: - seen.add(key) - UniqueFiles.append((FilePath, RelPath)) - - return UniqueFiles - - def _GenerateGuardName(self, FilePath: str) -> str: - """生成宏守卫名称""" - # 获取文件名(不含扩展名) - BaseName: str = os.path.splitext(os.path.basename(FilePath))[0] - - # 转换为大写,替换特殊字符为下划线 - guard: str = re.sub(r'[^a-zA-Z0-9_]', '_', BaseName).upper() - guard = re.sub(r'_+', '_', guard) # 合并多个下划线 - guard = guard.strip('_') - - return f'{guard}_DEFINE_H' - - def _GetOutputPath(self, RelPath: str) -> str: - """获取输出文件路径""" - # 更改扩展名为 .pyi (Python stub file) - BaseName: str = os.path.splitext(RelPath)[0] - OutputRelPath: str = BaseName + '.pyi' - - # 构建完整输出路径 - if self.config.OutputDir: - OutputPath: str = os.path.join(self.config.OutputDir, OutputRelPath) - else: - OutputPath = OutputRelPath - - return OutputPath - - def GenerateStub(self, InputFile: str, RelPath: str) -> bool: - """生成单个存根文件""" - try: - self.logger.info(f"Processing: {InputFile}") - - # 确定输出文件路径 - OutputFile: str = self._GetOutputPath(RelPath) - - # 确保输出目录存在 - OutputDir: str = os.path.dirname(OutputFile) - if OutputDir and not os.path.exists(OutputDir): - if not self.config.DryRun: - os.makedirs(OutputDir, exist_ok=True) - self.logger.debug(f"Created directory: {OutputDir}") - - if self.config.DryRun: - self.logger.info(f"[DRY RUN] Would generate: {OutputFile}") - return True - - # 根据文件类型选择处理方式 - ext: str = os.path.splitext(InputFile)[1].lower() - - if ext in ['.h', '.c']: - # C 文件:使用 CHeaderParser - content: str = self._GenerateFromC(InputFile, RelPath) - elif ext == '.py': - # Python 文件:使用 PythonToStubConverter - content = self._GenerateFromPy(InputFile, RelPath) - else: - self.logger.warning(f"Unsupported file type: {ext}") - return False - - # 写入文件 - with open(OutputFile, 'w', encoding='utf-8') as f: - f.write(content) - - self.GeneratedFiles.append(OutputFile) - self.logger.info(f"Generated: {OutputFile}") - return True - - except Exception as e: - self.logger.error(f"Failed to process {InputFile}: {e}") - traceback.print_exc() - self.FailedFiles.append(InputFile) - return False - - def _GenerateFromC(self, InputFile: str, RelPath: str) -> str: - """从 C 文件生成存根""" - parser: CHeaderParser = CHeaderParser() - parser.parse_file(InputFile) - - generator: PythonStubGenerator = PythonStubGenerator(parser) - ModuleName: str = os.path.splitext(os.path.basename(InputFile))[0] - content: str = generator.generate(ModuleName) - - # 添加宏守卫(如果需要) - if self.config.GenerateGuards: - guard_name: str = self._GenerateGuardName(InputFile) - guard_comment: str = f"\n# Guard: {guard_name}\n" - content = content + guard_comment - - return content - - def _GenerateFromPy(self, InputFile: str, RelPath: str) -> str: - """从 Python 文件生成存根""" - with open(InputFile, 'r', encoding='utf-8') as f: - PyContent: str = f.read() - - ModuleName: str = os.path.splitext(os.path.basename(InputFile))[0] - content: str = PythonToStubConverter.convert(PyContent, ModuleName) - - # 添加宏守卫(如果需要) - if self.config.GenerateGuards: - guard_name: str = self._GenerateGuardName(InputFile) - guard_comment: str = f"\n# Guard: {guard_name}\n" - content = content + guard_comment - - return content - - def run(self) -> bool: - """运行生成器""" - self.logger.info("=" * 60) - self.logger.info("StubGen - C/H/Py to Python Stub Generator") - self.logger.info("=" * 60) - - # 查找输入文件 - InputFiles: list[tuple[str, str]] = self.FindInputFiles() - - if not InputFiles: - self.logger.warning("No input files found!") - return False - - self.logger.info(f"Found {len(InputFiles)} input file(s)") - for FilePath, RelPath in InputFiles: - self.logger.debug(f" - {RelPath}") - - # 处理每个文件 - SuccessCount: int = 0 - for FilePath, RelPath in InputFiles: - if self.GenerateStub(FilePath, RelPath): - SuccessCount += 1 - - # 输出统计信息 - self.logger.info("=" * 60) - self.logger.info(f"Summary: {SuccessCount}/{len(InputFiles)} files generated successfully") - - if self.FailedFiles: - self.logger.warning(f"Failed files ({len(self.FailedFiles)}):") - for f in self.FailedFiles: - self.logger.warning(f" - {f}") - - return SuccessCount == len(InputFiles) - - -def main() -> None: - parser: argparse.ArgumentParser = argparse.ArgumentParser( - description='StubGen - Generate Python stub files from C/H/Py sources', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -Examples: - # 使用配置文件 - %(prog)s -c config.json - - # 处理单个文件 - %(prog)s -i input.h -o output.py - - # 批量处理目录(保持目录结构) - %(prog)s -d ./kernel -o ./kernel/include - - # 干运行(不实际生成文件) - %(prog)s -d ./kernel --dry-run - - # 不生成宏守卫 - %(prog)s -d ./kernel --no-guards - ''' - ) - - # 输入选项 - InputGroup: argparse._MutuallyExclusiveGroup = parser.add_mutually_exclusive_group(required=True) - InputGroup.add_argument('-c', '--config', help='Configuration file (JSON)') - InputGroup.add_argument('-i', '--input', help='Input file') - InputGroup.add_argument('-d', '--directory', help='Input directory') - - # 输出选项 - parser.add_argument('-o', '--output', help='Output directory') - - # 其他选项 - parser.add_argument('--include', action='append', - help='Include patterns (default: *.h, *.c, *.py)') - parser.add_argument('--exclude', action='append', - help='Exclude patterns') - parser.add_argument('--no-guards', action='store_true', - help='Do not generate guard macros') - parser.add_argument('--no-structure', action='store_true', - help='Do not preserve directory structure') - parser.add_argument('-v', '--verbose', action='store_true', - help='Verbose output') - parser.add_argument('--dry-run', action='store_true', - help='Dry run (do not create files)') - - args: argparse.Namespace = parser.parse_args() - - # 加载配置 - if args.config: - if not os.path.exists(args.config): - _vlog().error(f"配置文件未找到: {args.config}") - sys.exit(1) - config: StubGenConfig = StubGenConfig.from_file(args.config) - else: - config = StubGenConfig() - config.IncludePatterns = args.include or ['*.h', '*.c', '*.py'] - config.ExcludePatterns = args.exclude or [] - config.GenerateGuards = not args.no_guards - config.PreserveStructure = not args.no_structure - config.verbose = args.verbose - config.DryRun = args.dry_run - - if args.input: - config.InputFiles = [args.input] - if args.output: - config.OutputDir = os.path.dirname(args.output) or '.' - elif args.directory: - config.InputDir = args.directory - if args.output: - config.OutputDir = args.output - - # 创建生成器并运行 - generator: StubGen = StubGen(config) - - # 如果指定了单个输出文件,直接处理 - if args.input and args.output and not os.path.isdir(args.output): - RelPath: str = os.path.relpath(args.input, config.InputDir or '.') - success: bool = generator.GenerateStub(args.input, RelPath) - else: - success = generator.run() - - sys.exit(0 if success else 1) - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/App/lib/_bootstrap.py b/App/lib/_bootstrap.py deleted file mode 100644 index 8089950..0000000 --- a/App/lib/_bootstrap.py +++ /dev/null @@ -1,37 +0,0 @@ -"""集中化 sys.path 引导模块 - -在首次导入时一次性设置好编译器运行所需的 sys.path: -- 项目根目录:让 ``import TransPyC``、``from StubGen import``、动态 importlib 能解析 -- lib/includes:让用户注解模块中的 ``import t`` / ``import c`` 能解析 - -入口点(TransPyC.py / Projectrans.py)应在最开头 ``import lib._bootstrap``。 -lib 内部模块也可 ``import lib._bootstrap`` 作为安全网,重复导入是无副作用的 no-op。 -""" -from __future__ import annotations - -import os -import sys - -_BOOTSTRAPPED: bool = False - - -def _bootstrap() -> None: - global _BOOTSTRAPPED - if _BOOTSTRAPPED: - return - _BOOTSTRAPPED = True - - # lib/_bootstrap.py 所在目录 - _LibDir: str = os.path.dirname(os.path.abspath(__file__)) - # 项目根目录 = lib 的父目录 - _ProjectRoot: str = os.path.dirname(_LibDir) - # lib/includes 目录(编译器内部类型系统 t.py / c.py) - _IncludesDir: str = os.path.join(_LibDir, 'includes') - - if _ProjectRoot not in sys.path: - sys.path.insert(0, _ProjectRoot) - if _IncludesDir not in sys.path: - sys.path.append(_IncludesDir) - - -_bootstrap() diff --git a/App/lib/constants/__init__.py b/App/lib/constants/__init__.py deleted file mode 100644 index 013292a..0000000 --- a/App/lib/constants/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""全局常量定义""" diff --git a/App/lib/constants/config.py b/App/lib/constants/config.py deleted file mode 100644 index 250a029..0000000 --- a/App/lib/constants/config.py +++ /dev/null @@ -1,43 +0,0 @@ -# 常量定义 -from __future__ import annotations - -DEFAULT_INPUT_FILE: str = 'test.py' -DEFAULT_OUTPUT_FILE: str = 'test.ll' - -SLICE_THRESHOLD: int = 50 -SLICE_LEVEL_DEFAULT: int = 3 -SLICE_LEVELS: dict[int | str, str] = { - 0: 'no_optimize', - 1: 'conservative', - 2: 'moderate', - 3: 'aggressive', - 's': 'size', -} - -DEFAULT_COMPILE_COMMAND: str = 'gcc' -DEFAULT_COMPILE_FLAGS: str = '' - -DEFAULT_METADATA: dict[str, str] = { - 'PROJECT_NAME': 'TransPyC Project', - 'AUTHOR': 'TransPyC Team', - 'VERSION': '1.0.0', - 'DESCRIPTION': 'Auto-generated LLVM IR file', - 'COPYRIGHT_YEAR': '2026', - 'COPYRIGHT_HOLDER': 'Galactic Vorpal Software Development Studio (e.g. GVSDS Inc.)' -} - -ERROR_MESSAGES: dict[str, str] = { - 'MISSING_ARGS': 'Missing required arguments -f and/or -o', - 'UNKNOWN_ARG': 'Unknown argument', - 'UNSUPPORTED_TYPE': 'Unsupported file type', - 'FAILED_PARSE': 'Failed to parse file', - 'COMPILE_FAILED': 'Compilation or execution failed' -} - -HELP_MESSAGE: str = ''' -Usage: python TransPyC.py -f InputFile -o OutputFile [-wh header_files] [-debug DebugFile] - [-cc compile_command] [-cflags CompileFlags] [-run] [-args RunArgs] [-h HelperFiles] - -h: Specify helper files (C or Python) to help identify structs, functions, variables, and ptrs -''' - -mode: str = "strict" diff --git a/App/lib/core/BuildPipeline.py b/App/lib/core/BuildPipeline.py index 9f6627d..c8810aa 100644 --- a/App/lib/core/BuildPipeline.py +++ b/App/lib/core/BuildPipeline.py @@ -14,6 +14,7 @@ import lib.core.Handles.HandlesTranslator as HandlesTranslator import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesType as HandlesType import lib.core.Handles.HandlesImports as HandlesImports +import lib.Projectrans.Config as Config # ============================================================ # BuildPipeline - 编译管线 @@ -137,19 +138,74 @@ def ensure_dir(path: str) -> int: # 遇到分隔符时临时截断,创建每一层目录 # CreateDirectoryA 在目录已存在时返回 0(失败),忽略即可 - for i in range(path_len): - ch: int = c.Deref(buf + i) - if ch == ord('/') or ch == ord('\\'): + i: int = 0 + plen: int = path_len + while i < plen: + ch: int = buf[i] + if ch == 47 or ch == 92: # '/' = 47, '\\' = 92 saved: int = ch buf[i] = '\0' w32.win32file.CreateDirectoryA(buf, None) buf[i] = saved + i += 1 # 创建最终目录 w32.win32file.CreateDirectoryA(buf, None) return 0 +# ============================================================ +# build_sliced_path - 构建切片路径并确保目录存在 +# +# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: +# level=0 → {base_dir}/{sha1}.{ext} +# level=1 → {base_dir}/b7/{sha1}.{ext} +# level=2 → {base_dir}/b7/90/{sha1}.{ext} +# +# 自动调用 ensure_dir 创建子目录。 +# +# Args: +# base_dir: 基础目录(如 temp_dir) +# sha1: SHA1 字符串 +# ext: 文件扩展名(如 "stub.ll") +# +# Returns: +# 完整文件路径(mbuddy 分配),None 失败 +# ============================================================ +def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str: + """构建切片路径并确保目录存在""" + if base_dir is None or sha1 is None or ext is None: + return None + + subdir: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel) + base_len: t.CSizeT = string.strlen(base_dir) + sha1_len: t.CSizeT = string.strlen(sha1) + ext_len: t.CSizeT = string.strlen(ext) + + if subdir is not None: + sub_len: t.CSizeT = string.strlen(subdir) + # ensure_dir({base_dir}/{subdir}) + dir_path: str = _mbuddy.alloc(base_len + sub_len + 2) + if dir_path is not None: + viperlib.snprintf(dir_path, base_len + sub_len + 2, "%s/%s", base_dir, subdir) + ensure_dir(dir_path) + # 文件路径: {base_dir}/{subdir}/{sha1}.{ext} + path_len: t.CSizeT = base_len + sub_len + sha1_len + ext_len + 4 + path: str = _mbuddy.alloc(path_len) + if path is None: + return None + viperlib.snprintf(path, path_len, "%s/%s/%s.%s", base_dir, subdir, sha1, ext) + return path + else: + # 无切片: {base_dir}/{sha1}.{ext} + path_len = base_len + sha1_len + ext_len + 3 + path = _mbuddy.alloc(path_len) + if path is None: + return None + viperlib.snprintf(path, path_len, "%s/%s.%s", base_dir, sha1, ext) + return path + + def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int: """将 IR 缓冲区写入 .ll 文件 @@ -157,22 +213,18 @@ def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_na ir_buf: IR 文本缓冲区 ir_len: IR 文本长度 output_dir: 输出目录(temp 或 output) - module_name: 模块名(如 "main") + module_name: 模块名(SHA1) Returns: 0 成功,非 0 失败 """ - if ir_buf is None or output_dir is None: + if ir_buf is None or output_dir is None or module_name is None: return 1 - # 构造文件路径: output_dir/module_name.ll - dir_len: t.CSizeT = string.strlen(output_dir) - name_len: t.CSizeT = string.strlen(module_name) - path_len: t.CSizeT = dir_len + 1 + name_len + 4 # dir/module.ll\0 - path: bytes = _mbuddy.alloc(path_len) + # 构造切片路径: output_dir/{sha1前缀}/{module_name}.ll + path: str = build_sliced_path(output_dir, module_name, "ll") if path is None: return 1 - viperlib.snprintf(path, path_len, "%s/%s.ll", output_dir, module_name) # 打开文件写入 f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W) @@ -192,22 +244,27 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s Args: ir_path: .ll 文件路径 output_dir: 输出目录 - module_name: 模块名(用于生成 .obj 文件名) + module_name: 模块名(SHA1,用于生成 .obj 文件名) cc_cmd: 编译器命令(如 "llc") cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic") Returns: 0 成功,非 0 失败 """ - if ir_path is None or cc_cmd is None: + if ir_path is None or cc_cmd is None or output_dir is None or module_name is None: return 1 - # 构造命令: llc -filetype=obj -o output_dir/module_name.obj ir_path - cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(ir_path) + 64 + # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj + obj_path: str = build_sliced_path(output_dir, module_name, "obj") + if obj_path is None: + return 1 + + # 构造命令: llc -filetype=obj -o {obj_path} ir_path + cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(obj_path) + string.strlen(ir_path) + 64 cmd: bytes = _mbuddy.alloc(cmd_len) if cmd is None: return 1 - viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s.obj %s", cc_cmd, cc_flags, output_dir, module_name, ir_path) + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, ir_path) result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) if result is None: @@ -287,7 +344,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f Args: output_dir: 输出目录(包含 .obj 文件) - module_name: 模块名 + module_name: 模块名(SHA1) linker_cmd: 链接器命令(如 "clang++") linker_flags: 链接器参数 linker_output: 输出文件名(如 "test.exe") @@ -296,7 +353,12 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f Returns: 0 成功,非 0 失败 """ - if output_dir is None or linker_cmd is None: + if output_dir is None or linker_cmd is None or module_name is None: + return 1 + + # 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj + obj_path: str = build_sliced_path(output_dir, module_name, "obj") + if obj_path is None: return 1 # 收集 includes.binary 的 .obj 文件路径 @@ -312,19 +374,19 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f else: stdio.printf("[link] 警告: includes.binary 无 .obj 文件: %s\n", includes_binary_dir) - # 构造命令: clang++ main.obj extra_objs -o output linker_flags + # 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags # 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖 - cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128 + cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(linker_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128 cmd: bytes = _mbuddy.alloc(cmd_len) if cmd is None: return 1 if extra_len > 0: - viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj %s -o %s/%s %s", - linker_cmd, output_dir, module_name, extra_objs, + viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s", + linker_cmd, obj_path, extra_objs, output_dir, linker_output, linker_flags) else: - viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj -o %s/%s %s", - linker_cmd, output_dir, module_name, output_dir, linker_output, + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s", + linker_cmd, obj_path, output_dir, linker_output, linker_flags) result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) @@ -360,7 +422,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, Returns: 0 成功,非 0 失败 """ - if ir_buf is None or temp_dir is None or output_dir is None: + if ir_buf is None or temp_dir is None or output_dir is None or module_name is None: return 1 # Step 1: 写 .ll 文件 @@ -369,13 +431,10 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, stdio.printf("[compile] 写 .ll 失败: %s\n", module_name) return 1 - # Step 2: 构造 .ll 路径并编译 → .obj - name_len: t.CSizeT = string.strlen(module_name) - dir_len: t.CSizeT = string.strlen(temp_dir) - ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5) + # Step 2: 构造切片 .ll 路径并编译 → .obj + ir_path: str = build_sliced_path(temp_dir, module_name, "ll") if ir_path is None: return 1 - viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name) ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) if ret != 0: @@ -477,15 +536,12 @@ def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT, return result # Step 2: llc 编译 .ll → .obj - # 构造 .ll 文件路径 - name_len: t.CSizeT = string.strlen(module_name) - dir_len: t.CSizeT = string.strlen(temp_dir) - ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5) + # 构造切片 .ll 文件路径 + ir_path: str = build_sliced_path(temp_dir, module_name, "ll") if ir_path is None: result.Success = 0 result.ErrorMsg = "内存分配失败" return result - viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name) ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) if ret != 0: diff --git a/App/lib/core/CTypeInfo.py b/App/lib/core/CTypeInfo.py deleted file mode 100644 index 2e64c17..0000000 --- a/App/lib/core/CTypeInfo.py +++ /dev/null @@ -1,409 +0,0 @@ -"""CTypeInfo — C 类型信息对象,从 HandlesBase 中提取以避免 llvmlite 导入链。 - -本模块不导入 llvmlite,因此可以被 Projectrans 构建脚本安全导入。 -""" -from __future__ import annotations -from typing import TYPE_CHECKING, List, Any -if TYPE_CHECKING: - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - -import ast -from enum import IntFlag, auto - -from lib.includes import t -from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES - - -class FuncMeta(IntFlag): - NONE = 0 - STATIC_METHOD = auto() - PROPERTY_GETTER = auto() - PROPERTY_SETTER = auto() - PROPERTY_DELETER = auto() - CLASS_METHOD = auto() - ABSTRACT = auto() - - -class _Delegated: - """CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段 - - 替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由: - 描述符在类创建时绑定,访问时直接走 __get__/__set__, - 无 dict 查找和字符串比较的运行时开销。 - """ - __slots__ = ('_target_attr', '_field_name') - - def __init__(self, target_attr: str, field_name: str) -> None: - self._target_attr: str = target_attr # '_ts' or '_sm' - self._field_name: str = field_name - - def __get__(self, obj: Any, objtype: type | None = None) -> Any: - if obj is None: - return self - target: Any = object.__getattribute__(obj, self._target_attr) - return getattr(target, self._field_name) - - def __set__(self, obj: Any, value: Any) -> None: - target: Any = object.__getattribute__(obj, self._target_attr) - setattr(target, self._field_name, value) - - -class CTypeInfo: - """ - C 类型信息对象 - 统一符号表条目和类型计算 - - 设计原则: - - BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串 - - 描述符分为两种: - - VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const - - DataConst/DataVolatile: 指向数据的限定符,如 const int * - - 属性(类型计算): - - BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid()) - - PtrCount: int - 指针层数 - - VarConst: bool - 变量本身(指针)是否 const,如 int * const - - VarVolatile: bool - 变量本身(指针)是否 volatile - - DataConst: bool - 指向的数据是否 const,如 const int * - - DataVolatile: bool - 指向的数据是否 volatile - - ArrayDims: List[str] - 数组维度 - - Storage: t.CType - 存储类 (static, extern 等) - - IsFuncPtr: bool - 是否函数指针 - - FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型) - - FuncPtrReturn: CTypeInfo - 函数指针返回类型 - - IsBitField: bool - 是否位域 - - BitWidth: int - 位域宽度 - - IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类 - - 属性(符号表元数据): - - Name: str - 名称(struct/enum/union/typedef 名) - - Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union) - - OriginalType: str - typedef 的原始类型 - - DeclaredType: str - 声明类型 - - CreturnTypes: list - C 返回类型列表 - - Lineno: int - 定义行号 - - IsAnonymous: bool - 是否匿名类型 - - IsCpythonObject: bool - 是否 CPython 对象 - - IsEnumMember: bool - 是否枚举成员 - """ - - def __init__(self) -> None: - object.__setattr__(self, '_ts', TypeSpec()) - sm: SymbolMeta = SymbolMeta() - sm.meta_list = FuncMeta.NONE - object.__setattr__(self, '_sm', sm) - - # --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind --- - @property - def ts(self) -> TypeSpec: - """TypeSpec — 纯类型描述(只读)""" - return self._ts - - @property - def sm(self) -> SymbolMeta: - """SymbolMeta — 符号表元数据(只读)""" - return self._sm - - @property - def kind(self) -> 'SymbolKind': - """SymbolKind — 符号类型种类枚举""" - return self._sm.kind - - # 注:旧字段名(PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现, - # 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由 - - - @property - def BaseType(self) -> t.CType | tuple | None: - return self._ts._base_type - - @BaseType.setter - def BaseType(self, value: t.CType | type | tuple | List | None) -> None: - """设置 BaseType,接受以下类型: - - - None: 清空 - - t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志 - - type (CType 子类): 如 t.CStruct,自动实例化 - - tuple/list of t.CType: 多个组合类型 - """ - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - - if value is None: - ts._base_type = None - sm.is_struct = False - sm.is_enum = False - sm.is_union = False - sm.is_renum = False - return - - if isinstance(value, (tuple, list)): - ts._base_type = tuple(value) - for v in value: - if isinstance(v, t.CStruct): - sm.is_struct = True - elif isinstance(v, t.CEnum): - sm.is_enum = True - elif isinstance(v, t.CUnion): - sm.is_union = True - elif isinstance(v, t.REnum): - sm.is_renum = True - sm.is_enum = True - return - - if isinstance(value, type) and issubclass(value, t.CType): - ts._base_type = value() - return - - if isinstance(value, t.CType): - ts._base_type = value - if isinstance(value, t.CStruct): - sm.is_struct = True - sm.is_enum = False - sm.is_union = False - sm.is_renum = False - elif isinstance(value, t.REnum): - sm.is_renum = True - sm.is_enum = True - sm.is_struct = False - sm.is_union = False - elif isinstance(value, t.CEnum): - sm.is_enum = True - sm.is_struct = False - sm.is_union = False - sm.is_renum = False - elif isinstance(value, t.CUnion): - sm.is_union = True - sm.is_struct = False - sm.is_enum = False - sm.is_renum = False - return - - raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") - - @property - def TypeCls(self) -> type | None: - """获取 CType 类(从 BaseType 推断)""" - bt: t.CType | tuple | None = self._ts._base_type - if bt: - return type(bt) - sm: SymbolMeta = self._sm - if sm.is_struct: - return t.CStruct - if sm.is_enum: - return t.CEnum - if sm.is_union: - return t.CUnion - if sm.is_typedef: - return t._CTypedef - return None - - @property - def IsPtr(self) -> bool: - return self._ts.ptr_count > 0 - - @property - def IsVoid(self) -> bool: - return isinstance(self._ts._base_type, t.CVoid) - - @property - def IsStr(self) -> bool: - return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0 - - @property - def IsInt(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid) - - @property - def IsUInt(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False - - @property - def IsFloat(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid) - - def ToString(self) -> str: - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - bt: t.CType | tuple | None = ts._base_type - - if ts.is_func_ptr: - return 'Callable' - parts: list[str] = [] - - if ts.storage and not isinstance(ts.storage, t.CExport): - parts.append(type(ts.storage).__name__) - - if ts.data_const or ts.data_volatile: - qualifiers: list[str] = [] - if ts.data_const: - qualifiers.append("const") - if ts.data_volatile: - qualifiers.append("volatile") - parts.append("_".join(qualifiers)) - - if sm.is_typedef and sm.name: - return sm.name - elif sm.is_renum and sm.name: - base_name: str = sm.name - elif bt: - if isinstance(bt, str): - base_name = bt - elif isinstance(bt, type) and issubclass(bt, t.CType): - base_name = bt.__name__ - elif isinstance(bt, t.CType): - # 对命名的 CType(CStruct/CEnum/CUnion/REnum),优先使用其 name 属性 - # 否则回退到类名(如 'CInt'、'CChar') - _named: str | None = getattr(bt, 'name', None) - base_name = _named if _named else type(bt).__name__ - else: - base_name = str(bt) - else: - base_name = "void" - - if ts.is_array_ptr: - ptr_str: str = "" - if ts.ptr_count > 0: - ptr_str = "*" * ts.ptr_count - if ts.array_ptr: - inner: str = ts.array_ptr.ToString() - if ptr_str: - parts.append(f"{base_name} {ptr_str}({inner})") - else: - parts.append(f"{base_name} ({inner})") - else: - if ptr_str: - parts.append(f"{base_name} {ptr_str}()") - else: - parts.append(f"{base_name} ()") - elif ts.array_ptr: - inner = ts.array_ptr.ToString() - if ts.ptr_count > 0: - parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})") - else: - parts.append(f"{base_name} ({inner})") - else: - parts.append(base_name) - if ts.ptr_count > 0: - parts.append("*" * ts.ptr_count) - if ts.var_const: - parts.append("const") - if ts.var_volatile: - parts.append("volatile") - - for dim in ts.array_dims: - if dim: - parts.append(f"[{dim}]") - else: - parts.append("[]") - - return " ".join(parts) if parts else "void" - - @staticmethod - def CreateFromTypeName(TypeName: str) -> "CTypeInfo": - """从类型名字符串创建 CTypeInfo(兼容旧 API)""" - info: CTypeInfo = CTypeInfo() - if TypeName.startswith('struct '): - info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct() - elif TypeName.startswith('enum '): - info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum() - elif TypeName.startswith('union '): - info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion() - else: - info.BaseType = t.CStruct(name=TypeName) - return info - - # LLVM primitive type name → (CTypeClass, PtrCount) mapping - # Used when generic type inference produces LLVM type names like 'i64', 'double', etc. - _LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None - - @classmethod - def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]: - if cls._LLVM_PRIMITIVE_MAP is not None: - return cls._LLVM_PRIMITIVE_MAP - cls._LLVM_PRIMITIVE_MAP = { - 'void': (t.CVoid, 0), - 'i1': (t.CInt, 0), - 'i8': (t.CChar, 0), - 'i16': (t.CShort, 0), - 'i32': (t.CInt, 0), - 'i64': (t.CLong, 0), - 'i128': (t.CInt, 0), - 'float': (t.CFloat, 0), - 'double': (t.CDouble, 0), - 'fp128': (t.CFloat128T, 0), - } - return cls._LLVM_PRIMITIVE_MAP - - @staticmethod - def FromTypeName(TypeName: str) -> "CTypeInfo": - """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.from_type_name(TypeName) - - @staticmethod - def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any: - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable) - - @classmethod - def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo": - """从 AST 节点解析 CTypeInfo(类方法) - - Args: - Node: AST 节点(如 ast.Name, ast.Attribute 等) - SymbolTable: 符号表字典 - """ - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.from_node(Node, SymbolTable) - - - def Copy(self) -> "CTypeInfo": - NewInfo: CTypeInfo = CTypeInfo() - NewInfo._ts = self._ts.copy() - NewInfo._sm = self._sm.copy() - # CTypeInfo 引用字段需要深拷贝 - if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo): - NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy() - if isinstance(NewInfo._ts.original_type, CTypeInfo): - NewInfo._ts.original_type = NewInfo._ts.original_type.Copy() - if NewInfo._ts.array_ptr: - NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy() - return NewInfo - - def get(self, key: str, default: Any = None) -> Any: - """获取额外属性""" - return self._sm._extra.get(key, default) - - def set(self, key: str, value: Any) -> None: - """设置额外属性""" - self._sm._extra[key] = value - - @staticmethod - def VoidTypeInfo() -> "CTypeInfo": - info: CTypeInfo = CTypeInfo() - info.BaseType = t.CVoid() - return info - - def ToLLVM(self, Gen: LlvmCodeGenerator) -> Any: - from llvmlite import ir as _ir - if Gen is None: - return _ir.IntType(32) - return Gen._ctype_to_llvm(self) - - def __str__(self) -> str: - return self.ToString() - - def __repr__(self) -> str: - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})" - - -# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类 -# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由 -for _old_name, (_target, _field) in FIELD_ROUTES.items(): - setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field)) -del _old_name, _target, _field \ No newline at end of file diff --git a/App/lib/core/ConstEvaluator.py b/App/lib/core/ConstEvaluator.py deleted file mode 100644 index 9897e2b..0000000 --- a/App/lib/core/ConstEvaluator.py +++ /dev/null @@ -1,515 +0,0 @@ -"""统一常量表达式求值器 - -整合了原先分散在 5 处的常量求值逻辑: - - SymbolTable._eval_const_expr - - CTypeInfo.TryEvalConstExpr - - ConstEvalMixin._try_eval_const_expr - - HandlesAssign._eval_const_expr - - HandlesIf._eval_const_expr - -ConstEvaluator 提供三个级别的求值: - 1. eval_basic(node) — 纯 AST 常量 + 算术(无外部依赖) - 2. eval_with_symtab(node) — + SymbolTable 中的 define 查找 - 3. eval_full(node, ctx) — + Gen._define_constants / _all_define_constants / 平台宏 -""" -from __future__ import annotations - -import ast -from typing import Any, Callable, Optional, TYPE_CHECKING - -import llvmlite.ir as ir - -from lib.core.Handles.HandlesBase import CTypeInfo - -if TYPE_CHECKING: - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - - -class ConstEvaluator: - """统一常量表达式求值器""" - - # ================================================================== - # Level 2: + SymbolTable define 查找 - # ================================================================== - - @staticmethod - def eval_with_symtab(node: ast.AST, symtab: Any) -> Optional[Any]: - """求值常量表达式,支持从 SymbolTable 查找 define 值。 - - 支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define) - """ - if isinstance(node, ast.Constant): - return node.value - if isinstance(node, ast.Name): - if hasattr(symtab, '__contains__') and node.id in symtab: - info: CTypeInfo = symtab[node.id] - if info.IsDefine and isinstance(info.DefineValue, int): - return info.DefineValue - return None - if isinstance(node, ast.Attribute): - # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) - size_val = ConstEvaluator._eval_ctype_size_attr(node) - if size_val is not None: - return size_val - return ConstEvaluator._eval_attribute_define(node, symtab) - return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab)) - - # ================================================================== - # Level 3: + Gen._define_constants / _all_define_constants / 平台宏 - # ================================================================== - - @staticmethod - def eval_full(node: ast.AST, ctx: 'EvalContext') -> Optional[Any]: - """完整求值,支持 define_constants、平台宏、BoolOp、Compare。 - - ctx: EvalContext 实例,封装了 Gen、SymbolTable 等上下文。 - """ - # BoolOp (HandlesIf 逻辑) - if isinstance(node, ast.BoolOp): - if isinstance(node.op, ast.And): - for val in node.values: - result: Any = ConstEvaluator.eval_full(val, ctx) - if result is None: - return None - if not result: - return 0 - return 1 - elif isinstance(node.op, ast.Or): - for val in node.values: - result: Any = ConstEvaluator.eval_full(val, ctx) - if result is None: - return None - if result: - return 1 - return 0 - return None - - # Compare (HandlesIf 逻辑) - if isinstance(node, ast.Compare): - left: Any = ConstEvaluator.eval_full(node.left, ctx) - if left is None: - return None - op: ast.cmpop - comparator: ast.AST - for op, comparator in zip(node.ops, node.comparators): - right: Any = ConstEvaluator.eval_full(comparator, ctx) - if right is None: - return None - result: bool | None = ConstEvaluator._eval_compare_op(op, left, right) - if result is None: - return None - if not result: - return 0 - left = right - return 1 - - # Constant — 直接返回原始值,bool→0/1 转换由 HandlesIf 自行处理 - if isinstance(node, ast.Constant): - return node.value - - # Name — 查 define_constants / SymbolTable / 平台宏 - if isinstance(node, ast.Name): - return ctx.lookup_name(node.id) - - # Attribute — 查 define_constants / SymbolTable / 平台宏 - if isinstance(node, ast.Attribute): - # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) - size_val = ConstEvaluator._eval_ctype_size_attr(node) - if size_val is not None: - return size_val - return ctx.lookup_attribute(node) - - # UnaryOp - if isinstance(node, ast.UnaryOp): - operand: Any = ConstEvaluator.eval_full(node.operand, ctx) - if operand is None: - return None - if isinstance(node.op, ast.Not): - return 1 if not operand else 0 - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.UAdd): - return +operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - - # Call — 编译时函数调用(如 ctraits.isptr(x)) - if isinstance(node, ast.Call): - return ConstEvaluator._eval_compile_time_call(node, ctx) - - # BinOp - return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx)) - - # ================================================================== - # 内部辅助 - # ================================================================== - - @staticmethod - def _eval_compile_time_call(node: ast.Call, ctx: 'EvalContext') -> Optional[Any]: - """处理编译时函数调用,如 ctraits.isptr(x)""" - func: ast.expr = node.func - func_name: str | None = None - module_name: str | None = None - - if isinstance(func, ast.Attribute): - if isinstance(func.value, ast.Name): - module_name = func.value.id - func_name = func.attr - elif isinstance(func, ast.Name): - func_name = func.id - - # ctraits.isptr(x) — 带模块前缀 - # isptr(x) — 通过 from ctraits import isptr 导入 - is_isptr: bool = False - if module_name == 'ctraits' and func_name == 'isptr': - is_isptr = True - elif func_name == 'isptr' and not module_name: - # 检查是否通过 from ctraits import isptr 导入 - t_c_imported = getattr(ctx.translator, '_t_c_imported_names', {}) if ctx.translator else {} - if func_name in t_c_imported: - src_module, _ = t_c_imported[func_name] - if src_module == 'ctraits': - is_isptr = True - # 也检查符号表中是否有 ctraits.isptr - if not is_isptr and ctx.symtab: - sym = ctx.symtab.lookup('ctraits.isptr') if hasattr(ctx.symtab, 'lookup') else None - if sym: - is_isptr = True - - if is_isptr and node.args and ctx.translator: - try: - arg_node: ast.expr = node.args[0] - # 局部变量:优先通过 LLVM 类型判断(GetCTypeInfo 无法解析局部变量名) - if ctx.Gen and isinstance(arg_node, ast.Name): - var_name: str = arg_node.id - variables: dict = getattr(ctx.Gen, 'variables', {}) - if var_name in variables: - var_val: Any = variables[var_name] - if hasattr(var_val, 'type') and isinstance(var_val.type, ir.PointerType): - pointee: ir.Type = var_val.type.pointee - if isinstance(pointee, ir.PointerType): - return 1 - return 0 - # 类型名 / typedef:通过 TypeMergeHandler 获取 CTypeInfo - type_info = ctx.translator.TypeMergeHandler.GetCTypeInfo(arg_node) - if type_info and (type_info.IsPtr or type_info.PtrCount > 0): - return 1 - if type_info and not (type_info.IsPtr or type_info.PtrCount > 0): - return 0 - return None - except Exception: - return None - return None - - @staticmethod - def _eval_arith(node: ast.AST, recurse: Callable[[ast.AST], Any]) -> Optional[Any]: - """通用算术求值:BinOp + UnaryOp""" - if isinstance(node, ast.BinOp): - left: Any = recurse(node.left) - right: Any = recurse(node.right) - if left is None or right is None: - return None - return ConstEvaluator._apply_binop(node.op, left, right) - if isinstance(node, ast.UnaryOp): - operand: Any = recurse(node.operand) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.UAdd): - return +operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - return None - - @staticmethod - def _apply_binop(op: ast.operator, left: Any, right: Any) -> Optional[Any]: - """应用二元运算符""" - try: - if isinstance(op, ast.Add): - return left + right - elif isinstance(op, ast.Sub): - return left - right - elif isinstance(op, ast.Mult): - return left * right - elif isinstance(op, ast.Div): - return left // right if isinstance(left, int) and isinstance(right, int) else left / right - elif isinstance(op, ast.FloorDiv): - if isinstance(right, (int, float)) and right == 0: - return None - return left // right - elif isinstance(op, ast.Mod): - if isinstance(right, (int, float)) and right == 0: - return None - return left % right - elif isinstance(op, ast.Pow): - return left ** right - elif isinstance(op, ast.LShift): - return left << right - elif isinstance(op, ast.RShift): - return left >> right - elif isinstance(op, ast.BitOr): - return left | right - elif isinstance(op, ast.BitXor): - return left ^ right - elif isinstance(op, ast.BitAnd): - return left & right - except Exception: - return None - return None - - @staticmethod - def _eval_compare_op(op: ast.cmpop, left: Any, right: Any) -> Optional[bool]: - """应用比较运算符""" - if isinstance(op, ast.Eq): - return left == right - elif isinstance(op, ast.NotEq): - return left != right - elif isinstance(op, ast.Lt): - return left < right - elif isinstance(op, ast.LtE): - return left <= right - elif isinstance(op, ast.Gt): - return left > right - elif isinstance(op, ast.GtE): - return left >= right - return None - - @staticmethod - def _eval_ctype_size_attr(node: ast.Attribute) -> Optional[int]: - """求值 t.CSizeT().Size 等类型构造调用 + .Size 属性模式。 - - 匹配 AST 形态: Attribute(attr='Size', value=Call(func=Attribute(value=Name(id='t'), attr='CSizeT'))) - 或直接 Call(func=Name(id='CSizeT'))(from t import CSizeT 后的使用方式)。 - 返回类型大小(位数),如 CSizeT().Size 返回 64(64 位平台)。 - """ - if node.attr != 'Size': - return None - if not isinstance(node.value, ast.Call): - return None - call_node: ast.Call = node.value - if call_node.args or call_node.keywords: - return None - func: ast.expr = call_node.func - type_name: str | None = None - if isinstance(func, ast.Attribute) and isinstance(func.value, ast.Name) and func.value.id == 't': - type_name = func.attr - elif isinstance(func, ast.Name): - type_name = func.id - if not type_name: - return None - # 延迟导入避免循环依赖 - try: - from lib.includes.t import CTypeRegistry - except Exception: - return None - cls = CTypeRegistry.GetClassByName(type_name) - if cls is None: - return None - try: - instance = cls() - size_val = getattr(instance, 'Size', None) - if isinstance(size_val, int): - return size_val - except Exception: - pass - return None - - @staticmethod - def _eval_attribute_define(node: ast.Attribute, symtab: Any) -> Optional[Any]: - """从 SymbolTable 查找 Attribute 形式的 define 值""" - parts: list[str] = [] - current: ast.AST = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - attr_name: str = parts[-1] - possible_keys: list[str] = [attr_name, '.'.join(parts)] - for key in possible_keys: - if hasattr(symtab, '__contains__') and key in symtab: - info: CTypeInfo = symtab[key] - if info.IsDefine and isinstance(info.DefineValue, int): - return info.DefineValue - # 模糊匹配 - if len(parts) >= 2: - mod_key: str - mod_info: CTypeInfo - for mod_key, mod_info in (symtab.items() if hasattr(symtab, 'items') else []): - if mod_info.IsDefine and isinstance(mod_info.DefineValue, int): - if mod_key.endswith('.' + attr_name) or mod_key == attr_name: - return mod_info.DefineValue - return None - - @staticmethod - def _intify(val: Any) -> Any: - """float → int 转换(仅当 float 值恰好是整数时)""" - if isinstance(val, float) and val == int(val): - return int(val) - return val - - -class EvalContext: - """常量求值上下文,封装 Gen / SymbolTable / 平台宏查找逻辑。 - - 由调用方构造并传入 ConstEvaluator.eval_full()。 - """ - - def __init__(self, Gen: LlvmCodeGenerator | None = None, symtab: Any = None, platform_macros: dict | None = None, translator: Any = None): - self.Gen: LlvmCodeGenerator | None = Gen - self.symtab: Any = symtab - self._platform_macros: dict | None = platform_macros - self.translator: Any = translator - - def lookup_name(self, name: str) -> Optional[Any]: - """查找 Name 节点的值:define_constants → SymbolTable → 平台宏""" - # 1. Gen._define_constants - if self.Gen and name in self.Gen._define_constants: - val: Any = self.Gen._define_constants[name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 2. Gen._DefineConstants (大写版本) - if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants: - val: Any = self.Gen._DefineConstants[name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 3. SymbolTable - if self.symtab and name in self.symtab: - info: CTypeInfo = self.symtab[name] - val: Any = info.value - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 4. 平台宏 - macros: dict = self._get_platform_macros() - if name in macros: - return macros[name] - - return None - - def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]: - """查找 Attribute 节点的值""" - module_name: str | None = node.value.id if isinstance(node.value, ast.Name) else None - attr_name: str = node.attr - - if module_name and attr_name: - combined_key: str = f"{module_name}.{attr_name}" - - # 1. Gen._define_constants - if self.Gen and combined_key in self.Gen._define_constants: - val: Any = self.Gen._define_constants[combined_key] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 2. SymbolTable (精确匹配 + 后缀匹配) - if self.symtab: - key: str - info: CTypeInfo - for key, info in self.symtab.items(): - if key.endswith(f".{combined_key}") or key == combined_key: - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 3. _all_define_constants - all_dc: dict = self._get_all_define_constants() - if combined_key in all_dc: - val: Any = all_dc[combined_key] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - if attr_name in all_dc: - val: Any = all_dc[attr_name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - dc_key: str - dc_val: Any - for dc_key, dc_val in all_dc.items(): - if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): - if isinstance(dc_val, (int, float)): - return ConstEvaluator._intify(dc_val) - - # 4. SymbolTable 短名查找 - if self.symtab and attr_name in self.symtab: - info: CTypeInfo = self.symtab[attr_name] - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 5. Gen._define_constants 短名 - if self.Gen and attr_name in self.Gen._define_constants: - val: Any = self.Gen._define_constants[attr_name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 6. 平台宏 - macros: dict = self._get_platform_macros() - full_key: str | None = self._get_attr_full_name(node) - if full_key: - if full_key in macros: - return macros[full_key] - short_name: str = full_key.split('.')[-1] if '.' in full_key else full_key - if short_name in macros: - return macros[short_name] - - return None - - def _get_all_define_constants(self) -> dict: - """获取 _all_define_constants""" - if self.Gen and hasattr(self.Gen, '_all_define_constants'): - return self.Gen._all_define_constants - return {} - - def _get_platform_macros(self) -> dict: - """获取平台宏""" - if self._platform_macros is not None: - return self._platform_macros - if not self.Gen: - return {} - macros: dict[str, int] = {} - pi: dict = self.Gen._platform_info - ptr_size: int = self.Gen.ptr_size - if pi.get('is_windows'): - macros['_WIN32'] = 1 - if not pi.get('is_32bit'): - macros['_WIN64'] = 1 - macros['WIN64'] = 1 - macros['WIN32'] = 1 - if pi.get('is_linux'): - macros['__linux__'] = 1 - if pi.get('is_macos'): - macros['__APPLE__'] = 1 - macros['__MACH__'] = 1 - if pi.get('is_x86_64'): - macros['__x86_64__'] = 1 - macros['__x86_64'] = 1 - macros['_M_X64'] = 1 - elif pi.get('is_arm64'): - macros['__aarch64__'] = 1 - macros['_M_ARM64'] = 1 - if not pi.get('is_32bit') and pi.get('is_linux'): - macros['__LP64__'] = 1 - elif pi.get('is_32bit'): - macros['_ILP32'] = 1 - macros['SIZEOF_VOID_P'] = ptr_size - macros['__SIZEOF_POINTER__'] = ptr_size - macros['NDEBUG'] = 0 - return macros - - @staticmethod - def _get_attr_full_name(node: ast.Attribute) -> Optional[str]: - """从 Attribute 节点提取完整名称 (e.g. 'module.name')""" - parts: list[str] = [] - current: ast.AST = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - return '.'.join(parts) if parts else None diff --git a/App/lib/core/DecoratorPass.py b/App/lib/core/DecoratorPass.py deleted file mode 100644 index 475f3f3..0000000 --- a/App/lib/core/DecoratorPass.py +++ /dev/null @@ -1,547 +0,0 @@ -""" -DecoratorPass - Viper 语言自定义装饰器的 IR 层包装转换 (v4) - -v4 增强版特性: -1. 栈帧局部上下文 (ctx):替代全局变量,解决并发/递归状态错乱 -2. 流程劫持:handler 返回 i32 控制原函数调用次数 - - 返回 0:跳过原函数调用(@cache, @mock) - - 返回 1:正常调用一次(默认) - - 返回 N > 1:循环调用 N 次(@repeat) -3. alwaysinline 属性:消除 wrapper 调用开销 -4. 参数打包与修改:pre-phase 后从 args_struct 读回参数,装饰器可修改入参 -5. 返回值修改:ret_ptr 可写,装饰器可在后置阶段修改返回值 -6. 递归装饰保护:最外层 wrapper 检查全局标志位,递归调用时跳过所有装饰逻辑 - -装饰器调用约定 (v4): - i32 decor_name(i8* ctx, i8* func_name, i32 phase, - i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) - - 参数说明: - ctx : i8* - 栈帧局部上下文缓冲区(32字节),每次调用独立分配 - 前置阶段可写入状态,后置阶段可读取,生命周期绑定本次调用 - 多线程/递归完全隔离,替代全局变量 - func_name : i8* - 原始函数名字符串 - phase : i32 - 执行阶段(0=前置, 1=后置) - args_ptr : i8* - 指向函数参数打包结构体(可读写,无参数时为 null) - 前置阶段可写入修改参数值,wrapper 会从结构体读回修改后的参数 - ret_ptr : i8* - 指向返回值(前置阶段为 null,void 函数始终为 null) - 后置阶段可读写,装饰器可修改返回值 - decor_args_ptr : i8* - 指向装饰器参数打包结构体(无参数装饰器为 null) - - 返回值(仅前置阶段有效,后置阶段忽略): - 0 : 跳过原函数调用(@cache, @mock, @skip) - 1 : 调用原函数一次(默认行为,@log, @timing, @trace) - N>1: 循环调用原函数 N 次(@repeat, @benchmark) - - 编译器生成的 wrapper(以 add(i32, i32) -> i32, @log 为例): - define i32 @__decor_wrap_add(i32 %a, i32 %b) alwaysinline { - entry: - ; 递归保护:检查标志位 - %rec_val = Load i8, i8* @__decor_rec___decor_wrap_add - %is_rec = icmp ne i8 %rec_val, 0 - br i1 %is_rec, label %recursive_call, label %decorated_entry - - recursive_call: - ; 递归调用:跳过所有装饰逻辑,直接调用原函数 - %rec_result = call i32 @add(i32 %a, i32 %b) - ret i32 %rec_result - - decorated_entry: - ; 设置递归保护标志 - store i8 1, i8* @__decor_rec___decor_wrap_add - - ; 分配栈帧局部上下文 - %ctx = alloca [32 x i8] - %ctx_ptr = bitcast [32 x i8]* %ctx to i8* - - ; 打包函数参数到结构体(装饰器可通过 args_ptr 修改) - %args = alloca {i32, i32} - store i32 %a, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) - store i32 %b, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) - %args_ptr = bitcast {i32, i32}* %args to i8* - - ; 分配返回值存储(零初始化) - %ret = alloca i32 - store i32 0, i32* %ret - - ; 前置阶段:handler 返回调用次数 - %n = call i32 @log(i8* %ctx_ptr, i8* "add", i32 0, - i8* %args_ptr, i8* null, i8* null) - br label %loop.header - - loop.header: - %i = phi i32 [0, %decorated_entry], [%i.next, %loop.body] - %cond = icmp slt i32 %i, %n - br i1 %cond, label %loop.body, label %post - - loop.body: - ; 从结构体读回参数(装饰器可能已修改) - %a.Loaded = Load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) - %b.Loaded = Load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) - %result = call i32 @add(i32 %a.Loaded, i32 %b.Loaded) - store i32 %result, i32* %ret - %i.next = add i32 %i, 1 - br label %loop.header - - post: - %ret_ptr = bitcast i32* %ret to i8* - call i32 @log(i8* %ctx_ptr, i8* "add", i32 1, - i8* %args_ptr, i8* %ret_ptr, i8* null) - - ; 清除递归保护标志 - store i8 0, i8* @__decor_rec___decor_wrap_add - - %final = Load i32, i32* %ret - ret i32 %final - } - -链式装饰器(从下到上嵌套): - @log - @timing - def f(x) -> int: - 等价于 log(timing(f)) - 执行顺序:log_pre → timing_pre → f → timing_post → log_post - 生成:__decor_wrap_f (log) → __decor_wrap_f_timing (timing) → f - 递归保护仅在最外层 wrapper 生效,递归调用直接跳到原始 f -""" -from __future__ import annotations -import llvmlite.ir as ir -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - - -# 栈帧局部上下文缓冲区大小(字节) -_CTX_SIZE: int = 32 - -# 装饰器处理函数的 LLVM 签名:i32 (i8*, i8*, i32, i8*, i8*, i8*) -_DECOR_HANDLER_PARAM_TYPES: ir.FunctionType | None = None # 延迟初始化 - - -def _get_decor_handler_func_type() -> ir.FunctionType: - """获取装饰器处理函数的 LLVM FunctionType: i32 (i8*, i8*, i32, i8*, i8*, i8*)""" - global _DECOR_HANDLER_PARAM_TYPES - if _DECOR_HANDLER_PARAM_TYPES is None: - i8_ptr: ir.PointerType = ir.IntType(8).as_pointer() - _DECOR_HANDLER_PARAM_TYPES = ir.FunctionType( - ir.IntType(32), - [i8_ptr, i8_ptr, ir.IntType(32), i8_ptr, i8_ptr, i8_ptr] - ) - return _DECOR_HANDLER_PARAM_TYPES - - -def _find_or_declare_handler(module: ir.Module, handler_name: str) -> ir.Function: - """在 module 中查找或声明装饰器处理函数""" - f: ir.Function - for f in module.functions: - if f.name == handler_name: - return f - func_type: ir.FunctionType = _get_decor_handler_func_type() - handler: ir.Function = ir.Function(module, func_type, name=handler_name) - return handler - - -def _make_string_constant(module: ir.Module, text: str, name_prefix: str = "decor.str") -> ir.Constant: - """在 module 中创建一个全局字符串常量,返回 i8* 指针""" - counter: int = getattr(_make_string_constant, '_counter', 0) + 1 - _make_string_constant._counter = counter - const_name: str = f"{name_prefix}.{counter}" - - encoded: bytes = text.encode('utf-8') + b'\x00' - const_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(encoded)) - const_val: ir.Constant = ir.Constant(const_type, bytearray(encoded)) - - global_var: ir.GlobalVariable = ir.GlobalVariable(module, const_type, name=const_name) - global_var.global_constant = True - global_var.linkage = 'private' - global_var.initializer = const_val - - return global_var.bitcast(ir.IntType(8).as_pointer()) - - -def _make_decor_args_constant(module: ir.Module, decorator_info: dict) -> ir.Constant: - """ - 为带参数的装饰器生成全局常量结构体,返回 i8* 指针。 - 无参数装饰器返回 null。 - - 支持的参数类型: - - int → i32 / i64 - - float → f64 - - bool → i1 - - str → i8*(全局字符串常量) - """ - deco_args: list = decorator_info.get('args', []) - deco_kwargs: dict = decorator_info.get('kwargs', {}) - - if not deco_args and not deco_kwargs: - return ir.Constant(ir.IntType(8).as_pointer(), None) - - field_types: list = [] - field_values: list = [] - - arg: int | str | float | bool - for arg in deco_args: - llvm_type: ir.Type | None - llvm_val: ir.Constant | None - llvm_type, llvm_val = _python_value_to_llvm(module, arg) - if llvm_type is None: - return ir.Constant(ir.IntType(8).as_pointer(), None) - field_types.append(llvm_type) - field_values.append(llvm_val) - - kw: str - for kw in sorted(deco_kwargs.keys()): - llvm_type: ir.Type | None - llvm_val: ir.Constant | None - llvm_type, llvm_val = _python_value_to_llvm(module, deco_kwargs[kw]) - if llvm_type is None: - return ir.Constant(ir.IntType(8).as_pointer(), None) - field_types.append(llvm_type) - field_values.append(llvm_val) - - struct_type: ir.LiteralStructType = ir.LiteralStructType(field_types) - struct_const: ir.Constant = ir.Constant(struct_type, field_values) - - counter: int = getattr(_make_decor_args_constant, '_counter', 0) + 1 - _make_decor_args_constant._counter = counter - global_name: str = f"__decor_args.{counter}" - - global_var: ir.GlobalVariable = ir.GlobalVariable(module, struct_type, name=global_name) - global_var.global_constant = True - global_var.linkage = 'private' - global_var.initializer = struct_const - - return global_var.bitcast(ir.IntType(8).as_pointer()) - - -def _python_value_to_llvm(module: ir.Module, value: int | str | float | bool) -> tuple[ir.Type | None, ir.Constant | None]: - """将 Python 值转换为 (LLVM类型, LLVM常量) 元组。""" - if isinstance(value, bool): - return ir.IntType(1), ir.Constant(ir.IntType(1), int(value)) - elif isinstance(value, int): - if -2**31 <= value < 2**31: - return ir.IntType(32), ir.Constant(ir.IntType(32), value) - else: - return ir.IntType(64), ir.Constant(ir.IntType(64), value) - elif isinstance(value, float): - return ir.DoubleType(), ir.Constant(ir.DoubleType(), value) - elif isinstance(value, str): - str_const = _make_string_constant(module, value, name_prefix="decor.arg") - return ir.IntType(8).as_pointer(), str_const - else: - return None, None - - -def _ZeroConstant(llvm_type: ir.Type) -> ir.Constant | None: - """为给定 LLVM 类型创建零值常量""" - 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_zero: ir.Constant | None = _ZeroConstant(llvm_type.element) - if elem_zero is None: - return None - return ir.Constant(llvm_type, [elem_zero] * llvm_type.count) - else: - return None - - -def _generate_single_wrapper(module: ir.Module, original_func: ir.Function, wrapper_name: str, func_name_str: str, - decorator_info: dict, is_export: bool = False, - is_outermost: bool = False, true_original_func: ir.Function | None = None) -> ir.Function: - """ - 为单个装饰器生成一层 wrapper 函数。 - - v4 Wrapper 结构(最外层含递归保护): - entry → 递归保护检查(仅最外层) - recursive_call → 递归时直接调用原函数,跳过所有装饰(仅最外层) - decorated_entry → 设置递归标志,分配 ctx/args/ret,调用 handler 前置 - loop.header → phi 计数器,比较 i < n_calls - loop.body → 从 args_struct 读回参数(支持修改),调用原函数 - post → 调用 handler 后置,清除递归标志,返回结果 - """ - decor_name: str = decorator_info['name'] - handler: ir.Function = _find_or_declare_handler(module, decor_name) - func_name_const: ir.Constant = _make_string_constant(module, func_name_str, name_prefix="decor.fn") - - func_type: ir.FunctionType = original_func.ftype - return_type: ir.Type = func_type.return_type - param_types: list[ir.Type] = [p.type for p in original_func.args] - is_void: bool = isinstance(return_type, ir.VoidType) - - wrapper_type: ir.FunctionType = ir.FunctionType(return_type, param_types) - wrapper: ir.Function = ir.Function(module, wrapper_type, name=wrapper_name) - - # 添加 alwaysinline 属性,优化器完全内联消除调用开销 - wrapper.attributes.add('alwaysinline') - - i32: ir.IntType = ir.IntType(32) - i8: ir.IntType = ir.IntType(8) - i8_ptr: ir.PointerType = ir.IntType(8).as_pointer() - phase_pre: ir.Constant = ir.Constant(i32, 0) - phase_post: ir.Constant = ir.Constant(i32, 1) - null_ptr: ir.Constant = ir.Constant(i8_ptr, None) - zero_i32: ir.Constant = ir.Constant(i32, 0) - one_i32: ir.Constant = ir.Constant(i32, 1) - one_i8: ir.Constant = ir.Constant(i8, 1) - zero_i8: ir.Constant = ir.Constant(i8, 0) - - # 递归保护:仅最外层 wrapper 生成 - rec_flag: ir.GlobalVariable | None = None - if is_outermost and true_original_func is not None: - rec_flag_name: str = f"__decor_rec_{wrapper_name}" - # 检查是否已存在 - rec_flag = None - g: ir.GlobalValue - for g in module.global_values: - if g.name == rec_flag_name: - rec_flag = g - break - if rec_flag is None: - rec_flag = ir.GlobalVariable(module, i8, name=rec_flag_name) - rec_flag.global_constant = False - rec_flag.linkage = 'internal' - rec_flag.initializer = zero_i8 - - # 创建基本块 - entry_block: ir.Block = wrapper.append_basic_block("entry") - - recursive_call_block: ir.Block | None - decorated_entry_block: ir.Block | None - if rec_flag is not None: - recursive_call_block = wrapper.append_basic_block("recursive_call") - decorated_entry_block = wrapper.append_basic_block("decorated_entry") - else: - recursive_call_block = None - decorated_entry_block = None - - loop_header_block: ir.Block = wrapper.append_basic_block("loop.header") - loop_body_block: ir.Block = wrapper.append_basic_block("loop.body") - post_block: ir.Block = wrapper.append_basic_block("post") - - # ==== Entry block ==== - builder: ir.IRBuilder = ir.IRBuilder(entry_block) - - loop_predecessor: ir.Block - if rec_flag is not None: - # 递归保护:检查标志位 - rec_val: ir.LoadInstr = builder.load(rec_flag, name="rec_val") - is_recursive: ir.ICMPInstr = builder.icmp_signed('!=', rec_val, zero_i8) - builder.cbranch(is_recursive, recursive_call_block, decorated_entry_block) - - # ==== Recursive call block ==== - builder = ir.IRBuilder(recursive_call_block) - # 递归调用:直接调用真正的原函数,跳过所有装饰逻辑 - rec_call_args: list[ir.Argument] = [arg for arg in wrapper.args] - rec_ret_val: ir.CallInstr = builder.call(true_original_func, rec_call_args) - if is_void: - builder.ret_void() - else: - builder.ret(rec_ret_val) - - # ==== Decorated entry block ==== - builder = ir.IRBuilder(decorated_entry_block) - # 设置递归保护标志 - builder.store(one_i8, rec_flag) - - # 记录 loop.header 的前置块为 decorated_entry_block - loop_predecessor = decorated_entry_block - else: - loop_predecessor = entry_block - - # 1. 分配栈帧局部上下文(每次调用独立,线程安全,递归安全) - ctx_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), _CTX_SIZE) - ctx_alloca: ir.AllocaInstr = builder.alloca(ctx_type, name="ctx") - ctx_ptr: ir.BitCastInstr = builder.bitcast(ctx_alloca, i8_ptr) - - # 2. 打包函数参数到结构体(装饰器可通过 args_ptr 读写修改) - args_alloca: ir.AllocaInstr | None = None - args_struct_type: ir.LiteralStructType | None = None - if param_types: - args_struct_type = ir.LiteralStructType(param_types) - args_alloca = builder.alloca(args_struct_type, name="args") - zero: ir.Constant = ir.Constant(i32, 0) - i: int - arg: ir.Argument - for i, arg in enumerate(wrapper.args): - field_idx: ir.Constant = ir.Constant(i32, i) - gep: ir.GEPInstr = builder.gep(args_alloca, [zero, field_idx], inbounds=True) - builder.store(arg, gep) - args_ptr: ir.BitCastInstr | ir.Constant = builder.bitcast(args_alloca, i8_ptr) - else: - args_ptr = null_ptr - - # 3. 分配返回值存储(零初始化,确保跳过原函数时返回安全默认值) - ret_alloca: ir.AllocaInstr | None - if not is_void: - ret_alloca = builder.alloca(return_type, name="ret") - zero_val: ir.Constant | None = _ZeroConstant(return_type) - if zero_val is not None: - builder.store(zero_val, ret_alloca) - else: - ret_alloca = None - - # 4. 获取装饰器参数指针 - decor_args_ptr: ir.Constant = _make_decor_args_constant(module, decorator_info) - - # 5. 前置阶段:handler 返回调用次数 - n_calls: ir.CallInstr = builder.call(handler, [ctx_ptr, func_name_const, phase_pre, - args_ptr, null_ptr, decor_args_ptr]) - - # 6. 跳转到循环头 - builder.branch(loop_header_block) - - # ==== Loop header block ==== - builder = ir.IRBuilder(loop_header_block) - i_phi: ir.PhiInstr = builder.phi(i32, "i") - i_phi.add_incoming(zero_i32, loop_predecessor) - cond: ir.ICMPInstr = builder.icmp_signed('<', i_phi, n_calls) - builder.cbranch(cond, loop_body_block, post_block) - - # ==== Loop body block ==== - builder = ir.IRBuilder(loop_body_block) - - # v4: 从 args_struct 读回参数(装饰器可能在 pre-phase 中修改了参数) - call_args: list[ir.LoadInstr | ir.Argument] = [] - if args_alloca is not None and args_struct_type is not None: - zero = ir.Constant(i32, 0) - for i in range(len(param_types)): - field_idx: ir.Constant = ir.Constant(i32, i) - gep: ir.GEPInstr = builder.gep(args_alloca, [zero, field_idx], inbounds=True) - Loaded_arg: ir.LoadInstr = builder.load(gep, name=f"arg.{i}") - call_args.append(Loaded_arg) - - ret_val: ir.CallInstr = builder.call(original_func, call_args) - if ret_alloca is not None: - builder.store(ret_val, ret_alloca) - i_next: ir.AddInstr = builder.add(i_phi, one_i32) - i_phi.add_incoming(i_next, loop_body_block) - builder.branch(loop_header_block) - - # ==== Post block ==== - builder = ir.IRBuilder(post_block) - - # 后置阶段 - ret_ptr: ir.BitCastInstr | ir.Constant - if ret_alloca is not None: - ret_ptr = builder.bitcast(ret_alloca, i8_ptr) - else: - ret_ptr = null_ptr - builder.call(handler, [ctx_ptr, func_name_const, phase_post, - args_ptr, ret_ptr, decor_args_ptr]) - - # 递归保护:清除标志(必须在 post-phase 之后、return 之前) - if rec_flag is not None: - builder.store(zero_i8, rec_flag) - - # 返回 - if is_void: - builder.ret_void() - else: - final_ret: ir.LoadInstr = builder.load(ret_alloca, name="final_ret") - builder.ret(final_ret) - - return wrapper - - -def _redirect_calls(module: ir.Module, old_func: ir.Function, new_func: ir.Function, skip_func_names: set[str] | None = None) -> None: - """ - 替换 module 中所有对 old_func 的调用指令为对 new_func 的调用。 - 跳过 skip_func_names 中的函数(wrapper 函数内部不应被重定向)。 - """ - if skip_func_names is None: - skip_func_names = set() - - func: ir.Function - for func in module.functions: - if func.name in skip_func_names: - continue - if func.name == new_func.name: - continue - block: ir.Block - for block in func.blocks: - instr: ir.Instruction - for instr in list(block.instructions): - if not isinstance(instr, ir.CallInstr): - continue - callee: ir.Function = instr.callee - if isinstance(callee, ir.Function) and callee is old_func: - instr.callee = new_func - - -def run(Gen: LlvmCodeGenerator) -> None: - """ - 执行 DecoratorPass。 - - 处理流程: - 1. 遍历 _decorated_funcs 中所有带装饰标记的函数 - 2. 对每个函数,按装饰器列表从底到顶生成嵌套 wrapper - 3. 将原函数改为 internal 链接 - 4. 替换所有调用点 - """ - if not Gen._decorated_funcs: - return - - module: ir.Module = Gen.module - decorated: dict = Gen._decorated_funcs.copy() - - mangled_name: str - info: dict - for mangled_name, info in decorated.items(): - decorators: list = info['decorators'] - func_name: str = info['func_name'] - is_export: bool = info['is_export'] - - # 查找原始函数 - original_func: ir.Function | None = None - f: ir.Function - for f in module.functions: - if f.name == mangled_name: - original_func = f - break - if original_func is None: - continue - - # 原函数改为 internal 链接(仅 wrapper 调用) - original_func.linkage = 'internal' - - # 按装饰器列表从底到顶生成嵌套 wrapper - # Python 装饰器顺序:@a @b def f() => a(b(f)) - # 执行顺序:先应用最靠近函数的 @b,再应用 @a - - current_func: ir.Function = original_func - all_wrapper_names: set[str] = set() - - i: int - for i in range(len(decorators) - 1, -1, -1): - deco: dict = decorators[i] - is_outermost: bool = (i == 0) - deco_name: str = deco['name'] - - wrapper_name: str - if is_outermost: - wrapper_name = f"__decor_wrap_{mangled_name}" - else: - wrapper_name = f"__decor_wrap_{mangled_name}_{deco_name}" - - all_wrapper_names.add(wrapper_name) - - wrapper: ir.Function = _generate_single_wrapper( - module, current_func, wrapper_name, - func_name, deco, is_export=is_export, - is_outermost=is_outermost, - true_original_func=original_func if is_outermost else None - ) - current_func = wrapper - - # 更新 functions 映射,使原函数名指向最外层 wrapper - Gen.functions[mangled_name] = current_func - if func_name in Gen.functions: - Gen.functions[func_name] = current_func - - # 替换所有非 wrapper 函数中对原函数的调用 - _redirect_calls(module, original_func, current_func, all_wrapper_names) diff --git a/App/lib/core/DiagnosticCollector.py b/App/lib/core/DiagnosticCollector.py deleted file mode 100644 index 33b7357..0000000 --- a/App/lib/core/DiagnosticCollector.py +++ /dev/null @@ -1,48 +0,0 @@ -"""诊断系统 — 收集编译过程中的警告和错误 - -替代原先静默回退的模式: - - return 'i32' → 记录 Warning + 回退到 'i32' - - return [] → 记录 Error + 回退到 [] - -使用方式: - diag = DiagnosticCollector() - diag.warn(file, lineno, "无法解析类型,回退到 i32") - diag.error(file, lineno, f"加载模块失败: {path}") - diag.report() # 打印所有诊断信息 -""" -from __future__ import annotations - -import os -from dataclasses import dataclass, field -from enum import Enum -from typing import List - - -class DiagnosticLevel(Enum): - WARNING = "WARNING" - ERROR = "ERROR" - - -@dataclass -class Diagnostic: - level: DiagnosticLevel - file: str - lineno: int - message: str - - def __str__(self) -> str: - short_file: str = os.path.basename(self.file) if self.file else "" - return f"[{self.level.value}] {short_file}:{self.lineno} — {self.message}" - - -class DiagnosticCollector: - """诊断信息收集器""" - - def __init__(self) -> None: - self._diagnostics: list[Diagnostic] = [] - - def warn(self, file: str, lineno: int, message: str) -> None: - self._diagnostics.append(Diagnostic(DiagnosticLevel.WARNING, file, lineno, message)) - - def error(self, file: str, lineno: int, message: str) -> None: - self._diagnostics.append(Diagnostic(DiagnosticLevel.ERROR, file, lineno, message)) diff --git a/App/lib/core/Exportable.py b/App/lib/core/Exportable.py deleted file mode 100644 index ca6f9d7..0000000 --- a/App/lib/core/Exportable.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -""" -导出表模块 - 用于收集和存储文件的公开符号信息 -""" -from __future__ import annotations -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Any - - -@dataclass -class EnumMember: - """枚举成员信息""" - name: str - value: int - lineno: int - - -@dataclass -class EnumInfo: - """枚举类型信息""" - name: str - members: List[EnumMember] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class FunctionParam: - """函数参数信息""" - name: str - type_name: str - is_pointer: bool = False - - -@dataclass -class FunctionInfo: - """函数信息""" - name: str - return_type: str - params: List[FunctionParam] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class StructMember: - """结构体成员信息""" - name: str - type_name: str - is_pointer: bool = False - array_size: Optional[int] = None - - -@dataclass -class StructInfo: - """结构体类型信息""" - name: str - members: List[StructMember] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class TypedefInfo: - """类型别名信息""" - name: str - original_type: str - lineno: int = 0 - is_public: bool = True - - -@dataclass -class Exportable: - """导出表 - 存储文件的所有公开符号""" - filename: str - enums: List[EnumInfo] = field(default_factory=list) - functions: List[FunctionInfo] = field(default_factory=list) - structs: List[StructInfo] = field(default_factory=list) - typedefs: List[TypedefInfo] = field(default_factory=list) - - def add_enum(self, name: str, lineno: int, is_public: bool = True) -> EnumInfo: - """添加枚举类型""" - enum_info: EnumInfo = EnumInfo(name=name, lineno=lineno, is_public=is_public) - self.enums.append(enum_info) - return enum_info - - def add_function(self, name: str, return_type: str, lineno: int, is_public: bool = True) -> FunctionInfo: - """添加函数""" - func_info: FunctionInfo = FunctionInfo(name=name, return_type=return_type, lineno=lineno, is_public=is_public) - self.functions.append(func_info) - return func_info - - def add_struct(self, name: str, lineno: int, is_public: bool = True) -> StructInfo: - """添加结构体""" - struct_info: StructInfo = StructInfo(name=name, lineno=lineno, is_public=is_public) - self.structs.append(struct_info) - return struct_info - - def add_typedef(self, name: str, original_type: str, lineno: int, is_public: bool = True) -> TypedefInfo: - """添加类型别名""" - typedef_info: TypedefInfo = TypedefInfo(name=name, original_type=original_type, lineno=lineno, is_public=is_public) - self.typedefs.append(typedef_info) - return typedef_info - - def to_dict(self) -> Dict[str, Any]: - """转换为字典格式""" - return { - 'filename': self.filename, - 'enums': [ - { - 'name': enum.name, - 'lineno': enum.lineno, - 'is_public': enum.is_public, - 'members': [ - {'name': m.name, 'value': m.value, 'lineno': m.lineno} - for m in enum.members - ] - } - for enum in self.enums - ], - 'functions': [ - { - 'name': func.name, - 'return_type': func.return_type, - 'lineno': func.lineno, - 'is_public': func.is_public, - 'params': [ - {'name': p.name, 'type_name': p.type_name, 'is_pointer': p.is_pointer} - for p in func.params - ] - } - for func in self.functions - ], - 'structs': [ - { - 'name': struct.name, - 'lineno': struct.lineno, - 'is_public': struct.is_public, - 'members': [ - { - 'name': m.name, - 'type_name': m.type_name, - 'is_pointer': m.is_pointer, - 'array_size': m.array_size - } - for m in struct.members - ] - } - for struct in self.structs - ], - 'typedefs': [ - { - 'name': typedef.name, - 'original_type': typedef.original_type, - 'lineno': typedef.lineno, - 'is_public': typedef.is_public - } - for typedef in self.typedefs - ] - } - diff --git a/App/lib/core/Handles/HandlesAssert.py b/App/lib/core/Handles/HandlesAssert.py deleted file mode 100644 index 93b0392..0000000 --- a/App/lib/core/Handles/HandlesAssert.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - -class AssertHandle(BaseHandle): - def _HandleAssertLlvm(self, Node: ast.Assert) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - cond_val: ir.Value | None = self.HandleExprLlvm(Node.test) - if not cond_val: - return - if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1: - zero: ir.Constant = ir.Constant(cond_val.type, 0) - cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond") - AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail") - AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok") - Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB) - Gen.builder.position_at_start(AssertFailBB) - exc_code: int = 9 - exc_msg: ir.Value | None = None - if Node.msg: - if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str): - exc_msg = self.HandleExprLlvm(Node.msg) - elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name): - exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99) - if Node.msg.args: - first_arg: ast.expr = Node.msg.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - exc_msg = self.HandleExprLlvm(first_arg) - elif isinstance(Node.msg, ast.Name): - exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99) - else: - exc_msg = self.HandleExprLlvm(Node.msg) - if Gen.eh_except_block_stack: - ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] - EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] - exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] - eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] - Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code) - if exc_msg: - Gen._store(exc_msg, eh_message) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen._store(null_ptr, eh_message) - Gen.builder.branch(ExceptBB) - else: - printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - if exc_msg: - fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string') - Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print") - else: - fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string') - Gen.builder.call(printf_func, [fmt], name="assert_fail_print") - exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)])) - Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit") - Gen.builder.unreachable() - Gen.builder.position_at_start(AssertOkBB) \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesDelete.py b/App/lib/core/Handles/HandlesDelete.py deleted file mode 100644 index f4871d9..0000000 --- a/App/lib/core/Handles/HandlesDelete.py +++ /dev/null @@ -1,102 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta -import ast -import llvmlite.ir as ir - - -class DeleteHandle(BaseHandle): - def _HandleDeleteLlvm(self, Node: ast.Delete) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for target in Node.targets: - if isinstance(target, ast.Subscript): - ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__delitem__'): - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value) - idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice) - if obj_val and idx_val: - # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 - if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8: - obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__") - elif isinstance(target, ast.Name): - ClassName: str | None = Gen.var_struct_class.get(target.id) - if ClassName and Gen._has_function(f'{ClassName}.__delete__'): - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) - if obj_val: - # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 - if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8: - obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__") - elif isinstance(target, ast.Attribute): - # 检查 property deleter - AttrName: str = target.attr - ClassName: str | None = None - obj_val_for_prop: ir.Value | None = None - - if isinstance(target.value, ast.Name) and target.value.id == 'self': - # del self.attr — 检查当前类的 property deleter - ClassName = self.Trans._CurrentCpythonObjectClass - if ClassName: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: - SelfVar: ir.Value | None = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr: ir.Value = Gen._load(SelfVar, name="self") - DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') - if DeleterFunc and SelfPtr: - Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}") - continue - else: - # del obj.attr — 检查 obj 类的 property deleter - ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen) - if ClassName: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value) - if obj_val: - DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') - if DeleterFunc: - Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}") - continue - - # 原有的 __del__ 处理逻辑 - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType): - obj_val = Gen._load(obj_val, name="Load_del_ptr") - ClassName = None - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - for CN, ST in Gen.structs.items(): - if obj_val.type.pointee == ST: - ClassName = CN - break - elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if isinstance(target.value, ast.Name) and target.value.id == 'self': - AttrName = target.attr - SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass - if SelfClassName and SelfClassName in Gen.class_members: - for member_name, member_type in Gen.class_members[SelfClassName]: - if member_name == AttrName: - for CN in Gen.structs: - if CN == AttrName or Gen._has_function(f'{CN}.__del__'): - ClassName = CN - break - break - if not ClassName: - for CN, ST in Gen.structs.items(): - if Gen._has_function(f'{CN}.__del__'): - ClassName = CN - break - if ClassName and Gen._has_function(f'{ClassName}.__del__'): - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__") \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesExprAsm.py b/App/lib/core/Handles/HandlesExprAsm.py deleted file mode 100644 index 22cff72..0000000 --- a/App/lib/core/Handles/HandlesExprAsm.py +++ /dev/null @@ -1,580 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -import ast -import re -import llvmlite.ir as ir -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -from lib.core.SymbolUtils import IsTModule -from lib.includes import t - -# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数 -# 添加保护避免重复补丁 -_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False) - -if not _InlineAsmPatched: - _OrigInlineAsmInit = ir.InlineAsm.__init__ - _OrigInlineAsmDescr = ir.InlineAsm.descr - - def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None): - _OrigInlineAsmInit(self, ftype, asm, constraint, side_effect) - self.asm_dialect = asm_dialect - - def _patched_inline_asm_descr(self, buf): - sideeffect = 'sideeffect' if self.side_effect else '' - dialect_str = getattr(self, 'asm_dialect', None) - if dialect_str == 'intel': - dialect = 'inteldialect' - else: - dialect = '' - fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"' - buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm, - constraint=self.constraint)) - - ir.InlineAsm.__init__ = _patched_inline_asm_init - ir.InlineAsm.descr = _patched_inline_asm_descr - ir.InlineAsm._transpyc_patched = True - - -class ExprAsmHandle(BaseHandle): - @staticmethod - def _format_to_dialect(asm_format: str | None) -> str | None: - """将用户指定的 format 参数转换为 LLVM asm_dialect 值""" - fmt: str = asm_format.lower() if asm_format else 'intel' - if fmt == 'att': - return 'att' - elif fmt == 'arm': - return None # ARM 没有专门的 dialect 标记 - else: - return 'intel' # 默认 Intel - - def _HandleAsmLlvm(self, Node: ast.Call) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - - op_arg: Any = None - input_arg: Any = None - output_arg: Any = None - asm_format: str = 'Intel' # 汇编格式: Intel / AT&T / ARM - for kw in Node.keywords: - if kw.arg == 'op': - op_arg = kw.value - elif kw.arg in ('input', 'inp', 'inputs'): - input_arg = kw.value - elif kw.arg in ('output', 'out', 'outputs'): - output_arg = kw.value - elif kw.arg == 'format': - if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): - asm_format = kw.value.value - - if len(Node.args) >= 1: - pos_op: Any = None - if len(Node.args) >= 2 and op_arg is None: - pos_op = Node.args[1] - return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format) - - if len(Node.args) < 2: - return ir.Constant(ir.IntType(32), 1) - - args: list[ast.AST] = Node.args - - if len(args) == 4: - output_type_arg: ast.AST = args[0] - asm_template_arg: ast.AST = args[1] - constraint_arg: ast.AST = args[2] - clobber_arg: ast.AST = args[3] - - output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg) - if not output_type: - output_type = ir.IntType(32) - - asm_template: str = '' - if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) - - constraint: str = '' - if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str): - constraint = constraint_arg.value - - clobber: str = '' - if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str): - clobber = clobber_arg.value - - full_constraint: str = constraint - func_type: ir.FunctionType = ir.FunctionType(output_type, []) - asm_dialect: str | None = self._format_to_dialect(asm_format) - inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect) - result: Any = Gen.builder.call(inline_asm, [], name="asm_result") - return result - - elif len(args) >= 2: - output_type_arg: ast.AST = args[0] - asm_template_arg: ast.AST = args[1] - - output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg) - if not output_type: - output_type = ir.IntType(32) - - asm_template: str = '' - if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) - - output_constraints: list[str] = [] - output_values: list[Any] = [] - if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)): - for item in args[2].elts: - if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - constraint_node: ast.AST = item.elts[0] - value_node: ast.AST = item.elts[1] - if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): - output_constraints.append(constraint_node.value) - value: Any = self.HandleExprLlvm(value_node) - if value: - output_values.append(value) - - input_constraints: list[str] = [] - input_values: list[Any] = [] - if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)): - for item in args[3].elts: - if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - constraint_node: ast.AST = item.elts[0] - value_node: ast.AST = item.elts[1] - if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): - input_constraints.append(constraint_node.value) - value: Any = self.HandleExprLlvm(value_node) - if value: - input_values.append(value) - - clobbers: list[str] = [] - if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)): - for item in args[4].elts: - if isinstance(item, ast.Constant) and isinstance(item.value, str): - clobbers.append(item.value) - - constraint_parts: list[str] = [] - for oc in output_constraints: - constraint_parts.append(oc) - - input_start_idx: int = len(output_constraints) - for ic in input_constraints: - constraint_parts.append(ic) - - full_constraint: str = ",".join(constraint_parts) - - if clobbers: - if full_constraint: - full_constraint += "," - for c in clobbers: - full_constraint += f"~{{{c}}}" - - operands: list[Any] = output_values + input_values - param_types: list[ir.Type] = [v.type for v in operands] - func_type: ir.FunctionType = ir.FunctionType(output_type, param_types) - asm_dialect: str | None = self._format_to_dialect(asm_format) - inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect) - result: Any = Gen.builder.call(inline_asm, operands, name="asm_result") - return result - - return None - - def _prepare_intel_asm(self, template: str) -> str: - template = re.sub(r'%(\d+)', r'$\1', template) - template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template) - return template - - def _normalize_asm_template(self, template: str) -> str: - lines = template.split('\n') - if len(lines) <= 1: - return template - first_line = lines[0] - rest_lines = lines[1:] - stripped = [] - for line in rest_lines: - s = line.lstrip() - if s: - stripped.append(s) - else: - stripped.append('') - return '\n'.join([first_line] + stripped) - - def _process_joined_str_template(self, node: ast.AST, out_input_ops: list[Any], out_input_constraints: list[str], - out_output_ops: list[Any], out_output_constraints: list[str]) -> str: - if not isinstance(node, ast.JoinedStr): - if isinstance(node, ast.Constant) and isinstance(node.value, str): - return node.value - return '' - - raw_parts: list[tuple[str, str | int]] = [] - for value in node.values: - if isinstance(value, ast.Constant) and isinstance(value.value, str): - raw_parts.append(('text', value.value)) - elif isinstance(value, ast.FormattedValue): - expr: ast.AST = value.value - if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): - if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': - if expr.func.attr == 'AsmInp': - if expr.args: - v: Any = self.HandleExprLlvm(expr.args[0]) - if v: - c: str = 'r' - if len(expr.args) >= 2: - c = self._parse_asm_descr(expr.args[1]) - if not c: - c = 'r' - out_input_ops.append(v) - out_input_constraints.append(c) - raw_parts.append(('input', len(out_input_ops) - 1)) - elif expr.func.attr == 'AsmOut': - if expr.args: - target_ptr: Any = self._get_var_ptr_for_asm(expr.args[0]) - if target_ptr: - v = target_ptr - else: - v = self.HandleExprLlvm(expr.args[0]) - if v: - c: str = '=r' - if len(expr.args) >= 2: - c = self._parse_asm_descr(expr.args[1]) - if not c: - c = '=r' - if not c.startswith('='): - c = '=' + c - out_output_ops.append(v) - out_output_constraints.append(c) - raw_parts.append(('output', len(out_output_ops) - 1)) - else: - fallback: Any = self.HandleExprLlvm(expr) - if fallback and isinstance(fallback.type, ir.IntType): - out_input_ops.append(fallback) - out_input_constraints.append('r') - raw_parts.append(('input', len(out_input_ops) - 1)) - else: - raw_parts.append(('text', '')) - - num_outputs: int = len(out_output_ops) - parts: list[str] = [] - for kind, data in raw_parts: - if kind == 'text': - parts.append(data) - elif kind == 'output': - parts.append(f'%{data}') - elif kind == 'input': - parts.append(f'%{num_outputs + data}') - return ''.join(parts) - - _X86_REGISTERS = frozenset({ - 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', - 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', - 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp', - 'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp', - 'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh', - 'sil', 'dil', 'bpl', 'spl', - 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', - 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', - 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', - }) - - def _mangle_asm_calls(self, template: str) -> str: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - sha1: str = getattr(Gen, 'module_sha1', '') - if not sha1: - return template - - def replace_call(m: re.Match[str]) -> str: - prefix: str = m.group(1) - func_name: str = m.group(2) - if func_name.lower() in self._X86_REGISTERS: - return m.group(0) - mangled: str = Gen._mangle_func_name(func_name) - if '.' in mangled: - return f'{prefix}\\22{mangled}\\22' - return f"{prefix}{mangled}" - - return re.sub(r'(call\s+)(\w+)', replace_call, template) - - def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - - input_ops: list[Any] = [] - input_constraints: list[str] = [] - output_ops: list[Any] = [] - output_constraints: list[str] = [] - - if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)): - for item in output_arg.elts: - if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): - if item.func.value.id == 'c' and item.func.attr == 'AsmOut': - if len(item.args) >= 1: - target_ptr: Any = self._get_var_ptr_for_asm(item.args[0]) - if target_ptr: - output_ops.append(target_ptr) - else: - value: Any = self.HandleExprLlvm(item.args[0]) - if value: - output_ops.append(value) - constraint: str = '=r' - if len(item.args) >= 2: - base_constraint: str = self._parse_asm_descr(item.args[1]) - if base_constraint: - if base_constraint.startswith('='): - constraint = base_constraint - else: - constraint = '=' + base_constraint - output_constraints.append(constraint) - - raw_template: str - if isinstance(asm_template_arg, ast.JoinedStr): - raw_template = self._normalize_asm_template( - self._process_joined_str_template( - asm_template_arg, input_ops, input_constraints, output_ops, output_constraints - ) - ) - elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - raw_template = self._normalize_asm_template(asm_template_arg.value) - else: - raw_template = '' - - raw_template = self._mangle_asm_calls(raw_template) - asm_dialect: str | None = self._format_to_dialect(asm_format) - asm_template: str - if asm_format == 'AT&T': - asm_template = raw_template # AT&T 不需要转换 - elif asm_format == 'ARM': - asm_template = raw_template # ARM 不需要转换 - else: - asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式 - - if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)): - for item in input_arg.elts: - if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): - if item.func.value.id == 'c' and item.func.attr == 'AsmInp': - if len(item.args) >= 1: - value: Any = self.HandleExprLlvm(item.args[0]) - if value: - input_ops.append(value) - constraint: str = 'r' - if len(item.args) >= 2: - constraint = self._parse_asm_descr(item.args[1]) - if not constraint: - constraint = 'r' - input_constraints.append(constraint) - elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - value_node: ast.AST = item.elts[0] - descr_node: ast.AST = item.elts[1] - value: Any = self.HandleExprLlvm(value_node) - if value: - input_ops.append(value) - constraint: str = self._parse_asm_descr(descr_node) - if not constraint: - constraint = 'r' - input_constraints.append(constraint) - - clobbers: list[str] = [] - if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)): - for item in op_arg.elts: - clobber: str = self._parse_asm_descr(item) - if clobber: - clobbers.append(clobber) - - constraint_parts: list[str] = [] - for oc in output_constraints: - c: str = oc if oc.startswith('=') else ('=' + oc) - constraint_parts.append(c) - for ic in input_constraints: - if ic in ('d', 'edx', 'rdx'): - constraint_parts.append('{dx}') - else: - constraint_parts.append(ic) - - full_constraint: str = ",".join(constraint_parts) - - constraint_to_reg: dict[str, str] = { - 'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx', - 'S': 'rsi', 'D': 'rdi', - 'A': 'rax', 'U': 'r8', - } - used_regs: set[str] = set() - for ic in input_constraints: - if ic in constraint_to_reg: - used_regs.add(constraint_to_reg[ic]) - for oc in output_constraints: - base_oc: str = oc.lstrip('=').lstrip('+') - if base_oc in constraint_to_reg: - used_regs.add(constraint_to_reg[base_oc]) - - if clobbers: - has_memory: bool = 'memory' in clobbers - if has_memory and output_ops: - clobbers = [c for c in clobbers if c != 'memory'] - clobber_final: list[str] - if asm_format == 'ARM': - # ARM 不需要 x86 的 e→r 寄存器名转换 - clobber_final = [c for c in clobbers if c not in used_regs] - else: - clobber_64bit: list[str] = [] - for c in clobbers: - if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']: - clobber_64bit.append(c.replace('e', 'r')) - else: - clobber_64bit.append(c) - clobber_final = [c for c in clobber_64bit if c not in used_regs] - if clobber_final: - if full_constraint: - full_constraint += "," - full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final]) - - if output_ops: - single_out: bool = len(output_ops) == 1 - if single_out: - op: Any = output_ops[0] - ret_type: ir.Type - if isinstance(op, ir.AllocaInstr): - ret_type = op.type.pointee - elif isinstance(op, ir.GlobalVariable): - ret_type = op.type.pointee - elif isinstance(op, (ir.GEPInstr, ir.CastInstr)): - ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type - else: - ret_type = op.type - else: - def _get_ret_type(op: Any) -> ir.Type: - if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)): - return op.type.pointee - return op.type - ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops]) - if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType): - ret_type = ir.IntType(64) - operands: list[Any] = input_ops - param_types: list[ir.Type] = [op.type for op in operands] - func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect) - result: Any = Gen.builder.call(inline_asm, operands, name="asm_result") - if single_out: - target: Any = output_ops[0] - if isinstance(target, ir.AllocaInstr): - if target.type.pointee != result.type: - i64t: ir.IntType = ir.IntType(64) - iv: Any = Gen.builder.ptrtoint(result, i64t) - ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(result, target) - elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)): - target_pointee: ir.Type = target.type.pointee - if target_pointee != result.type: - if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64): - ptr_val: Any = Gen.builder.inttoptr(result, target_pointee) - Gen.builder.store(ptr_val, target) - else: - i64t: ir.IntType = ir.IntType(64) - iv: Any = Gen.builder.ptrtoint(result, i64t) - ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(result, target) - else: - dst: Any = Gen._allocaEntry(result.type) - Gen.builder.store(result, dst) - else: - for i, out_op in enumerate(output_ops): - val: Any = Gen.builder.extract_value(result, i, name=f"asm_out_{i}") - target: Any = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._allocaEntry(val.type) - if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type: - i64t: ir.IntType = ir.IntType(64) - iv: Any = Gen.builder.ptrtoint(val, i64t) - ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(val, target) - else: - operands: list[Any] = input_ops - param_types: list[ir.Type] = [op.type for op in operands] - func_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), param_types) - inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect) - Gen.builder.call(inline_asm, operands, name="asm_call") - return ir.Constant(ir.IntType(32), 1) - - def _get_var_ptr_for_asm(self, node: ast.AST) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(node, ast.Name): - var_name: str = node.id - if var_name in Gen.variables and Gen.variables[var_name] is not None: - ptr: Any = Gen.variables[var_name] - if isinstance(ptr, ir.AllocaInstr): - return ptr - if isinstance(ptr, ir.GlobalVariable): - return ptr - elif isinstance(node, ast.Attribute): - obj_ptr: Any = self._get_var_ptr_for_asm(node.value) - if obj_ptr is not None: - obj_type: ir.Type = obj_ptr.type.pointee - if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType): - Loaded: Any = Gen.builder.load(obj_ptr, name="asm_attr_Load") - struct_type: ir.IdentifiedStructType = obj_type.pointee - class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None - if class_name: - offset: int = Gen._get_member_offset(node.attr, class_name) - gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), offset)], - inbounds=True) - return gep - for idx, elem_type in enumerate(struct_type.elements): - gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), idx)], - inbounds=True) - return gep - elif isinstance(obj_type, ir.IdentifiedStructType): - class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None - if class_name: - offset: int = Gen._get_member_offset(node.attr, class_name) - gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), offset)], - inbounds=True) - return gep - for idx, elem_type in enumerate(obj_type.elements): - gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), idx)], - inbounds=True) - return gep - return None - - def _parse_asm_descr(self, expr: ast.AST) -> str: - if isinstance(expr, ast.BinOp): - left_val: str = self._parse_asm_descr(expr.left) - right_val: str = self._parse_asm_descr(expr.right) - return left_val + right_val - - elif isinstance(expr, ast.Attribute): - if isinstance(expr.value, ast.Attribute): - if (isinstance(expr.value.value, ast.Name) and - IsTModule(expr.value.value.id, self.Trans.SymbolTable) and - expr.value.attr == 'ASM_DESCR'): - AttrName: str = expr.attr - return getattr(t.ASM_DESCR, AttrName, "") - elif isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable): - AttrName: str = expr.attr - return getattr(t.ASM_DESCR, AttrName, "") - - elif isinstance(expr, ast.Constant): - return expr.value - - return "" - - def _infer_expr_llvm_type(self, expr: ast.AST) -> ir.Type | None: - if isinstance(expr, ast.Name): - type_name: str = expr.id - if hasattr(t, type_name): - ctype: Any = getattr(t, type_name) - if isinstance(ctype, type) and issubclass(ctype, t.CType): - size: Any = getattr(ctype, 'Size', None) - if size is not None: - return ir.IntType(size) - if type_name == 'CFloat': - return ir.FloatType() - elif type_name == 'CDouble': - return ir.DoubleType() - elif isinstance(expr, ast.Attribute): - if isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable): - return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load())) - return None diff --git a/App/lib/core/Handles/HandlesExprAttr.py b/App/lib/core/Handles/HandlesExprAttr.py deleted file mode 100644 index dbfc085..0000000 --- a/App/lib/core/Handles/HandlesExprAttr.py +++ /dev/null @@ -1,1480 +0,0 @@ -from __future__ import annotations -from typing import Any, TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta -import ast -import llvmlite.ir as ir - - -class ExprAttrHandle(BaseHandle): - - # ========== 辅助方法 ========== - - def _apply_bswap_on_Load(self, val: ir.Value, ClassName: str, AttrName: str) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - byte_order: str = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "") - return Gen._apply_bswap_if_big(val, byte_order, f"bswap_load_{AttrName}") - - def _load_arr_elem_with_bswap(self, Gen: LlvmCodeGenerator, ElemPtr: ir.Value, arr_byte_order: str) -> ir.Value: - """加载数组元素并按字节序应用 bswap""" - val: ir.Value = Gen._load(ElemPtr, name="arr_elem_load") - return Gen._apply_bswap_if_big(val, arr_byte_order, "bswap_arr_load") - - def _gep_and_Load_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, offset: int | None, AttrName: str, ClassName: str, ST: ir.Type | None = None) -> ir.Value | None: - """从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况""" - if offset is None: - return None - if isinstance(ObjVal.type, ir.PointerType): - pointee: Any = ObjVal.type.pointee - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements): - # sha1 冲突修复:pointee 字段不足时,尝试 bitcast 到 ST(更完整的版本) - if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements): - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_gep_{ClassName}") - else: - return None - MemberPtr: Any = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType): - return MemberPtr - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType): - return MemberPtr - # 检查 pointer-to-pointer 且实际元素是 ArrayType - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType): - actual_elem_type: Any = None - if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements): - actual_elem_type = ST.elements[offset] - if isinstance(actual_elem_type, ir.ArrayType): - return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}") - # 检查 class_members 中的 ArrayType - if ClassName in Gen.class_members: - for member_name, member_type in Gen.class_members[ClassName]: - if member_name == AttrName and isinstance(member_type, ir.ArrayType): - return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}") - val: Any = Gen._load(MemberPtr, name=AttrName) - return self._apply_bswap_on_Load(val, ClassName, AttrName) - - def _try_Load_struct_from_stub(self, Gen: LlvmCodeGenerator, ClassName: str) -> tuple[ir.Type | None, bool]: - """尝试从 stub 加载结构体定义,返回 (struct_type, ok)""" - if ClassName not in Gen.structs: - return None, False - st: Any = Gen.structs[ClassName] - if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - st = Gen.structs.get(ClassName, st) - if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): - return st, False - return st, True - - def _find_specialized_struct_with_body(self, Gen: LlvmCodeGenerator, opaque_struct: Any) -> tuple[ir.IdentifiedStructType, str] | None: - """查找 opaque 非特化泛型结构体的特化版本(如 GSList -> GSList[Param])。 - 所有特化版本布局相同,可用于 GEP 偏移计算。""" - if not isinstance(opaque_struct, ir.IdentifiedStructType): - return None - base_name: str = opaque_struct.name or "" - short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name - if not short_name or '[' in short_name: - return None - for CN2, ST2 in Gen.structs.items(): - if not isinstance(ST2, ir.IdentifiedStructType): - continue - if ST2 is opaque_struct: - continue - if ST2.elements is None: - continue - st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "") - if st2_short.startswith(short_name + '['): - return (ST2, CN2) - return None - - def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str, parent_hint: str | None = None) -> ir.Value | None: - """通过特化版本访问 opaque 非特化泛型结构体成员。 - - 遍历所有候选特化版本(如 GSList[Param]/GSList[NameEntry]), - 优先选择 class_members 中包含 Node.attr 字段的版本, - 避免选到错误特化版本(如 GSList[NameEntry] 而非 GSList[Param]) - 导致 _get_member_offset 返回 None 而生成 ret null。 - - parent_hint: 父上下文提供的特化提示(如 'GSList[BasicBlock]'), - 当所有候选都有目标字段(如 Head/Tail/Count)时, - 用此提示选择正确特化版本。""" - # 收集所有候选特化版本(有 body 的) - candidates: list[tuple[ir.IdentifiedStructType, str]] = [] - if isinstance(opaque_struct, ir.IdentifiedStructType): - base_name: str = opaque_struct.name or "" - short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name - if short_name and '[' not in short_name: - for CN2, ST2 in Gen.structs.items(): - if not isinstance(ST2, ir.IdentifiedStructType): - continue - if ST2 is opaque_struct: - continue - if ST2.elements is None: - continue - st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "") - if st2_short.startswith(short_name + '['): - candidates.append((ST2, CN2)) - if not candidates: - return None - # 优先级 1: parent_hint 精确匹配(如 'GSList[BasicBlock]') - # 当父对象字段声明记录了特化名时,直接使用,避免 Head/Tail/Count 等公共字段歧义 - if parent_hint: - hint_short: str = parent_hint.split('.')[-1] if '.' in parent_hint else parent_hint - for spec_st, spec_CN in candidates: - spec_short: str = spec_CN.split('.')[-1] if '.' in spec_CN else spec_CN - if spec_short == hint_short: - CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}") - for lookup_CN in (spec_CN, orig_CN): - bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr) - offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN) - if offset is not None: - return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st) - break - # 优先级 2: class_members 中包含 Node.attr 字段的特化版本 - best_candidate: tuple[ir.IdentifiedStructType, str] | None = None - for spec_st, spec_CN in candidates: - for lookup_CN in (spec_CN, orig_CN): - lookup_short: str = lookup_CN.split('.')[-1] if '.' in lookup_CN else lookup_CN - for chk_CN in (lookup_CN, lookup_short): - if chk_CN in Gen.class_members: - if any(name == Node.attr for name, _ in Gen.class_members[chk_CN]): - best_candidate = (spec_st, spec_CN) - break - if best_candidate: - break - if best_candidate: - break - if best_candidate is None: - best_candidate = candidates[0] - spec_st: ir.IdentifiedStructType - spec_CN: str - spec_st, spec_CN = best_candidate - CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}") - for lookup_CN in (spec_CN, orig_CN): - bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr) - offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN) - if offset is not None: - return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st) - return None - - def _make_define_constant(self, Gen: LlvmCodeGenerator, val: int | float | str) -> ir.Value | None: - """将 CDefine 值转为 LLVM 常量""" - if isinstance(val, int): - if abs(val) > 2147483647: - return ir.Constant(ir.IntType(64), val) - return ir.Constant(ir.IntType(32), val) - elif isinstance(val, float): - return ir.Constant(ir.DoubleType(), val) - elif isinstance(val, str): - return Gen._create_string_global(val) - return None - - def _lookup_cdefine(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None: - """在符号表和模块中查找 CDefine 常量值""" - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - if not imported_modules: - return None - PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - key: str = f"{mod_name}.{AttrName}" - if key not in PossibleKeys: - PossibleKeys.append(key) - for lookup_key in PossibleKeys: - SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key) - if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None: - return self._make_define_constant(Gen, SymInfo.DefineValue) - # 也检查 _define_constants - define_constants: Any = getattr(Gen, '_define_constants', {}) - for key in (f"{VarName}.{AttrName}", AttrName): - if key in define_constants: - return self._make_define_constant(Gen, define_constants[key]) - return None - - def _lookup_module_global(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None: - """在模块全局变量中查找 import 的属性""" - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - if not imported_modules: - return None - resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) - if VarName not in imported_modules and resolved_mod not in imported_modules: - return None - PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - key: str = f"{mod_name}.{AttrName}" - if key not in PossibleKeys: - PossibleKeys.append(key) - for key in PossibleKeys: - if key in Gen.module.globals: - GVar: Any = Gen.module.globals[key] - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return Gen._load(GVar, name=AttrName) - # SHA1 前缀查找 - ModuleSha1Map: Any = getattr(Gen, 'ModuleSha1Map', {}) - sha1_candidates: list[str] = [VarName, resolved_mod] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - if mod_name not in sha1_candidates: - sha1_candidates.append(mod_name) - for cand in sha1_candidates: - sha1: str | None = ModuleSha1Map.get(cand) - if sha1: - prefixed: str = f"{sha1}.{AttrName}" - if prefixed in Gen.module.globals: - GVar2: Any = Gen.module.globals[prefixed] - if isinstance(GVar2, ir.Function): - return GVar2 - if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar2 - return Gen._load(GVar2, name=AttrName) - if AttrName in Gen.module.globals: - gv: Any = Gen.module.globals[AttrName] - if AttrName in Gen.variables and Gen.variables[AttrName] is None: - str_gv_name: str = AttrName + '_str' - if str_gv_name in Gen.module.globals: - str_gv: Any = Gen.module.globals[str_gv_name] - return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") - return Gen.builder.load(gv, name=AttrName) - return None - - def _resolve_var_classname(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None: - """根据变量名解析其结构体类名""" - ClassName: str | None = Gen.var_struct_class.get(VarName) - if not ClassName and getattr(Gen, 'global_struct_class', None): - ClassName = Gen.global_struct_class.get(VarName) - if ClassName: - Gen.var_struct_class[VarName] = ClassName - if not ClassName and VarName in Gen.module.globals: - GVar: Any = Gen.module.globals[VarName] - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found: Any = Gen.find_struct_by_pointee(GVar.type.pointee) - if found: - ClassName = found[0] - Gen.var_struct_class[VarName] = ClassName - if getattr(Gen, 'global_struct_class', None): - Gen.global_struct_class[VarName] = ClassName - if not ClassName and VarName in Gen.variables: - VarPtr: Any = Gen.variables[VarName] - if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType): - pointee: Any = VarPtr.type.pointee - if isinstance(pointee, ir.PointerType): - pointee = pointee.pointee - found = Gen.find_struct_by_pointee(pointee) - if found: - ClassName = found[0] - return ClassName - - def _check_struct_match(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, ClassName: str) -> bool: - """检查 ObjVal 是否指向 ClassName 对应的结构体""" - if ClassName not in Gen.structs: - return False - if isinstance(ObjVal.type, ir.PointerType): - ST: Any = Gen.structs[ClassName] - if ObjVal.type.pointee == ST: - return True - if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType): - # 精确名匹配(含 sha1 前缀)或短名匹配(去掉 sha1 前缀) - if ObjVal.type.pointee.name == ST.name: - return True - if Gen._extract_short_name(ObjVal.type.pointee.name) == Gen._extract_short_name(ST.name): - return True - return False - - # ========== _HandleAttributeLlvm 子方法 ========== - - def _handle_attr_self(self, Node: ast.Attribute, VarName: str) -> ir.Value | None: - """处理 self.xxx 属性访问""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ClassName: str | None = self.Trans._CurrentCpythonObjectClass - if not ClassName: - return None - # 检查 property getter - PropKey: str = f'{ClassName}.{Node.attr}' - PropInfo: Any = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: - SelfVar: Any = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr: Any = Gen._load(SelfVar, name="self") - GetterFunc: Any = Gen._get_function(PropKey) - if GetterFunc and SelfPtr: - return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}") - offset: int | None = Gen._get_member_offset(Node.attr, ClassName) - SelfVar = Gen._get_var_ptr('self') - if not SelfVar: - return None - SelfPtr = Gen._load(SelfVar, name="self") - if not isinstance(SelfPtr.type, ir.PointerType): - return None - pointee: Any = SelfPtr.type.pointee - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: - # 修复 Bug 4/5:NoVTable fix 清除 struct elements 后,_handle_attr_self - # 必须主动从 stub 文件重新加载 struct 定义,否则 self.Trans 等属性访问 - # 会因 pointee.elements 为 None 返回 None,导致 AnnAssign/Store 不生成 IR。 - # 与 _handle_attr_nested 的处理保持一致。 - # 策略:先用 ClassName 直接尝试加载;若失败,遍历 Gen.structs 按名字匹配 - # 找到对应的 dict key(可能是 sha1 前缀形式),再用该 key 加载。 - loaded: bool = False - for TryCN in (ClassName,): - st, ok = self._try_Load_struct_from_stub(Gen, TryCN) - if ok and isinstance(st, ir.IdentifiedStructType) and st.elements is not None: - pointee = st - loaded = True - break - if not loaded: - for CN2, ST2 in Gen.structs.items(): - if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name: - st2, ok2 = self._try_Load_struct_from_stub(Gen, CN2) - if ok2 and isinstance(st2, ir.IdentifiedStructType) and st2.elements is not None: - pointee = st2 - loaded = True - break - if not loaded: - # 最后回退:在 Gen.structs 中查找同名非 opaque 版本 - for CN2, ST2 in Gen.structs.items(): - if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None: - pointee = ST2 - break - # 当 pointee 元素数不足以容纳 offset 时(常见于跨模块继承:子类 struct - # 在父类 class_members 加载前生成,只有部分继承字段),从 Gen.structs - # 中查找同名且元素数更多的完整定义。 - if (isinstance(pointee, ir.IdentifiedStructType) - and offset is not None - and pointee.elements is not None - and offset >= len(pointee.elements)): - _cur_count: int = len(pointee.elements) - for CN2, ST2 in Gen.structs.items(): - if (isinstance(ST2, ir.IdentifiedStructType) - and ST2.name == pointee.name - and ST2.elements is not None - and len(ST2.elements) > _cur_count - and offset < len(ST2.elements)): - pointee = ST2 - break - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements): - if isinstance(pointee.elements[offset], ir.VoidType): - return None - return self._gep_and_Load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee) - DynamicVarName: str = f"self.{Node.attr}" - if DynamicVarName in Gen.variables: - return Gen._load(Gen.variables[DynamicVarName], name=Node.attr) - return None - - def _handle_attr_enum(self, Node: ast.Attribute, VarName: str) -> ir.Value | None: - """处理枚举成员访问 (VarName 是枚举类型名)""" - SymInfo: Any = self.Trans.SymbolTable.lookup(VarName) - if not SymInfo or not SymInfo.IsEnum: - return None - # 优先用带前缀的 key 查找(避免短名被同名函数/变量覆盖) - FullKey: str = f"{VarName}.{Node.attr}" - MemberInfo: Any = self.Trans.SymbolTable.lookup(FullKey) - if not MemberInfo or not MemberInfo.IsEnumMember or MemberInfo.EnumName != VarName: - # 回退到短名查找 - MemberInfo = self.Trans.SymbolTable.lookup(Node.attr) - if not MemberInfo or not MemberInfo.IsEnumMember or MemberInfo.EnumName != VarName: - # 最后遍历符号表 - for key, info in self.Trans.SymbolTable.items(): - if info.IsEnumMember and info.EnumName == VarName and key == Node.attr: - if isinstance(info.value, int): - return ir.Constant(ir.IntType(32), info.value) - return None - if isinstance(MemberInfo.value, int): - return ir.Constant(ir.IntType(32), MemberInfo.value) - return None - - def _handle_attr_name(self, Node: ast.Attribute, VarName: str) -> ir.Value | None: - """处理 x.attr 形式 (x 是普通 Name)""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - AttrName: str = Node.attr - - # __doc__ 魔法字符串:函数/结构体的 docstring - if AttrName == '__doc__': - doc_ptr: ir.Value | None = Gen._get_doc_ptr(VarName) - if doc_ptr is not None: - return doc_ptr - - # 先尝试枚举成员 - result: Any = self._handle_attr_enum(Node, VarName) - if result is not None: - return result - - # 尝试 CDefine 常量 - result = self._lookup_cdefine(Gen, VarName, AttrName) - if result is not None: - return result - - # 尝试 import 模块全局变量 - result = self._lookup_module_global(Gen, VarName, AttrName) - if result is not None: - return result - - # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) - # 当 a 是 str 变量时, a 本身是 char*, 但 a__meta__ 存储了 __data__/__mbuddy__ 等字段 - # 直接通过 a.__field__ 访问影子结构体字段 (语法糖) - _fd_meta_name: str = f"{VarName}__meta__" - if _fd_meta_name in Gen.variables and '_str' in Gen.structs: - _fd_offset = Gen._get_member_offset(AttrName, '_str') - if _fd_offset is not None: - _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] - _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") - return Gen._load(_fd_field_ptr, name=f"{VarName}_{AttrName}_val") - - # 解析结构体类名:若 VarName 是结构体变量,优先走结构体字段访问路径 - # 避免结构体字段名(如 stdout)与全局变量名冲突时被误解析为全局变量 - ClassName: str | None = self._resolve_var_classname(Gen, VarName) - - # 尝试 attr 直接作为全局变量(仅当 VarName 不是结构体变量时) - if not ClassName and AttrName in Gen.module.globals: - gv: Any = Gen.module.globals[AttrName] - if AttrName in Gen.variables and Gen.variables[AttrName] is None: - str_gv_name: str = AttrName + '_str' - if str_gv_name in Gen.module.globals: - str_gv: Any = Gen.module.globals[str_gv_name] - return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") - return Gen.builder.load(gv, name=AttrName) - - if not ClassName: - return None - - # 检查 property getter - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: Any = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: - ObjVal: Any = self.HandleExprLlvm(Node.value) - GetterFunc: Any = Gen._get_function(PropKey) - if GetterFunc and ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}") - - # 获取类型信息 - TypeInfo: Any = self.Trans.SymbolTable.lookup(ClassName) - IsUnion: bool = TypeInfo.IsUnion if TypeInfo else False - IsCenum: bool = TypeInfo.IsEnum if TypeInfo else False - IsRenum: bool = TypeInfo.IsRenum if TypeInfo else False - - # REnum 处理 - if IsRenum: - if AttrName == 'tag': - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - tag_ptr: Any = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr") - return Gen._load(tag_ptr, name="tag_val") - NestedStructName: str = f"{ClassName}_{AttrName}" - if NestedStructName in Gen.structs: - NestedStructType: Any = Gen.structs[NestedStructName] - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") - - # CEnum 处理 - if IsCenum: - for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"): - info: Any = self.Trans.SymbolTable.lookup(qname) - if info and info.IsEnumMember and isinstance(info.value, int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if key == AttrName: - if info.IsEnumMember and info.EnumName == ClassName: - if isinstance(info.value, int): - return ir.Constant(ir.IntType(32), info.value) - break - - # CUnion 处理 - if IsUnion: - NestedStructName = f"{ClassName}_{AttrName}" - if NestedStructName in Gen.structs: - NestedStructType = Gen.structs[NestedStructName] - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") - - # 普通结构体成员访问 - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal: - return None - # char* → struct* cast - if self._is_char_pointer(ObjVal): - if ClassName in Gen.structs: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - # 二级指针解引用 - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - - # 检查结构体匹配 - struct_match: bool = self._check_struct_match(Gen, ObjVal, ClassName) - if not struct_match and ClassName and VarName: - if VarName in Gen.var_struct_class: - CN: str = Gen.var_struct_class[VarName] - if CN != ClassName and CN in Gen.structs: - ClassName = CN - struct_match = self._check_struct_match(Gen, ObjVal, ClassName) - # 最终回退:var_struct_class 可能被前一个函数污染(如 cur 在不同函数中 - # 分别是 Line/Param/BasicBlock),通过 ObjVal 的实际 pointee 类型恢复正确类名。 - # 但若 var_struct_class 已记录特化名(如 ndarray[double]),且 ObjVal 的 - # pointee 是对应的 opaque 基础类型(如 ndarray),则 bitcast 到特化版本, - # 不覆盖为裸模板名(否则后续方法调用会查找 ndarray.xxx 而非 ndarray[double].xxx) - if not struct_match and isinstance(ObjVal.type, ir.PointerType): - found: Any = Gen.find_struct_by_pointee(ObjVal.type.pointee) - if found: - found_name: str = found[0] - # 检查 var_struct_class 是否已记录 found_name 的特化版本 - preserved: bool = False - if VarName and VarName in Gen.var_struct_class: - cur_spec: str = Gen.var_struct_class[VarName] - if ('[' in cur_spec - and cur_spec.split('[')[0] == found_name - and cur_spec in Gen.structs): - # bitcast ObjVal (opaque base*) 到特化类型指针,保留特化名 - ObjVal = Gen.builder.bitcast( - ObjVal, ir.PointerType(Gen.structs[cur_spec]), - name=f"cast_spec_{cur_spec}") - ClassName = cur_spec - struct_match = True - preserved = True - if not preserved: - ClassName = found_name - struct_match = True - if VarName: - Gen.var_struct_class[VarName] = ClassName - elif isinstance(ObjVal.type.pointee, ir.IdentifiedStructType): - # sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时, - # 用短名匹配,优先选字段最多的完整版本 - pointee_short: str = Gen._extract_short_name(ObjVal.type.pointee.name) - best_elem_count: int = 0 - for CN, ST in Gen.structs.items(): - if isinstance(ST, ir.IdentifiedStructType): - st_short: str = Gen._extract_short_name(ST.name) - if st_short == pointee_short: - elem_count: int = len(ST.elements) if ST.elements else 0 - if elem_count > best_elem_count: - ClassName = CN - best_elem_count = elem_count - struct_match = True - if struct_match and VarName: - # 同样保护特化名:若已记录的特化名的短名基础部分与 ClassName 匹配,保留 - cur_spec2: str = Gen.var_struct_class.get(VarName, '') - if ('[' in cur_spec2 - and cur_spec2.split('[')[0] == ClassName - and cur_spec2 in Gen.structs): - ObjVal = Gen.builder.bitcast( - ObjVal, ir.PointerType(Gen.structs[cur_spec2]), - name=f"cast_spec_{cur_spec2}") - ClassName = cur_spec2 - else: - Gen.var_struct_class[VarName] = ClassName - if not struct_match: - return None - - st: Any - ok: bool - st, ok = self._try_Load_struct_from_stub(Gen, ClassName) - if not ok: - return None - - # bitfield 处理 - bitfield_offsets: Any = Gen.class_member_bitoffsets.get(ClassName, {}) - bitfields: Any = Gen.class_member_bitfields.get(ClassName, {}) - if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0: - return self._load_bitfield_member(ObjVal, ClassName, AttrName) - if AttrName in bitfields and bitfields[AttrName] > 0: - if ClassName not in Gen.class_member_bitoffsets: - Gen.class_member_bitoffsets[ClassName] = {} - if AttrName not in Gen.class_member_bitoffsets[ClassName]: - bo: int = 0 - for bf_name, bf_width in bitfields.items(): - if bf_name == AttrName: - break - bo += bf_width - Gen.class_member_bitoffsets[ClassName][AttrName] = bo - return self._load_bitfield_member(ObjVal, ClassName, AttrName) - - offset = Gen._get_member_offset(AttrName, ClassName) - # 检查 offset 是否超出实际结构体 - if isinstance(ObjVal.type, ir.PointerType): - actual_pointee: Any = ObjVal.type.pointee - if isinstance(actual_pointee, ir.IdentifiedStructType): - actual_elems: Any = actual_pointee.elements - if actual_elems is not None and offset is not None and offset >= len(actual_elems): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - actual_elems = actual_pointee.elements - if actual_elems is not None and offset >= len(actual_elems): - # sha1 冲突修复:ObjVal 的 pointee 可能是字段不全的版本(如 2 字段 Function), - # 而 st(来自 _try_Load_struct_from_stub)可能是字段完整的版本。 - # bitcast ObjVal 到 st 的类型,使 GEP 能正确访问完整字段。 - if st is not None and isinstance(st, ir.IdentifiedStructType) and st.elements is not None and offset < len(st.elements): - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_load_{ClassName}") - else: - return None - result = self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st) - return result - - def _handle_attr_nested(self, Node: ast.Attribute) -> ir.Value | None: - """处理 a.b.c 嵌套属性访问""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(Node.value.value, ast.Name): - ParentVarName: str = Node.value.value.id - ParentAttrName: str = Node.value.attr - # __doc__ 魔法字符串:ClassName.method.__doc__ 或 module.ClassName.__doc__ - if Node.attr == '__doc__': - full_symbol: str = f"{ParentVarName}.{ParentAttrName}" - doc_ptr: ir.Value | None = Gen._get_doc_ptr(full_symbol) - if doc_ptr is not None: - return doc_ptr - # 回退:module.ClassName.__doc__ → 仅用 ClassName 查找 - doc_ptr = Gen._get_doc_ptr(ParentAttrName) - if doc_ptr is not None: - return doc_ptr - enum_result: Any = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr) - if enum_result is not None: - return enum_result - # 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量 - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - if imported_modules: - full_ModulePath: str = f"{ParentVarName}.{ParentAttrName}" - if full_ModulePath in imported_modules: - result: Any = self._lookup_module_global(Gen, full_ModulePath, Node.attr) - if result is not None: - return result - elif isinstance(Node.value.value, ast.Attribute) and isinstance(Node.value.value.value, ast.Name): - # 三层嵌套:module.ClassName.method.__doc__ - if Node.attr == '__doc__': - ModuleName: str = Node.value.value.value.id - ClassName2: str = Node.value.value.attr - MethodName: str = Node.value.attr - FullSymbol3: str = f"{ModuleName}.{ClassName2}.{MethodName}" - doc_ptr3: ir.Value | None = Gen._get_doc_ptr(FullSymbol3) - if doc_ptr3 is not None: - return doc_ptr3 - # 回退:ClassName.method.__doc__ - doc_ptr3 = Gen._get_doc_ptr(f"{ClassName2}.{MethodName}") - if doc_ptr3 is not None: - return doc_ptr3 - # 三层嵌套:module.submodule.EnumClass.MEMBER - ModuleAlias3: str = f"{Node.value.value.value.id}.{Node.value.value.attr}" - EnumClassName3: str = Node.value.attr - enum_result3: Any = self._try_resolve_cross_module_enum(ModuleAlias3, EnumClassName3, Node.attr) - if enum_result3 is not None: - return enum_result3 - cdefine_result: Any = self._try_resolve_nested_cdefine(Node) - if cdefine_result is not None: - return cdefine_result - ObjVal: Any = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee: Any = ObjVal.type.pointee - - # char* → struct* cast + 成员访问 - if isinstance(pointee, ir.IntType) and pointee.width == 8: - AttrClassName: str | None = self._get_attr_class(Node.value, Gen) - if AttrClassName and AttrClassName in Gen.structs: - st: Any - ok: bool - st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}") - offset: int | None = Gen._get_member_offset(Node.attr, AttrClassName) - if offset is None: - return None - if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): - return None - return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st) - - # 已知结构体类型 → 直接成员访问 - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - # 提取父上下文特化提示:当 Node.value 是 Attribute(Name, attr) 时, - # 从 var_struct_class 和 class_member_element_class 获取字段声明的特化名。 - # 例如 func.Blocks.Head 中,func 是 Function,Blocks 字段声明为 GSList[BasicBlock], - # 提示为 'GSList[BasicBlock]',避免在所有 GSList[T] 都有 Head 字段时选错特化版本。 - parent_hint: str | None = None - if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name): - p_var: str = Node.value.value.id - p_attr: str = Node.value.attr - p_CN: str | None = Gen.var_struct_class.get(p_var) - if p_CN: - p_elem_map: Any = Gen.class_member_element_class.get(p_CN, {}) - parent_hint = p_elem_map.get(p_attr) - for CN, ST in Gen.structs.items(): - if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): - st, ok = self._try_Load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint) - if spec_val is not None: - return spec_val - break - bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(ObjVal, CN, Node.attr) - offset = Gen._get_member_offset(Node.attr, CN) - if offset is None: - break - return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) - return None - - def _handle_attr_call_result(self, Node: ast.Attribute) -> ir.Value | None: - """处理 func().attr 属性访问""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - # Check if this is c.Deref(...) — we need the pointer, not the Loaded value - ObjVal: Any = None - is_cderef: bool = (isinstance(Node.value, ast.Call) and - isinstance(Node.value.func, ast.Attribute) and - isinstance(Node.value.func.value, ast.Name) and - Node.value.func.value.id == 'c' and - Node.value.func.attr == 'Deref' and - Node.value.args) - if is_cderef: - deref_arg: ast.expr = Node.value.args[0] - inner_val: Any = self.HandleExprLlvm(deref_arg) - if inner_val and isinstance(inner_val.type, ir.PointerType): - if isinstance(inner_val.type.pointee, ir.PointerType): - ObjVal = Gen._load(inner_val, name="deref_load_ptr") - else: - ObjVal = inner_val - if ObjVal is None: - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee: Any = ObjVal.type.pointee - if isinstance(pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") - pointee = ObjVal.type.pointee - found: Any = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN: str - ST: Any - CN, ST = found - st: Any - ok: bool - st, ok = self._try_Load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN) - if spec_val is not None: - return spec_val - return None - bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(ObjVal, CN, Node.attr) - offset: int | None = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - def _handle_attr_subscript_result(self, Node: ast.Attribute) -> ir.Value | None: - """处理 arr[i].attr 属性访问""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ObjVal: Any = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee: Any = ObjVal.type.pointee - if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - return None - found: Any = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN: str - ST: Any - CN, ST = found - st: Any - ok: bool - st, ok = self._try_Load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN) - if spec_val is not None: - return spec_val - return None - offset: int | None = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - def _handle_attr_fallback(self, Node: ast.Attribute) -> ir.Value | None: - """兜底:对任意值尝试指针解引用后查找结构体成员""" - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ObjVal: Any = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee: Any = ObjVal.type.pointee - if isinstance(pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback") - pointee = ObjVal.type.pointee - if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - return None - found: Any = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN: str - ST: Any - CN, ST = found - st: Any - ok: bool - st, ok = self._try_Load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN) - if spec_val is not None: - return spec_val - return None - offset: int | None = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - # ========== 主入口 ========== - - def _HandleAttributeLlvm(self, Node: ast.Attribute) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - - if isinstance(Node.value, ast.Name): - VarName: str = Node.value.id - # 处理 t/c import 的别名重定向 - t_c_imported: Any = getattr(self.Trans, '_t_c_imported_names', {}) - if VarName != 'self' and VarName in t_c_imported: - src_module: str - src_name: str - src_module, src_name = t_c_imported[VarName] - virtual_attr: ast.Attribute = ast.Attribute( - value=ast.Name(id=src_module, ctx=ast.Load()), - attr=src_name, ctx=ast.Load() - ) - ast.copy_location(virtual_attr, Node) - return self._HandleAttributeLlvm(ast.Attribute( - value=virtual_attr, attr=Node.attr, ctx=ast.Load() - )) - if VarName == 'self': - return self._handle_attr_self(Node, VarName) - return self._handle_attr_name(Node, VarName) - - elif isinstance(Node.value, ast.Attribute): - return self._handle_attr_nested(Node) - - elif isinstance(Node.value, ast.Call): - return self._handle_attr_call_result(Node) - - elif isinstance(Node.value, ast.Subscript): - return self._handle_attr_subscript_result(Node) - - # 兜底 - return self._handle_attr_fallback(Node) - - # ========== HandleSubscript 及其辅助 ========== - - def _HandleSubscriptLlvm(self, Node: ast.Subscript) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - # 查询数组元素字节序 - arr_byte_order: str = '' - if isinstance(Node.value, ast.Name) and Node.value.id in Gen.local_var_byteorders: - arr_byte_order = Gen.local_var_byteorders[Node.value.id] - ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.value, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__getitem__'): - obj_val: Any = self.HandleExprLlvm(Node.value) - idx_val: Any = self.HandleExprLlvm(Node.slice) - if obj_val and idx_val: - # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 - # 需要先 inttoptr 转换为 i8*,再 bitcast 到目标 struct 指针 - if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8: - obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: - idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") - _getitem_func: Any = Gen._get_function(f'{ClassName}.__getitem__') - # 处理泛型特化类型不匹配:obj_val 可能是通用类型,而函数期望特化类型 - if _getitem_func.ftype.args and _getitem_func.ftype.args[0] != obj_val.type: - _expected_type = _getitem_func.ftype.args[0] - if isinstance(_expected_type, ir.PointerType) and isinstance(obj_val.type, ir.PointerType): - obj_val = Gen.builder.bitcast(obj_val, _expected_type, name=f"cast_{ClassName}_getitem") - result: Any = Gen.builder.call(_getitem_func, [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") - return result - ValueVal: Any = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - IndexVal: Any = self.HandleExprLlvm(Node.slice) - if not IndexVal: - return None - if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: - Loaded_byte: Any = Gen._load(IndexVal, name="Load_char_idx") - IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx") - if isinstance(ValueVal.type, ir.IntType): - var_ptr: Any = self._get_int_ptr(Node.value) - if var_ptr: - i8_ptr: Any = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") - ptr: Any = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") - return Gen._load(ptr, name="int_subscript_val") - return None - # 当变量本身是二级指针(如 elem_ptr: T | t.CPtr = AST**), - # 但 HandleExprLlvm 已自动 load 返回 AST*(一级指针), - # 需要检查 Gen.variables 中的原始 alloca 类型, - # 若是二级指针且存储的是结构体指针,应 bitcast ValueVal 为 AST** 后 GEP 再 load, - # 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)。 - # 仅当 var_ptr_element 标记为 True 时触发(由 AnnAssign 检测 (S|t.CPtr)|t.CPtr 注解设置), - # 防止 pts: Point | t.CPtr(简单结构体指针)错误走二级指针路径。 - if (isinstance(Node.value, ast.Name) - and isinstance(ValueVal.type, ir.PointerType) - and isinstance(ValueVal.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))): - VarName: str = Node.value.id - _vpe_load: bool = (getattr(Gen, 'var_ptr_element', {}).get(VarName, False) - or getattr(Gen, 'global_var_ptr_element', {}).get(VarName, False)) - if _vpe_load and VarName in Gen.variables and Gen.variables[VarName] is not None: - VarAlloca: ir.Value = Gen.variables[VarName] - if (isinstance(VarAlloca.type, ir.PointerType) - and isinstance(VarAlloca.type.pointee, ir.PointerType)): - # 原始 alloca 是二级指针,ValueVal 是已 load 的一级结构体指针 - # 该指针指向数据缓冲区,缓冲区存储的是 AST* 指针数组, - # 需 bitcast ValueVal 为 AST** 后 GEP 指针数组再 load 出 AST* - PtrToStruct: ir.Type = ValueVal.type.pointee - BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal, - ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp_load") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_load") - ElemPtrLoad: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript_pp_load") - return Gen._load(ElemPtrLoad, name="ptr_elem_load") - if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") - ElemPtr: Any = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8: - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - if isinstance(ValueVal.type, ir.PointerType): - pointee: Any = ValueVal.type.pointee - if isinstance(pointee, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") - elem_type: Any = pointee.element - if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - else: - if isinstance(pointee, ir.IntType) and pointee.width == 8: - elem_class: str | None = self._infer_element_struct_class(Node.value, Gen) - if elem_class and elem_class in Gen.structs: - CastedPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index") - ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript") - if isinstance(pointee, ir.IntType): - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - return ElemPtr - # 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr) - # elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] 应加载 8 字节 - if isinstance(Node.value, ast.Name): - _ptr_elem_flag: bool = (getattr(Gen, 'var_ptr_element', {}).get(Node.value.id, False) - or getattr(Gen, 'global_var_ptr_element', {}).get(Node.value.id, False)) - if _ptr_elem_flag: - CastedPtrPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index") - ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript") - return Gen._load(ElemPtr, name="str_ptr_load") - arr_type: Any = self._infer_array_member_type(Node.value, Gen) - if arr_type and isinstance(arr_type, ir.ArrayType): - arr_ptr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript") - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript") - arr_elem_type: Any = arr_type.element - if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - elif isinstance(ValueVal.type, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(Node.value, ast.Name): - VarName: str = Node.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: Any = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") - var_arr_elem_type: Any = VarPtr.type.pointee.element - if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - if isinstance(Node.value, ast.Attribute): - AttrPtr: Any = self._get_attr_ptr(Node.value) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") - attr_arr_elem_type: Any = AttrPtr.type.pointee.element - if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - if isinstance(Node.value, ast.Subscript): - InnerPtr: Any = self.HandleSubscriptPtrLlvm(Node.value) - if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): - inner_pointee: Any = InnerPtr.type.pointee - if isinstance(inner_pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") - inner_elem_type: Any = inner_pointee.element - if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - arr_alloc: Any = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") - Gen._store(ValueVal, arr_alloc) - ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") - alloc_arr_elem_type: Any = ValueVal.type.element - if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return self._load_arr_elem_with_bswap(Gen, ElemPtr, arr_byte_order) - return None - - def HandleSubscriptPtrLlvm(self, Node: ast.Subscript) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ValueVal: Any = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - IndexVal: Any = self.HandleExprLlvm(Node.slice) - if not IndexVal: - return None - if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: - Loaded_byte: Any = Gen._load(IndexVal, name="Load_char_idx_ptr") - IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr") - if isinstance(ValueVal.type, ir.PointerType): - pointee: Any = ValueVal.type.pointee - if isinstance(pointee, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr: Any = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - elif isinstance(pointee, ir.PointerType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_ptr") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") - return ElemPtr - else: - # 指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr, bytes | t.CPtr) - # elem_ptr 是 i8* 但实际指向 i8* (指针数组), 应按 8 字节步长 GEP - if isinstance(Node.value, ast.Name): - _ptr_elem_flag: bool = (getattr(Gen, 'var_ptr_element', {}).get(Node.value.id, False) - or getattr(Gen, 'global_var_ptr_element', {}).get(Node.value.id, False)) - if _ptr_elem_flag: - CastedPtrPtr: Any = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str_ptr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_ptr") - ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript_ptr") - return ElemPtr - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") - return ElemPtr - elif isinstance(ValueVal.type, ir.IntType): - var_ptr: Any = self._get_int_ptr(Node.value) - if var_ptr: - i8_ptr: Any = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") - ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") - return ElemPtr - elif isinstance(ValueVal.type, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(Node.value, ast.Name): - VarName: str = Node.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: Any = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - if isinstance(Node.value, ast.Subscript): - InnerPtr: Any = self.HandleSubscriptPtrLlvm(Node.value) - if InnerPtr: - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - if isinstance(Node.value, ast.Attribute): - AttrPtr: Any = self._get_attr_ptr(Node.value) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - arr_alloc: Any = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") - Gen._store(ValueVal, arr_alloc) - ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - return None - - # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ========== - - def _get_attr_ptr(self, Node: ast.Attribute) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if not isinstance(Node, ast.Attribute): - return None - if isinstance(Node.value, ast.Name): - VarName: str = Node.value.id - if VarName == 'self': - ClassName: str | None = self.Trans._CurrentCpythonObjectClass - if ClassName: - offset: int | None = Gen._get_member_offset(Node.attr, ClassName) - SelfVar: Any = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr: Any = Gen._load(SelfVar, name="self") - if isinstance(SelfPtr.type, ir.PointerType): - MemberPtr: Any = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - ClassName = Gen.var_struct_class.get(VarName) - if not ClassName and getattr(Gen, 'global_struct_class', None): - ClassName = Gen.global_struct_class.get(VarName) - if not ClassName: - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) - if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): - AttrName: str = Node.attr - ModuleSha1Map: Any = getattr(Gen, 'ModuleSha1Map', {}) - candidates: list[str] = [VarName, resolved_mod] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - if mod_name not in candidates: - candidates.append(mod_name) - for cand in candidates: - sha1: str | None = ModuleSha1Map.get(cand) - if sha1: - prefixed: str = f"{sha1}.{AttrName}" - if prefixed in Gen.module.globals: - return Gen.module.globals[prefixed] - if AttrName in Gen.module.globals: - gv: Any = Gen.module.globals[AttrName] - if isinstance(gv, ir.GlobalVariable): - return gv - if ClassName and ClassName in Gen.structs: - VarPtr: Any = Gen.variables.get(VarName) - if VarPtr: - ObjVal: Any = VarPtr - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") - if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: - ST: Any = Gen.structs[ClassName] - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - ST = Gen.structs.get(ClassName, ST) - if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}") - offset = Gen._get_member_offset(Node.attr, ClassName) - if offset is not None and ST.elements is not None: - MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(Node.value, ast.Attribute): - InnerPtr: Any = self._get_attr_ptr(Node.value) - if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): - pointee: Any = InnerPtr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found: Any = Gen.find_struct_by_pointee(pointee) - if found: - CN: str - ST: Any - CN, ST = found - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None: - InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}") - offset = Gen._get_member_offset(Node.attr, CN) - if offset is not None and ST.elements is not None: - MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - AttrClassName: str | None = self._get_attr_class(Node.value, Gen) - if AttrClassName and AttrClassName in Gen.structs: - CastedObj: Any = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}") - offset = Gen._get_member_offset(Node.attr, AttrClassName) - if offset is not None: - MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(Node.value, ast.Subscript): - SubPtr: Any = self.HandleSubscriptPtrLlvm(Node.value) - if SubPtr and isinstance(SubPtr.type, ir.PointerType): - pointee = SubPtr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(pointee) - if found: - CN, ST = found - offset = Gen._get_member_offset(Node.attr, CN) - if offset is not None: - MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - return None - - def _HandleSliceLlvm(self, base_val: ir.Value, slice_node: ast.Slice | ast.Index, base_ast: ast.AST) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - lower_val: Any = None - upper_val: Any = None - step_val: Any = None - if isinstance(slice_node, ast.Slice): - if slice_node.lower: - lower_val = self.HandleExprLlvm(slice_node.lower) - if slice_node.upper: - upper_val = self.HandleExprLlvm(slice_node.upper) - if slice_node.step: - step_val = self.HandleExprLlvm(slice_node.step) - if isinstance(slice_node, ast.Index): - return self.HandleExprLlvm(slice_node.value) - return None - - def _infer_element_struct_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: - if isinstance(node, ast.Attribute): - attr_name: str = node.attr - if isinstance(node.value, ast.Name) and node.value.id == 'self': - current_class: str | None = self.Trans._CurrentCpythonObjectClass - if current_class: - if current_class in Gen.class_member_element_class: - elem_class: str | None = Gen.class_member_element_class[current_class].get(attr_name) - if elem_class and elem_class in Gen.structs: - return elem_class - if current_class in Gen.class_members: - for member_name, member_type in Gen.class_members[current_class]: - if member_name == attr_name: - if isinstance(member_type, ir.IdentifiedStructType): - found: Any = Gen.find_struct_by_pointee(member_type) - if found: - return found[0] - break - class_name: str | None = Gen.var_struct_class.get(attr_name) - if class_name: - return class_name - elif isinstance(node, ast.Name): - var_name: str = node.id - class_name = Gen.var_struct_class.get(var_name) - if class_name: - return class_name - return None - - def _get_int_ptr(self, target: ast.AST) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(target, ast.Name): - VarName: str = target.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: Any = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType): - pointee: Any = VarPtr.type.pointee - if isinstance(pointee, ir.ArrayType): - return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") - return VarPtr - elif isinstance(target, ast.Attribute): - if isinstance(target.value, ast.Name): - obj_name: str = target.value.id - if obj_name in Gen.variables and Gen.variables[obj_name] is not None: - obj_ptr: Any = Gen.variables[obj_name] - if isinstance(obj_ptr.type, ir.PointerType): - pointee = obj_ptr.type.pointee - if isinstance(pointee, ir.PointerType): - obj_ptr = Gen._load(obj_ptr, name=f"Load_{obj_name}") - pointee = obj_ptr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - StructName: str | None = None - if isinstance(pointee, ir.IdentifiedStructType): - StructName = pointee.name - if not StructName: - found: Any = Gen.find_struct_by_pointee(pointee) - if found: - StructName = found[0] - if StructName and StructName in Gen.structs: - offset: int | None = Gen._get_member_offset(target.attr, StructName) - if offset is not None: - return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") - obj_val: Any = self.HandleExprLlvm(target.value) - if obj_val and isinstance(obj_val.type, ir.PointerType): - if isinstance(obj_val.type.pointee, ir.PointerType): - obj_val = Gen._load(obj_val, name="Load_attr_ptr") - pointee = obj_val.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - StructName = None - if isinstance(pointee, ir.IdentifiedStructType): - StructName = pointee.name - if not StructName: - found = Gen.find_struct_by_pointee(pointee) - if found: - StructName = found[0] - if StructName and StructName in Gen.structs: - offset = Gen._get_member_offset(target.attr, StructName) - if offset is not None: - return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") - return None - - def _resolve_struct_class_for_attr(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: - if isinstance(Node, ast.Name): - VarName: str = Node.id - if VarName in Gen.var_struct_class: - return Gen.var_struct_class[VarName] - elif isinstance(Node, ast.Attribute): - ClassName: str | None = self._resolve_struct_class_for_attr(Node.value, Gen) - if ClassName and ClassName in Gen.class_members: - for member_name, _ in Gen.class_members[ClassName]: - if member_name == Node.attr: - return ClassName - return None - - def _infer_array_member_type(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> ir.ArrayType | None: - if isinstance(Node, ast.Attribute): - parent_class: str | None = self._get_attr_class(Node, Gen) - if parent_class and parent_class in Gen.class_members: - for m_name, m_type in Gen.class_members[parent_class]: - if m_name == Node.attr and isinstance(m_type, ir.ArrayType): - return m_type - if parent_class and parent_class in Gen.structs: - st: Any = Gen.structs[parent_class] - if isinstance(st, ir.IdentifiedStructType) and st.elements is not None: - offset: int | None = Gen._get_member_offset(Node.attr, parent_class) - if offset is not None and offset < len(st.elements): - elem: Any = st.elements[offset] - if isinstance(elem, ir.ArrayType): - return elem - return None - - def _build_attr_path(self, node: ast.AST) -> list[str]: - parts: list[str] = [] - current: ast.AST = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - return parts - - def _try_resolve_nested_cdefine(self, Node: ast.Attribute) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - if not imported_modules: - return None - parts: list[str] = self._build_attr_path(Node) - if len(parts) < 2: - return None - attr_name: str = parts[-1] - module_parts: list[str] = parts[:-1] - possible_keys: list[str] = [attr_name] - full_path: str = '.'.join(parts) - possible_keys.append(full_path) - if module_parts: - ModulePath: str = '.'.join(module_parts) - resolved_first: str = self.Trans.SymbolTable.resolve_alias(module_parts[0]) - if resolved_first != module_parts[0]: - resolved_parts: list[str] = [resolved_first] + module_parts[1:] - resolved_path: str = '.'.join(resolved_parts) - possible_keys.append(f"{resolved_path}.{attr_name}") - for mod_name in imported_modules: - if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath: - key: str = f"{mod_name}.{attr_name}" - if key not in possible_keys: - possible_keys.append(key) - if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]): - key = f"{mod_name}.{attr_name}" - if key not in possible_keys: - possible_keys.append(key) - for lookup_key in possible_keys: - SymInfo: Any = self.Trans.SymbolTable.lookup(lookup_key) - if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None: - val: Any = SymInfo.DefineValue - if isinstance(val, int): - if val > 0x7FFFFFFF or val < -0x80000000: - return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) - return ir.Constant(ir.IntType(32), val) - elif isinstance(val, float): - return ir.Constant(ir.FloatType(), val) - return None - - def _try_resolve_cross_module_enum(self, module_alias: str, enum_class_name: str, member_name: str) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - imported_modules: Any = getattr(self.Trans, '_ImportedModules', None) - if not imported_modules: - return None - resolved_module: str = self.Trans.SymbolTable.resolve_alias(module_alias) - if resolved_module not in imported_modules and module_alias not in imported_modules: - return None - enum_keys: list[str] = [enum_class_name, f"{resolved_module}.{enum_class_name}"] - for enum_key in enum_keys: - SymInfo: Any = self.Trans.SymbolTable.lookup(enum_key) - if SymInfo: - if SymInfo.IsEnum: - for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"): - info: Any = self.Trans.SymbolTable.lookup(qname) - if info and info.IsEnumMember and isinstance(info.value, int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if info.IsEnumMember and info.EnumName == enum_key and key == member_name: - if isinstance(info.value, int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if info.IsEnumMember and key == member_name: - if isinstance(info.value, int): - for enum_key in enum_keys: - if info.EnumName == enum_key: - return ir.Constant(ir.IntType(32), info.value) - return None - - def _get_attr_class(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: - if isinstance(Node, ast.Attribute): - # 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找 - if isinstance(Node.value, ast.Name) and Node.value.id == 'self': - ClassName: str | None = self.Trans._CurrentCpythonObjectClass - if ClassName and ClassName in Gen.class_member_element_class: - return Gen.class_member_element_class[ClassName].get(Node.attr) - if isinstance(Node.value, ast.Name): - VarName: str = Node.value.id - if VarName in Gen.var_struct_class: - ParentClass: str = Gen.var_struct_class[VarName] - if ParentClass in Gen.class_member_element_class: - return Gen.class_member_element_class[ParentClass].get(Node.attr) - if isinstance(Node.value, ast.Attribute): - ParentClass = self._get_attr_class(Node.value, Gen) - if ParentClass and ParentClass in Gen.class_member_element_class: - return Gen.class_member_element_class[ParentClass].get(Node.attr) - return None - - def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None: - return Gen._get_member_offset(field_name, ClassName) \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesExprBuiltin.py b/App/lib/core/Handles/HandlesExprBuiltin.py deleted file mode 100644 index ae09c61..0000000 --- a/App/lib/core/Handles/HandlesExprBuiltin.py +++ /dev/null @@ -1,991 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -import ast -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode -from lib.includes.t import CTypeRegistry -from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp - - -class ExprBuiltinHandle(BaseHandle): - _C_LIB_FUNCS: dict[str, object] = { - 'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), - 'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), - 'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]), - 'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), - 'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), - 'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), - 'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), - 'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), - 'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), - 'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), - 'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), - 'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), - 'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), - 'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), - 'abs': lambda: (ir.IntType(32), [ir.IntType(32)]), - 'labs': lambda: (ir.IntType(64), [ir.IntType(64)]), - } - - def _HandleBuiltinCallLlvm(self, Node: ast.Call) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not isinstance(Node.func, ast.Name): - return None - FuncName: str = Node.func.id - - if FuncName == 'print': - return self._HandlePrintLlvm(Node) - elif FuncName == 'len': - if Node.args: - return self._HandleLenLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'sizeof': - if Node.args: - return self._HandleSizeofLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'abs': - if Node.args: - return self._HandleAbsLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'arg': - return self._HandleArgLlvm(Node.args) - elif FuncName == 'bool': - if Node.args: - Val = self.HandleExprLlvm(Node.args[0]) - if Val: - if isinstance(Val.type, ir.IntType): - if Val.type.width == 1: - return Val - return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") - elif isinstance(Val.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") - return Val - return ir.Constant(ir.IntType(1), 0) - elif FuncName == 'int': - if Node.args: - Val = self.HandleExprLlvm(Node.args[0]) - if Val: - if isinstance(Val.type, ir.IntType): - if Val.type.width < 32: - return Gen.builder.zext(Val, ir.IntType(32), name="cast_int") - elif Val.type.width > 32: - return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int") - return Val - elif isinstance(Val.type, ir.PointerType): - if isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: - result = self._HandleAtoiLlvm(Val) - if result: - return result - elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fptosi(Val, ir.IntType(32), name="float_to_int") - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'float' or FuncName == 'double': - if Node.args: - Val = self.HandleExprLlvm(Node.args[0]) - if Val: - target_type = ir.DoubleType() if FuncName == 'double' else ir.FloatType() - if isinstance(Val.type, (ir.FloatType, ir.DoubleType)): - if Val.type != target_type: - if isinstance(target_type, ir.DoubleType): - return Gen.builder.fpext(Val, target_type, name="fpext_double") - return Gen.builder.fptrunc(Val, target_type, name="fptrunc_float") - return Val - elif isinstance(Val.type, ir.IntType): - if Val.type.width == 1: - return Gen.builder.uitofp(Val, target_type, name="uitofp") - return Gen.builder.sitofp(Val, target_type, name="sitofp") - return ir.Constant(ir.DoubleType() if FuncName == 'double' else ir.FloatType(), 0.0) - elif FuncName == 'min': - if len(Node.args) >= 2: - a = self.HandleExprLlvm(Node.args[0]) - b = self.HandleExprLlvm(Node.args[1]) - if a and b: - is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType)) - if is_float: - fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="min_int2float") - fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="min_int2float") - cmp = Gen.builder.fcmp_ordered('olt', fa, fb, name="min_cmp") - return Gen.builder.select(cmp, fa, fb, name="min_val") - else: - cmp = Gen.builder.icmp_signed('<', a, b, name="min_cmp") - return Gen.builder.select(cmp, a, b, name="min_val") - elif len(Node.args) == 1: - return self.HandleExprLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'max': - if len(Node.args) >= 2: - a = self.HandleExprLlvm(Node.args[0]) - b = self.HandleExprLlvm(Node.args[1]) - if a and b: - is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType)) - if is_float: - fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="max_int2float") - fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="max_int2float") - cmp = Gen.builder.fcmp_ordered('ogt', fa, fb, name="max_cmp") - return Gen.builder.select(cmp, fa, fb, name="max_val") - else: - cmp = Gen.builder.icmp_signed('>', a, b, name="max_cmp") - return Gen.builder.select(cmp, a, b, name="max_val") - elif len(Node.args) == 1: - return self.HandleExprLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'str': - if Node.args: - arg_node = Node.args[0] - arg_val = self.HandleExprLlvm(arg_node) - if arg_val: - if isinstance(arg_val.type, ir.PointerType): - ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__str__'): - if isinstance(arg_val.type, ir.PointerType) and isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8: - if ClassName in Gen.structs: - arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str") - str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__") - return str_val - return arg_val - return self._EmitStringFromValue(arg_val) - return ir.Constant(ir.IntType(8).as_pointer(), None) - elif FuncName == 'bytes': - # bytes() — 类型转换为 i8* 指针 (等同于 t.CPtr / str) - # bytes(int_addr) → inttoptr; bytes(ptr) → bitcast - if Node.args: - arg_val = self.HandleExprLlvm(Node.args[0]) - if arg_val: - if isinstance(arg_val.type, ir.PointerType): - if isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8: - return arg_val - return Gen.builder.bitcast(arg_val, ir.IntType(8).as_pointer(), name="bytes_cast") - if isinstance(arg_val.type, ir.IntType): - return Gen.builder.inttoptr(arg_val, ir.IntType(8).as_pointer(), name="bytes_int2ptr") - return ir.Constant(ir.IntType(8).as_pointer(), None) - elif FuncName == 'input': - return self._HandleInputLlvm(Node) - elif FuncName == 'ord': - if Node.args: - return self._HandleOrdLlvm(Node.args[0]) - return ir.Constant(ir.IntType(32), 0) - elif FuncName == 'chr': - if Node.args: - return self._HandleChrLlvm(Node.args[0]) - return ir.Constant(ir.IntType(8), 0) - elif FuncName == 'malloc': - return self._HandleMallocLlvm(Node.args) - elif FuncName == 'realloc': - return self._HandleReallocLlvm(Node.args) - elif FuncName == 'free': - return self._HandleFreeLlvm(Node.args) - elif FuncName == 'memcpy': - return self._HandleMemcpyLlvm(Node.args) - elif FuncName == 'memset': - return self._HandleMemsetLlvm(Node.args) - elif FuncName == 'va_start': - return self._HandleVaStartLlvm(Node.args) - elif FuncName == 'va_end': - return self._HandleVaEndLlvm(Node.args) - elif FuncName == 'va_arg': - return self._HandleVaArgLlvm(Node.args) - elif FuncName == 'dir': - return self._HandleDirLlvm(Node) - elif FuncName == 'type': - return self._HandleTypeLlvm(Node) - return None - - def _HandlePrintLlvm(self, Node: ast.Call) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - args: list[ast.expr] = Node.args - end_arg: ast.expr | None = None - sep_arg: ast.expr | None = None - if Node.keywords: - for kw in Node.keywords: - if kw.arg == 'end': - end_arg = kw.value - elif kw.arg == 'sep': - sep_arg = kw.value - sep_str: str = ' ' - if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str): - sep_str = sep_arg.value - end_str: str = '\n' - if end_arg: - if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str): - end_str = end_arg.value - elif isinstance(end_arg, ast.Constant) and end_arg.value is None: - end_str = '' - if not args: - if end_str: - nl_fmt = Gen.emit_constant(end_str, 'string') - Gen.builder.call(printf_func, [nl_fmt], name="print_nl") - return ir.Constant(ir.IntType(32), 0) - has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args) - if has_fstring: - return self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str) - fmt_parts = [] - fmt_args = [] - for i, arg in enumerate(args): - if i > 0: - fmt_parts.append(sep_str) - val = self.HandleExprLlvm(arg) - if not val: - fmt_parts.append('(null)') - continue - if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None: - fmt_parts.append('nil') - continue - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - fmt_parts.append('%s') - fmt_args.append(val) - elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: - elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr") - fmt_parts.append('%s') - fmt_args.append(elem_ptr) - elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) - if not ClassName and isinstance(arg, ast.Name): - ClassName = Gen.var_struct_class.get(arg.id) - if ClassName and Gen._has_function(f'{ClassName}.__str__'): - if isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8: - if ClassName in Gen.structs: - val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__") - fmt_parts.append('%s') - fmt_args.append(str_val) - else: - int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") - fmt_parts.append('0x%llx') - fmt_args.append(int_val) - else: - int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") - fmt_parts.append('%lld') - fmt_args.append(int_val) - elif isinstance(val.type, ir.IntType): - is_unsigned = self._is_val_unsigned(arg, val) - if val.type.width == 1: - fmt_parts.append('%d') - val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") - elif val.type.width == 8: - if self._is_char_type(arg): - char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf") - Gen.builder.store(val, char_var) - fmt_parts.append('%c') - fmt_args.append(char_var) - continue - fmt_parts.append('%d') - if is_unsigned: - val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print") - else: - val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print") - elif val.type.width == 16: - fmt_parts.append('%u' if is_unsigned else '%d') - if is_unsigned: - val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print") - else: - val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print") - elif val.type.width == 32: - fmt_parts.append('%u' if is_unsigned else '%d') - elif val.type.width == 64: - fmt_parts.append('%llu' if is_unsigned else '%lld') - else: - fmt_parts.append('%d') - val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print") - fmt_args.append(val) - elif isinstance(val.type, ir.FloatType): - fmt_parts.append('%f') - fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float")) - elif isinstance(val.type, ir.DoubleType): - fmt_parts.append('%f') - fmt_args.append(val) - else: - fmt_parts.append('(unknown)') - fmt_parts.append(end_str) - fmt_str = ''.join(fmt_parts) - fmt_ptr = Gen._create_string_global(fmt_str) - call_args = [fmt_ptr] + fmt_args - return Gen.builder.call(printf_func, call_args, name="print_call") - - def _HandlePrintWithFString(self, Node: ast.Call, printf_func: ir.Function, args: list[ast.expr], sep_str: str, end_str: str) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - for i, arg in enumerate(args): - if i > 0: - sep_const = Gen.emit_constant(sep_str, 'string') - Gen.builder.call(printf_func, [sep_const], name="print_sep") - if isinstance(arg, ast.JoinedStr): - str_val = self.HandleExprLlvm(arg) - if str_val: - Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) - else: - ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__str__'): - obj_val = self.HandleExprLlvm(arg) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if ClassName in Gen.structs: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") - Gen._RegisterTempPtr(str_val) - Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) - else: - val = self.HandleExprLlvm(arg) - if val: - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if not (isinstance(pointee, ir.IntType) and pointee.width == 8): - try: - val = Gen._load(val, name="print_Load") - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - is_u = Gen._check_node_unsigned(arg) - if not is_u and id(val) in Gen._unsigned_results: - is_u = True - Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None) - if end_str: - end_const = Gen.emit_constant(end_str, 'string') - Gen.builder.call(printf_func, [end_const], name="print_end") - return ir.Constant(ir.IntType(32), 0) - - def _is_char_type(self, arg_node: ast.AST) -> bool: - if isinstance(arg_node, ast.Call): - if isinstance(arg_node.func, ast.Name): - return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T') - if isinstance(arg_node.func, ast.Attribute): - return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T') - return False - - def _is_val_unsigned(self, arg_node: ast.AST, val: ir.Value) -> bool: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if isinstance(arg_node, ast.Name): - var_name: str = arg_node.id - signedness: object = Gen.var_signedness.get(var_name) - if signedness: - if isinstance(signedness, bool): - return signedness - return 'unsigned' in signedness - if isinstance(val.type, ir.IntType): - return False - return False - - def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None: - if func_name not in self._C_LIB_FUNCS: - return None - ret_type: ir.Type - param_types: list[ir.Type] - ret_type, param_types = self._C_LIB_FUNCS[func_name]() - func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - func: ir.Function = ir.Function(Gen.module, func_type, name=func_name) - Gen.functions[func_name] = func - return func - - def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self': - attr_name = arg_node.attr - len_member = f'{attr_name}__len' - current_class = self.Trans._CurrentCpythonObjectClass - if current_class and current_class in Gen.class_members: - for m_name, m_type in Gen.class_members[current_class]: - if m_name == len_member: - self_val = Gen._get_var_ptr('self') - if self_val: - self_ptr = Gen._load(self_val, name="self_for_len") - offset = Gen._get_member_offset(len_member, current_class) - len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr") - return Gen._load(len_ptr, name=f"self_{len_member}") - val = self.HandleExprLlvm(arg_node) - if not val: - return None - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, ir.PointerType): - val = Gen._load(val, name="len_deref") - pointee = val.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen) - if result is not None: - return result - break - if isinstance(pointee, ir.ArrayType): - return ir.Constant(ir.IntType(64), pointee.count) - if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8: - return ir.Constant(ir.IntType(64), 0) - if val.type != ir.PointerType(ir.IntType(8)): - val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast") - correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))]) - strlen_func = None - if 'strlen' in Gen.functions: - existing = Gen.functions['strlen'] - if existing.ftype == correct_strlen_type: - strlen_func = existing - if not strlen_func: - try: - strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen') - Gen.functions['strlen'] = strlen_func - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - if strlen_func: - result = Gen.builder.call(strlen_func, [val], name="strlen_call") - return result - elif isinstance(val.type, ir.ArrayType): - return ir.Constant(ir.IntType(64), val.type.count) - return ir.Constant(ir.IntType(64), 0) - - def _resolve_nested_opaque_structs(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, visited: set | None = None) -> None: - """递归解析嵌套的 opaque struct,从 stub 文件中加载其定义""" - if visited is None: - visited = set() - if isinstance(struct_type, ir.PointerType): - self._resolve_nested_opaque_structs(struct_type.pointee, Gen, visited) - return - if not isinstance(struct_type, ir.IdentifiedStructType): - return - if struct_type in visited: - return - visited.add(struct_type) - if struct_type.elements is None or len(struct_type.elements) == 0: - # 尝试从 stub 加载 opaque struct - try: - st_name = struct_type.name - except Exception: - st_name = None - if st_name: - # 提取短名称(去掉模块前缀) - if '.' in st_name: - short_name = st_name.split('.', 1)[1] - else: - short_name = st_name - self.Trans.ImportHandler._TryLoadStructFromStub(short_name, Gen) - return - # 递归解析嵌套的 struct 成员 - for elem in struct_type.elements: - self._resolve_nested_opaque_structs(elem, Gen, visited) - - def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - type_name: str | None - if isinstance(Node, ast.Name): - type_name = Node.id - elif isinstance(Node, ast.Attribute): - type_name = Node.attr - else: - return ir.Constant(ir.IntType(64), 0) - - if type_name not in Gen.structs: - # str/bytes 是指针类型 (char*/void*),sizeof = 指针大小 - if type_name in ('str', 'bytes'): - return ir.Constant(ir.IntType(64), 8) - ctype_cls = CTypeRegistry.GetClassByName(type_name) - if ctype_cls is not None: - try: - ctype_inst = ctype_cls() - size_bits = getattr(ctype_inst, 'Size', 0) or 0 - size_bytes = size_bits // 8 - return ir.Constant(ir.IntType(64), size_bytes) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析类型失败: {_e}", "Exception") - resolved = CTypeRegistry.ResolveName(type_name) - if resolved: - ctype_cls, ptr_level = resolved - try: - ctype_inst = ctype_cls() - size_bits = getattr(ctype_inst, 'Size', 0) or 0 - size_bytes = size_bits // 8 - if ptr_level > 0: - size_bytes = 8 - return ir.Constant(ir.IntType(64), size_bytes) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析类型失败: {_e}", "Exception") - return ir.Constant(ir.IntType(64), 0) - - struct_type = Gen.structs[type_name] - if isinstance(struct_type, ir.PointerType): - struct_type = struct_type.pointee - if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen) - struct_type = Gen.structs.get(type_name, struct_type) - # 递归解析所有嵌套的 opaque struct,确保 sizeof 计算正确 - self._resolve_nested_opaque_structs(struct_type, Gen) - size = Gen._get_struct_size(struct_type) - if size > 0: - return ir.Constant(ir.IntType(64), size) - return ir.Constant(ir.IntType(64), 0) - - def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - val: ir.Value | None = self.HandleExprLlvm(arg_node) - if not val: - return None - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen) - if result is not None: - return result - break - if isinstance(val.type, ir.IntType): - neg_val = Gen.builder.neg(val, name="abs_neg") - is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg") - return Gen.builder.select(is_neg, neg_val, val, name="abs_result") - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - zero = ir.Constant(val.type, 0.0) - neg_val = Gen.builder.fneg(val, name="fabs_neg") - is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg") - return Gen.builder.select(is_neg, neg_val, val, name="fabs_result") - return None - - def _HandleDirLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - return ir.Constant(ir.IntType(8).as_pointer(), None) - - def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - type_str: str - if not Node.args: - type_str = "" - else: - arg = Node.args[0] - enum_type_name = None - - def _get_attr_path(node: ast.AST) -> str | None: - if isinstance(node, ast.Name): - return node.id - elif isinstance(node, ast.Attribute): - return f"{_get_attr_path(node.value)}.{node.attr}" - return None - - if isinstance(arg, ast.Name): - arg_name = arg.id - Gen = self.Trans.LlvmGen - if arg_name in Gen.var_type_info: - type_info = Gen.var_type_info[arg_name] - if isinstance(type_info, dict) and type_info.get('type') == 'enum': - enum_type_name = type_info.get('name') - if not enum_type_name and self.Trans.SymbolTable.has(arg_name): - TypeInfo = self.Trans.SymbolTable[arg_name] - if TypeInfo.IsEnum: - enum_type_name = arg_name - elif isinstance(arg, ast.Attribute): - LastPart = None - enum_class_name = None - if isinstance(arg.value, ast.Name): - LastPart = arg.attr - if self.Trans.SymbolTable.has(LastPart): - AttrInfo = self.Trans.SymbolTable[LastPart] - if AttrInfo.IsEnumMember and AttrInfo.EnumName: - enum_type_name = AttrInfo.EnumName - elif isinstance(arg.value, ast.Attribute): - attr_path = _get_attr_path(arg) - if attr_path: - parts = attr_path.split('.') - if len(parts) >= 2: - enum_class_name = parts[-2] - LastPart = parts[-1] - qualified_name_dot = f"{enum_class_name}.{LastPart}" - qualified_name_under = f"{enum_class_name}_{LastPart}" - enum_member_found = None - for qname in (qualified_name_dot, qualified_name_under): - if self.Trans.SymbolTable.has(qname): - info = self.Trans.SymbolTable[qname] - if info.IsEnumMember and info.EnumName == enum_class_name: - enum_member_found = info - break - if not enum_member_found: - for key in self.Trans.SymbolTable: - if key == LastPart: - info = self.Trans.SymbolTable[key] - if info.IsEnumMember and info.EnumName == enum_class_name: - enum_member_found = info - break - if enum_member_found: - enum_type_name = enum_class_name - if enum_type_name: - type_str = f"" - else: - llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg) - if isinstance(llvm_type, ir.PointerType): - pointee = llvm_type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - llvm_type = pointee - type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type) - type_str = f"" - return Gen.emit_constant(type_str, 'string') - - def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str): - prompt = Node.args[0].value - prompt_ptr = Gen.emit_constant(prompt, 'string') - printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - Gen.builder.call(printf_func, [prompt_ptr]) - scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer") - result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer]) - return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result") - - def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - atoi_func: ir.Function = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))])) - return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result") - - def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - val: ir.Value | None = self.HandleExprLlvm(expr_node) - if val and isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8: - return Gen._load(val, name="ord_result") - return ir.Constant(ir.IntType(32), 0) - - def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - val: ir.Value | None = self.HandleExprLlvm(expr_node) - if val: - char_ptr = Gen._alloca(ir.IntType(8), name="chr_char") - Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr) - return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") - return ir.Constant(ir.IntType(8).as_pointer(), None) - - def _EmitStringFromValue(self, val: ir.Value) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2)) - null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte") - Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr) - Gen.builder.store(val, buf) - return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") - buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) - snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ - ir.PointerType(ir.IntType(8)), - ir.IntType(64), - ir.PointerType(ir.IntType(8)) - ], var_arg=True)) - fmt_ptr = Gen.emit_constant("%d", 'string') - Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val]) - return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") - return ir.Constant(ir.IntType(8).as_pointer(), None) - - def _HandleMallocLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) - malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type) - param_type: ir.Type = malloc_func.type.pointee.args[0] - size_val: ir.Value | None = None - if args: - size_val = self.HandleExprLlvm(args[0]) - if size_val and isinstance(size_val.type, ir.IntType): - if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width: - if size_val.type.width < param_type.width: - size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size") - else: - size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size") - if not size_val: - size_val = ir.Constant(param_type, 1) - result: ir.Value = Gen.builder.call(malloc_func, [size_val], name="malloc_result") - return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast") - - def _HandleReallocLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - realloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]) - realloc_func: ir.Function = Gen._get_or_declare_func('realloc', realloc_type) - size_param_type: ir.Type = realloc_func.type.pointee.args[1] - ptr_val: ir.Value | None = None - size_val: ir.Value | None = None - if len(args) >= 2: - ptr_val = self.HandleExprLlvm(args[0]) - size_val = self.HandleExprLlvm(args[1]) - elif len(args) == 1: - size_val = self.HandleExprLlvm(args[0]) - if not ptr_val: - ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None) - if isinstance(ptr_val.type, ir.PointerType) and not (isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8): - ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr") - if size_val and isinstance(size_val.type, ir.IntType): - if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width: - if size_val.type.width < size_param_type.width: - size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size") - else: - size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size") - if not size_val: - size_val = ir.Constant(size_param_type, 0) - result: ir.Value = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result") - return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast") - - def _HandleFreeLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) - free_func: ir.Function = Gen._get_or_declare_func('free', free_type) - if args: - var_name: str | None = None - if isinstance(args[0], ast.Name): - var_name = args[0].id - ptr_val: ir.Value | None = self.HandleExprLlvm(args[0]) - if ptr_val is not None: - if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr: - registered_val = Gen._var_to_heap_ptr[var_name] - Gen._unregister_local_heap_ptr(registered_val) - del Gen._var_to_heap_ptr[var_name] - if isinstance(ptr_val.type, ir.PointerType): - if isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8: - pass - else: - ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr") - elif isinstance(ptr_val.type, ir.IntType): - ptr_val = Gen.builder.inttoptr(ptr_val, ir.PointerType(ir.IntType(8)), name="free_inttoptr") - Gen.builder.call(free_func, [ptr_val], name="free_call") - return ir.Constant(ir.IntType(32), 0) - - def _HandleMemcpyLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if 'llvm.memcpy' not in Gen.functions: - memcpy_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) - Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') - if len(args) >= 3: - dst: ir.Value | None = self.HandleExprLlvm(args[0]) - src: ir.Value | None = self.HandleExprLlvm(args[1]) - size: ir.Value | None = self.HandleExprLlvm(args[2]) - if dst and src and size: - i8ptr: ir.PointerType = ir.PointerType(ir.IntType(8)) - if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr: - dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast") - elif isinstance(dst.type, ir.IntType): - if dst.type.width < 64: - dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr") - dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr") - if isinstance(src.type, ir.PointerType) and src.type != i8ptr: - src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast") - elif isinstance(src.type, ir.IntType): - if src.type.width < 64: - src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr") - src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr") - if isinstance(size.type, ir.IntType) and size.type.width < 64: - size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size") - isvolatile: ir.Constant = ir.Constant(ir.IntType(1), 0) - Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call") - return ir.Constant(ir.IntType(32), 0) - - def _HandleMemsetLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - memset_func: ir.Function = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)])) - if len(args) >= 3: - dst: ir.Value | None = self.HandleExprLlvm(args[0]) - val: ir.Value | None = self.HandleExprLlvm(args[1]) - size: ir.Value | None = self.HandleExprLlvm(args[2]) - if dst and val is not None and size: - if isinstance(dst.type, ir.PointerType) and not (isinstance(dst.type.pointee, ir.IntType) and dst.type.pointee.width == 8): - dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast") - elif isinstance(dst.type, ir.IntType): - if dst.type.width < 64: - dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_memset_dst") - elif dst.type.width > 64: - dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst") - dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr") - if isinstance(val.type, ir.PointerType): - # 0 字面量被推断为 null 指针(i8*),memset 第二参数需要 i32 - val = ir.Constant(ir.IntType(32), 0) - elif isinstance(val.type, ir.IntType) and val.type.width != 32: - if val.type.width < 32: - val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val") - else: - val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val") - if isinstance(size.type, ir.IntType) and size.type.width < 64: - size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size") - elif isinstance(size.type, ir.IntType) and size.type.width > 64: - size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size") - Gen.builder.call(memset_func, [dst, val, size], name="memset_call") - return ir.Constant(ir.IntType(32), 0) - - def _HandleVaStartLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - return ir.Constant(ir.IntType(32), 0) - - def _HandleVaEndLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - return ir.Constant(ir.IntType(32), 0) - - def _HandleArgLlvm(self, args: list[ast.expr], CallNode: ast.Call | None = None) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - va_list_ptr: ir.Value | None = None - variadic_info: dict | None = getattr(Gen, '_va_arg_info', None) - if not variadic_info: - variadic_info = getattr(Gen, '_variadic_info', None) - if variadic_info: - va_list_ptr = variadic_info.get('va_list_ptr') - if not va_list_ptr: - vararg_name: str = variadic_info.get('vararg_name', 'args') if variadic_info else 'args' - if vararg_name in Gen._direct_values: - va_list_ptr = Gen._direct_values[vararg_name] - elif vararg_name in Gen.variables: - va_list_ptr = Gen.variables[vararg_name] - if not va_list_ptr: - return ir.Constant(ir.IntType(32), 0) - target_type: ir.Type = ir.IntType(32) - if args: - type_arg: ast.expr = args[0] - if isinstance(type_arg, ast.Name): - type_name: str = type_arg.id - if type_name in ('str', 'bytes'): - target_type = ir.PointerType(ir.IntType(8)) - elif type_name == 'CPtr': - target_type = ir.PointerType(ir.IntType(8)) - elif type_name in Gen.structs: - target_type = ir.PointerType(Gen.structs[type_name]) - else: - ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - else: - resolved: tuple | None = CTypeRegistry.ResolveName(type_name) - if resolved is not None: - ctype_cls, ptr_level = resolved - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - base: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if base is not None: - for _ in range(ptr_level): - if isinstance(base, ir.VoidType): - base = ir.IntType(8).as_pointer() - else: - base = ir.PointerType(base) - target_type = base - elif isinstance(type_arg, ast.Attribute): - if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable): - attr_name: str = type_arg.attr - ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - else: - assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None) - if assign_node: - ann: ast.AST | None = getattr(assign_node, 'annotation', None) - if ann: - ann_name: str | None = None - if isinstance(ann, ast.Name): - ann_name = ann.id - elif isinstance(ann, ast.Attribute): - ann_name = ann.attr - elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): - ann_name = ExtractTypeNameFromBinOp(ann) - if ann_name: - ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - elif ann_name in Gen.structs: - target_type = ir.PointerType(Gen.structs[ann_name]) - if not getattr(Gen, '_va_arg_counter', None): - Gen._va_arg_counter = 0 - Gen._va_arg_counter += 1 - result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type) - if result is not None and getattr(result, 'name', None): - result.name = f"va_arg_result_{Gen._va_arg_counter}" - return result - - def _resolve_vararg_type(self, type_arg: ast.expr, Gen: LlvmGeneratorMixin) -> ir.Type: - """将类型表达式解析为 LLVM 类型(供 arg/va_arg 共用)。""" - target_type: ir.Type = ir.IntType(32) - if isinstance(type_arg, ast.Name): - type_name: str = type_arg.id - if type_name in ('str', 'bytes'): - target_type = ir.PointerType(ir.IntType(8)) - elif type_name == 'CPtr': - target_type = ir.PointerType(ir.IntType(8)) - elif type_name in Gen.structs: - target_type = ir.PointerType(Gen.structs[type_name]) - else: - ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - else: - resolved_tuple: tuple | None = CTypeRegistry.ResolveName(type_name) - if resolved_tuple is not None: - ctype_cls, ptr_level = resolved_tuple - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - base: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if base is not None: - for _ in range(ptr_level): - if isinstance(base, ir.VoidType): - base = ir.IntType(8).as_pointer() - else: - base = ir.PointerType(base) - target_type = base - elif isinstance(type_arg, ast.Attribute): - if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable): - attr_name: str = type_arg.attr - ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - return target_type - - def _infer_vararg_type_from_context(self, Gen: LlvmGeneratorMixin) -> ir.Type: - """从当前赋值上下文推断 va_arg/arg 的目标类型。""" - target_type: ir.Type = ir.IntType(32) - assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None) - if assign_node: - ann: ast.AST | None = getattr(assign_node, 'annotation', None) - if ann: - ann_name: str | None = None - if isinstance(ann, ast.Name): - ann_name = ann.id - elif isinstance(ann, ast.Attribute): - ann_name = ann.attr - elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): - ann_name = ExtractTypeNameFromBinOp(ann) - if ann_name: - ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name) - if ctype_cls is not None: - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - target_type = resolved - elif ann_name in Gen.structs: - target_type = ir.PointerType(Gen.structs[ann_name]) - return target_type - - def _HandleVaArgLlvm(self, args: list[ast.expr]) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not args: - return ir.Constant(ir.IntType(32), 0) - # 求值 va_list 指针(args[0]) - va_list_ptr: ir.Value = self.HandleExprLlvm(args[0]) - if va_list_ptr is None: - return ir.Constant(ir.IntType(32), 0) - # 解析目标类型 - if len(args) >= 2: - target_type: ir.Type = self._resolve_vararg_type(args[1], Gen) - else: - target_type: ir.Type = self._infer_vararg_type_from_context(Gen) - if not getattr(Gen, '_va_arg_counter', None): - Gen._va_arg_counter = 0 - Gen._va_arg_counter += 1 - result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type) - if result is not None and getattr(result, 'name', None): - result.name = f"va_arg_explicit_{Gen._va_arg_counter}" - return result if result is not None else ir.Constant(ir.IntType(32), 0) diff --git a/App/lib/core/Handles/HandlesExprFormat.py b/App/lib/core/Handles/HandlesExprFormat.py deleted file mode 100644 index 02693cf..0000000 --- a/App/lib/core/Handles/HandlesExprFormat.py +++ /dev/null @@ -1,271 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import re -import llvmlite.ir as ir - - -class ExprFormatHandle(BaseHandle): - def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if not Gen or not Gen.builder: - return ir.Constant(ir.IntType(8).as_pointer(), None) - format_str: str = "" - cast_args: list[Any] = [] - for part in Node.values: - if isinstance(part, ast.Constant) and isinstance(part.value, str): - format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') - elif isinstance(part, ast.FormattedValue): - fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen) - if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): - obj_val: Any = self.HandleExprLlvm(part.value) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if fmt_class in Gen.structs: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") - val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") - Gen._RegisterTempPtr(val) - format_str += "%s" - cast_args.append(val) - else: - format_str += "%s" - cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - val = self.HandleExprLlvm(part.value) - if not val: - format_str += "%d" - cast_args.append(ir.Constant(ir.IntType(32), 0)) - continue - # 检查 format_spec(Python f-string 格式说明符) - if part.format_spec is not None: - c_fmt: str | None = self._parse_format_spec(part.format_spec, val) - if c_fmt is not None: - cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value) - format_str += c_fmt - cast_args.append(cast_val) - continue - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - format_str += "%s" - cast_args.append(val) - elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") - trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") - format_str += "%d" - cast_args.append(trunc_val) - else: - Loaded: Any = Gen._load(val, name="fstr_deref") - if isinstance(Loaded.type, ir.IntType): - if Loaded.type.width == 8: - format_str += "%c" - ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - else: - format_str += "%d" - cast_args.append(Loaded) - elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(Loaded) - elif isinstance(Loaded.type, ir.PointerType): - format_str += "%s" - cast_args.append(Loaded) - else: - format_str += "%d" - cast_args.append(Loaded) - elif isinstance(val.type, ir.IntType): - if val.type.width == 8: - format_str += "%c" - ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - elif val.type.width == 1: - zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") - format_str += "%d" - cast_args.append(zext) - else: - is_u: bool = Gen._check_node_unsigned(part.value) - format_str += "%u" if is_u else "%d" - cast_args.append(val) - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(val) - else: - format_str += "%d" - cast_args.append(val) - if not format_str: - return Gen.emit_constant("", 'string') - format_ptr: Any = Gen._create_string_global(format_str) - # 统一使用 snprintf 生成字符串,返回 i8* - # __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放) - in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')) - snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ - ir.PointerType(ir.IntType(8)), - ir.IntType(64), - ir.PointerType(ir.IntType(8)) - ], var_arg=True) - snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type) - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - # 第一遍:获取所需长度(NULL 缓冲,size=0) - len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len") - # 加 1 用于 null 终止符 - size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size") - size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext") - if in_str_method: - # 堆分配(__str__ 返回值需跨函数生命周期) - malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) - malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type) - buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf") - Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") - Gen._RegisterTempPtr(buf_ptr) - return buf_ptr - # 栈分配(局部使用,自动释放) - buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val) - Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") - return buf_ptr - - def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None: - """将 Python f-string format_spec 转换为 C printf 格式说明符。 - - 支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。 - 返回 None 表示无法解析,调用方应回退到类型推断。 - """ - if isinstance(format_spec_node, ast.JoinedStr): - parts: list[str] = [] - for v in format_spec_node.values: - if isinstance(v, ast.Constant) and isinstance(v.value, str): - parts.append(v.value) - else: - return None - spec_str: str = ''.join(parts) - elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str): - spec_str = format_spec_node.value - else: - return None - - if not spec_str: - return None - - m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str) - if not m: - return None - - fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups() - - c_flags: str = '' - if sign == '+': - c_flags += '+' - elif sign == ' ': - c_flags += ' ' - if alt: - c_flags += '#' - - if fill_align: - align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0] - if align_char in ('<', '^'): - c_flags += '-' - if zero: - c_flags += '0' - - c_width: str = width or '' - c_precision: str = precision or '' - - length_mod: str = '' - if isinstance(val.type, ir.IntType): - if val.type.width == 64: - length_mod = 'll' - elif val.type.width == 32: - length_mod = 'l' - elif val.type.width == 16: - length_mod = 'h' - elif val.type.width == 8: - length_mod = 'hh' - - c_specifier: str = '' - if fmt_type in ('d', 'n'): - c_specifier = f'{length_mod}d' - elif fmt_type == 'x': - c_specifier = f'{length_mod}x' - elif fmt_type == 'X': - c_specifier = f'{length_mod}X' - elif fmt_type == 'o': - c_specifier = f'{length_mod}o' - elif fmt_type == 'b': - return None - elif fmt_type == 'c': - c_specifier = 'c' - elif fmt_type in ('f', 'F'): - c_specifier = 'f' - elif fmt_type in ('e', 'E', 'g', 'G'): - c_specifier = fmt_type - elif fmt_type == 's': - c_specifier = 's' - elif fmt_type == '%': - c_specifier = 'f%%' - else: - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - c_specifier = 'c' - elif val.type.width == 1: - c_specifier = 'd' - else: - c_specifier = f'{length_mod}d' - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - c_specifier = 'f' - elif isinstance(val.type, ir.PointerType): - c_specifier = 's' - else: - c_specifier = 'd' - - return f'%{c_flags}{c_width}{c_precision}{c_specifier}' - - def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value: - """根据 C printf 格式说明符转换值类型。""" - fmt_type_char: str = '' - for ch in reversed(c_fmt): - if ch.isalpha() and ch not in ('l', 'h'): - fmt_type_char = ch - break - elif ch == '%': - break - - if fmt_type_char == 's': - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - return val - if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: - return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr") - return val - elif fmt_type_char == 'c': - if isinstance(val.type, ir.IntType) and val.type.width < 32: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c") - return val - elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'): - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - is_u: bool = Gen._check_node_unsigned(arg_node) - if is_u: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8") - return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8") - elif val.type.width == 16: - is_u = Gen._check_node_unsigned(arg_node) - if is_u: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16") - return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16") - elif val.type.width == 1: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool") - return val - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i") - return val - elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'): - if isinstance(val.type, ir.FloatType): - return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext") - elif isinstance(val.type, ir.IntType): - return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f") - return val - return val \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesExprLambda.py b/App/lib/core/Handles/HandlesExprLambda.py deleted file mode 100644 index 7003785..0000000 --- a/App/lib/core/Handles/HandlesExprLambda.py +++ /dev/null @@ -1,249 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprLambdaHandle(BaseHandle): - def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if not getattr(Gen, '_lambda_counter', None): - Gen._lambda_counter = 0 - lambda_id: int = Gen._lambda_counter - Gen._lambda_counter += 1 - fn_name: str = f"lambda_fn_{lambda_id}" - captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node) - env_types: list[ir.Type] = [] - env_var_names: list[str] = [] - for var_name, var_val in captured_vars: - env_types.append(var_val.type) - env_var_names.append(var_name) - env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) - ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) - param_types: list[ir.Type] = [ir.PointerType(env_struct_type)] - if Node.args: - for arg in Node.args.args: - param_types.append(ir.IntType(32)) - fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name) - Gen.functions[fn_name] = fn - entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry") - prev_builder: Any = Gen.builder - prev_func: Any = Gen.func - prev_vars: dict[str, Any] = dict(Gen.variables) - Gen.builder = ir.IRBuilder(entry_block) - Gen.func = fn - Gen.variables = {} - for i, arg in enumerate(fn.args): - arg.name = f"arg_{i}" if i > 0 else "env" - if env_types: - for idx, var_name in enumerate(env_var_names): - env_ptr: Any = fn.args[0] - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") - Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}") - temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}") - Gen._store(Loaded, temp_alloca) - Gen.variables[var_name] = temp_alloca - if Node.args: - for i, arg in enumerate(Node.args.args): - Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) - Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) - body_val: Any = self.HandleExprLlvm(Node.body) - if body_val: - if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): - body_val = Gen._load(body_val, name="Load_lambda_ret") - if body_val.type != ret_type: - if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): - if body_val.type.width < ret_type.width: - body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") - elif body_val.type.width > ret_type.width: - body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") - elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): - body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") - Gen.builder.ret(body_val) - else: - if isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - else: - Gen.builder.ret(ir.Constant(ret_type, 0)) - Gen.builder = prev_builder - Gen.func = prev_func - Gen.variables = prev_vars - closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([ - ir.PointerType(ir.IntType(8)), - ir.PointerType(fn_type) - ]) - closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") - env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") - if env_types: - for idx, (var_name, var_val) in enumerate(captured_vars): - zero = ir.Constant(ir.IntType(32), 0) - member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") - Gen._store(var_val, member_ptr) - zero = ir.Constant(ir.IntType(32), 0) - env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") - env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") - Gen._store(env_i8_ptr, env_field_ptr) - fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") - Gen._store(fn, fn_field_ptr) - return closure_ptr - - def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - captured: list[tuple[str, Any]] = [] - free_vars: list[str] = self._get_lambda_free_vars(Node) - for var_name in free_vars: - if var_name in Gen.variables: - var_ptr: Any = Gen.variables[var_name] - if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): - Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}") - captured.append((var_name, Loaded)) - return captured - - def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]: - bound_vars: set[str] = set() - free_vars: set[str] = set() - # 收集 lambda body 中的 bound 和 free 变量 - self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) - # lambda 参数也是 bound 的 - if Node.args: - for arg in Node.args.args: - bound_vars.add(arg.arg) - # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 - result: list[str] = list(free_vars - bound_vars) - return result - - def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - TestVal: Any = self.HandleExprLlvm(Node.test) - if not TestVal: - return None - if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: - TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond") - ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then") - ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else") - MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end") - Gen.builder.cbranch(TestVal, ThenBB, ElseBB) - # 先在 ThenBB 中生成 BodyVal - Gen.builder.position_at_start(ThenBB) - BodyVal: Any = self.HandleExprLlvm(Node.body) - if not BodyVal: - BodyVal = ir.Constant(ir.IntType(32), 0) - ThenEndBB: ir.Block = Gen.builder.block - # 在 ElseBB 中生成 OrelseVal - Gen.builder.position_at_start(ElseBB) - OrelseVal: Any = self.HandleExprLlvm(Node.orelse) - if not OrelseVal: - OrelseVal = ir.Constant(ir.IntType(32), 0) - ElseEndBB: ir.Block = Gen.builder.block - # 确定 phi 节点的目标类型 - result_type: ir.Type = BodyVal.type - if BodyVal.type != OrelseVal.type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): - result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): - # 指针类型,使用 BodyVal 的类型 - result_type = BodyVal.type - elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): - # BodyVal 是整数,OrelseVal 是指针(字符串字面量) - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): - # BodyVal 是指针(字符串字面量),OrelseVal 是整数 - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = BodyVal.type - else: - result_type = OrelseVal.type - # 在 ThenBB 末尾添加类型转换(如果需要)和分支 - if not ThenEndBB.is_terminated: - Gen.builder.position_at_end(ThenEndBB) - if BodyVal.type != result_type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if BodyVal.type.width < result_type.width: - BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") - else: - BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") - elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 Else 分支的类型转换 - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 指针转整数 - BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") - Gen.builder.branch(MergeBB) - # 在 ElseBB 末尾添加类型转换(如果需要)和分支 - if not ElseEndBB.is_terminated: - Gen.builder.position_at_end(ElseEndBB) - if OrelseVal.type != result_type: - if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if OrelseVal.type.width < result_type.width: - OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") - else: - OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") - elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) - elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 如果指针指向 i8,加载字符值 - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char") - else: - OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") - Gen.builder.branch(MergeBB) - Gen.builder.position_at_start(MergeBB) - result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result") - result_phi.add_incoming(BodyVal, ThenEndBB) - result_phi.add_incoming(OrelseVal, ElseEndBB) - return result_phi - - def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ValueVal: Any = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - TargetName: str = Node.target.id - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - if TargetName in Gen.variables and Gen.variables[TargetName] is not None: - VarPtr: Any = Gen.variables[TargetName] - if VarPtr.type.pointee == ValueVal.type: - Gen._store(ValueVal, VarPtr) - else: - NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - else: - NewVar = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - Gen._reg_values[TargetName] = ValueVal - return ValueVal \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesExprUtils.py b/App/lib/core/Handles/HandlesExprUtils.py deleted file mode 100644 index de3deb8..0000000 --- a/App/lib/core/Handles/HandlesExprUtils.py +++ /dev/null @@ -1,285 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -import ast -import llvmlite.ir as ir -from lib.core.SymbolUtils import IsTModule - - -class ExprUtils: - def __init__(self, translator: "Translator") -> None: - self.Trans: Translator = translator - - def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None: - OpMap: dict[type, str] = { - ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', - ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', - ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', - ast.MatMult: '@', - } - return OpMap.get(type(Op), None) - - def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None: - OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} - return OpMap.get(type(Op), None) - - def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None: - OpMap: dict[type, str] = { - ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', - ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', - ast.In: 'in', ast.NotIn: 'not in', - } - return OpMap.get(type(Op), None) - - def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: - if isinstance(node, ast.Name): - VarName: str = node.id - return Gen.var_struct_class.get(VarName) - if isinstance(node, ast.Attribute): - AttrName: str = node.attr - # 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable) - # 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派 - # (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST') - BaseClass: str | None = self._get_var_class(node.value, Gen) - if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self': - BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None) - if BaseClass and BaseClass in Gen.class_members: - for m_name, m_type in Gen.class_members[BaseClass]: - if m_name == AttrName: - if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(m_type.pointee) - if found: - return found[0] - # 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时, - # 从 class_member_element_class 查找泛型特化类名 - element_class_map = getattr(Gen, 'class_member_element_class', {}) - element_class = element_class_map.get(BaseClass, {}).get(AttrName) - if element_class: - return element_class - break - # Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后, - # 避免字段名和变量名冲突导致错误分派) - cls: str | None = Gen.var_struct_class.get(AttrName) - if cls: - return cls - return None - return None - - def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None: - FullMethodName: str = f'{ClassName}.{op_name}' - if not Gen._has_function(FullMethodName): - FullMethodName = f'{ClassName}.{op_name}__' - if not Gen._has_function(FullMethodName): - # 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且 - # 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本 - # (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时, - # var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。 - # 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。 - if '[' not in ClassName: - SpecClass: str | None = None - for CN in Gen.structs.keys(): - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'): - SpecClass = CN - break - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'): - SpecClass = CN - break - if SpecClass: - FullMethodName = f'{SpecClass}.{op_name}' - if not Gen._has_function(FullMethodName): - FullMethodName = f'{SpecClass}.{op_name}__' - if Gen._has_function(FullMethodName): - func: Any = Gen._get_function(FullMethodName) - call_args: list[Any] = [obj_val] - if other_val is not None: - call_args.append(other_val) - if len(func.ftype.args) == len(call_args): - for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): - if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): - if expected_type != actual_val.type: - if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") - result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") - return result - return None - - def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]: - info: dict[str, Any] = { - 'name': "unknown", - 'size': 0, - 'signed': False, - 'ptr': False - } - if isinstance(llvm_type, ir.IntType): - info['size'] = llvm_type.width // 8 - info['signed'] = True - if llvm_type.width == 8: - info['name'] = "char" - elif llvm_type.width == 16: - info['name'] = "short" - elif llvm_type.width == 32: - info['name'] = "int" - elif llvm_type.width == 64: - info['name'] = "long long" - else: - info['name'] = f"int{llvm_type.width}" - elif isinstance(llvm_type, ir.DoubleType): - info['size'] = 8 - info['signed'] = True - info['name'] = "double" - elif isinstance(llvm_type, ir.FloatType): - info['size'] = 4 - info['signed'] = True - info['name'] = "float" - elif isinstance(llvm_type, ir.PointerType): - info['size'] = 8 - info['signed'] = False - info['ptr'] = True - pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee) - info['name'] = f"{pointee_info['name']}*" - elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): - size: int = 0 - for elem in llvm_type.elements: - elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem) - size += elem_info['size'] - info['size'] = size - info['signed'] = False - if isinstance(llvm_type, ir.IdentifiedStructType): - info['name'] = llvm_type.name - else: - info['name'] = "struct" - elif isinstance(llvm_type, ir.ArrayType): - elem_info = self._llvm_type_to_detailed_string(llvm_type.element) - info['size'] = elem_info['size'] * llvm_type.count - info['signed'] = elem_info['signed'] - info['name'] = f"{elem_info['name']}[]" - elif isinstance(llvm_type, ir.VoidType): - info['size'] = 0 - info['signed'] = False - info['name'] = "void" - else: - info['size'] = 0 - info['signed'] = False - info['name'] = str(llvm_type) - return info - - def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return ir.IntType(32) - elif isinstance(node.value, int): - return ir.IntType(32) - elif isinstance(node.value, float): - return ir.DoubleType() - elif isinstance(node.value, str): - if getattr(node, 'kind', None) == 'u': - return ir.PointerType(ir.IntType(16)) - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Name): - if node.id in Gen.variables: - var_ptr: Any = Gen.variables[node.id] - if isinstance(var_ptr.type, ir.PointerType): - return var_ptr.type.pointee - return var_ptr.type - if node.id in Gen._reg_values: - return Gen._reg_values[node.id].type - return ir.IntType(32) - elif isinstance(node, ast.Attribute): - attr_name: str = node.attr - AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name) - if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None): - return ir.IntType(32) - return ir.IntType(32) - elif isinstance(node, ast.BinOp): - left_type: ir.Type = self._infer_expr_llvm_type_full(node.left) - right_type: ir.Type = self._infer_expr_llvm_type_full(node.right) - if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): - return ir.DoubleType() - if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.UnaryOp): - return self._infer_expr_llvm_type_full(node.operand) - elif isinstance(node, ast.Subscript): - val_type: ir.Type = self._infer_expr_llvm_type_full(node.value) - if isinstance(val_type, ir.PointerType): - if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: - return ir.IntType(8) - if isinstance(val_type.pointee, ir.ArrayType): - return ir.PointerType(val_type.pointee.element) - return val_type.pointee - if isinstance(val_type, ir.ArrayType): - return val_type.element - if isinstance(val_type, ir.IntType): - return ir.IntType(8) - return ir.IntType(32) - elif isinstance(node, ast.Call): - if isinstance(node.func, ast.Name): - func_name: str = node.func.id - if Gen._has_function(func_name): - fn: Any = Gen._get_function(func_name) - return fn.function_type.return_type - if func_name == 'len': - return ir.IntType(32) - if func_name == 'sizeof': - return ir.IntType(32) - if func_name == 'ord': - return ir.IntType(32) - if func_name == 'chr': - return ir.IntType(8) - if func_name == 'int': - return ir.IntType(32) - if func_name == 'float' or func_name == 'double': - return ir.DoubleType() - elif isinstance(node.func, ast.Attribute): - if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': - if node.func.attr == 'Deref': - return ir.IntType(64) - if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable): - if node.func.attr == 'CChar': - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Compare): - return ir.IntType(1) - elif isinstance(node, ast.BoolOp): - return ir.IntType(1) - elif isinstance(node, ast.IfExp): - return self._infer_expr_llvm_type_full(node.body) - elif isinstance(node, ast.Attribute): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - - def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None: - """收集 AST 节点中的绑定变量和自由变量 - - Args: - node: AST 节点 - bound: 集合,收集绑定变量(ast.Store 上下文) - free: 集合,收集自由变量(ast.Load 上下文),可为 None - """ - if free is None: - free = set() - if isinstance(node, ast.Name): - if isinstance(node.ctx, ast.Store): - bound.add(node.id) - elif isinstance(node.ctx, ast.Load): - free.add(node.id) - elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): - # 这些节点有自己的作用域,不递归进入 - # 但需要收集参数名作为 bound - if hasattr(node, 'args') and node.args: - for arg in node.args.args: - bound.add(arg.arg) - elif getattr(node, '_fields', None): - for field in node._fields: - value: Any = getattr(node, field, None) - if isinstance(value, list): - for item in value: - if isinstance(item, (ast.stmt, ast.expr)): - self._collect_names(item, bound, free) - elif isinstance(value, (ast.stmt, ast.expr)): - self._collect_names(value, bound, free) \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesMatch.py b/App/lib/core/Handles/HandlesMatch.py deleted file mode 100644 index 4b8e78a..0000000 --- a/App/lib/core/Handles/HandlesMatch.py +++ /dev/null @@ -1,382 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class MatchHandle(BaseHandle): - def _HandleMatchLlvm(self, Node: ast.Match) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject) - if not SubjectVal: - return - - IsRenumMatch: bool = False - RenumName: str | None = None - SubjectPtr: ir.Value | None = None - if isinstance(Node.subject, ast.Name): - VarName: str = Node.subject.id - TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) - if TypeInfo and TypeInfo.IsRenum: - IsRenumMatch = True - RenumName = TypeInfo.Name - SubjectPtr = Gen._Load_var(VarName) - - if not IsRenumMatch: - for case in Node.cases: - if isinstance(case.pattern, ast.MatchClass): - cls_node: ast.expr = case.pattern.cls - VariantName: str | None = None - QualifiedName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - # Extract enum name for qualified lookup to avoid collision - # with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr) - if isinstance(cls_node.value, ast.Attribute): - QualifiedName = f"{cls_node.value.attr}.{VariantName}" - elif isinstance(cls_node.value, ast.Name): - QualifiedName = f"{cls_node.value.id}.{VariantName}" - if VariantName: - # Try qualified name first (e.g., "LLVMType.Ptr") to avoid - # collision with same-name functions (e.g., def Ptr(...)) - SymInfo: "SymbolTable.SymbolInfo" = None - if QualifiedName: - SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) - if not (SymInfo and SymInfo.IsEnumMember): - SymInfo = self.Trans.SymbolTable.lookup(VariantName) - if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName: - EnumName: str = SymInfo.EnumName - EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName) - if EnumInfo and EnumInfo.IsRenum: - IsRenumMatch = True - RenumName = EnumName - if SubjectPtr is None: - SubjectPtr = self.HandleExprLlvm(Node.subject) - break - - if IsRenumMatch and SubjectPtr: - self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) - return - - if not isinstance(SubjectVal.type, ir.IntType): - try: - SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") - SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") - except Exception: # 回退:ptrtoint 失败时直接返回 - return - SwitchIntType: ir.IntType = SubjectVal.type - DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") - AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") - CaseBBs: list[ir.Block] = [] - CaseValues: list[ir.Value] = [] - HasDefault: bool = False - HasNoBreak: list[bool] = [] - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(pattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchOr): - for j, SubPattern in enumerate(pattern.patterns): - if isinstance(SubPattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) - elif isinstance(pattern, ast.MatchSingleton): - if pattern.value is None: - CaseValues.append(ir.Constant(SwitchIntType, 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - def _HasNoBreak(stmts: list[ast.stmt]) -> bool: - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx: int = 0 - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchOr): - NumSubCases: int = len(pattern.patterns) - for j in range(NumSubCases): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): - SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj") - # Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。 - # 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store - # 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast - NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType) - NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and - not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))) - if NeedAlloca or NeedBitcast: - RenumStructType: Any = Gen.structs.get(RenumName) - if RenumStructType is None: - # 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册 - # (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。 - # 使用 _get_or_create_struct 按需创建(可能为 opaque)。 - RenumStructType = Gen._get_or_create_struct(RenumName) - if NeedAlloca: - AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca") - CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast") - Gen._store(SubjectPtr, CastedPtr) - SubjectPtr = AllocaPtr - else: - SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast") - # REnum 布局为 { i32 __tag, },tag 在偏移 0。 - # 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体 - # (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。 - tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr") - TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val") - DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") - AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") - CaseBBs: list[ir.Block] = [] - CaseValues: list[ir.Value] = [] - CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = [] - HasDefault: bool = False - HasNoBreak: list[bool] = [] - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - bindings: list[tuple[str, str, ir.Type, int]] = [] - if isinstance(pattern, ast.MatchClass): - cls_node: ast.expr = pattern.cls - VariantName: str | None = None - QualifiedName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if isinstance(cls_node.value, ast.Attribute): - QualifiedName = f"{cls_node.value.attr}.{VariantName}" - elif isinstance(cls_node.value, ast.Name): - QualifiedName = f"{cls_node.value.id}.{VariantName}" - if VariantName: - TagValue: int | None = None - SymInfo: "SymbolTable.SymbolInfo" = None - if QualifiedName: - SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) - if not (SymInfo and SymInfo.IsEnumMember): - SymInfo = self.Trans.SymbolTable.lookup(VariantName) - if SymInfo and SymInfo.IsEnumMember: - TagValue = SymInfo.value - if TagValue is not None: - CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) - CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}") - CaseBBs.append(CaseBB) - NestedStructName: str = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, []) - payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag'] - for j, sub_pat in enumerate(pattern.patterns): - if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members): - bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j)) - CaseBindings.append(bindings) - else: - CaseValues.append(ir.Constant(ir.IntType(32), 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(pattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(ir.IntType(32), 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - def _HasNoBreak(stmts: list[ast.stmt]) -> bool: - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx: int = 0 - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchClass): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] - cls_node: ast.expr = pattern.cls - VariantName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if VariantName: - NestedStructName: str = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - NestedStructType: ir.Type = Gen.structs[NestedStructName] - NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType) - variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") - for bind_name, member_name, member_type, member_idx in bindings: - elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") - # REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与 - # 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。 - if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type: - elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast") - Gen.variables[bind_name] = elem_ptr - self.HandleBodyLlvm(case.body) - for bind_name, _, _, _ in bindings: - if bind_name in Gen.variables: - del Gen.variables[bind_name] - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchValue): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesRaise.py b/App/lib/core/Handles/HandlesRaise.py deleted file mode 100644 index 9802e92..0000000 --- a/App/lib/core/Handles/HandlesRaise.py +++ /dev/null @@ -1,155 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -import ast -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -from lib.constants.config import mode as _config_mode - - -class RaiseHandle(BaseHandle): - def _get_exception_code(self, ExcName: str) -> int: - if ExcName in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[ExcName] - if ExcName in self.Trans.exception_registry: - return self.Trans.exception_registry[ExcName] - return 1 - - def _HandleRaiseLlvm(self, Node: ast.Raise) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1) - exc_msg: ir.Value | None = None - IsStopIteration: bool = False - if Node.exc: - if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): - exc_val = ir.Constant(ir.IntType(32), Node.exc.value) - elif isinstance(Node.exc, ast.Name): - ExcName: str = Node.exc.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): - ExcName: str = Node.exc.func.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - if Node.exc.args: - first_arg: ast.expr = Node.exc.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - exc_msg = self.HandleExprLlvm(first_arg) - elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): - arg_val: ir.Value | None = self.HandleExprLlvm(first_arg) - if arg_val: - if isinstance(arg_val.type, ir.PointerType): - if self._is_char_pointer(arg_val): - exc_msg = arg_val - else: - try: - exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - try: - exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - val: ir.Value | None = self.HandleExprLlvm(Node.exc) - if val: - if isinstance(val.type, ir.IntType): - if val.type.width != 32: - try: - val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") - except Exception: # 回退:trunc 失败时设默认值 1 - val = ir.Constant(ir.IntType(32), 1) - exc_val = val - else: - try: - val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") - exc_val = val - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - if IsStopIteration: - if Gen._stop_iter_flag_param is not None: - Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) - if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): - ret_type: ir.Type = Gen.func.type.pointee.return_type - if isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - else: - Gen.builder.ret(ir.Constant(ret_type, 0)) - else: - Gen.builder.ret_void() - return - if Gen.eh_except_block_stack: - ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] - EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] - exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] - eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] - Gen._store(exc_val, exception_code) - if exc_msg: - Gen._store(exc_msg, eh_message) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen._store(null_ptr, eh_message) - if Gen.func and ExceptBB and ExceptBB.function is Gen.func: - Gen.builder.branch(ExceptBB) - else: - eh_msg_arg: ir.Argument | None = None - eh_code_arg: ir.Argument | None = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen.builder.ret_void() - else: - eh_msg_arg: ir.Argument | None = None - eh_code_arg: ir.Argument | None = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen.builder.ret_void() \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesSpecialCall.py b/App/lib/core/Handles/HandlesSpecialCall.py deleted file mode 100644 index 61ea1de..0000000 --- a/App/lib/core/Handles/HandlesSpecialCall.py +++ /dev/null @@ -1,467 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -import ast -import llvmlite.ir as ir -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -from lib.core.Handles.HandlesBase import BaseHandle, BuiltinTypeMap -from lib.includes.t import CTypeRegistry -from lib.core.SymbolUtils import IsTModule -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode - - -class CSpecialCallHandle(BaseHandle): - def _HandleCIfLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if Node.args: - ArgVal: ir.Value | None = self.HandleExprLlvm(Node.args[0]) - if ArgVal: - if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): - return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) - if isinstance(ArgVal.type, ir.IntType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") - if isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") - return ir.Constant(ir.IntType(1), 0) - def _HandleCAddrLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(8).as_pointer(), None) - Arg = Node.args[0] - if isinstance(Arg, ast.Call): - ClassName = None - if isinstance(Arg.func, ast.Name): - ClassName = Arg.func.id - elif isinstance(Arg.func, ast.Attribute): - ClassName = Arg.func.attr - if ClassName and ClassName in Gen.structs: - StructType = Gen.structs[ClassName] - if isinstance(StructType, ir.PointerType): - StructType = StructType.pointee - ObjPtr = Gen._allocaEntry(StructType, name=f"{ClassName}_obj") - zero_val = Gen._zero_value_for_type(StructType) - if zero_val is not None: - Gen.builder.store(zero_val, ObjPtr) - ConstructorName = f"{ClassName}.__init__" - if ConstructorName in Gen.functions: - func = Gen.functions[ConstructorName] - InitArgs = [ObjPtr] - for carg in Arg.args: - ArgVal = self.HandleExprLlvm(carg) - if ArgVal: - InitArgs.append(ArgVal) - for kw in Arg.keywords: - ArgVal = self.HandleExprLlvm(kw.value) - if ArgVal: - InitArgs.append(ArgVal) - if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'): - self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen) - adjusted = Gen._adjust_args(InitArgs, func) - Gen.builder.call(func, adjusted, name=f"{ClassName}_construct") - return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr") - if isinstance(Arg, ast.Subscript): - SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg) - if SubPtr and isinstance(SubPtr.type, ir.PointerType): - return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr") - if isinstance(Arg, ast.Attribute): - AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType): - return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr") - if isinstance(Arg, ast.Name): - VarName = Arg.id - if VarName in Gen.functions: - func = Gen.functions[VarName] - return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr") - if VarName in Gen.variables and Gen.variables[VarName] is not None: - var_ptr = Gen.variables[VarName] - if isinstance(var_ptr.type, ir.PointerType): - # For pointer-to-pointer allocas (var_ptr is T**): - # - If T is a named struct (@t.Object class), the variable semantically - # IS the struct, so c.Addr should return the struct pointer value. - # - If T is a primitive pointer type (e.g., i8*), the variable semantically - # holds a pointer, so c.Addr should return &var (alloca address). - if isinstance(var_ptr.type.pointee, ir.PointerType): - pointee = var_ptr.type.pointee.pointee - if isinstance(pointee, ir.IdentifiedStructType): - # @t.Object class variable — return Loaded struct pointer - ArgVal = self.HandleExprLlvm(Arg) - if ArgVal and isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - # Pointer-type variable — return alloca address (&var) - return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - ArgVal = self.HandleExprLlvm(Arg) - if ArgVal: - if isinstance(ArgVal.type, ir.IntType): - alloca = Gen._alloca(ArgVal.type, name="addr_tmp") - Gen._store(ArgVal, alloca) - return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - elif isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast") - return ir.Constant(ir.IntType(8).as_pointer(), None) - - def _HandleCSetLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if len(Node.args) >= 2: - target_arg: ast.expr = Node.args[0] - value_arg: ast.expr = Node.args[1] - target_ptr: ir.Value | None = None - if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute): - if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c': - if target_arg.func.attr == 'Deref' and target_arg.args: - deref_arg = target_arg.args[0] - if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None: - target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr") - else: - inner_value = self.HandleExprLlvm(deref_arg) - if inner_value: - if isinstance(inner_value.type, ir.PointerType): - if isinstance(inner_value.type.pointee, ir.PointerType): - inner_value = Gen._load(inner_value, name="cast_deref") - target_ptr = inner_value - elif target_arg.func.attr == 'Addr' and target_arg.args: - target_ptr = self.HandleExprLlvm(target_arg) - elif isinstance(target_arg.func.value, ast.Name) and IsTModule(target_arg.func.value.id, self.Trans.SymbolTable): - type_attr = target_arg.func.attr - resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr) - if target_arg.args and resolved_cname is not None: - inner_val = self.HandleExprLlvm(target_arg.args[0]) - if inner_val and isinstance(inner_val.type, ir.PointerType): - target_llvm_type = Gen._basic_type_to_llvm(resolved_cname) - if target_llvm_type: - target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr") - if not target_ptr: - if isinstance(target_arg, ast.Subscript): - target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg) - else: - target_ptr = self.HandleExprLlvm(target_arg) - Val = self.HandleExprLlvm(value_arg) - if target_ptr and Val: - if isinstance(target_ptr.type, ir.PointerType): - ValToStore = Val - pointee = target_ptr.type.pointee - if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8: - if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: - ValToStore = Val - elif isinstance(Val.type, ir.IntType): - ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set") - elif isinstance(pointee, ir.IntType): - if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8: - zero = ir.Constant(ir.IntType(32), 0) - value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr") - ValToStore = Gen._load(value_ptr, name="Load_value") - elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: - ValToStore = Gen._load(Val, name="Load_char_value") - if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType): - if ValToStore.type.width < pointee.width: - ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set") - elif ValToStore.type.width > pointee.width: - ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set") - elif Val.type != pointee: - if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType): - ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set") - Gen._store(ValToStore, target_ptr) - return ir.Constant(ir.IntType(32), 1) - - def _HandleCLoadLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if len(Node.args) < 2: - return ir.Constant(ir.IntType(32), 0) - # c.Load(a, b) 语义: *a = *b(a 是目标,b 是源) - # wiki 文档: c.Load(ptr, value) -> *ptr = *value; - dst_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) - src_val: ir.Value | None = self.HandleExprLlvm(Node.args[1]) - if not src_val or not dst_val: - return ir.Constant(ir.IntType(32), 0) - if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType): - return ir.Constant(ir.IntType(32), 0) - pointee = dst_val.type.pointee - # c.Addr 统一返回 i8* 通用指针,丢失原始类型信息。 - # 若 dst 是 c.Addr(var),从 var 的 alloca 类型推断真实 pointee(如 i64), - # 否则 c.Load 只会按 i8 加载 1 字节(IEEE 754 double→u64 位重解释 bug)。 - if (isinstance(pointee, ir.IntType) and pointee.width == 8 - and isinstance(Node.args[0], ast.Call) - and isinstance(Node.args[0].func, ast.Attribute) - and Node.args[0].func.attr == 'Addr' - and Node.args[0].args - and isinstance(Node.args[0].args[0], ast.Name)): - var_name = Node.args[0].args[0].id - if var_name in Gen.variables and Gen.variables[var_name] is not None: - var_ptr = Gen.variables[var_name] - if isinstance(var_ptr.type, ir.PointerType): - pointee = var_ptr.type.pointee - # 按 pointee 类型 bitcast src 加载,bitcast dst 存储 - if src_val.type.pointee != pointee: - src_cast = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_src_cast") - else: - src_cast = src_val - Loaded = Gen._load(src_cast, name="cLoad_loaded") - if Loaded is None: - return ir.Constant(ir.IntType(32), 0) - if dst_val.type.pointee != pointee: - dst_cast = Gen.builder.bitcast(dst_val, ir.PointerType(pointee), name="cLoad_dst_cast") - else: - dst_cast = dst_val - Gen._store(Loaded, dst_cast) - return ir.Constant(ir.IntType(32), 1) - - def _HandleCDerefLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(64), 0) - # 检测嵌套 c.Deref(c.Deref(...)):设置标志让内层 Deref 加载为指针 - IsNestedDeref: bool = ( - isinstance(Node.args[0], ast.Call) - and isinstance(Node.args[0].func, ast.Attribute) - and Node.args[0].func.attr == 'Deref' - ) - if IsNestedDeref: - Gen._nested_deref_load_ptr = True - try: - arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) - finally: - if IsNestedDeref: - Gen._nested_deref_load_ptr = False - if arg_val is None: - return ir.Constant(ir.IntType(32), 0) - if isinstance(arg_val.type, ir.PointerType): - pointee: ir.Type = arg_val.type.pointee - # 嵌套 Deref 的内层:加载为指针 (i8*),不推断目标类型 - # 因为结果会被外层 Deref 再次解引用 - NestedLoadPtr: bool = getattr(Gen, '_nested_deref_load_ptr', False) - if NestedLoadPtr: - PtrType: ir.Type = ir.PointerType(ir.IntType(8)) - casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(PtrType), name="deref_cast") - Loaded = Gen._load(casted, name="deref") - if Loaded is not None: - return Loaded - # void* (i8*) 需要根据赋值目标类型推断加载类型 - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - target_type: ir.Type | None = self._infer_deref_target_type(Gen, Node) - if target_type is not None and not isinstance(target_type, ir.IntType): - # bitcast i8* -> target_type* then load - casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast") - Loaded = Gen._load(casted, name="deref") - if Loaded is not None: - return Loaded - elif target_type is not None and isinstance(target_type, ir.IntType): - # 目标是整数类型 (如 i32/i64): bitcast 并加载 - if target_type.width != 8: - casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast") - Loaded = Gen._load(casted, name="deref") - if Loaded is not None: - return Loaded - Loaded = Gen._load(arg_val, name="deref") - if Loaded is not None: - return Loaded - return arg_val - - def _infer_deref_target_type(self, Gen: LlvmGeneratorMixin, DerefNode: ast.Call | None = None) -> ir.Type | None: - """从当前赋值上下文推断 c.Deref 的目标加载类型。 - 当用户写 v: int = c.Deref(ptr) 时,从赋值注解推断目标类型。 - 注意:仅当 c.Deref 是赋值的直接 RHS 时才推断;若 c.Deref 嵌套在 - ifexp/compare/binop 中(如 `a = 1 if c.Deref(p) == 65 else 0`), - 不应推断,否则会把 i8* 错误 bitcast 为 i32* 加载 4 字节。""" - assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None) - if not assign_node: - return None - # 仅当 c.Deref 是赋值的直接 RHS 时才推断类型 - if DerefNode is not None and getattr(assign_node, 'value', None) is not DerefNode: - return None - ann: ast.AST | None = getattr(assign_node, 'annotation', None) - if not ann: - return None - ann_name: str | None = None - if isinstance(ann, ast.Name): - ann_name = ann.id - elif isinstance(ann, ast.Attribute): - ann_name = ann.attr - elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): - # 处理 int | t.CPtr 形式的联合类型注解 - for side in (ann.left, ann.right): - if isinstance(side, ast.Name): - ann_name = side.id - break - elif isinstance(side, ast.Attribute): - ann_name = side.attr - break - if not ann_name: - return None - # 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记) - entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name) - if entry is not None: - ctype_cls: type = entry[0] - llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str) - if resolved: - return resolved - # 检查是否是已注册的结构体类型 - if ann_name in Gen.structs: - return Gen.structs[ann_name] - return None - - def _HandleCPtrToIntLlvm(self, Node: ast.Call) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(64), 0) - arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) - if arg_val is None: - return ir.Constant(ir.IntType(64), 0) - if isinstance(arg_val.type, ir.PointerType): - return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result") - if isinstance(arg_val.type, ir.IntType): - if arg_val.type.width < 64: - return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint") - elif arg_val.type.width > 64: - return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint") - return arg_val - return ir.Constant(ir.IntType(64), 0) - - -class TSpecialCallHandle(BaseHandle): - - @staticmethod - def _ResolveTAttrToCName(attr: str) -> str | None: - ctype_cls: type | None = CTypeRegistry.GetClassByName(attr) - if ctype_cls is not None: - try: - inst = ctype_cls() - cname = type(inst).__name__ - if cname: - return cname - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"处理函数调用失败: {_e}", "Exception") - return None - - def _HandleTSpecialCallLlvm(self, Node: ast.Call) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if not Node.args: - return None - attr: str = Node.func.attr - - if attr == 'CType': - return self._HandleCTypeLlvm(Node) - - target_type: str | None = self._ResolveTAttrToCName(attr) - if target_type is not None: - IsPtr_cast = False - if len(Node.args) >= 2: - second_arg = Node.args[1] - if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and IsTModule(second_arg.value.id, self.Trans.SymbolTable) and second_arg.attr == 'CPtr': - IsPtr_cast = True - elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr': - IsPtr_cast = True - if IsPtr_cast: - return self._HandleTPtrCastLlvm(Node, attr) - if target_type == 'void': - target_type = 'void *' - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type) - return None - - def _HandleCTypeLlvm(self, Node: ast.Call) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0]) - if not arg_val: - return None - target_type_str: str = 'unsigned long long' - if len(Node.args) >= 2: - type_parts: list[str] = [] - ptr_count: int = 0 - for i in range(1, len(Node.args)): - type_arg = Node.args[i] - if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable): - type_attr = type_arg.attr - _PREFIX_MAP: dict[str, str] = { - 'CUnsigned': 'unsigned', 'CSigned': 'signed', - 'CConst': 'const', 'CVolatile': 'volatile', - } - if type_attr in _PREFIX_MAP: - type_parts.append(_PREFIX_MAP[type_attr]) - elif type_attr in ('CPtr', 'CArrayPtr'): - ptr_count += 1 - else: - resolved = self._ResolveTAttrToCName(type_attr) - if resolved is not None: - type_parts.append(resolved) - if type_parts: - target_type_str = ' '.join(type_parts) - if ptr_count > 0: - target_type_str += ' ' + '*' * ptr_count - if isinstance(arg_val.type, ir.PointerType): - int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int") - return int_val - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str) - - def _HandleTPtrCastLlvm(self, Node: ast.Call, attr: str) -> ir.Value | None: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if attr in ('CChar', 'CUnsignedChar'): - first_arg = Node.args[0] - if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and IsTModule(first_arg.func.value.id, self.Trans.SymbolTable) and first_arg.func.attr == 'CInt' and first_arg.args: - inner_val = self.HandleExprLlvm(first_arg.args[0]) - if isinstance(inner_val.type, ir.PointerType): - return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint") - expr_val = self.HandleExprLlvm(Node.args[0]) - if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8: - var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr") - zero = ir.Constant(ir.IntType(32), 0) - char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr") - Gen._store(expr_val, char_ptr) - null_char = ir.Constant(ir.IntType(8), 0) - null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr") - Gen._store(null_char, null_ptr) - return char_ptr - elif isinstance(expr_val.type, ir.PointerType): - if isinstance(expr_val.type.pointee, ir.PointerType): - Loaded_ptr = Gen._load(expr_val, name="load_ptr") - if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8: - return Loaded_ptr - if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8: - return expr_val - return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr") - elif isinstance(expr_val.type, ir.IntType): - if expr_val.type.width == 32: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}") - return Gen.emit_constant(0, 'int') - elif attr == 'CVoid': - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *') - elif attr == 'CInt': - expr_val = self.HandleExprLlvm(Node.args[0]) - if expr_val: - if isinstance(expr_val.type, ir.IntType): - if expr_val.type.width < 64: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") - return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") - else: - ctype_cls = CTypeRegistry.GetClassByName(attr) - if ctype_cls is not None: - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - target_type = Gen._type_str_to_llvm(llvm_str) - if target_type: - # 基础类型 (int/float) → 加一层指针 → T* - if isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)): - target_ptr_type = ir.PointerType(target_type) - expr_val = self.HandleExprLlvm(Node.args[0]) - if expr_val: - if isinstance(expr_val.type, ir.IntType): - if expr_val.type.width < 64: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - # 指针类型 (如 CPtr → i8*) → 再加一层指针 → i8** - elif isinstance(target_type, ir.PointerType): - target_ptr_type = ir.PointerType(target_type) - expr_val = self.HandleExprLlvm(Node.args[0]) - if expr_val: - if isinstance(expr_val.type, ir.IntType): - if expr_val.type.width < 64: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - return None diff --git a/App/lib/core/Handles/HandlesTry.py b/App/lib/core/Handles/HandlesTry.py deleted file mode 100644 index 1fd04e7..0000000 --- a/App/lib/core/Handles/HandlesTry.py +++ /dev/null @@ -1,214 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - - -class TryHandle(BaseHandle): - def _get_exception_type_code(self, type_node: ast.expr) -> int: - if isinstance(type_node, ast.Name): - name: str = type_node.id - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Attribute): - name: str = type_node.attr - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Tuple): - for elt in type_node.elts: - code: int = self._get_exception_type_code(elt) - if code != 1: - return code - return 1 - return 1 - - def _get_exception_name(self, type_node: ast.expr) -> str | None: - if isinstance(type_node, ast.Name): - return type_node.id - if isinstance(type_node, ast.Attribute): - return type_node.attr - return None - - def _get_all_match_codes(self, type_node: ast.expr) -> list[int]: - name: str | None = self._get_exception_name(type_node) - if name is None: - return [self._get_exception_type_code(type_node)] - if name not in self.Trans.exception_registry: - return [self._get_exception_type_code(type_node)] - codes: list[int] = [self.Trans.exception_registry[name]] - self._collect_descendant_codes(name, codes) - return codes - - def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None: - for child_name, parent in self.Trans.exception_parents.items(): - if parent == parent_name: - child_code: int | None = self.Trans.exception_registry.get(child_name) - if child_code is not None and child_code not in codes: - codes.append(child_code) - self._collect_descendant_codes(child_name, codes) - - def _HandleTryLlvm(self, Node: ast.Try) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not Gen.func: - return - exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code") - eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message") - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) - HasFinally: bool = bool(Node.finalbody) - if HasFinally: - Gen.eh_finally_stack.append((None, None, None)) - else: - Gen.eh_finally_stack.append(None) - DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch") - AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after") - except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = [] - for i, handler in enumerate(Node.handlers): - ExcTypeCodes: list[int] = [1] - if handler.type: - ExcTypeCodes = self._get_all_match_codes(handler.type) - ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}") - Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) - except_blocks.append((ExceptBB, ExcTypeCodes, handler)) - TryBB: ir.Block = Gen.func.append_basic_block(name="try.body") - ElseBB: ir.Block | None = None - if Node.orelse: - ElseBB = Gen.func.append_basic_block(name="try.else") - Gen.builder.branch(TryBB) - Gen.builder.position_at_start(TryBB) - self.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - if ElseBB: - Gen.builder.branch(ElseBB) - else: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(DispatchBB) - eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code") - next_check_bb: ir.Block | None = None - handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {} - UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled") - for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}") - if i > 0 and next_check_bb is not None: - Gen.builder.position_at_start(next_check_bb) - eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}") - if handler.type is None: - Gen.builder.branch(MatchBB) - else: - match_cond: ir.Value | None = None - for code in ExcTypeCodes: - is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") - if match_cond is None: - match_cond = is_code_match - else: - match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") - if i < len(except_blocks) - 1: - next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") - else: - next_check_bb = UnhandledBB - Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) - Gen.builder.position_at_start(MatchBB) - if handler.name: - var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name) - eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}") - Gen._store(eh_msg_val, var_alloca) - handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) - Gen.builder.branch(ExceptBB) - Gen.builder.position_at_start(UnhandledBB) - eh_msg_out_arg: ir.Argument | None = None - eh_code_out_arg: ir.Argument | None = None - if Gen.func and len(Gen.func.args) > 0: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_out_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_out_arg = arg - if eh_msg_out_arg is not None and eh_code_out_arg is not None: - eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate") - eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate") - Gen._store(eh_msg_val, eh_msg_out_arg) - Gen._store(eh_code_val_prop, eh_code_out_arg) - ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None - if isinstance(ret_type, ir.IdentifiedStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - elif isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 1)) - elif isinstance(ret_type, ir.VoidType): - Gen.builder.ret_void() - else: - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen.builder.branch(AfterBB) - for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - Gen.builder.position_at_start(ExceptBB) - old_var: ir.Value | None = None - if idx in handler_var_map: - hname: str = handler_var_map[idx][0] - var_alloca: ir.AllocaInstr = handler_var_map[idx][1] - old_var = handler_var_map[idx][2] - Gen.variables[hname] = var_alloca - self.HandleBodyLlvm(handler.body) - if idx in handler_var_map: - hname = handler_var_map[idx][0] - old_var = handler_var_map[idx][2] - if old_var is not None: - Gen.variables[hname] = old_var - elif hname in Gen.variables: - del Gen.variables[hname] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.eh_except_block_stack.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - if HasFinally: - Gen.eh_finally_stack.pop() - if Node.finalbody: - FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally") - pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag") - pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None - Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) - Gen.builder.branch(FinallyBB) - Gen.builder.position_at_start(FinallyBB) - Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) - self.HandleBodyLlvm(Node.finalbody) - if Gen.eh_finally_stack: - _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] - Gen.eh_finally_stack.pop() - ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag") - ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") - RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret") - ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue") - Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) - Gen.builder.position_at_start(RetBB) - if pending_ret_val: - ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val") - Gen.builder.ret(ret_val) - else: - Gen.builder.ret_void() - Gen.builder.position_at_start(ContinueBB) \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesTypeMerge.py b/App/lib/core/Handles/HandlesTypeMerge.py deleted file mode 100644 index 4af492f..0000000 --- a/App/lib/core/Handles/HandlesTypeMerge.py +++ /dev/null @@ -1,976 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from typing import List -from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo -from lib.core.SymbolUtils import IsTModule, IsListAnnotation -from lib.includes import t -import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes) -import ast - - -class HandlesTypeMerge(BaseHandle): - """处理类型合并逻辑 - 所有类型分析的核心模块""" - - def _MakeVoidCTypeInfo(self) -> CTypeInfo: - Info = CTypeInfo() - Info.BaseType = t.CVoid - return Info - - @staticmethod - def _MakeCTypeInfoFromName(TypeName: str) -> CTypeInfo: - """直接从类型名构造 CTypeInfo,不经过 FromStr/字符串解析""" - return CTypeInfo.FromTypeName(TypeName) - - def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo: - """获取 CTypeInfo 对象""" - Result = self._GetCTypeInfoInternal(Node) - if isinstance(Result, CTypeInfo): - return Result - elif isinstance(Result, str): - return self._MakeCTypeInfoFromName(Result) - else: - return self._MakeVoidCTypeInfo() - - def _GetCTypeInfoInternal(self, Node: ast.AST) -> CTypeInfo | str | None: - """鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo""" - LineNum = getattr(Node, 'lineno', None) - - self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...") - - if isinstance(Node, ast.Constant): - TypeName = Node.value - return self._MakeCTypeInfoFromName(TypeName) - - if isinstance(Node, ast.Name): - TypeName = Node.id - t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) - if TypeName in t_c_imported: - src_module, src_name = t_c_imported[TypeName] - virtual_attr = ast.Attribute( - value=ast.Name(id=src_module, ctx=ast.Load()), - attr=src_name, - ctx=ast.Load() - ) - ast.copy_location(virtual_attr, Node) - return self.GetCTypeInfo(virtual_attr) - Entry = self.Trans.SymbolTable.lookup(TypeName) - if Entry and Entry.IsTypedef: - if isinstance(Entry, CTypeInfo) and Entry.BaseType: - if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: - Result = Entry.Copy() - Result.IsTypedef = True - Result.Name = TypeName - return Result - if Entry.OriginalType: - if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, CTypeInfo): - Resolved = Entry.OriginalType.Copy() - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - elif isinstance(Entry.OriginalType, str): - # 字符串 OriginalType(如 'void *')需解析为 CTypeInfo, - # 否则返回的 Entry BaseType=None 会被下游误判为 i32 - Resolved = CTypeInfo.FromTypeName(Entry.OriginalType) - if Resolved and Resolved.BaseType: - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - return Entry - # REnum 优先于 IsEnum 处理(REnum 同时有 IsEnum=True 和 IsStruct=True) - # 必须设置 Name 和 PtrCount=1,否则 BinOp `LLVMType | t.CPtr` 合并后丢失 REnum 语义 - if isinstance(Entry, CTypeInfo) and Entry.IsRenum: - Result = Entry.Copy() - Result.Name = TypeName - Result.PtrCount = 1 # REnum 变量默认为指针(和 struct 一致) - return Result - # 类名与枚举成员名冲突时(如 Constant 既是 ASTKind.Constant 枚举成员又是结构体类名), - # 优先检查 Gen.structs:类型注解应解析为结构体而非枚举值 - _Gen = getattr(self.Trans, 'LlvmGen', None) - if _Gen and TypeName in _Gen.structs: - Result = CTypeInfo() - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - Result.Name = TypeName - Result.PtrCount = 1 - return Result - if isinstance(Entry, CTypeInfo) and Entry.IsEnum: - return Entry.Copy() - if isinstance(Entry, dict) and Entry.get('IsEnum'): - Result = CTypeInfo() - Result.BaseType = t.CEnum(TypeName) - Result.IsEnum = True - return Result - # 检测结构体类型 (CTypeInfo with IsStruct=True, 来自 _InsertClassSymbol) - if isinstance(Entry, CTypeInfo) and Entry.IsStruct: - Result = Entry.Copy() - if Result.BaseType is None: - Result.BaseType = t.CStruct(name=TypeName) - Result.Name = TypeName - Result.PtrCount = 1 # struct 变量默认为指针 - return Result - return self._MakeCTypeInfoFromName(TypeName) - - elif isinstance(Node, ast.Attribute): - ModuleParts = [] - Current = Node - while isinstance(Current, ast.Attribute): - ModuleParts.insert(0, Current.attr) - Current = Current.value - - if isinstance(Current, ast.Name): - ModuleParts.insert(0, Current.id) - - if len(ModuleParts) >= 2: - TypeName = ModuleParts[-1] - ModulePath = '.'.join(ModuleParts[:-1]) - elif len(ModuleParts) == 1: - TypeName = ModuleParts[0] - ModulePath = None - else: - return self._MakeVoidCTypeInfo() - - # 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types - if ModulePath: - import_aliases = self.Trans.SymbolTable.import_aliases - if ModulePath in import_aliases: - ModulePath = import_aliases[ModulePath] - else: - # 也尝试在符号表中查找模块别名 - entry = self.Trans.SymbolTable.lookup(ModulePath) - if isinstance(entry, CTypeInfo) and entry.IsModuleAlias: - resolved = entry.ResolvedModule - if resolved: - ModulePath = resolved - - self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}") - - if ModulePath == 't' and TypeName == 'State': - Info = CTypeInfo() - Info.BaseType = t.CVoid - Info.IsState = True - return Info - - if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')): - if self._IsTModuleType(TypeName): - TypeClass = CTypeHelper.GetTModuleCType(TypeName) or getattr(t, TypeName, None) - if TypeClass == t.CArrayPtr: - Info = CTypeInfo() - Info.IsArrayPtr = True - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CPtr: - Info = CTypeInfo() - Info.PtrCount = 1 - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CConst: - Info = CTypeInfo() - Info.DataConst = True - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CVolatile: - Info = CTypeInfo() - Info.DataVolatile = True - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CInline: - Info = CTypeInfo() - Info.Storage = t.CInline() - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CStatic: - Info = CTypeInfo() - Info.Storage = t.CStatic() - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CExtern: - Info = CTypeInfo() - Info.Storage = t.CExtern() - Info.BaseType = t.CVoid - return Info - elif TypeClass == t.CExport: - Info = CTypeInfo() - Info.Storage = t.CExport() - Info.BaseType = t.CVoid - return Info - elif TypeClass in (t.BigEndian, t.LittleEndian): - Info = CTypeInfo() - Info.BaseType = t.CInt() - Info.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little' - return Info - elif TypeClass: - Info = CTypeInfo() - Info.BaseType = TypeClass - return Info - elif CTypeHelper.GetCName(TypeName): - return self._MakeCTypeInfoFromName(CTypeHelper.GetCName(TypeName)) - - FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName - - # 优先检查 Gen.structs:类名与枚举成员名冲突时(如 Import 既是 ASTKind.Import - # 枚举成员又是 ast.Import 结构体类名),类型注解应解析为结构体而非枚举值 - # (与 ast.Name 路径 line 100-107 的逻辑一致) - _Gen = getattr(self.Trans, 'LlvmGen', None) - if _Gen and TypeName in _Gen.structs: - Result = CTypeInfo() - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - Result.Name = TypeName - Result.PtrCount = 1 - return Result - - Entry = self.Trans.SymbolTable.lookup(TypeName) - if Entry and Entry.IsTypedef: - if isinstance(Entry, CTypeInfo) and Entry.BaseType: - if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: - Result = Entry.Copy() - Result.IsTypedef = True - Result.Name = TypeName - return Result - if Entry.OriginalType: - if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, CTypeInfo): - Resolved = Entry.OriginalType.Copy() - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - elif isinstance(Entry.OriginalType, str): - # 字符串 OriginalType(如 'void *')需解析为 CTypeInfo, - # 否则返回的 Result BaseType=_CTypedef 会被下游误判为 i32 - Resolved = CTypeInfo.FromTypeName(Entry.OriginalType) - if Resolved and Resolved.BaseType: - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - Result = CTypeInfo() - Result.BaseType = t._CTypedef(TypeName) - Result.IsTypedef = True - Result.Name = TypeName - return Result - if Entry: - # If BaseType is None but this is a class/struct, set BaseType to CStruct - Result = Entry.Copy() - if Result.BaseType is None: - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - # struct 变量默认为指针(与 ast.Name 路径一致,见 line 121) - # 同时确保 Name 字段被设置,供 ToString() 使用 - if Result.IsStruct: - if Result.PtrCount == 0: - Result.PtrCount = 1 - if not Result.Name: - Result.Name = TypeName - return Result - return CTypeInfo() - - elif isinstance(Node, ast.Call): - if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': - ReturnTypeInfo = self._GetCTypeInfoInternal(Node.args[0]) if Node.args else None - if isinstance(ReturnTypeInfo, CTypeInfo): - ReturnType = ReturnTypeInfo - else: - ReturnType = CTypeInfo() - ReturnType.BaseType = t.CVoid() - - ParamTypes = [] - ParamNames = [] - for kw in Node.keywords: - ParamTypeInfo = self._GetCTypeInfoInternal(kw.value) - if not isinstance(ParamTypeInfo, CTypeInfo): - ParamTypeInfo = self._MakeCTypeInfoFromName('int') - ParamTypes.append(ParamTypeInfo) - ParamNames.append(kw.arg) - - for arg in Node.args[1:]: - if isinstance(arg, ast.Tuple): - for elt in arg.elts: - ParamTypeInfo = self._GetCTypeInfoInternal(elt) - if not isinstance(ParamTypeInfo, CTypeInfo): - ParamTypeInfo = self._MakeCTypeInfoFromName('int') - ParamTypes.append(ParamTypeInfo) - ParamNames.append('') - else: - ParamTypeInfo = self._GetCTypeInfoInternal(arg) - if not isinstance(ParamTypeInfo, CTypeInfo): - ParamTypeInfo = self._MakeCTypeInfoFromName('int') - ParamTypes.append(ParamTypeInfo) - ParamNames.append('') - - if not ParamTypes: - ParamTypes.append(self._MakeCTypeInfoFromName('void')) - ParamNames.append('') - - Info = CTypeInfo() - Info.IsFuncPtr = True - Info.FuncPtrReturn = ReturnType - Info.FuncPtrParams = list(zip(ParamNames, ParamTypes)) - return Info - - if isinstance(Node.func, ast.Attribute) and isinstance(Node.func.value, ast.Name): - ModuleName = Node.func.value.id - TypeName = Node.func.attr - - if ModuleName == 't' and CTypeHelper.GetTModuleCType(TypeName) == t._CTypedef and Node.args: - TypeArg = Node.args[0] - if isinstance(TypeArg, ast.Name): - return TypeArg.id - elif isinstance(TypeArg, ast.Attribute): - AttrModule = TypeArg.value.id if isinstance(TypeArg.value, ast.Name) else None - AttrName = TypeArg.attr - if AttrModule == 't' and getattr(t, AttrName, None): - TypeObj = getattr(t, AttrName) - if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType): - return TypeObj.__name__ - return AttrName - elif isinstance(TypeArg, ast.Constant): - return str(TypeArg.value) - - if ModuleName in self.Trans._UserTypeModules: - module = self.Trans._UserTypeModules[ModuleName] - if getattr(module, TypeName, None): - TypeObj = getattr(module, TypeName) - if isinstance(TypeObj, type): - if issubclass(TypeObj, t.CType): - return TypeObj.__name__ - - if ModuleName == 't': - TypeObj = CTypeHelper.GetTModuleCType(TypeName) - if TypeObj is None: - TypeObj = getattr(t, TypeName, None) - if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType): - Result = CTypeInfo() - Result.BaseType = TypeObj - return Result - - if ModuleName == 't' and TypeName == 'State': - Result = CTypeInfo() - Result.IsState = True - return Result - - if ModuleName == 't' and TypeName == 'Bit': - if Node.args and isinstance(Node.args[0], ast.Constant): - BitWidth = Node.args[0].value - Result = CTypeInfo() - Result.IsBitField = True - Result.BitWidth = BitWidth - Result.BaseType = t.CInt - return Result - - Result = CTypeInfo() - Result.BaseType = t.CVoid - return Result - - elif isinstance(Node, ast.Subscript): - if (isinstance(Node.value, ast.Attribute) - and isinstance(Node.value.value, ast.Name) - and IsTModule(Node.value.value.id, self.Trans.SymbolTable) - and Node.value.attr == 'Bit'): - if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): - Result = CTypeInfo() - Result.IsBitField = True - Result.BitWidth = Node.slice.value - Result.BaseType = t.CInt - return Result - return self._HandleSubscript(Node) - - elif isinstance(Node, ast.BinOp): - return self.MergeTypes(Node) - - elif isinstance(Node, ast.List): - if Node.elts: - BaseTypes = [] - for elt in Node.elts: - EltType = self._GetCTypeInfoInternal(elt) - if isinstance(EltType, CTypeInfo) and EltType.BaseType: - BaseTypes.append(EltType.BaseType) - if BaseTypes: - Result = CTypeInfo() - Result.BaseType = tuple(BaseTypes) - return Result - return self._MakeVoidCTypeInfo() - - return self._MakeVoidCTypeInfo() - - def _HandleSubscript(self, Node: ast.Subscript) -> CTypeInfo: - """澶勭悊 Subscript 鑺傜偣锛屼娇鐢?CTypeInfo 鏍戝舰缁撴瀯鍒嗘瀽 AST - - 例如? - t.CVoid[5] -> void *[5] - t.CPtr[t.CPtr[t.CPtr]][5][6] -> void ***[5][6] - t.CArrayPtr[t.CArrayPtr] -> void *(*)[] - t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[] - """ - def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo: - """鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo""" - if isinstance(node, ast.Subscript): - value_node = node.value - slice_node = node.slice - - if isinstance(value_node, ast.Attribute): - VtInfo = self.GetCTypeInfo(value_node) - - if isinstance(value_node, ast.Attribute) and value_node.attr == 'Callable' and isinstance(value_node.value, ast.Name) and IsTModule(value_node.value.id, self.Trans.SymbolTable): - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - params_list = slice_node.elts[0] - return_node = slice_node.elts[1] - ParamTypes = [] - ParamNames = [] - if isinstance(params_list, ast.List): - for elt in params_list.elts: - ParamTypeInfo = self._GetCTypeInfoInternal(elt) - if isinstance(ParamTypeInfo, CTypeInfo): - ParamTypes.append(ParamTypeInfo) - ParamNames.append('') - else: - ParamTypes.append(self._MakeCTypeInfoFromName('int')) - ParamNames.append('') - if not ParamTypes: - ParamTypes.append(self._MakeCTypeInfoFromName('void')) - ParamNames.append('') - ReturnTypeInfo = self._GetCTypeInfoInternal(return_node) - if isinstance(ReturnTypeInfo, CTypeInfo): - ReturnType = ReturnTypeInfo - else: - ReturnType = CTypeInfo() - ReturnType.BaseType = t.CVoid() - Info = CTypeInfo() - Info.IsFuncPtr = True - Info.FuncPtrReturn = ReturnType - Info.FuncPtrParams = list(zip(ParamNames, ParamTypes)) - return Info - - if VtInfo and VtInfo.IsArrayPtr: - ResultInfo = CTypeInfo() - ResultInfo.PtrCount = VtInfo.PtrCount - ResultInfo.IsArrayPtr = True - if isinstance(slice_node, ast.Attribute): - SliceVtInfo = self.GetCTypeInfo(slice_node) - if SliceVtInfo and SliceVtInfo.IsArrayPtr: - ResultInfo.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr.IsArrayPtr = True - ResultInfo.ArrayPtr.PtrCount = SliceVtInfo.PtrCount - if SliceVtInfo.ArrayPtr: - ResultInfo.ArrayPtr.ArrayPtr = SliceVtInfo.ArrayPtr - elif SliceVtInfo and SliceVtInfo.PtrCount > 0: - ResultInfo.ArrayPtr = SliceVtInfo - else: - ResultInfo.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr.IsArrayPtr = True - elif isinstance(slice_node, ast.Subscript): - ResultInfo.ArrayPtr = CollectAll(slice_node) - elif isinstance(slice_node, ast.Name): - ResultInfo.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType - elif isinstance(slice_node, ast.BinOp): - ResultInfo.ArrayPtr = CTypeInfo() - try: - ResultInfo.ArrayPtr.ArrayDims.append(ast.unparse(slice_node)) - except Exception: # 回退:unparse 失败时用 'N' - ResultInfo.ArrayPtr.ArrayDims.append('N') - elif isinstance(slice_node, ast.Constant): - ResultInfo.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr.ArrayDims.append(str(slice_node.value)) - else: - ResultInfo.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr.IsArrayPtr = True - elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr: - ResultInfo = CTypeInfo() - ResultInfo.BaseType = t.CVoid - ResultInfo.PtrCount = 1 - if isinstance(slice_node, ast.Subscript): - inner_info = CollectAll(slice_node) - if inner_info and inner_info.PtrCount > 0: - ResultInfo.PtrCount += inner_info.PtrCount - if inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid): - ResultInfo.BaseType = inner_info.BaseType - elif inner_info and inner_info.ArrayPtr: - ResultInfo.ArrayPtr = inner_info - elif inner_info and inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid): - ResultInfo.BaseType = inner_info.BaseType - elif isinstance(slice_node, ast.Attribute): - SliceVtInfo = self.GetCTypeInfo(slice_node) - if SliceVtInfo and SliceVtInfo.PtrCount == 1 and not SliceVtInfo.ArrayPtr: - ResultInfo.PtrCount = 2 - if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): - ResultInfo.BaseType = SliceVtInfo.BaseType - elif SliceVtInfo and SliceVtInfo.IsArrayPtr: - inner = CTypeInfo() - inner.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr = inner - elif SliceVtInfo and SliceVtInfo.ArrayPtr: - ResultInfo.ArrayPtr = SliceVtInfo - elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): - ResultInfo.BaseType = SliceVtInfo.BaseType - elif isinstance(slice_node, ast.Name): - SliceType = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - ResultInfo.PtrCount += 1 - elif SliceType == t.CArrayPtr: - inner = CTypeInfo() - inner.ArrayPtr = CTypeInfo() - ResultInfo.ArrayPtr = inner - else: - ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType - elif isinstance(slice_node, ast.BinOp): - merged = self.MergeTypes(slice_node) - if merged: - ResultInfo.PtrCount += merged.PtrCount - if merged.BaseType and not isinstance(merged.BaseType, t.CVoid): - ResultInfo.BaseType = merged.BaseType - if merged.ArrayPtr: - ResultInfo.ArrayPtr = merged.ArrayPtr - elif isinstance(slice_node, ast.Constant): - ResultInfo.ArrayDims.append(str(slice_node.value)) - elif VtInfo: - ResultInfo = CTypeInfo() - ResultInfo.BaseType = VtInfo.BaseType - if isinstance(slice_node, ast.Constant): - ResultInfo.ArrayDims.append(str(slice_node.value)) - elif isinstance(slice_node, ast.Name): - ResultInfo.ArrayDims.append(slice_node.id) - elif isinstance(slice_node, ast.BinOp): - try: - ResultInfo.ArrayDims.append(ast.unparse(slice_node)) - except Exception: # 回退:unparse 失败时用 'N' - ResultInfo.ArrayDims.append('N') - elif isinstance(slice_node, ast.Subscript): - ResultInfo.ArrayPtr = CollectAll(slice_node) - else: - ResultInfo = CTypeInfo() - if isinstance(slice_node, ast.Constant): - ResultInfo.ArrayDims.append(str(slice_node.value)) - elif isinstance(slice_node, ast.Name): - SliceType = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - ResultInfo.PtrCount += 1 - elif SliceType == t.CArrayPtr: - ResultInfo.ArrayPtr = CTypeInfo() - else: - ResultInfo.ArrayDims.append(slice_node.id) - elif isinstance(value_node, ast.Subscript): - ResultInfo = CollectAll(value_node) - if isinstance(slice_node, ast.Attribute): - SliceVtInfo = self.GetCTypeInfo(slice_node) - if SliceVtInfo and SliceVtInfo.PtrCount >= 1 and not SliceVtInfo.ArrayPtr: - ResultInfo.PtrCount += SliceVtInfo.PtrCount - if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): - ResultInfo.BaseType = SliceVtInfo.BaseType - elif SliceVtInfo and SliceVtInfo.IsArrayPtr: - NewInfo = CTypeInfo() - NewInfo.ArrayPtr = ResultInfo - ResultInfo = NewInfo - elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): - ResultInfo.BaseType = SliceVtInfo.BaseType - elif isinstance(slice_node, ast.Subscript): - InnerNode = CollectAll(slice_node) - if ResultInfo.ArrayPtr is None: - ResultInfo.ArrayPtr = InnerNode - else: - current = ResultInfo - while current.ArrayPtr is not None: - current = current.ArrayPtr - current.ArrayPtr = InnerNode - elif isinstance(slice_node, ast.Constant): - ResultInfo.ArrayDims.append(str(slice_node.value)) - elif isinstance(slice_node, ast.Name): - SliceType = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - ResultInfo.PtrCount += 1 - elif SliceType == t.CArrayPtr: - ResultInfo.ArrayPtr = CTypeInfo() - else: - ResultInfo.ArrayDims.append(slice_node.id) - elif isinstance(slice_node, ast.BinOp): - try: - ResultInfo.ArrayDims.append(ast.unparse(slice_node)) - except Exception: # 回退:unparse 失败时用 'N' - ResultInfo.ArrayDims.append('N') - elif isinstance(value_node, ast.Name): - ResultInfo = CTypeInfo() - if IsListAnnotation(node): - if not isinstance(slice_node, ast.Tuple): - ElementType = self._GetCTypeInfoInternal(slice_node) - if ElementType and isinstance(ElementType, CTypeInfo): - ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid() - ResultInfo.PtrCount = ElementType.PtrCount + 1 - ResultInfo.IsFuncPtr = ElementType.IsFuncPtr - ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn - ResultInfo.FuncPtrParams = ElementType.FuncPtrParams - else: - ResultInfo.BaseType = t.CVoid() - ResultInfo.PtrCount = 1 - elif isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: - ElementType = self._GetCTypeInfoInternal(slice_node.elts[0]) - if ElementType and isinstance(ElementType, CTypeInfo): - ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid() - ResultInfo.PtrCount = ElementType.PtrCount - ResultInfo.IsFuncPtr = ElementType.IsFuncPtr - ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn - ResultInfo.FuncPtrParams = ElementType.FuncPtrParams - for elt in slice_node.elts[1:]: - if isinstance(elt, ast.Constant): - ResultInfo.ArrayDims.append(str(elt.value)) - elif isinstance(elt, ast.Name): - ResultInfo.ArrayDims.append(elt.id) - else: - try: - ResultInfo.ArrayDims.append(ast.unparse(elt)) - except Exception: # 回退:unparse 失败时用 'N' - ResultInfo.ArrayDims.append('N') - else: - ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType - else: - # 检查是否为泛型类特化(如 list[str]) - _is_generic_template: bool = ( - hasattr(self.Trans, 'ClassHandler') - and hasattr(self.Trans.ClassHandler, '_generic_class_templates') - and value_node.id in self.Trans.ClassHandler._generic_class_templates - ) - if _is_generic_template: - # 走和 _ResolveGenericSlice 同样的规范化路径(_resolve_generic_slice_type), - # 确保字段类型名与特化名完全一致: - # - ast.Name: 用原始名(如 'Param' → 'Param',不加 SHA1 前缀), - # 与 _resolve_generic_slice_type 的 ast.Name 分支一致 - # - BinOp/Attribute: 走 _resolve_type_arg_str(加 SHA1 前缀 / 'ptr' 标记) - # 避免字段类型用 'GSList[sha1.Param]' 而特化名用 'GSList[Param]' 导致 - # find_struct_by_pointee 匹配到 opaque 副本,方法分派失败 - type_arg_str: str - if isinstance(slice_node, ast.Tuple): - arg_parts: list[str] = [] - for elt in slice_node.elts: - slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(elt) - arg_parts.append(slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(elt)) - # 必须用 '][' 分隔以匹配 _mangle_generic_class_name 的格式 - # (class_name + '[' + ']['.join(mangled_args) + ']') - type_arg_str = ']['.join(arg_parts) - else: - slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node) - type_arg_str = slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(slice_node) - full_spec_name: str = f'{value_node.id}[{type_arg_str}]' - ResultInfo.BaseType = t.CStruct(name=full_spec_name) - ResultInfo.Name = full_spec_name - ResultInfo.IsStruct = True - ResultInfo.PtrCount = 1 - # 触发泛型特化发射:确保特化的方法被发射 + struct sha1 注册 - # 与局部变量 AnnAssign 路径一致;否则函数参数注解路径 - # 只构建 mangled 名,方法调用分派时 class_sha1=None 导致 - # "Undefined method" 错误(如 lst.__len__() 在 list[T] | t.CPtr 参数上) - # _specialize_generic_class 内部有 spec_key 去重,重复调用安全 - if hasattr(self.Trans, 'ExprCallHandle') and self.Trans.ExprCallHandle is not None: - self.Trans.ExprCallHandle._ResolveGenericSlice(node) - else: - ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType - if isinstance(slice_node, ast.Constant): - ResultInfo.ArrayDims.append(str(slice_node.value)) - elif isinstance(slice_node, ast.Name): - SliceType = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - ResultInfo.PtrCount += 1 - elif SliceType == t.CArrayPtr: - ResultInfo.ArrayPtr = CTypeInfo() - else: - ResultInfo.ArrayDims.append(slice_node.id) - elif isinstance(slice_node, ast.BinOp): - try: - ResultInfo.ArrayDims.append(ast.unparse(slice_node)) - except Exception: # 回退:unparse 失败时用 'N' - ResultInfo.ArrayDims.append('N') - elif isinstance(slice_node, ast.Subscript): - InnerNode = CollectAll(slice_node) - ResultInfo.ArrayDims.extend(InnerNode.ArrayDims) - else: - ResultInfo = CTypeInfo() - - return ResultInfo - elif isinstance(node, ast.Attribute): - VtInfo = self.GetCTypeInfo(node) - result = CTypeInfo() - if VtInfo and VtInfo.IsArrayPtr: - result.ArrayPtr = CTypeInfo() - return result - elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr: - result.BaseType = t.CVoid - result.PtrCount = 1 - return result - elif VtInfo and VtInfo.BaseType: - result.BaseType = VtInfo.BaseType - return result - else: - return CTypeInfo() - elif isinstance(node, ast.Name): - result = CTypeInfo() - result.BaseType = CTypeInfo.CreateFromTypeName(node.id).BaseType - return result - else: - return CTypeInfo() - - return CollectAll(Node) - - def _CollectAllOperandTypes(self, Node: ast.AST) -> List: - """递归收集所有操作数的类型(用于一次性合并)""" - Types = [] - - if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): - Types.extend(self._CollectAllOperandTypes(Node.left)) - Types.extend(self._CollectAllOperandTypes(Node.right)) - else: - Types.append(Node) - - return Types - - def _GetTypeFromNode(self, Node: ast.AST) -> CTypeInfo: - """浠?AST 鑺傜偣鑾峰彇绫诲瀷""" - if isinstance(Node, ast.Call): - if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': - return self.GetCTypeInfo(Node) - elif isinstance(Node.func, ast.Attribute) and CTypeHelper.GetTModuleCType(Node.func.attr) == t._CTypedef: - return self.GetCTypeInfo(Node) - elif isinstance(Node.func, ast.Attribute) and Node.func.attr == 'Bit': - if Node.args and isinstance(Node.args[0], ast.Constant): - Result = CTypeInfo() - Result.BaseType = t.CInt - Result.IsBitField = True - Result.BitWidth = Node.args[0].value - return Result - return self._MakeVoidCTypeInfo() - elif isinstance(Node, ast.Subscript): - if (isinstance(Node.value, ast.Attribute) - and isinstance(Node.value.value, ast.Name) - and IsTModule(Node.value.value.id, self.Trans.SymbolTable) - and Node.value.attr == 'Bit'): - if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): - Result = CTypeInfo() - Result.BaseType = t.CInt - Result.IsBitField = True - Result.BitWidth = Node.slice.value - return Result - return self.GetCTypeInfo(Node) - else: - return self.GetCTypeInfo(Node) - - def MergeTypes(self, Node: ast.BinOp): - """处理类型组合,如 t.CInt | t.CPtr ?t.CStatic | t.CInt - - 这是 | 运算符的类型合并处理函数 - 收集所有操作数,一次性合? - """ - if not isinstance(Node, ast.BinOp) or not isinstance(Node.op, ast.BitOr): - return None - - AllOperands = self._CollectAllOperandTypes(Node) - - AllTypes = [] - for Operand in AllOperands: - TypeItem = self._GetTypeFromNode(Operand) - AllTypes.append(TypeItem) - - if isinstance(Node.left, ast.Attribute): - LeftParts = [] - current = Node.left - while isinstance(current, ast.Attribute): - attr_type = getattr(t, current.attr, None) - if attr_type and isinstance(attr_type, type) and issubclass(attr_type, t.CType): - LeftParts.insert(0, attr_type) - current = current.value - if isinstance(current, ast.Name): - name_type = getattr(t, current.id, None) - if name_type and isinstance(name_type, type) and issubclass(name_type, t.CType): - LeftParts.insert(0, name_type) - if LeftParts and LeftParts[-1] == t._CTypedef: - for type_item in AllTypes: - if isinstance(type_item, CTypeInfo) and type_item.IsFuncPtr: - type_item.IsTypedef = True - type_item.OriginalType = CTypeInfo() - type_item.OriginalType.IsFuncPtr = True - type_item.OriginalType.FuncPtrReturn = type_item.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - type_item.OriginalType.FuncPtrParams = list(type_item.FuncPtrParams) if type_item.FuncPtrParams else [] - return type_item - Result = CTypeInfo() - if isinstance(AllTypes[-1], CTypeInfo): - Result.BaseType = AllTypes[-1].BaseType - else: - Result.BaseType = t.CInt - Result.IsTypedef = True - return Result - - return self._MergeAllComponentTypes(*AllTypes) - - def _MergeAllComponentTypes(self, *Types: CTypeInfo) -> CTypeInfo: - """合并多个类型 - 直接使用 CTypeInfo 类""" - if not Types: - return CTypeInfo() - - Result = CTypeInfo() - # 统计 t.CPtr(CVoid + PtrCount=1)的个数,用于正确累加指针层数 - # 因为 (AST | t.CPtr) | t.CPtr 展开后会包含多个 t.CPtr,每个都需要累加 - cptr_count: int = 0 - - for TypeItem in Types: - if TypeItem is None: - continue - if TypeItem.IsState: - Result.IsState = True - if not Result.Storage: - Result.Storage = t.CExport() - continue - if TypeItem.IsBitField: - Result.BaseType = t.CInt - Result.IsBitField = True - Result.BitWidth = TypeItem.BitWidth - return Result - if TypeItem.IsFuncPtr: - Result.BaseType = t.CVoid - Result.IsFuncPtr = True - Result.FuncPtrParams = TypeItem.FuncPtrParams - Result.FuncPtrReturn = TypeItem.FuncPtrReturn - return Result - if TypeItem.IsTypedef: - if TypeItem.BaseType and (not isinstance(TypeItem.BaseType, (t._CTypedef,)) or TypeItem.PtrCount > 0): - if Result.BaseType is None or isinstance(Result.BaseType, (t.CVoid, t._CTypedef)): - Result.BaseType = TypeItem.BaseType - Result.Name = TypeItem.Name - Result.IsTypedef = True - Result.PtrCount = max(Result.PtrCount, TypeItem.PtrCount) - if TypeItem.OriginalType: - Result.OriginalType = TypeItem.OriginalType - else: - Result.IsTypedef = True - Result.Name = TypeItem.Name - if TypeItem.OriginalType: - Result.OriginalType = TypeItem.OriginalType - continue - # 统计 t.CPtr(CVoid + PtrCount>0) - # 注意: t.CPtr[t.CPtr] 的 PtrCount=2(双重指针),需要完整累加 - if TypeItem.PtrCount > 0 and TypeItem.BaseType and (TypeItem.BaseType is t.CVoid or isinstance(TypeItem.BaseType, t.CVoid)): - cptr_count += TypeItem.PtrCount - # BaseType 保持不变,只计数,后续统一累加 - if TypeItem.IsRenum and TypeItem.Name: - Result.IsRenum = True - Result.IsEnum = True - Result.IsStruct = True - if not Result.Name: - Result.Name = TypeItem.Name - continue - self._MergeCTypeInfoInto(Result, TypeItem) - - # 对所有 t.CPtr 统一累加指针层数 - # 仅对 struct 类型吸收第一个 CPtr(struct 变量默认是指针,AST | t.CPtr = AST*)。 - # 对于本身已是指针的类型(如 bytes=CChar*),bytes | t.CPtr = i8**(不吸收)。 - base_ptr_count: int = Result.PtrCount - Result.PtrCount += cptr_count - if Result.IsStruct and base_ptr_count > 0 and cptr_count > 0: - Result.PtrCount -= 1 - - if Result.BaseType is None: - Result.BaseType = t.CVoid - - return Result - - def _MergeCTypeInfoInto(self, Target: CTypeInfo, Source: CTypeInfo): - if Source.PtrCount > 0 and Source.BaseType and (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)): - # t.CPtr 的处理已提升到 _MergeAllComponentTypes 中统一计数累加, - # 此处保留仅作为兜底(从其他路径直接调用 _MergeCTypeInfoInto 时) - if Target.PtrCount < Source.PtrCount: - Target.PtrCount = Source.PtrCount - elif Source.PtrCount > 0 and Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, t.CVoid): - if Target.BaseType is None or Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid): - Target.BaseType = Source.BaseType - # 当 Target 已有 PtrCount(来自之前的 t.CPtr),累加而非替换 - Target.PtrCount = Source.PtrCount + Target.PtrCount - elif Target.PtrCount == 0: - Target.PtrCount = Source.PtrCount - elif Source.PtrCount > Target.PtrCount: - Target.PtrCount = Source.PtrCount - elif Source.PtrCount > Target.PtrCount: - Target.PtrCount = Source.PtrCount - if Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, (t.CVoid, t._CTypedef)): - if Target.BaseType is None: - Target.BaseType = Source.BaseType - elif (Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid)) and Target.PtrCount == 0: - Target.BaseType = Source.BaseType - elif (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)) and Target.BaseType is None: - Target.BaseType = Source.BaseType - # Struct 名称保留:BinOp `list[AST | t.CPtr] | t.CPtr` 合并时, - # _HandleSubscript 已在 Source.Name 设置了特化名(如 'list[5dab8cb390496d22.ASTptr]'), - # 合并后 Target.Name 必须保留此名称,否则 class_member_element_class - # 无法获取正确的特化类名 → 方法分派 fallback 到错误的类 - if Source.IsStruct and Source.Name and not Target.Name: - Target.Name = Source.Name - # REnum 标志和名称保留(BinOp `LLVMType | t.CPtr` 合并时不能丢失 REnum 语义) - # 同时传播 IsStruct=True,让 CPtr 吸收逻辑生效(REnum 在内存布局上是 struct) - if Source.IsRenum and Source.Name: - Target.IsRenum = True - Target.IsEnum = True - Target.IsStruct = True - if not Target.Name: - Target.Name = Source.Name - if Source.IsTypedef and Source.Name: - if Source.BaseType and (not isinstance(Source.BaseType, (t._CTypedef,)) or Source.PtrCount > 0): - if Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)): - Target.BaseType = Source.BaseType - Target.IsTypedef = True - Target.Name = Source.Name - if Source.OriginalType: - Target.OriginalType = Source.OriginalType - elif Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)): - if Source.OriginalType: - if isinstance(Source.OriginalType, CTypeInfo) and Source.OriginalType.BaseType: - Target.BaseType = Source.OriginalType.BaseType - Target.PtrCount = max(Target.PtrCount, Source.OriginalType.PtrCount) - Target.IsTypedef = True - Target.Name = Source.Name - Target.OriginalType = Source.OriginalType - elif isinstance(Source.OriginalType, CTypeInfo): - Target.IsTypedef = True - Target.Name = Source.Name - Target.OriginalType = Source.OriginalType - else: - Target.BaseType = t.CStruct(name=Source.Name) - Target.IsStruct = True - else: - Target.BaseType = t.CStruct(name=Source.Name) - Target.IsStruct = True - if Source.ArrayPtr: - if Target.ArrayPtr is None: - Target.ArrayPtr = Source.ArrayPtr - else: - if Source.PtrCount > Target.PtrCount: - Target.PtrCount = Source.PtrCount - Target.ArrayPtr = Source.ArrayPtr - if Source.PtrCount > 0: - Target.ArrayDims = [] - elif Source.ArrayDims: - Target.ArrayDims.extend(Source.ArrayDims) - if Source.VarConst: - Target.VarConst = True - if Source.VarVolatile: - Target.VarVolatile = True - if Source.DataConst: - Target.DataConst = True - if Source.DataVolatile: - Target.DataVolatile = True - if Source.IsFuncPtr: - Target.IsFuncPtr = True - Target.FuncPtrParams = Source.FuncPtrParams - Target.FuncPtrReturn = Source.FuncPtrReturn - if Source.Storage and not Target.Storage: - Target.Storage = Source.Storage - if Source.ByteOrder and not Target.ByteOrder: - Target.ByteOrder = Source.ByteOrder diff --git a/App/lib/core/Handles/HandlesWith.py b/App/lib/core/Handles/HandlesWith.py deleted file mode 100644 index 6f5d06d..0000000 --- a/App/lib/core/Handles/HandlesWith.py +++ /dev/null @@ -1,206 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class WithHandle(BaseHandle): - def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]: - """沿继承链查找方法,返回 (定义方法的类名, 函数对象) - - 当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。 - _generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装, - 不包括父类独有方法,因此 with 语句需要单独处理继承查找。 - """ - # 先检查子类自身 - FullName: str = f'{ClassName}.{MethodName}' - func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName) - if func: - return (ClassName, func) - # 沿继承链查找 - p: str | None = Gen.class_parent.get(ClassName) if hasattr(Gen, 'class_parent') else None - while p: - parent_full: str = f'{p}.{MethodName}' - parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full) - if parent_func: - return (p, parent_func) - p = Gen.class_parent.get(p) - return (None, None) - - def _HandleWithLlvm(self, Node: ast.With) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for item in Node.items: - context_expr: ast.expr = item.context_expr - asname: str | None = None - target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) - if target and isinstance(target, ast.Name): - asname = target.id - ClassName: str | None = None - if isinstance(context_expr, ast.Call): - if isinstance(context_expr.func, ast.Name): - ClassName = context_expr.func.id - elif isinstance(context_expr.func, ast.Attribute): - ClassName = context_expr.func.attr - if ClassName and ClassName not in Gen.structs: - SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName) - if SymInfo: - if SymInfo.IsStruct or SymInfo.IsRenum: - pass - else: - ClassName = None - else: - ClassName = None - elif isinstance(context_expr, ast.Name): - VarName: str = context_expr.id - if VarName in Gen.var_struct_class: - ClassName = Gen.var_struct_class[VarName] - ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr) - if not ctx_val: - continue - original_ctx_val: ir.Value = ctx_val - if ClassName and isinstance(ctx_val.type, ir.PointerType): - pointee: ir.Type = ctx_val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - ClassName = CN - StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None - if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): - ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") - ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx") - Gen._store(ctx_val, ctx_alloca) - Gen._UnregisterTempPtr(ctx_val) - if ClassName: - Gen.var_struct_class['__with_ctx'] = ClassName - Gen._var_to_heap_ptr['__with_ctx'] = ctx_val - original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None - ctx_is_var_ref: bool = isinstance(context_expr, ast.Name) - enter_result: ir.Value | None = None - if ClassName: - # 沿继承链查找 __enter__(子类可能未覆写,使用父类实现) - enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen) - if enter_func is not None: - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - # 父类方法需要 self 为父类指针类型,bitcast 子类指针 - if enter_class != ClassName and enter_class in Gen.structs: - parent_ptr_type = ir.PointerType(Gen.structs[enter_class]) - if ctx_Loaded.type != parent_ptr_type: - ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self") - enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter") - enter_result = enter_call - if isinstance(enter_call.type, ir.PointerType): - pointee: ir.Type = enter_call.type.pointee - if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - enter_result = Gen._load(enter_call, name="enter_deref") - elif self._is_char_pointer(enter_call) and StructPtrType: - enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") - if asname and enter_result: - if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - Gen.var_struct_class[asname] = CN - Gen._var_to_heap_ptr[asname] = enter_result - Gen._register_local_heap_ptr(enter_result, VarName=asname) - if asname in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[asname] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname) - Gen._store(OldVal, var) - Gen.variables[asname] = var - del Gen._reg_values[asname] - if asname in Gen.variables and Gen.variables[asname] is not None: - VarPtr: ir.Value = Gen.variables[asname] - if VarPtr.type.pointee == enter_result.type: - Gen._store(enter_result, VarPtr) - elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") - Gen._store(CastedVal, VarPtr) - else: - NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname) - Gen._store(enter_result, NewVar) - Gen.variables[asname] = NewVar - else: - Gen._reg_values[asname] = enter_result - Gen.variables[asname] = None - # 如果类有 __provides__,自动生成 push 代码 - if ClassName and ClassName in Gen.class_provides: - # 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32) - # _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈 - current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack) - new_fields: int = len(Gen.class_provides[ClassName]) - if current_depth + new_fields > 32: - raise SyntaxError( - f"[TransPyC] with provider stack overflow at line {Node.lineno}: " - f"current depth {current_depth} + new {new_fields} fields > max 32. " - f"Class '{ClassName}' provides too many fields or with nesting too deep." - ) - # 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查 - Gen._with_provides_stack.append(Gen.class_provides[ClassName]) - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - ctx_i8: ir.Value = ctx_Loaded - if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)): - ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8") - for field_name in Gen.class_provides[ClassName]: - field_str: ir.Value = Gen._create_string_global(field_name) - push_func = Gen.functions.get('_push_provider') - if push_func: - Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider") - self.Trans.VarScopes.append({}) - if asname: - self.Trans.VarScopes[-1][asname] = True - self.HandleBodyLlvm(Node.body) - if self.Trans.VarScopes: - self.Trans.VarScopes.pop() - # 如果类有 __provides__,自动生成 pop 代码 - if ClassName and ClassName in Gen.class_provides: - for _ in Gen.class_provides[ClassName]: - pop_func = Gen.functions.get('_pop_provider') - if pop_func: - Gen.builder.call(pop_func, [], name="call_pop_provider") - # 编译期弹栈 - if Gen._with_provides_stack: - Gen._with_provides_stack.pop() - if ClassName: - # 沿继承链查找 __exit__(子类可能未覆写,使用父类实现) - exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen) - if exit_func is not None: - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - # 父类方法需要 self 为父类指针类型,bitcast 子类指针 - if exit_class != ClassName and exit_class in Gen.structs: - parent_ptr_type = ir.PointerType(Gen.structs[exit_class]) - if ctx_Loaded.type != parent_ptr_type: - ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self") - Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit") - Gen._unregister_local_heap_ptr(original_ctx_val) - if ctx_val is not original_ctx_val: - Gen._unregister_local_heap_ptr(ctx_val) - if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: - Gen._unregister_local_heap_ptr(original_asname_heap_ptr) - if '__with_ctx' in Gen._var_to_heap_ptr: - del Gen._var_to_heap_ptr['__with_ctx'] - if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") - enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") - same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") - with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx") - with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free") - Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) - Gen.builder.position_at_start(with_free_bb) - raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) - Gen.builder.branch(with_skip_bb) - Gen.builder.position_at_start(with_skip_bb) - Gen._unregister_local_heap_ptr(enter_result) - Gen._unregister_local_heap_ptr(original_ctx_val) - elif isinstance(ctx_val.type, ir.PointerType): - raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) - Gen._unregister_local_heap_ptr(original_ctx_val) \ No newline at end of file diff --git a/App/lib/core/LLVMCG/BaseGen.py b/App/lib/core/LLVMCG/BaseGen.py deleted file mode 100644 index cd0b890..0000000 --- a/App/lib/core/LLVMCG/BaseGen.py +++ /dev/null @@ -1,669 +0,0 @@ -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 = {} - 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) - 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) - 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 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(非整数) - - 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 _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 \ No newline at end of file diff --git a/App/lib/core/LLVMCG/ExprGen.py b/App/lib/core/LLVMCG/ExprGen.py deleted file mode 100644 index e8eb6a1..0000000 --- a/App/lib/core/LLVMCG/ExprGen.py +++ /dev/null @@ -1,368 +0,0 @@ -from __future__ import annotations -from typing import Any -import logging -import llvmlite.ir as ir -from lib.constants.config import mode as _config_mode - - -class ExprGenMixin: - def emit_constant(self, value: Any, type_name: str = 'int') -> ir.Value: - if type_name == 'int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'uint64_t' or type_name == 'unsigned long long': - return ir.Constant(ir.IntType(64), int(value)) - elif type_name == 'uint32_t' or type_name == 'unsigned int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'uint16_t' or type_name == 'unsigned short': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'uint8_t' or type_name == 'unsigned char': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'int64_t' or type_name == 'long long': - return ir.Constant(ir.IntType(64), int(value)) - elif type_name == 'int32_t' or type_name == 'int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'int16_t' or type_name == 'short': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'int8_t' or type_name == 'char': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'float' or type_name == 'float32_t' or type_name == 'FLOAT32': - return ir.Constant(ir.FloatType(), float(value)) - elif type_name == 'double' or type_name == 'float64_t' or type_name == 'FLOAT64': - return ir.Constant(ir.DoubleType(), float(value)) - elif type_name == 'float16_t' or type_name == 'FLOAT16': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'float8_t' or type_name == 'FLOAT8': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'float128_t' or type_name == 'FLOAT128': - return ir.Constant(ir.IntType(128), int(value)) - elif type_name == 'string': - encoded: bytes = value.encode('utf-8') + b'\x00' - str_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(encoded)) - str_const: ir.Constant = ir.Constant(str_type, bytearray(encoded)) - global_var: ir.GlobalVariable = ir.GlobalVariable(self.module, str_type, name=f"str_const_{self.string_const_counter}") - self.string_const_counter += 1 - global_var.initializer = str_const - global_var.linkage = 'internal' - return self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)), name="str") - return ir.Constant(ir.IntType(32), int(value)) - - def emit_binary_op(self, op: str, left: ir.Value, right: ir.Value, is_unsigned: bool = False) -> ir.Value: - if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType): - # 数组指针需要先 decay 为元素指针,否则 GEP 会以整个数组为步长 - # 例如 [64 x i8]* + 1 会前进 64 字节而非 1 字节 - if isinstance(left.type.pointee, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - left = self.builder.gep(left, [zero, zero], name="array_decay") - right = self.builder.zext(right, ir.IntType(64), name="int2ptrint") - if op == '+' or op == 'Add': - return self.builder.gep(left, [right], name="ptr_add") - elif op == '-' or op == 'Sub': - return self.builder.gep(left, [self.builder.neg(right, name="neg")], name="ptr_sub") - if isinstance(left.type, ir.IntType) and isinstance(right.type, ir.PointerType): - if isinstance(right.type.pointee, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - right = self.builder.gep(right, [zero, zero], name="array_decay_rev") - left = self.builder.zext(left, ir.IntType(64), name="int2ptrint2") - if op == '+' or op == 'Add': - return self.builder.gep(right, [left], name="ptr_add_rev") - is_float: bool = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \ - isinstance(right.type, (ir.FloatType, ir.DoubleType)) - if is_float: - ftype: ir.Type - if isinstance(left.type, (ir.FloatType, ir.DoubleType)): - ftype = left.type - elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): - ftype = right.type - else: - ftype = ir.DoubleType() - if not isinstance(left.type, (ir.FloatType, ir.DoubleType)): - left = self._to_float(left, ftype) - elif left.type != ftype: - if isinstance(left.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - left = self.builder.fpext(left, ftype, name="fpext_l") - else: - left = self.builder.fptrunc(left, ftype, name="fptrunc_l") - if not isinstance(right.type, (ir.FloatType, ir.DoubleType)): - right = self._to_float(right, ftype) - elif right.type != ftype: - if isinstance(right.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - right = self.builder.fpext(right, ftype, name="fpext_r") - else: - right = self.builder.fptrunc(right, ftype, name="fptrunc_r") - float_ops: dict[str, Any] = { - '+': self.builder.fadd, 'Add': self.builder.fadd, - '-': self.builder.fsub, 'Sub': self.builder.fsub, - '*': self.builder.fmul, 'Mult': self.builder.fmul, - '/': self.builder.fdiv, 'Div': self.builder.fdiv, - '%': self.builder.frem, 'Mod': self.builder.frem, - } - float_cmp_ops: dict[str, str] = { - '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', - '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', - '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', - } - if op in float_ops: - return float_ops[op](left, right, name=op) - if op in float_cmp_ops: - return self.builder.fcmp_ordered(float_cmp_ops[op], left, right, name=op) - ops: dict[str, Any] - if is_unsigned: - ops = { - '+': self.builder.add, 'Add': self.builder.add, - '-': self.builder.sub, 'Sub': self.builder.sub, - '*': self.builder.mul, 'Mult': self.builder.mul, - '/': self.builder.udiv, 'Div': self.builder.udiv, - '%': self.builder.urem, 'Mod': self.builder.urem, - '//': self.builder.udiv, 'FloorDiv': self.builder.udiv, - } - else: - ops = { - '+': self.builder.add, 'Add': self.builder.add, - '-': self.builder.sub, 'Sub': self.builder.sub, - '*': self.builder.mul, 'Mult': self.builder.mul, - '/': self.builder.sdiv, 'Div': self.builder.sdiv, - '%': self.builder.srem, 'Mod': self.builder.srem, - '//': self.builder.sdiv, 'FloorDiv': self.builder.sdiv, - } - cmp_ops: dict[str, str] = { - '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', - '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', - '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', - } - logic_ops: dict[str, Any] = { - '&&': self.builder.and_, 'And': self.builder.and_, - '||': self.builder.or_, 'Or': self.builder.or_, - } - if op in ('>>', 'RShift') and not is_unsigned: - if isinstance(left.type, ir.IntType): - if left.type.width == 8: - is_unsigned = True - elif left.type.width == 16: - is_unsigned = True - elif left.type.width == 32: - if self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) - elif left.type.width == 64: - if self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) - shift_ops: dict[str, Any] = { - '>>': self.builder.lshr if is_unsigned else self.builder.ashr, - 'RShift': self.builder.lshr if is_unsigned else self.builder.ashr, - '<<': self.builder.shl, 'LShift': self.builder.shl, - } - bit_ops: dict[str, Any] = { - '&': self.builder.and_, - '|': self.builder.or_, - '^': self.builder.xor, - } - if op == '**' or op == 'Pow': - if isinstance(left, ir.Constant) and isinstance(right, ir.Constant): - try: - lv: Any = left.constant - rv: Any = right.constant - if isinstance(lv, int) and isinstance(rv, int) and rv >= 0: - result: int = lv ** rv - return ir.Constant(left.type, result) - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - pass - ftype: ir.Type - if isinstance(left.type, (ir.FloatType, ir.DoubleType)): - ftype = left.type - elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): - ftype = right.type - else: - ftype = ir.DoubleType() - lf: ir.Value = self._to_float(left, ftype) - rf: ir.Value = self._to_float(right, ftype) - powf: ir.Function | None = self.module.globals.get('llvm.pow.f64') - if not powf: - fnty: ir.FunctionType = ir.FunctionType(ir.DoubleType(), [ir.DoubleType(), ir.DoubleType()]) - powf = ir.Function(self.module, fnty, name='llvm.pow.f64') - if lf.type != ir.DoubleType(): - lf = self.builder.fpext(lf, ir.DoubleType(), name="ext_f64") - if rf.type != ir.DoubleType(): - rf = self.builder.fpext(rf, ir.DoubleType(), name="ext_f64") - result: ir.Value = self.builder.call(powf, [lf, rf], name="pow") - both_int: bool = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType) - right_is_pos_int_const: bool = isinstance(right, ir.Constant) and isinstance(right.constant, int) and right.constant >= 0 - if both_int and right_is_pos_int_const: - return self.builder.fptosi(result, left.type, name="pow2int") - if isinstance(left.type, ir.FloatType): - return self.builder.fptrunc(result, ir.FloatType(), name="pow2f32") - return result - if op in ops: - try: - return ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in shift_ops: - try: - return shift_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in bit_ops: - try: - return bit_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in cmp_ops: - try: - if is_unsigned: - return self.builder.icmp_unsigned(cmp_ops[op], left, right, name=op) - return self.builder.icmp_signed(cmp_ops[op], left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in logic_ops: - try: - return logic_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - return left - - def _to_float(self, val: ir.Value, ftype: ir.Type | None = None) -> ir.Value: - if ftype is None: - ftype = ir.DoubleType() - if isinstance(val.type, (ir.FloatType, ir.DoubleType)): - if val.type == ftype: - return val - if isinstance(val.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - return self.builder.fpext(val, ftype, name="fpext") - return self.builder.fptrunc(val, ftype, name="fptrunc") - if isinstance(val.type, ir.IntType): - if val.type.width == 1: - val = self.builder.zext(val, ir.IntType(32), name="bool2i32") - return self.builder.sitofp(val, ftype, name="int2float") - return val - - def emit_return(self, value: ir.Value | None = None) -> None: - if not self.builder or self.builder.block.is_terminated: - return - if value is not None: - self._unregister_local_heap_ptr(value) - self._emit_local_heap_frees() - if self._variadic_info and self._variadic_info.get('va_start_called'): - va_list_ptr: ir.Value = self._variadic_info['va_list_ptr'] - self.emit_va_end(va_list_ptr) - if value is None: - if self.func and hasattr(self.func, 'ftype'): - ret_type: ir.Type = self.func.ftype.return_type - if isinstance(ret_type, ir.IntType): - self.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, ir.PointerType): - self.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - self.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - self.builder.ret(zero_val) - elif isinstance(ret_type, ir.ArrayType): - self.builder.ret(ir.Constant(ret_type, None)) - else: - self.builder.ret_void() - else: - self.builder.ret_void() - else: - if self.func and hasattr(self.func, 'ftype'): - ret_type: ir.Type = self.func.ftype.return_type - if ret_type != value.type: - if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType): - value = self.builder.bitcast(value, ret_type, name="ret_cast") - elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): - if isinstance(value.type.pointee, ir.IntType) and isinstance(ret_type, ir.IntType) and value.type.pointee.width == ret_type.width: - value = self._load(value, name="ret_Load") - elif isinstance(ret_type, ir.IntType): - value = self.builder.ptrtoint(value, ret_type, name="ret_ptrtoint") - elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType): - value = self._load(value, name="ret_Load") - elif isinstance(value.type.pointee, ir.PointerType): - Loaded: ir.Value = self._load(value, name="ret_deref") - if Loaded.type == ret_type: - value = Loaded - elif isinstance(ret_type, ir.IntType): - value = self.builder.ptrtoint(Loaded, ret_type, name="ret_ptrtoint") - elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType): - if value.type.width < ret_type.width: - if value.type.width == 1: - # i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext - value = self.builder.zext(value, ret_type, name="ret_zext_bool") - else: - is_unsigned: bool = id(value) in self._unsigned_results - if is_unsigned: - value = self.builder.zext(value, ret_type, name="ret_zext") - else: - value = self.builder.sext(value, ret_type, name="ret_sext") - elif value.type.width > ret_type.width: - value = self.builder.trunc(value, ret_type, name="ret_trunc") - elif isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.IntType): - value = self.builder.inttoptr(value, ret_type, name="ret_inttoptr") - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, ir.IntType): - value = self.builder.sitofp(value, ret_type, name="ret_int2float") - elif isinstance(ret_type, ir.IntType) and isinstance(value.type, (ir.FloatType, ir.DoubleType)): - value = self.builder.fptosi(value, ret_type, name="ret_float2int") - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)): - if ret_type != value.type: - if isinstance(value.type, ir.FloatType) and isinstance(ret_type, ir.DoubleType): - value = self.builder.fpext(value, ret_type, name="ret_fpext") - elif isinstance(value.type, ir.DoubleType) and isinstance(ret_type, ir.FloatType): - value = self.builder.fptrunc(value, ret_type, name="ret_fptrunc") - self.builder.ret(value) - - def _emit_printf(self, args: list[ir.Value], unsigned_flags: list[bool] | None = None, sep: str = " ", end: str = "\n") -> ir.Value | None: - if not args: - return None - if unsigned_flags is None: - unsigned_flags = [] - format_str: str = "" - cast_args: list[ir.Value] = [] - for i, arg in enumerate(args): - is_u: bool = i < len(unsigned_flags) and unsigned_flags[i] - if isinstance(arg.type, ir.IntType): - if arg.type.width == 1: - # i1 是布尔值(来自 icmp/fcmp/__contains__),zext 到 i32 后用 %d - format_str += "%d" - ext: ir.Value = self.builder.zext(arg, ir.IntType(32), name="bool2int") - cast_args.append(ext) - elif arg.type.width == 8: - format_str += "%c" - ext: ir.Value = self.builder.zext(arg, ir.IntType(32), name="char2int") - cast_args.append(ext) - elif arg.type.width == 64: - format_str += "%llu" if is_u else "%lld" - cast_args.append(arg) - else: - format_str += "%u" if is_u else "%d" - cast_args.append(arg) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(arg) - elif isinstance(arg.type, ir.PointerType): - if isinstance(arg.type.pointee, ir.IntType) and arg.type.pointee.width == 8: - format_str += "%s" - cast_args.append(arg) - else: - format_str += "%d" - int_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int") - trunc_val: ir.Value = self.builder.trunc(int_val, ir.IntType(32), name="trunc") - cast_args.append(trunc_val) - else: - format_str += "%d" - cast_args.append(arg) - if sep is not None and i < len(args) - 1: - format_str += sep - if end is not None: - format_str += end - string_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(format_str.encode('utf-8')) + 1) - string_const: ir.Constant = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8')) - global_var: ir.GlobalVariable = ir.GlobalVariable(self.module, string_type, name=f"str_const_{self.string_const_counter}") - self.string_const_counter += 1 - global_var.initializer = string_const - global_var.linkage = 'internal' - format_ptr: ir.Value = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) - call_args: list[ir.Value] = [format_ptr] + cast_args - printf_func: ir.Function | None = self.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - return self.builder.call(printf_func, call_args, name="call_printf") \ No newline at end of file diff --git a/App/lib/core/LLVMCG/FuncGen.py b/App/lib/core/LLVMCG/FuncGen.py deleted file mode 100644 index dc743c6..0000000 --- a/App/lib/core/LLVMCG/FuncGen.py +++ /dev/null @@ -1,524 +0,0 @@ -from __future__ import annotations -from typing import Any -import ast -import os -import re -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode - - -class FuncGenMixin: - - def setup_from_symbol_table(self, SymbolTable: Any) -> None: - self.SymbolTable: Any = SymbolTable - for name, info in SymbolTable.items(): - if isinstance(info, CTypeInfo): - # CTypeInfo 对象:struct/union 由 StructGen 处理,此处只处理 dict 格式 - continue - if not isinstance(info, dict): - if hasattr(info, 'get'): - info = dict(info) if hasattr(info, '__iter__') else {} - else: - continue - TypeKind: str = info.get('type', '') - if TypeKind == 'struct': - ClassName: str = name - self.class_methods[ClassName] = [] - self.class_members[ClassName] = [] - members: dict[str, Any] = info.get('members', {}) - if members: - for MemberName, MemberInfo in members.items(): - if isinstance(MemberInfo, dict): - MemberType: ir.Type = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) - self.class_members[ClassName].append((MemberName, MemberType)) - elif isinstance(MemberInfo, CTypeInfo): - MemberType: ir.Type = self._ctype_to_llvm(MemberInfo) - if MemberType is None: - MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) - self.class_members[ClassName].append((MemberName, MemberType)) - self._generate_structs() - self._create_Vtable_globals() - - def register_method(self, ClassName: str, MethodName: str) -> None: - if ClassName not in self.class_methods: - self.class_methods[ClassName] = [] - if ClassName not in self.class_members: - self.class_members[ClassName] = [] - self._generate_structs() - self._create_Vtable_globals() - # 构造函数(__new__/__init__/__before_init__)不放入 vtable, - # 避免子类与基类 vtable 大小不一致导致虚分派索引偏移 - _short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName - if _short_name in ('__new__', '__init__', '__before_init__'): - return - if MethodName not in self.class_methods[ClassName]: - self.class_methods[ClassName].append(MethodName) - - def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]: - """对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。 - - 在调用前对标记为 auto-addr 的参数自动取地址: - - 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer) - - 'always' (t.CAutoPtr): 无条件取地址 - """ - modes: list[str | None] | None = self._auto_addr_params.get(func_name) - if not modes: - return args - new_args: list[ir.Value] = list(args) - for i, mode in enumerate(modes): - if i >= len(new_args) or mode is None: - continue - arg: ir.Value = new_args[i] - is_ptr: bool = isinstance(arg.type, ir.PointerType) - if mode == 'always' or (mode == 'need' and not is_ptr): - # alloca + store + get pointer - slot: ir.Value = self.builder.alloca(arg.type) - self.builder.store(arg, slot) - new_args[i] = slot - return new_args - - def _adjust_args(self, args: list[ir.Value], func: ir.Function) -> list[ir.Value]: - adjusted: list[ir.Value] = [] - for i, (arg, param) in enumerate(zip(args, func.args)): - if arg.type != param.type: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - # C 语言中数组参数退化为指针,不做 load 而是退化为元素指针 - if isinstance(param.type, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - adjusted.append(elem_ptr) - else: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - continue - try: - if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: - # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 - # 为字符值分配内存,创建 null-terminated 字符串 - tmp: ir.AllocaInstr = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - char_ptr: ir.Value = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") - self._store(arg, char_ptr) - null_ptr: ir.Value = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") - self._store(ir.Constant(ir.IntType(8), 0), null_ptr) - adjusted.append(char_ptr) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - else: - if arg.type.width < 32: - arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): - if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): - Loaded: ir.Value = self._load(arg, name=f"Load_arg_{i}") - adjusted.append(Loaded) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") - Loaded: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - Loaded_val: ir.Value = self._load(Loaded, name=f"Load_arg_{i}") - self._store(Loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) - else: - tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") - cast_ptr: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - Loaded_val: ir.Value = self._load(cast_ptr, name=f"Load_arg_{i}") - self._store(Loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): - if arg.type.width < param.type.width: - # 整数扩展:使用 sext(符号扩展)以正确处理负数 - adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): - adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) - elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): - adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) - else: - adjusted.append(arg) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): - adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - # 整数转指针:inttoptr - if arg.type.width < 64: - i64_val: ir.Value = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") - adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) - else: - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 指针转整数:ptrtoint - i64_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") - if i64_val.type.width > param.type.width: - adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) - elif i64_val.type.width < param.type.width: - adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(i64_val) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - except Exception: # 参数类型调整失败时使用简化回退逻辑 - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): - # 任意指针到指针的类型转换(如 struct* -> i8*) - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(arg) - else: - adjusted.append(arg) - while len(adjusted) < len(func.args): - missing_idx: int = len(adjusted) - param: ir.Argument = func.args[missing_idx] - param_type: ir.Type = param.type if hasattr(param, 'type') else param - if isinstance(param_type, ir.PointerType): - adjusted.append(ir.Constant(param_type, None)) - elif isinstance(param_type, ir.IntType): - adjusted.append(ir.Constant(param_type, 0)) - elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): - adjusted.append(ir.Constant(param_type, 0.0)) - else: - adjusted.append(ir.Constant(ir.IntType(32), 0)) - if func.type.pointee.var_arg: - for i in range(len(func.args), len(args)): - arg: ir.Value = args[i] - adjusted.append(arg) - return adjusted - - def _get_member_offset(self, field_name: str, ClassName: str | None = None) -> int | None: - # 治本修复:同名类 sha1 冲突检测。 - # 当 class_sha1_map[ClassName] 的 sha1 与 Gen.structs[ClassName] 的 sha1 不一致时, - # class_members[ClassName] 可能存储了错误模块的同名类成员。 - # 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。 - _ResolvedClass: str = ClassName if ClassName else '' - if ClassName: - _ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {}) - _ExpectedSha1: str | None = _ClassSha1Map.get(ClassName) - if _ExpectedSha1: - _ExistingStruct = self.structs.get(ClassName) - if isinstance(_ExistingStruct, ir.IdentifiedStructType): - _ExistingSha1: str = self._extract_struct_sha1(_ExistingStruct) - if _ExistingSha1 and _ExistingSha1 != _ExpectedSha1: - # sha1 冲突:使用全名查找 class_members - _FullKey: str = f"{_ExpectedSha1}.{ClassName}" - if _FullKey in self.class_members and self.class_members[_FullKey]: - _ResolvedClass = _FullKey - else: - # 从正确 stub 加载 class_members - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - _StubName: str = f"{_ExpectedSha1}.stub.ll" - # 临时保存旧值,清除短名条目以绕过 guard,加载后恢复 - _OldMembers = self.class_members.get(ClassName) - self.class_members[ClassName] = [] - try: - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, _StubName, self) - except Exception: - pass - _NewMembers = self.class_members.get(ClassName) - if _NewMembers: - self.class_members[_FullKey] = _NewMembers - _ResolvedClass = _FullKey - # 恢复旧值(避免影响其他代码对短名的依赖) - if _OldMembers: - self.class_members[ClassName] = _OldMembers - else: - self.class_members.pop(ClassName, None) - has_vtable: bool = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) - base: int = 1 if has_vtable else 0 - if ClassName and ClassName in self.structs: - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - if ClassName in self.class_members: - expected_fields: int = len(self.class_members[ClassName]) - actual_elements: int = len(struct_type.elements) - if base > 0 and actual_elements == expected_fields: - base = 0 - elif base == 0 and actual_elements == expected_fields + 1: - # 跨模块类可能未被检测为 CVTable(如 Name 继承 AST@t.CVTable), - # 但实际 struct 首元素是 vtable ptr → 需 base=1。 - # 但若类有继承(class_parent 有值),多出的 1 可能是继承字段而非 vtable, - # 需检查 struct 首元素类型:i8*/i8** 为 vtable,其他为继承字段。 - _first_elem = struct_type.elements[0] if actual_elements > 0 else None - _has_parent = self.class_parent.get(ClassName) is not None - _is_vtable_ptr = (isinstance(_first_elem, ir.PointerType) and - isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8) - if not _has_parent or _is_vtable_ptr: - base = 1 - if _ResolvedClass and _ResolvedClass in self.class_members: - for i, (name, _) in enumerate(self.class_members[_ResolvedClass]): - if name == field_name: - return base + i - # 继承链回退:当字段不在当前类的 class_members 中时(常见于跨模块导入 - # 父类未加载,字段被填充为 __inherited_N 占位名),沿 class_parent 链向上查找。 - # 子类 struct 布局为 [vtable?] + [基类字段...] + [子类字段...], - # 基类字段在子类 struct 中的起始偏移即为 base(子类), - # 因此祖先 class_members 中的索引 i 对应子类 struct 中的偏移 base + i。 - if ClassName and field_name: - _parent: str | None = self.class_parent.get(ClassName) - _visited: set = {ClassName} if ClassName else set() - while _parent and _parent not in _visited: - _visited.add(_parent) - # 跳过 __inherited_N 占位条目,只在真实字段名中查找 - if _parent in self.class_members: - _members: list = self.class_members[_parent] - _has_placeholder: bool = any(n.startswith('__inherited_') for n, _ in _members) - if not _has_placeholder: - for i, (name, _) in enumerate(_members): - if name == field_name: - return base + i - # 父类 class_members 未加载或含占位条目,尝试从 stub 加载真实字段 - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(_parent, stub_name, self) - if _parent in self.class_members and not any(n.startswith('__inherited_') for n, _ in self.class_members[_parent]): - for i, (name, _) in enumerate(self.class_members[_parent]): - if name == field_name: - return base + i - break - _parent = self.class_parent.get(_parent) - short_name: str | None = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - if ClassName and field_name: - if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) - if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - break - if short_name: - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) - if short_name in self.class_members and len(self.class_members[short_name]) > 0: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - if ClassName and field_name: - for cn_key in self.class_members: - if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return base + i - # REnum 变体搜索: ClassName 是 REnum(如 MetaType),成员注册在变体结构 - # (MetaType_Var, MetaType_Concrete, MetaType_App)中。变体与 REnum 主结构 - # 共享 max_variant_struct 布局,偏移一致(__tag 在偏移 0,字段从偏移 1 开始) - if ClassName and field_name: - variant_prefix: str = f"{ClassName}_" - for cn_key in self.class_members: - if cn_key.startswith(variant_prefix): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return i - if short_name: - variant_prefix = f"{short_name}_" - for cn_key in self.class_members: - if cn_key.startswith(variant_prefix): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return i - if ClassName and ClassName in self.structs: - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - for cn_key, members in self.class_members.items(): - if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - else: - if short_name: - for cn_key, members in self.class_members.items(): - sn: str = cn_key.split('.')[-1] if '.' in cn_key else cn_key - if sn == short_name: - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - if ClassName and field_name and ClassName not in self.class_members: - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: - if temp_dir_candidate and os.path.isdir(temp_dir_candidate): - for pyi_file in os.listdir(temp_dir_candidate): - if pyi_file.endswith('.pyi'): - stub_name: str = pyi_file.replace('.pyi', '.stub.ll') - short_cn: str = short_name if short_name else ClassName - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) - if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: - for i, (name, _) in enumerate(self.class_members[short_cn]): - if name == field_name: - return base + i - break - if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: - if self._Trans and hasattr(self._Trans, 'ClassHandler'): - class_handler: Any = self._Trans.ClassHandler - if self._current_tree: - for node in ast.iter_child_nodes(self._current_tree): - if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): - if node.name not in self.class_members: - self.class_members[node.name] = [] - if len(self.class_members[node.name]) == 0: - class_handler._PreRegisterClassMembers(node, self) - if ClassName in self.class_members: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - # 最后回退:当继承链回退失败但 struct body 已加载时, - # 从 struct elements 数和 class_members 数推断继承字段偏移。 - # 继承字段在 struct 开头(base 之后),此 fallback 仅适用于单继承字段的情况 - # (如 GSListNode[T] 的 Next 字段)。子类 struct 布局: - # [vtable?] + [基类字段...] + [子类字段...] - # 当 class_members 只含子类自身字段、基类 class_members 未加载时, - # 继承字段数 = struct_elements - class_members_count, - # 若该值 == 1,则所查字段(如 Next)的偏移 = base + 0。 - if ClassName and field_name: - _st_final = self.structs.get(ClassName) - if isinstance(_st_final, ir.IdentifiedStructType) and _st_final.elements is not None: - _num_elements_final: int = len(_st_final.elements) - _members_final: list = self.class_members.get(ClassName, []) - _num_members_final: int = len(_members_final) - if _num_elements_final > _num_members_final: - _num_inherited_final: int = _num_elements_final - _num_members_final - if _num_inherited_final == 1: - # 单继承字段,偏移 = base(vtable 之后第一个位置) - return base + 0 - return None - - def _resolve_class_for_var(self, var_name: str) -> str | None: - for ClassName in self.class_methods: - if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): - return ClassName - if var_name in self.variables: - var: ir.Value = self.variables[var_name] - if isinstance(var.type, ir.PointerType): - for ClassName, struct_type in self.structs.items(): - if var.type.pointee == struct_type: - return ClassName - if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: - return ClassName - return None - - def _infer_return_type(self, FuncName: str) -> ir.Type: - if FuncName in self.functions: - return self.functions[FuncName].type.pointee.return_type - # 也尝试混淆后的名称 - mangled: str = self._mangle_func_name(FuncName) - if mangled != FuncName and mangled in self.functions: - return self.functions[mangled].type.pointee.return_type - if FuncName in self.known_return_types: - return self.known_return_types[FuncName] - if mangled != FuncName and mangled in self.known_return_types: - return self.known_return_types[mangled] - for ClassName, methods in self.class_methods.items(): - for method in methods: - if FuncName == method: - return ir.VoidType() - if self._import_handler_ref: - try: - # 先用原始名称查找,再用混淆名称查找 - stub_func_type: Any = self._import_handler_ref._LookupStubFuncType(FuncName, self) - if stub_func_type is None and mangled != FuncName: - stub_func_type = self._import_handler_ref._LookupStubFuncType(mangled, self) - if stub_func_type and hasattr(stub_func_type, 'return_type'): - return stub_func_type.return_type - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"查找桩函数返回类型失败: {_e}", "Exception") - return ir.IntType(32) - - def _get_or_declare_func(self, name: str, func_type: ir.FunctionType) -> ir.Function: - for fname, fobj in self.functions.items(): - if fname == name: - return fobj - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - func_decl: ir.Function = ir.Function(self.module, func_type, name=name) - self.functions[name] = func_decl - return func_decl - - def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None: - if name in self.functions: - return self.functions[name] - for fname, fobj in self.functions.items(): - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - stub_func_type: ir.FunctionType | None = None - if self._import_handler_ref: - try: - stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"查找桩函数类型失败: {_e}", "Exception") - if stub_func_type: - func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name) - self.functions[name] = func_decl - return func_decl - if fallback_type is not None: - func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name) - self.functions[name] = func_decl - return func_decl - return None \ No newline at end of file diff --git a/App/lib/core/LLVMCG/MemoryOps.py b/App/lib/core/LLVMCG/MemoryOps.py deleted file mode 100644 index 07003e6..0000000 --- a/App/lib/core/LLVMCG/MemoryOps.py +++ /dev/null @@ -1,286 +0,0 @@ -from __future__ import annotations -import llvmlite.ir as ir - - -class MemoryOpsMixin: - - def _register_local_heap_ptr(self, val: ir.Value, ClassName: str | None = None, VarName: str | None = None) -> None: - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - self._local_heap_ptrs.append((val, 'struct', ClassName)) - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - self._local_heap_ptrs.append((val, 'i8', ClassName)) - if VarName: - self._var_to_heap_ptr[VarName] = val - - def _unregister_local_heap_ptr(self, val: ir.Value) -> None: - self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val] - - def _emit_local_heap_frees(self) -> None: - if not self._local_heap_ptrs or not self.builder: - return - deleted_objects: set[ir.Value] = set() - for ptr, ptr_type, ClassName in self._local_heap_ptrs: - if ptr_type == 'i8': - Loaded_ptr: ir.Value = self.builder.load(ptr, name="load_ptr") - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - is_null: ir.Value = self.builder.icmp_unsigned('==', Loaded_ptr, null_ptr, name="is_null") - not_null_block: ir.Block = self.builder.append_basic_block(name="not_null") - next_block: ir.Block = self.builder.append_basic_block(name="next") - self.builder.cbranch(is_null, next_block, not_null_block) - self.builder.position_at_end(not_null_block) - if ClassName and self._has_function(f'{ClassName}.__del__'): - cast_ptr: ir.Value - if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: - cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}") - else: - cast_ptr = ptr - if cast_ptr not in deleted_objects: - self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__") - deleted_objects.add(cast_ptr) - raw: ir.Value - if ptr_type == 'struct': - raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast") - elif ptr_type == 'i8': - raw = ptr - else: - continue - free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) - free_func: ir.Function = self._get_or_declare_func('free', free_type) - self.builder.call(free_func, [raw]) - if ptr_type == 'i8': - self.builder.branch(next_block) - self.builder.position_at_end(next_block) - self._local_heap_ptrs = [] - - def _RegisterTempPtr(self, val: ir.Value) -> None: - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - for CN, ST in self.structs.items(): - if pointee == ST: - self._temp_struct_ptrs.append(val) - return - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - self._temp_struct_ptrs.append(val) - - def _UnregisterTempPtr(self, val: ir.Value) -> None: - self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val] - - def _EmitTempFrees(self) -> None: - if not self._temp_struct_ptrs or not self.builder: - return - for ptr in self._temp_struct_ptrs: - raw: ir.Value - if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast") - elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: - raw = ptr - else: - continue - free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) - free_func: ir.Function = self._get_or_declare_func('free', free_type) - self.builder.call(free_func, [raw]) - self._temp_struct_ptrs = [] - - def _ZeroConst(self, typ: ir.Type) -> ir.Constant: - if isinstance(typ, ir.PointerType): - return ir.Constant(typ, None) - if isinstance(typ, (ir.LiteralStructType, ir.IdentifiedStructType)): - return ir.Constant(typ, None) - if isinstance(typ, ir.ArrayType): - return ir.Constant(typ, None) - return ir.Constant(typ, 0) - - def _alloca(self, typ: ir.Type, name: str = '', align: int | None = None, size: ir.Value | None = None) -> ir.AllocaInstr: - if align is None: - align = self._get_align(typ) - instr: ir.AllocaInstr - if size is not None: - instr = self.builder.alloca(typ, size=size, name=name) - else: - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - return instr - - def _allocaEntry(self, typ: ir.Type, name: str = '', align: int | None = None) -> ir.AllocaInstr: - if align is None: - align = self._get_align(typ) - saved_block: ir.Block = self.builder.block - entry_block: ir.Block = self.func.entry_basic_block - instr: ir.AllocaInstr - if entry_block.instructions: - first_instr: ir.Instruction = entry_block.instructions[0] - self.builder.position_before(first_instr) - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - self.builder.position_at_end(saved_block) - else: - self.builder.position_at_start(entry_block) - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - self.builder.position_at_end(saved_block) - return instr - - def _load(self, ptr: ir.Value, name: str = '', align: int | None = None) -> ir.LoadInstr: - if align is None: - if isinstance(ptr.type, ir.PointerType): - align = self._get_align(ptr.type.pointee) - else: - align = 0 - if isinstance(ptr.type, ir.PointerType): - pointee_type: ir.Type = ptr.type.pointee - if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in self.typedef_int_widths: - width: int = self.typedef_int_widths[pointee_type.name] - if width > 0: - actual_type: ir.IntType = ir.IntType(width) - bitcast_ptr: ir.Value = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_Load") - return self.builder.load(bitcast_ptr, name=name, align=align) - return self.builder.load(ptr, name=name, align=align) - - def _Load_var(self, name: str) -> ir.Value | None: - if name in self._direct_values: - return self._direct_values[name] - if name in self.variables and self.variables[name] is not None: - VarPtr: ir.Value = self.variables[name] - if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return VarPtr - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return VarPtr - return self._load(VarPtr, name=name) - if name in self.global_vars and name in self.module.globals: - GVar: ir.GlobalVariable = self.module.globals[name] - self.variables[name] = GVar - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return self._load(GVar, name=name) - if name in self.module.globals: - GVar = self.module.globals[name] - self.variables[name] = GVar - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return self._load(GVar, name=name) - return None - - def _coerce_value(self, val: ir.Value, target_type: ir.Type) -> ir.Value | None: - if val.type == target_type: - return val - if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: - if isinstance(val.type, ir.IntType): - return val - if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): - if target_type.width < val.type.width: - return self.builder.trunc(val, target_type, name="trunc_store") - elif val.type.width == 1: - # i1 是布尔值(来自 icmp/fcmp/__contains__ 归一化),无符号语义, - # 必须用 zext 而非 sext,否则 i1 的 1 会被符号扩展为 -1 - return self.builder.zext(val, target_type, name="zext_bool_store") - else: - return self.builder.sext(val, target_type, name="sext_store") - if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType): - if isinstance(val, ir.Constant) and val.constant is None: - return ir.Constant(target_type, None) - return self.builder.bitcast(val, target_type, name="ptr_bitcast_store") - if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType): - if val.type.width < 64: - val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store") - return self.builder.inttoptr(val, target_type, name="int_to_ptr_store") - if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType): - if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width: - return self.builder.load(val, name="load_ptr_as_int_store") - if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType): - Loaded: ir.Value = self.builder.load(val, name="load_ptr_byte_store") - if Loaded.type != target_type: - if isinstance(Loaded.type, ir.IntType) and isinstance(target_type, ir.IntType): - if target_type.width < Loaded.type.width: - return self.builder.trunc(Loaded, target_type, name="trunc_ptr_byte_store") - return self.builder.zext(Loaded, target_type, name="zext_ptr_byte_store") - return Loaded - return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store") - if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType): - return self.builder.fptrunc(val, target_type, name="fptrunc_store") - if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType): - return self.builder.fpext(val, target_type, name="fpext_store") - if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return self.builder.fptosi(val, target_type, name="fptosi_store") - if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType): - return self.builder.sitofp(val, target_type, name="sitofp_store") - if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType): - if target_type.count == val.type.count and target_type.element == val.type.element: - return val - if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8 - and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8): - if target_type.count > val.type.count: - padded: list[ir.Constant] = list(val.constant) if hasattr(val, 'constant') else [] - if padded and len(padded) == val.type.count: - padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count)) - return ir.Constant(target_type, padded) - elif target_type.count < val.type.count: - trimmed: list[ir.Constant] = list(val.constant) if hasattr(val, 'constant') else [] - if trimmed and len(trimmed) == val.type.count: - return ir.Constant(target_type, trimmed[:target_type.count]) - if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType): - if val.type.pointee == target_type: - return self.builder.load(val, name="Load_struct_for_store") - if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType): - if val.type.pointee.name == target_type.name: - Loaded: ir.Value = self.builder.load(val, name="Load_struct_for_store") - if Loaded.type == target_type: - return Loaded - return None - - def _store(self, val: ir.Value, ptr: ir.Value, align: int | None = None) -> ir.StoreInstr: - if align is None: - if isinstance(ptr.type, ir.PointerType): - align = self._get_align(ptr.type.pointee) - else: - align = 0 - if isinstance(ptr.type, ir.PointerType): - target_type: ir.Type = ptr.type.pointee - if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: - if isinstance(val.type, ir.IntType): - width: int = self.typedef_int_widths[target_type.name] - if width > 0: - actual_type: ir.IntType = ir.IntType(width) - bitcast_ptr: ir.Value = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast") - if val.type.width != actual_type.width: - if val.type.width > actual_type.width: - val = self.builder.trunc(val, actual_type, name="trunc_typedef") - else: - val = self.builder.zext(val, actual_type, name="zext_typedef") - return self.builder.store(val, bitcast_ptr, align=align) - if val.type != target_type: - if isinstance(val, ir.Constant) and val.constant is None: - if isinstance(target_type, ir.PointerType): - val = ir.Constant(target_type, None) - elif isinstance(target_type, ir.IdentifiedStructType): - val = ir.Constant(ir.PointerType(target_type), None) - ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast") - else: - coerced: ir.Value | None = self._coerce_value(val, target_type) - if coerced is not None: - val = coerced - else: - src_info: str = self._get_node_info() - raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}") - return self.builder.store(val, ptr, align=align) - - def _get_var_ptr(self, name: str) -> ir.Value | None: - if name in self._reg_values: - val: ir.Value = self._reg_values[name] - var: ir.AllocaInstr = self._alloca(val.type, name=name) - self._store(val, var) - self.variables[name] = var - del self._reg_values[name] - return var - if name in self.variables and self.variables[name] is not None: - return self.variables[name] - return None \ No newline at end of file diff --git a/App/lib/core/LLVMCG/StructGen.py b/App/lib/core/LLVMCG/StructGen.py deleted file mode 100644 index 13098bb..0000000 --- a/App/lib/core/LLVMCG/StructGen.py +++ /dev/null @@ -1,629 +0,0 @@ -from __future__ import annotations -from typing import Any -import re -import ast -import llvmlite.ir as ir -from llvmlite.ir.values import _Undefined -from lib.includes import t as _t - - -class StructGenMixin: - - def _get_align(self, llvm_type: ir.Type) -> int: - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_align(llvm_type.element) - if isinstance(llvm_type, ir.LiteralStructType): - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.IdentifiedStructType): - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer alignment - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.VoidType): - return 0 - return 4 - - def _resolve_opaque_struct(self, llvm_type: ir.Type) -> ir.Type: - """尝试从 Gen.structs 中查找已解析的同名 struct,解决跨模块 struct 类型对象不一致的问题""" - if not isinstance(llvm_type, ir.IdentifiedStructType): - return llvm_type - if llvm_type.elements is not None and len(llvm_type.elements) > 0: - return llvm_type - # opaque struct,尝试通过名称在 Gen.structs 中查找已解析的版本 - st_name: str - try: - st_name = llvm_type.name - except Exception: - return llvm_type - if not st_name: - return llvm_type - # 提取短名称 - short_name: str = st_name - if '.' in st_name: - short_name = st_name.split('.', 1)[1] - # 尝试短名称查找 - if short_name in self.structs: - resolved: ir.IdentifiedStructType = self.structs[short_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - # 尝试全名查找 - if st_name in self.structs: - resolved: ir.IdentifiedStructType = self.structs[st_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - # 尝试通过导入处理器从 stub 文件加载 struct 定义 - import_handler: Any = self._import_handler_ref - if import_handler is not None: - try: - import_handler._TryLoadStructFromStub(short_name, self) - except Exception: - pass - # 加载后再次查找 - if short_name in self.structs: - resolved = self.structs[short_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - if st_name in self.structs: - resolved = self.structs[st_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - return llvm_type - - def _get_struct_size(self, llvm_type: ir.Type) -> int: - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_struct_size(llvm_type.element) * llvm_type.count - if isinstance(llvm_type, ir.LiteralStructType): - total: int = 0 - max_align: int = 1 - for f in llvm_type.fields: - fa: int = self._get_align(f) - fs: int = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - if isinstance(llvm_type, ir.IdentifiedStructType): - # 尝试解析 opaque struct 为已注册的版本 - llvm_type = self._resolve_opaque_struct(llvm_type) - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer size - total: int = 0 - max_align: int = 1 - for f in llvm_type.elements: - fa: int = self._get_align(f) - fs: int = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - return 4 - - @staticmethod - def _strip_unnecessary_quotes(ir_str: str) -> str: - def _unquote(m: re.Match) -> str: - prefix: str = m.group(1) - name: str = m.group(2) - if '.' in name: - return m.group(0) - if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): - return prefix + name - return m.group(0) - return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) - - def finalize(self) -> str: - self._set_Vtable_initializers() - self._fix_global_var_init() - ir_text: str - try: - ir_text = str(self.module) - except TypeError as e: - for func in self.module.functions: - for block in func.blocks: - for instr in block.instructions: - try: - str(instr) - except TypeError as te: - pass - raise - ir_text = self._strip_unnecessary_quotes(ir_text) - struct_defs: list[str] = [] - struct_names: set[str] = set() - for ClassName, struct_type in self.structs.items(): - if isinstance(struct_type, ir.IdentifiedStructType): - sname: str = struct_type.name - sname_ir: str - if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): - sname_ir = f'%"{sname}"' - else: - sname_ir = f'%{sname}' - if struct_type.elements is None or len(struct_type.elements) == 0: - if ClassName not in self.typedef_int_widths: - struct_names.add(sname) - struct_defs.append(f'{sname_ir} = type opaque') - continue - elems: str = ', '.join(str(e) for e in struct_type.elements) - if struct_type.packed: - struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') - else: - struct_defs.append(f'{sname_ir} = type {{ {elems} }}') - struct_names.add(sname) - if struct_defs: - lines: list[str] = ir_text.split('\n') - filtered: list[str] = [] - for line in lines: - stripped: str = line.strip() - skip: bool = False - for name in struct_names: - patterns: list[str] - if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): - patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] - else: - patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] - for p in patterns: - if stripped.startswith(p): - skip = True - break - if skip: - break - if not skip: - filtered.append(line) - ir_text = '\n'.join(filtered) - header_end: int = ir_text.find('\ndefine') - if header_end == -1: - header_end = ir_text.find('\ndeclare') - if header_end == -1: - header_end = ir_text.find('\n@') - if header_end == -1: - header_end = len(ir_text) - insert_pos: int = ir_text.rfind('\n', 0, header_end) - if insert_pos == -1: - insert_pos = header_end - struct_block: str = '\n'.join(struct_defs) + '\n' - ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] - for name in struct_names: - if name[0].isdigit() or '.' in name: - ir_text = re.sub( - r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', - r'%"' + name + r'"', - ir_text - ) - - return ir_text - - def _generate_structs(self) -> None: - all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys()) - - preserved_structs: dict[str, ir.IdentifiedStructType] = {} - for name, st in self.structs.items(): - if name not in all_classes: - preserved_structs[name] = st - elif isinstance(st, ir.IdentifiedStructType): - preserved_structs[name] = st - - self.structs.clear() - - for name, st in preserved_structs.items(): - self.structs[name] = st - - # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 - all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) - for ClassName in all_classes: - is_packed: bool = ClassName in self.class_packed - if self.SymbolTable: - Entry = self.SymbolTable.lookup(ClassName) - if Entry and Entry.IsExceptionClass: - continue - # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Module 枚举成员与 Module 类同名) - # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, - # 不应被 IsEnum/IsTypedef 检查跳过 - if Entry and Entry.IsEnum and ClassName not in self.class_methods: - if not Entry.IsRenum: - continue - if Entry and Entry.IsTypedef and ClassName not in self.class_methods: - if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): - if not isinstance(Entry.BaseType, (_t._CTypedef,)): - continue - if ClassName in self.structs: - if is_packed: - self.structs[ClassName].packed = True - continue - # 修复跨模块类型定义冲突:如果类是从其他模块导入的(已在 class_sha1_map 注册), - # 必须使用导入的 source_sha1 作为前缀,而非本地模块的 sha1。 - # 否则会创建缺少基类字段(如 GSListNode.Next)的本地类型定义, - # 导致字段索引错位 → 访问违规崩溃。 - _imported_sha1: str = self.class_sha1_map.get(ClassName, '') - if _imported_sha1: - mangled_name: str = f"{_imported_sha1}.{ClassName}" - else: - mangled_name: str = self._mangle_name(ClassName) - struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) - self.structs[ClassName] = struct_type - - # Step 2: 解析跨模块的成员类型 - for ClassName, annotations in self.class_member_annotations.items(): - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if member_name in annotations: - annotation: Any = annotations[member_name] - ResolvedType: ir.Type | None = None - - if isinstance(annotation, ast.Attribute): - ClassTypeName: str = annotation.attr - if ClassTypeName in self.structs: - ResolvedType = self.structs[ClassTypeName] - elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - left: Any = annotation.left - if isinstance(left, ast.Attribute): - ClassTypeName: str = left.attr - if ClassTypeName in self.structs: - ResolvedType = self.structs[ClassTypeName] - - if ResolvedType: - self.class_members[ClassName][i] = (member_name, ResolvedType) - - struct_name_map: dict[str, ir.IdentifiedStructType] = {} - for struct_name, struct in self.structs.items(): - try: - struct_name_map[struct.name] = struct - except AssertionError: - struct_name_map[struct_name] = struct - orig: Any = getattr(struct, '_original_name', None) - if orig: - struct_name_map[orig] = struct - - # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 - for ClassName in all_classes: - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if isinstance(member_type, ir.PointerType): - pointee: ir.Type = member_type.pointee - if isinstance(pointee, ir.IdentifiedStructType): - pname: str | None - try: - pname = pointee.name - except AssertionError: - pname = None - struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None - if struct is None: - orig: Any = getattr(pointee, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) - else: - raw_name: str = pname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) - elif isinstance(member_type, ir.IdentifiedStructType): - mname: str | None - try: - mname = member_type.name - except AssertionError: - mname = None - struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None - if struct is None: - orig: Any = getattr(member_type, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, struct) - else: - raw_name: str = mname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, new_struct) - - # Step 4: 创建最终的 structs 并设置正确的成员类型 - for ClassName in all_classes: - if self.SymbolTable: - Entry = self.SymbolTable.lookup(ClassName) - if Entry and Entry.IsExceptionClass: - continue - # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Constant 枚举成员与 Constant 类同名) - # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, - # 不应被 IsEnum 检查跳过(与 Step 1 的守卫保持一致) - if Entry and Entry.IsEnum and ClassName not in self.class_methods: - if not Entry.IsRenum: - continue - existing_st: ir.IdentifiedStructType | None = self.structs.get(ClassName) - if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: - # 治本修复:检查 struct body 是否不完整(元素数少于 class_members + vtable 预期)。 - # 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成, - # stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32)。 - # 此处检测到不完整后清除 _elements 和 stub 缓存,让后续代码重新从 stub 加载。 - _has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes - if not _has_vtable_precheck: - _p_pre: str | None = self.class_parent.get(ClassName) - while _p_pre: - if _p_pre in self.class_vtable or _p_pre in self._cross_module_vtable_classes: - _has_vtable_precheck = True - break - _p_pre = self.class_parent.get(_p_pre) - _expected_count_pre: int = len(self.class_members.get(ClassName, [])) + (1 if _has_vtable_precheck else 0) - # has_vtable 时,首字段必须是 i8*(vtable 指针)。 - # 若首字段非指针(如 i8 占位符),struct body 不完整,需清除重新加载。 - _vtable_first_ok: bool = True - if _has_vtable_precheck and len(existing_st.elements) > 0: - _vtable_first_ok = isinstance(existing_st.elements[0], ir.PointerType) - # 检测 T* 占位类型(未特化的泛型类型参数)。 - # 当 struct 包含 T* 字段时(如 BasicBlock 继承 GSListNode[BasicBlock] 但 stub 未特化), - # 说明 stub 使用了未特化的基类,需清除重新生成。 - _has_t_placeholder_pre: bool = False - for _elem_pre in existing_st.elements: - if isinstance(_elem_pre, ir.PointerType) and isinstance(_elem_pre.pointee, ir.IdentifiedStructType): - _pname_pre: str = _elem_pre.pointee.name - _short_pre: str = _pname_pre.rsplit('.', 1)[-1] if '.' in _pname_pre else _pname_pre - if _short_pre == 'T': - _has_t_placeholder_pre = True - break - if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok and not _has_t_placeholder_pre: - if ClassName in self.class_packed and not existing_st.packed: - existing_st.packed = True - continue - # struct body 不完整,清除 _elements 和 stub 缓存以便重新加载 - existing_st._elements = None - _import_handler_pre: Any = self._import_handler_ref - if _import_handler_pre is not None: - _cache_key_pre: tuple = (id(self), ClassName) - if _cache_key_pre in _import_handler_pre._struct_Load_cache: - del _import_handler_pre._struct_Load_cache[_cache_key_pre] - has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes - if not has_vtable: - p: str | None = self.class_parent.get(ClassName) - while p: - if p in self.class_vtable or p in self._cross_module_vtable_classes: - has_vtable = True - self.class_vtable.add(ClassName) - break - p = self.class_parent.get(p) - has_bitfield: bool = ClassName in self.class_member_bitfields and any( - self.class_member_bitfields[ClassName].get(name, 0) > 0 - for name, _ in self.class_members.get(ClassName, []) - ) - all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, []) - # 跳过正在发射中且成员尚未填充的类(递归特化时避免过早设置空 body) - if not all_members and not has_vtable and ClassName in self._classes_in_progress: - continue - # 字段收集期间触发的嵌套 _generate_structs:class_members 可能不完整, - # set_body 只能调用一次,跳过等字段收集完成后再设置 body - if ClassName in self._collecting_members_set: - continue - all_bitfield: bool = all( - self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 - for name, _ in all_members - ) if all_members else False - - mangled_name: str = self._mangle_name(ClassName) - - member_types: list[ir.Type] - if has_bitfield and all_bitfield: - total_bits: int = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) - for name, _ in all_members) - storage_type: ir.IntType - if total_bits <= 8: - storage_type = ir.IntType(8) - elif total_bits <= 16: - storage_type = ir.IntType(16) - elif total_bits <= 32: - storage_type = ir.IntType(32) - else: - storage_type = ir.IntType(64) - member_types = [storage_type] - bitfield_offsets: dict[str, int] = {} - current_bit_offset: int = 0 - for name, _ in all_members: - bit_width: int = self.class_member_bitfields.get(ClassName, {}).get(name, 0) - bitfield_offsets[name] = current_bit_offset - current_bit_offset += bit_width - self.class_member_bitoffsets[ClassName] = bitfield_offsets - else: - member_types = [] - if has_vtable: - member_types.append(ir.PointerType(ir.IntType(8))) - if ClassName in self.class_members: - for _, member_type in self.class_members[ClassName]: - if member_type is None: - member_type = ir.IntType(32) - member_types.append(member_type) - else: - if has_vtable: - # has_vtable 但 class_members 为空(跨模块导入类): - # 保持 member_types 为空([i8*] 占位会导致 stub 加载跳过, - # 因为 set_body 后 is_opaque=False)。让 struct 保持 opaque, - # 由 _TryLoadStructFromStub 设置完整 body。 - member_types = [] - else: - # 无 vtable 且 class_members 为空:常见于 register_method 早期 - # 调用 _generate_structs(此时 class_members[ClassName]=[] 但尚未 - # 填充实际字段)。保持 opaque,避免 set_body(*[i8]) 永久损坏 struct - # (llvmlite 的 set_body 只能调用一次)。后续 _generate_structs 调用 - # 会从 class_members 或 stub 设置正确 body。 - member_types = [] - - # 获取之前创建的 struct 并设置成员 - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if ClassName in self.class_packed: - struct_type.packed = True - # 只在未设置 body 时设置,避免重复定义错误 - if struct_type.elements is None: - # 跨模块 struct 的 class_members 可能不完整(当前模块只解析了部分字段), - # 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次, - # 若用不完整 class_members 设置 body,后续无法修正,会导致 GEP 越界。 - # 但本地定义的类(_classes_in_progress)不从 stub 加载,因为 stub 可能 - # 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突) - import_handler: Any = self._import_handler_ref - if import_handler is not None and ClassName not in self._classes_in_progress: - try: - # 传入 source_sha1 确保从正确的 stub 文件加载完整定义 - _src_sha1: str = self.class_sha1_map.get(ClassName, '') - import_handler._TryLoadStructFromStub(ClassName, self, source_sha1=_src_sha1 or None) - except Exception: - pass - struct_type = self.structs.get(ClassName, struct_type) - # 检测 stub body 中的 T* 占位类型(未特化的泛型类型参数)。 - # 若 stub 使用了未特化的基类(如 GSListNode 而非 GSListNode[BasicBlock]), - # 清除 _elements 让 set_body 用正确的 class_members 重新设置。 - if struct_type.elements is not None and member_types: - _has_t_placeholder_post: bool = False - for _elem_post in struct_type.elements: - if isinstance(_elem_post, ir.PointerType) and isinstance(_elem_post.pointee, ir.IdentifiedStructType): - _pname_post: str = _elem_post.pointee.name - _short_post: str = _pname_post.rsplit('.', 1)[-1] if '.' in _pname_post else _pname_post - if _short_post == 'T': - _has_t_placeholder_post = True - break - if _has_t_placeholder_post: - struct_type._elements = None - if struct_type.elements is None: - # 防御性检查:member_types 为空时不调用 set_body。 - # set_body(*[]) 会设置 elements=() 使 is_opaque=False, - # 后续无法再次 set_body(llvmlite 限制),导致跨模块类型永久损坏。 - # 根因:register_method 在 class_members[ClassName]=[] 时立即调用 - # _generate_structs,此时 member_types 为空。保持 opaque 状态, - # 让后续 _TryLoadStructFromStub 能正确设置 body。 - if member_types: - struct_type.set_body(*member_types) - - def _create_Vtable_globals(self) -> None: - for ClassName, methods in self.class_methods.items(): - if ClassName in self.Vtables: - continue - if not methods: - continue - if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: - continue - # 跳过正在发射中的类:它们的方法列表可能还不完整(如继承方法已添加但自有方法未添加), - # 此时创建 vtable 会导致大小不匹配。这些类的 vtable 会在其 _EmitClassLlvm 完成后 - # 由 _create_vtable_for_class 显式创建,或在模块级 _create_Vtable_globals 调用中创建。 - if ClassName in self._classes_in_progress: - continue - # 跨模块虚表过滤:_precollect_vtable_state 会将所有 includes 的有方法类同时加入 - # _shared_class_vtable 和 _shared_cross_module_vtable,导致 class_vtable 与 - # _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。 - # _generate_structs 会为所有 class_methods 的类创建空 struct type,导致 self.structs - # 也包含所有类。过滤条件是 self.functions:只考虑本模块定义的函数(define,有函数体), - # 跳过跨模块的 declare(无函数体)。跨模块类的 declare 通过 HandlesImports 加入 - # self.functions(短名如 "MemManager.alloc"),但其 is_declaration=True。 - # 若只存在 declare 而无 define,说明本模块未定义该类,虚表应由定义模块创建。 - # vtable linkage='internal',跨模块调用通过对象的 vtable 指针(首字段)完成分派, - # 不依赖本模块的 vtable 全局变量。 - has_local_method: bool = False - prefix: str = f"{ClassName}." - for func_name, func_obj in self.functions.items(): - if func_name.startswith(prefix): - # 跳过跨模块的 declare(无函数体),只考虑本模块定义的函数 - if not getattr(func_obj, 'is_declaration', False): - has_local_method = True - break - if not has_local_method: - continue - VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) - Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - Vtable.linkage = 'internal' - self.Vtables[ClassName] = Vtable - - def _create_vtable_for_class(self, ClassName: str) -> None: - """为单个类创建 vtable(用于 _EmitClassLlvm 中当前类的方法已全部注册后)。""" - methods: list = self.class_methods.get(ClassName, []) - if not methods: - return - if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: - return - _vtable_name: str = self._mangle_name(f"{ClassName}_Vtable") - # 如果虚表已在导入阶段创建(方法列表不完整,缺少继承方法),删除旧虚表 - if ClassName in self.Vtables: - _old_vtable = self.Vtables[ClassName] - _old_name = _old_vtable.name - if _old_name in self.module.globals: - del self.module.globals[_old_name] - # llvmlite 的 NameScope._useset 追踪所有已使用的名字, - # del module.globals[name] 不会从 _useset 移除, - # 导致再次创建同名 GlobalVariable 时 scope.register() 报 DuplicatedNameError - self.module.scope._useset.discard(_old_name) - del self.Vtables[ClassName] - # 防御性:如果全局变量已存在但不在 Vtables 字典中,也删除 - if _vtable_name in self.module.globals: - del self.module.globals[_vtable_name] - self.module.scope._useset.discard(_vtable_name) - VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name) - Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - Vtable.linkage = 'internal' - self.Vtables[ClassName] = Vtable - - def _fix_global_var_init(self) -> None: - for gv_name, gv in list(self.module.globals.items()): - if not isinstance(gv, ir.GlobalVariable): - continue - if gv.linkage in ('external', 'extern_weak'): - continue - needs_fix: bool = False - if gv.initializer is None: - needs_fix = True - elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): - needs_fix = True - elif isinstance(gv.initializer, ir.Constant): - if isinstance(gv.initializer.constant, list): - if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): - needs_fix = True - if not needs_fix: - continue - gv.initializer = ir.Constant(gv.value_type, None) - if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): - gv.linkage = 'internal' - - def _set_Vtable_initializers(self) -> None: - for ClassName, methods in self.class_methods.items(): - if ClassName not in self.Vtables: - continue - if not methods: - continue - struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName) - if struct_type is None: - continue - Vtable: ir.GlobalVariable = self.Vtables[ClassName] - Vtable_entries: list[ir.Constant] = [] - for MethodName in methods: - short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName - full_MethodName: str = f"{ClassName}.{short_name}" - func: ir.Function | None = None - if full_MethodName in self.functions: - func = self.functions[full_MethodName] - if func is None: - parent_cls: str | None = self.class_parent.get(ClassName) - while parent_cls: - parent_full: str = f"{parent_cls}.{short_name}" - if parent_full in self.functions: - func = self.functions[parent_full] - break - parent_cls = self.class_parent.get(parent_cls) - if func is None: - Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) - Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries) \ No newline at end of file diff --git a/App/lib/core/LLVMCG/TypeConvert.py b/App/lib/core/LLVMCG/TypeConvert.py deleted file mode 100644 index f32d5b9..0000000 --- a/App/lib/core/LLVMCG/TypeConvert.py +++ /dev/null @@ -1,767 +0,0 @@ -from __future__ import annotations -from typing import Any -import ast -import re -import logging -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 -from lib.constants.config import mode as _config_mode -from lib.core.VLogger import get_logger as _vlog -from lib.core.SymbolUtils import IsTModule - - -class TypeConvertMixin: - - # 限定符前缀映射表:(前缀字符串, 去除长度) - # 这些限定符(const/volatile/static/extern/register/inline/export/CAuto 等) - # 仅影响 C 语义,对 LLVM IR 类型本身无影响,统一去除后递归解析内部类型。 - _QUALIFIER_PREFIXES: tuple[tuple[str, int], ...] = ( - ('const ', 6), ('volatile ', 9), ('const_', 6), ('volatile_', 9), - ('static ', 7), ('extern ', 7), ('register ', 9), ('inline ', 7), - ('export ', 7), - ('CStatic ', 8), ('CExtern ', 8), ('CRegister ', 10), - ('CInline ', 8), ('CAuto ', 6), - ) - - def _ctype_to_llvm(self, type_info: _CTypeInfo | str | None) -> ir.Type: - if type_info is None: - return ir.IntType(32) - - if isinstance(type_info, str): - return self._type_str_to_llvm(type_info) - - if not isinstance(type_info, _CTypeInfo): - return ir.IntType(32) - - if type_info.IsFuncPtr: - ret_type: ir.Type = self._ctype_to_llvm(type_info.FuncPtrReturn) if type_info.FuncPtrReturn else ir.VoidType() - param_types: list[ir.Type] = [] - if type_info.FuncPtrParams: - for _name, param_info in type_info.FuncPtrParams: - if isinstance(param_info, _CTypeInfo): - param_types.append(self._ctype_to_llvm(param_info)) - else: - param_types.append(ir.IntType(32)) - fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - return ir.PointerType(fn_type) - - if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: - if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): - return ir.VoidType() - - if type_info.IsTypedef and type_info.Name: - resolved: ir.Type | None = self._resolve_typedef_ctype(type_info) - if resolved is not None: - return resolved - - # REnum 类型:通过 Name 查找或创建结构体(BaseType 可能为 None) - # 这对 BinOp `LLVMType | t.CPtr` 合并后的 CTypeInfo 至关重要 - if type_info.IsRenum and type_info.Name: - if type_info.Name in self.structs: - base: ir.Type = self.structs[type_info.Name] - else: - base = self._get_or_create_struct(type_info.Name) - result: ir.Type = base - for _ in range(type_info.PtrCount): - result = ir.PointerType(result) - return result - - BaseType: ir.Type = self._base_ctype_to_llvm(type_info.BaseType, type_info) - - result: ir.Type = BaseType - for _ in range(type_info.PtrCount): - if isinstance(result, ir.VoidType): - result = ir.IntType(8).as_pointer() - else: - result = ir.PointerType(result) - - for dim in reversed(type_info.ArrayDims): - try: - dim_val: int = int(dim) - if dim_val > 0: - result = ir.ArrayType(result, dim_val) - except (ValueError, TypeError): - pass - - return result - - def _resolve_typedef_ctype(self, type_info: _CTypeInfo) -> ir.Type | None: - name: str = type_info.Name - if not name or not self.SymbolTable: - return None - - entry: Any = self.SymbolTable.lookup(name) - if not entry or not isinstance(entry, _CTypeInfo): - return None - - if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): - resolved: Any = entry.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - if entry.OriginalType: - if isinstance(entry.OriginalType, _CTypeInfo): - resolved: Any = entry.OriginalType.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - elif isinstance(entry.OriginalType, str): - resolved: Any = _CTypeInfo.FromTypeName(entry.OriginalType) - if resolved and resolved.BaseType: - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - return None - - def _base_ctype_to_llvm(self, BaseType: Any, type_info: _CTypeInfo | None = None) -> ir.Type: - if BaseType is None: - return ir.VoidType() - - if isinstance(BaseType, (tuple, list)): - elem_types: list[ir.Type] = [self._base_ctype_to_llvm(bt, type_info) for bt in BaseType] - return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) - - if isinstance(BaseType, type) and issubclass(BaseType, _t.CType): - BaseType = BaseType() - - if isinstance(BaseType, _t.CVoid): - return ir.VoidType() - - if isinstance(BaseType, _t.CStruct): - struct_name: str = getattr(BaseType, 'name', '') or (type_info.Name if type_info else '') - if struct_name and struct_name in self.structs: - return self.structs[struct_name] - if struct_name: - return self._get_or_create_struct(struct_name) - return ir.LiteralStructType([]) - - if isinstance(BaseType, (_t.CEnum, _t.REnum)): - enum_name: str = type_info.Name if type_info else '' - if enum_name and enum_name in self.structs: - return self.structs[enum_name] - return ir.IntType(32) - - if isinstance(BaseType, _t.CUnion): - union_name: str = type_info.Name if type_info else '' - if union_name and union_name in self.structs: - return self.structs[union_name] - if union_name: - return self._get_or_create_struct(union_name) - return ir.IntType(32) - - if isinstance(BaseType, _t._CTypedef): - typedef_name: str = getattr(BaseType, 'value', '') or (type_info.Name if type_info else '') - if typedef_name and self.SymbolTable: - entry: Any = self.SymbolTable.lookup(typedef_name) - if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: - if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: - return self._base_ctype_to_llvm(entry.BaseType, entry) - return ir.IntType(32) - - if isinstance(BaseType, _t.CDefine): - # Use 64-bit type if the define value exceeds 32-bit range - if type_info and isinstance(type_info.DefineValue, int): - if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: - return ir.IntType(64) - return ir.IntType(32) - - if isinstance(BaseType, _t.CPass): - return ir.VoidType() - - llvm_str: str = CTypeRegistry.CTypeToLLVM(type(BaseType)) - return self._llvm_str_to_ir(llvm_str) - - def _get_source_sha1_from_type_str(self, type_str: str) -> str | None: - """从类型字符串中提取模块名,返回对应的源模块 SHA1。 - 用于跨模块类型引用(如 memhub.MemBuddy),确保用源模块的 SHA1 创建 struct。 - """ - if not type_str or '.' not in type_str: - return None - # 去除指针标记和空格 - clean: str = type_str.replace('*', '').strip() - if '.' not in clean: - return None - # 提取模块名(最后一个 '.' 之前的部分) - parts: list[str] = clean.rsplit('.', 1) - if len(parts) < 2: - return None - module_name: str = parts[0] - # 跳过 t/c 等内建模块 - if module_name in {'t', 'c'}: - return None - # 从 ModuleSha1Map 查找 SHA1(支持完整路径名和短名) - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - source_sha1: str | None = sha1_map.get(module_name) - if not source_sha1 and '.' in module_name: - source_sha1 = sha1_map.get(module_name.split('.')[-1]) - return source_sha1 - - def _resolve_typedef(self, type_name: str) -> str: - if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'CPtr'}: - return type_name - if type_name == 'Callable': - return 'Callable' - visited: set[str] = set() - current: str = type_name - while current not in visited: - visited.add(current) - if self.SymbolTable: - Entry: _CTypeInfo | None = self.SymbolTable.lookup(current) - if isinstance(Entry, dict) and Entry.get('type') == 'typedef': - OriginalType: str = Entry.get('OriginalType', '') - if OriginalType: - current = OriginalType - continue - elif Entry and Entry.IsTypedef: - if Entry.OriginalType: - if isinstance(Entry.OriginalType, _CTypeInfo): - if Entry.OriginalType.IsFuncPtr: - return 'Callable' - return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current - elif isinstance(Entry.OriginalType, str): - current = Entry.OriginalType - continue - if Entry.BaseType: - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: - resolved: str = self._resolve_ctype_to_str(Entry) - if resolved and resolved != current: - current = resolved - continue - bm: Any = BuiltinTypeMap.Get(current) - if bm: - base_cls: Any = bm[0] - try: - instance: Any = base_cls() - cname: str = type(instance).__name__ - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - pass - bm: Any = BuiltinTypeMap.Get(current) - if bm and bm[1] > 0: - base_cls: Any = bm[0] - try: - instance: Any = base_cls() - cname: str = type(instance).__name__ - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - pass - break - return current - - def _resolve_ctype_to_str(self, type_info: _CTypeInfo) -> str: - parts: list[str] = [] - base: Any = type_info.BaseType - if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): - parts.append('void') - elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: - return '' - elif isinstance(base, _t.CStruct) or base is _t.CStruct: - parts.append(f'struct {getattr(base, "name", "")}') - elif isinstance(base, _t.CEnum) or base is _t.CEnum: - parts.append(f'enum {getattr(base, "name", "")}') - else: - cname: str = '' - if isinstance(base, type) and issubclass(base, _t.CType): - cname = base.__name__ - elif isinstance(base, _t.CType): - cname = type(base).__name__ - if cname: - parts.append(cname) - else: - return '' - if type_info.PtrCount > 0: - parts.append('*' * type_info.PtrCount) - return ' '.join(parts) - - def _type_str_to_llvm(self, type_str: str, IsPtr: bool = False) -> ir.Type: - type_str = type_str.strip() - cache_key: tuple[str, bool] = (type_str, IsPtr) - cached: ir.Type | None = self._type_cache.get(cache_key) - if cached is not None: - return cached - result: ir.Type = self._type_str_to_llvm_impl(type_str, IsPtr) - if result is not None: - if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): - self._type_cache[cache_key] = result - return result - - _CType2LLVM = _type_str_to_llvm - - def _type_str_to_llvm_impl(self, type_str: str, IsPtr: bool = False) -> ir.Type: - array_dims: list[int] = [] - dim_match: list[str] = re.findall(r'\[(\d+)\]', type_str) - if dim_match: - array_dims = [int(d) for d in dim_match] - type_str = re.sub(r'\s*\[\d+\]', '', type_str).strip() - result: ir.Type = self._type_str_to_llvm_base(type_str, IsPtr) - for dim in reversed(array_dims): - result = ir.ArrayType(result, dim) - return result - - def _type_str_to_llvm_base(self, type_str: str, IsPtr: bool = False) -> ir.Type: - ptr_depth: int = 0 - while type_str.endswith('*'): - ptr_depth += 1 - type_str = type_str[:-1].strip() - if ptr_depth > 0: - IsPtr = True - if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - result: ir.Type - if IsPtr: - result = ir.IntType(8).as_pointer() - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - return ir.IntType(32) - if type_str in {'const', 'volatile'}: - return ir.IntType(8) - if type_str == 'Callable': - return ir.IntType(8).as_pointer() - for _q_prefix, _q_offset in self._QUALIFIER_PREFIXES: - if type_str.startswith(_q_prefix): - return self._type_str_to_llvm(type_str[_q_offset:].strip(), IsPtr) - resolved: str = self._resolve_typedef(type_str) - if resolved != type_str: - if '*' in resolved: - IsPtr = False - return self._type_str_to_llvm(resolved, IsPtr) - if type_str.endswith('*'): - BaseType: str = type_str[:-1].strip() - base_llvm: ir.Type | None = self._basic_type_to_llvm(BaseType) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - result: ir.Type = ir.IntType(8).as_pointer() - for _ in range(ptr_depth): - result = ir.PointerType(result) - return result - if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): - if isinstance(base_llvm, ir.PointerType): - return base_llvm - return ir.PointerType(base_llvm) - if BaseType in self.structs: - return ir.PointerType(self.structs[BaseType]) - if BaseType.startswith('struct '): - stripped: str = BaseType[7:].strip() - if stripped in self.structs: - return ir.PointerType(self.structs[stripped]) - if '.' in BaseType: - LastPart: str = BaseType.split('.')[-1] - if LastPart in self.structs: - return ir.PointerType(self.structs[LastPart]) - _src_sha1: str | None = self._get_source_sha1_from_type_str(BaseType) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_src_sha1) - return ir.PointerType(placeholder) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - if type_str.startswith('{') and type_str.endswith('}'): - inner: str = type_str[1:-1].strip() - elem_strs: list[str] = [] - depth: int = 0 - current: str = '' - for ch in inner: - if ch == ',' and depth == 0: - elem_strs.append(current.strip()) - current = '' - else: - if ch == '{': - depth += 1 - elif ch == '}': - depth -= 1 - current += ch - if current.strip(): - elem_strs.append(current.strip()) - elem_types: list[ir.Type] = [] - for es in elem_strs: - et: ir.Type = self._type_str_to_llvm(es, '*' in es) - if isinstance(et, ir.VoidType): - et = ir.IntType(8).as_pointer() - elem_types.append(et) - if elem_types: - return ir.LiteralStructType(elem_types) - return ir.IntType(32) - if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - return ir.IntType(32) - if type_str.startswith('%'): - stripped: str = type_str[1:] - if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - basic_stripped: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_stripped is not None: - if IsPtr and not isinstance(basic_stripped, ir.VoidType): - return ir.PointerType(basic_stripped) - return basic_stripped - if self.SymbolTable: - _Entry: _CTypeInfo | None = self.SymbolTable.lookup(type_str) - if _Entry and _Entry.IsTypedef: - resolved_str: str = self._resolve_typedef(type_str) - if resolved_str != type_str: - return self._type_str_to_llvm(resolved_str, IsPtr) - 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, IsPtr) - if _Entry and _Entry.IsRenum: - if type_str in self.structs: - if IsPtr: - return ir.PointerType(self.structs[type_str]) - return self.structs[type_str] - # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), - # 需要通过 _get_or_create_struct 创建 opaque 结构体(自引用安全)。 - _renum_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque: ir.Type = self._get_or_create_struct(type_str, source_sha1=_renum_sha1) - if IsPtr: - return ir.PointerType(opaque) - return opaque - if _Entry and _Entry.IsStruct: - # 结构体类型(来自 _InsertClassSymbol):必须返回结构体类型而非 i32, - # 否则 (ast.Import | t.CPtr) 联合转换会得到 i32* 导致字段访问 GEP 偏移错误 - if type_str in self.structs: - if IsPtr: - return ir.PointerType(self.structs[type_str]) - return self.structs[type_str] - # 结构体尚未创建时,通过 _get_or_create_struct 创建 opaque 结构体 - # (_TryLoadStructFromStub 会在后续阶段填充字段) - _struct_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque_struct: ir.IdentifiedStructType = self._get_or_create_struct(type_str, source_sha1=_struct_sha1) - if IsPtr: - return ir.PointerType(opaque_struct) - return opaque_struct - if _Entry and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsFunction: - return ir.PointerType(ir.IntType(8)) - if _Entry and _Entry.BaseType: - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - for ClassName in self.structs: - if type_str == ClassName: - if IsPtr: - return ir.PointerType(self.structs[ClassName]) - return self.structs[ClassName] - if '.' in type_str and not type_str.startswith('%'): - LastPart: str = type_str.split('.')[-1] - basic_last: ir.Type | None = self._basic_type_to_llvm(LastPart) - if basic_last is not None: - if IsPtr and not isinstance(basic_last, ir.VoidType): - return ir.PointerType(basic_last) - return basic_last - if self.SymbolTable: - _Entry: _CTypeInfo | None = self.SymbolTable.lookup(LastPart) - if _Entry and _Entry.IsTypedef: - resolved_str: str = self._resolve_typedef(LastPart) - if resolved_str != LastPart: - return self._type_str_to_llvm(resolved_str, IsPtr) - 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, IsPtr) - if _Entry and _Entry.IsRenum: - if LastPart in self.structs: - if IsPtr: - return ir.PointerType(self.structs[LastPart]) - return self.structs[LastPart] - # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32)。 - _lp_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque_lp: ir.Type = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1) - if IsPtr: - return ir.PointerType(opaque_lp) - return opaque_lp - if _Entry and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsFunction: - return ir.PointerType(ir.IntType(8)) - if _Entry and _Entry.BaseType: - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if LastPart in self.structs: - if IsPtr: - return ir.PointerType(self.structs[LastPart]) - return self.structs[LastPart] - _lp_sha1_2: str | None = self._get_source_sha1_from_type_str(type_str) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1_2) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('struct '): - stripped: str = type_str[7:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - _stripped_sha1: str | None = self._get_source_sha1_from_type_str(stripped) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('%struct.'): - stripped: str = type_str[8:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - _stripped_sha1_2: str | None = self._get_source_sha1_from_type_str(stripped) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1_2) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('union '): - stripped: str = type_str[6:].strip() - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - if type_str.endswith('*'): - pointee: ir.Type = self._type_str_to_llvm(type_str[:-1].strip()) - if isinstance(pointee, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - return ir.PointerType(pointee) - result: ir.Type | None = self._basic_type_to_llvm(type_str) - if result is None: - # 未知类型:可能是跨模块结构体(如 'Import' 来自 ast 模块)。 - # 尝试通过 _get_or_create_struct 创建/查找结构体, - # 该方法内部会检查 typedef/enum 等并返回正确类型。 - # 必须在 fallback 到 i32 之前执行,否则 (ast.Import | t.CPtr) 联合转换 - # 会得到 i32* 导致字段访问 GEP 偏移错误(AccessViolation 崩溃)。 - _cand_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - candidate: ir.Type = self._get_or_create_struct(type_str, source_sha1=_cand_sha1) - if isinstance(candidate, ir.IdentifiedStructType): - result = candidate - else: - result = ir.IntType(32) - if IsPtr: - if isinstance(result, ir.VoidType): - result = ir.PointerType(ir.IntType(8)) - elif isinstance(result, ir.PointerType): - pass - else: - result = ir.PointerType(result) - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - - def _llvm_str_to_ir(self, llvm_str: str) -> ir.Type | None: - _LLVM_IR_TYPES: dict[str, ir.Type] = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - return _LLVM_IR_TYPES.get(llvm_str) - - def _basic_type_to_llvm(self, type_str: str) -> ir.Type | None: - _LLVM_IR_TYPES: dict[str, ir.Type] = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - if type_str in _LLVM_IR_TYPES: - return _LLVM_IR_TYPES[type_str] - resolved: Any = CTypeRegistry.ResolveName(type_str) - if resolved is not None: - ctype_cls: Any - ptr_level: int - ctype_cls, ptr_level = resolved - llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - # CTypeToLLVM 对 CPtr 等指针类型已返回含 * 的串(如 'i8*'), - # 此时 ptr_level 已内含在 llvm_str 中,直接解析即可 - if '*' in llvm_str: - return self._type_str_to_llvm(llvm_str) - base: ir.Type | None = self._llvm_str_to_ir(llvm_str) - if base is not None: - for _ in range(ptr_level): - if isinstance(base, ir.VoidType): - base = ir.IntType(8).as_pointer() - else: - base = ir.PointerType(base) - return base - if type_str == '*': - return ir.IntType(8) - if type_str in ('const_', 'const'): - return ir.IntType(8) - return None - - def _is_type_unsigned(self, type_str: str) -> bool: - s: str = type_str.strip() - if s.endswith('*'): - return True - if s.startswith('unsigned'): - return True - resolved: Any = CTypeRegistry.ResolveName(s) - if resolved is not None: - ctype_cls: Any - _: int - ctype_cls, _ = resolved - try: - inst: Any = ctype_cls() - if getattr(inst, 'IsSigned', None) is False: - return True - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"判断类型符号性失败: {_e}", "Exception") - return False - - def _record_var_signedness(self, name: str, type_str_or_bool: str | bool) -> None: - if isinstance(type_str_or_bool, bool): - self.var_signedness[name] = type_str_or_bool - else: - self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) - - def _is_var_unsigned(self, name: str) -> bool: - return self.var_signedness.get(name, False) - - def _check_node_unsigned(self, node: ast.AST) -> bool: - if isinstance(node, ast.Name): - return self._is_var_unsigned(node.id) - if isinstance(node, ast.BinOp): - return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) - if isinstance(node, ast.UnaryOp): - return self._check_node_unsigned(node.operand) - if isinstance(node, ast.Call): - return self._check_call_unsigned(node) - if isinstance(node, ast.Subscript): - return self._check_node_unsigned(node.value) - if isinstance(node, ast.Attribute): - # 检查是否为结构体字段,并查询其符号性 - field_signed: bool | None = self._check_attribute_signedness(node) - if field_signed is not None: - return not field_signed # IsSigned=False 表示无符号 → 返回 True - return self._check_node_unsigned(node.value) - return False - - def _check_call_unsigned(self, node: ast.Call) -> bool: - """推断函数调用返回值的无符号性。 - - 修复:原代码对所有 Call 节点返回 False,导致函数调用返回值 - 直接参与 >>/% 等运算时丢失无符号性,退化成 ashr/srem。 - - 规则(用户确认): - - a = b 赋值时,若 a 无显式类型注解,则自动推导为 b 的类型(含符号性) - - 若 a 有显式有符号类型,b 无符号,则相当于将 b 强转为 a 的有符号类型 - - 此处仅推断 b(调用本身)的符号性,赋值时的强转由赋值逻辑处理 - """ - func_node: ast.AST = node.func - func_name: str = '' - - if isinstance(func_node, ast.Name): - # 直接调用: rdrand64() - func_name = func_node.id - elif isinstance(func_node, ast.Attribute): - # t.CUInt64T(x) 等类型转换调用 - if hasattr(func_node.value, 'id') and IsTModule(func_node.value.id, self.SymbolTable): - if self._is_type_unsigned(func_node.attr): - return True - # module.func() 形式的调用 - try: - func_name = f"{func_node.value.id}.{func_node.attr}" - except AttributeError: - return False - else: - return False - - if not func_name or not self.SymbolTable: - return False - - try: - sym_info: Any = self.SymbolTable.lookup(func_name) - except Exception: - return False - - if sym_info and isinstance(sym_info, _CTypeInfo): - if sym_info.IsFunction or sym_info.IsFuncPtr: - ret_info: Any = sym_info.FuncPtrReturn - if ret_info and isinstance(ret_info, _CTypeInfo): - # 指针类型视为无符号 - if ret_info.PtrCount > 0: - return True - # 检查返回类型的 IsUInt 属性(IsSigned is False) - if ret_info.IsUInt: - return True - elif sym_info.IsTypedef: - # 修复:typedef 强转调用(如 ULONGLONG(0x11))需要解析底层类型的无符号性 - # IsUInt 对组合类型(CType | CType 产生的 list)会失败,需多策略回退 - if sym_info.IsUInt: - return True - # 策略1:直接检查 BaseType(可能是组合类型,如 ULONGLONG = CUnsignedLong | CLong) - bt: Any = sym_info.BaseType - if isinstance(bt, (tuple, list)): - for elem in bt: - if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: - return True - elif isinstance(bt, _t.CType) and getattr(bt, 'IsSigned', None) is False: - return True - # 策略2:通过 OriginalType 解析 - if sym_info.OriginalType: - ot: Any = sym_info.OriginalType - if isinstance(ot, str): - if self._is_type_unsigned(ot): - return True - elif isinstance(ot, _CTypeInfo): - if ot.IsUInt: - return True - elif isinstance(ot, (tuple, list)): - for elem in ot: - if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: - return True - # 策略3:通过 _resolve_typedef 解析为字符串后判断 - resolved_str: str = self._resolve_typedef(func_name) - if resolved_str and self._is_type_unsigned(resolved_str): - return True - return False - - def _check_attribute_signedness(self, node: ast.Attribute) -> bool | None: - """检查 Attribute 节点是否引用具有已知符号性的结构体字段。 - - Returns: - True: 字段是有符号类型 - False: 字段是无符号类型 - None: 无法确定(非结构体字段或符号性未知) - """ - if not isinstance(node.value, ast.Name): - return None - var_name: str = node.value.id - field_name: str = node.attr - class_name: str | None = self._resolve_class_for_var(var_name) - if not class_name: - return None - signed_dict: dict[str, bool] = self.class_member_signeds.get(class_name, {}) - if field_name in signed_dict: - return signed_dict[field_name] - return None \ No newline at end of file diff --git a/App/lib/core/LLVMCG/VaArg.py b/App/lib/core/LLVMCG/VaArg.py deleted file mode 100644 index b349639..0000000 --- a/App/lib/core/LLVMCG/VaArg.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations -import llvmlite.ir as ir -from lib.core.LLVMCG.BaseGen import VaArgInstruction - - -class VaArgMixin: - - def _get_va_start_intrinsic(self) -> ir.Function: - if 'llvm.va_start' in self.functions: - return self.functions['llvm.va_start'] - ftype: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) - func: ir.Function = ir.Function(self.module, ftype, name='llvm.va_start') - self.functions['llvm.va_start'] = func - return func - - def _get_va_end_intrinsic(self) -> ir.Function: - if 'llvm.va_end' in self.functions: - return self.functions['llvm.va_end'] - ftype: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) - func: ir.Function = ir.Function(self.module, ftype, name='llvm.va_end') - self.functions['llvm.va_end'] = func - return func - - def emit_va_start(self, va_list_ptr: ir.Value) -> None: - if not self.builder: - return None - func: ir.Function = self._get_va_start_intrinsic() - i8ptr_type: ir.PointerType = ir.IntType(8).as_pointer() - if va_list_ptr.type == i8ptr_type: - self.builder.call(func, [va_list_ptr]) - else: - ptr: ir.Value = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") - self.builder.call(func, [ptr]) - return None - - def _emit_stack_align(self, alignment: int = 16) -> None: - if not self.builder: - return None - void: ir.VoidType = ir.VoidType() - asm_type: ir.FunctionType = ir.FunctionType(void, []) - mask: int = -alignment - asm_str: str = f"andq $${mask}, %rsp" - asm_func: ir.InlineAsm = ir.InlineAsm(asm_type, asm_str, "~{dirflag},~{fpsr},~{flags},~{rsp}", side_effect=True) - self.builder.call(asm_func, [], name="align_stack") - return None - - def emit_va_end(self, va_list_ptr: ir.Value) -> None: - if not self.builder: - return None - func: ir.Function = self._get_va_end_intrinsic() - i8ptr_type: ir.PointerType = ir.IntType(8).as_pointer() - if va_list_ptr.type == i8ptr_type: - self.builder.call(func, [va_list_ptr]) - else: - ptr: ir.Value = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") - self.builder.call(func, [ptr]) - return None - - def emit_va_arg(self, va_list_ptr: ir.Value, arg_type: ir.Type) -> ir.Value: - if not self.builder: - return self._ZeroConst(arg_type) - if not hasattr(self, '_va_arg_counter'): - self._va_arg_counter: int = 0 - self._va_arg_counter += 1 - is_x86_64: bool = self._platform_info['is_x86_64'] - if is_x86_64: - va_arg_type: ir.Type - if isinstance(arg_type, ir.PointerType): - va_arg_type = ir.IntType(64) - elif isinstance(arg_type, (ir.FloatType, ir.DoubleType)): - va_arg_type = ir.DoubleType() - elif isinstance(arg_type, ir.IntType) and arg_type.width < 64: - va_arg_type = ir.IntType(64) - else: - va_arg_type = arg_type - instr: ir.Instruction = VaArgInstruction(self.builder.block, va_arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') - self.builder._insert(instr) - result: ir.Value - if va_arg_type != arg_type: - if isinstance(arg_type, ir.PointerType): - result = self.builder.inttoptr(instr, arg_type, name=f'va_arg_ptr_{self._va_arg_counter}') - elif isinstance(arg_type, ir.FloatType): - result = self.builder.fptrunc(instr, arg_type, name=f'va_arg_fptrunc_{self._va_arg_counter}') - else: - result = self.builder.trunc(instr, arg_type, name=f'va_arg_trunc_{self._va_arg_counter}') - else: - result = instr - return result - else: - if isinstance(arg_type, ir.IntType) and arg_type.width < 64: - arg_type = ir.IntType(64) - instr: ir.Instruction = VaArgInstruction(self.builder.block, arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') - self.builder._insert(instr) - return instr \ No newline at end of file diff --git a/App/lib/core/LLVMCG/__init__.py b/App/lib/core/LLVMCG/__init__.py deleted file mode 100644 index 6b231e9..0000000 --- a/App/lib/core/LLVMCG/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -LLVMCG 包 - LLVM 代码生成器模块 - -将 LlvmCodeGenerator.py 拆分为多个 Mixin 模块: -- BaseGen: 基础设施(__init__、平台解析、名称修饰、函数查找) -- TypeConvert: 类型转换(CType -> LLVM IR 类型) -- StructGen: 结构体生成(struct/vtable 定义与初始化) -- MemoryOps: 内存操作(alloca/Load/store/coerce) -- ExprGen: 表达式生成(常量、二元运算、返回、printf) -- FuncGen: 函数处理(参数调整、成员偏移、函数声明) -- VaArg: 变长参数处理(va_start/va_end/va_arg) -""" - -from lib.core.LLVMCG.BaseGen import ( - BaseGenMixin, - VaArgInstruction, -) -from lib.core.LLVMCG.TypeConvert import TypeConvertMixin -from lib.core.LLVMCG.StructGen import StructGenMixin -from lib.core.LLVMCG.MemoryOps import MemoryOpsMixin -from lib.core.LLVMCG.ExprGen import ExprGenMixin -from lib.core.LLVMCG.FuncGen import FuncGenMixin -from lib.core.LLVMCG.VaArg import VaArgMixin - -__all__ = [ - 'BaseGenMixin', - 'TypeConvertMixin', - 'StructGenMixin', - 'MemoryOpsMixin', - 'ExprGenMixin', - 'FuncGenMixin', - 'VaArgMixin', - 'VaArgInstruction', -] diff --git a/App/lib/core/LLVMTypeMapper.py b/App/lib/core/LLVMTypeMapper.py deleted file mode 100644 index 0e8cbe9..0000000 --- a/App/lib/core/LLVMTypeMapper.py +++ /dev/null @@ -1,301 +0,0 @@ -"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器 - -从 SymbolTable 中提取的类型解析逻辑,职责单一: -将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。 - -原 SymbolTable 上的 4 个方法: - - _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str - - _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str - - _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str - - _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type -""" -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap -from lib.core.SymbolUtils import IsTModule, IsListAnnotation -from lib.includes import t as _t -from lib.includes.t import CTypeRegistry - - -class LLVMTypeMapper: - """AST 注解节点 → LLVM IR 类型字符串 映射器""" - - def __init__(self, symtab: SymbolTable): - self._symtab = symtab - - # ================================================================== - # 公共 API - # ================================================================== - - def get_llvm_type_str(self, node: ast.AST | None) -> str: - """将 AST 注解节点转换为 LLVM IR 类型字符串""" - if node is None: - self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32") - return 'i32' - if isinstance(node, ast.Name): - return self._resolve_name(node) - elif isinstance(node, ast.Attribute): - return self._resolve_attribute(node) - elif isinstance(node, ast.Subscript): - return self._resolve_subscript(node) - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - return self._resolve_bitor(node) - elif isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return 'i8' - return 'i32' - elif isinstance(node, ast.Call): - return self._resolve_call(node) - self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32") - return 'i32' - - def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str: - """提取函数返回类型的 LLVM 字符串""" - if returns_node is None: - return 'i32' - if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(returns_node.left) - right_str: str = self.get_llvm_type_str(returns_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - return left_str - result: str = self.get_llvm_type_str(returns_node) - return result if result else 'i32' - - def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str: - """提取函数参数类型的 LLVM 字符串""" - if annotation_node is None: - return 'i8*' - if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(annotation_node.left) - right_str: str = self.get_llvm_type_str(annotation_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - return right_str if right_str else left_str - result: str = self.get_llvm_type_str(annotation_node) - return result if result else 'i8*' - - def resolve_typedef_value_type(self, node: ast.AST | None) -> str: - """解析 typedef 值表达式的 C 类型字符串""" - if node is None: - return '' - if isinstance(node, ast.Name): - if node.id in self._symtab: - Entry: CTypeInfo = self._symtab[node.id] - if Entry.IsTypedef and Entry.OriginalType: - return Entry.OriginalType - return '' - if isinstance(node, ast.Attribute): - if isinstance(node.value, ast.Name) and IsTModule(node.value.id): - # 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖) - if node.attr == 'CPtr': - return 'ptr' - CName: str | None = CTypeHelper.GetCName(node.attr) - if CName == 'CPtr': - return 'ptr' - if CName: - return CName - return '' - if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_str: str = self.resolve_typedef_value_type(node.left) - right_str: str = self.resolve_typedef_value_type(node.right) - if right_str == 'ptr' or (right_str and right_str.endswith('*')): - base: str = left_str if left_str and left_str != 'ptr' else '' - return base + ' *' if base else 'void *' - if left_str == 'ptr' or (left_str and left_str.endswith('*')): - base: str = right_str if right_str and right_str != 'ptr' else '' - return base + ' *' if base else 'void *' - if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'): - return right_str - if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'): - return left_str - return left_str if left_str else right_str - return '' - - # ================================================================== - # 内部解析方法 - # ================================================================== - - def _ctype_to_llvm_str(self, info: CTypeInfo) -> str: - """从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。 - - void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。 - """ - if not info or not info.BaseType: - return '' - base_type = info.BaseType - base_llvm: str = '' - if isinstance(base_type, type) and issubclass(base_type, _t.CType): - base_llvm = CTypeRegistry.CTypeToLLVM(base_type) - elif isinstance(base_type, _t.CType): - base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type)) - if not base_llvm: - return '' - if info.PtrCount > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * info.PtrCount - return base_llvm - - def _ctype_str_to_llvm(self, type_str: str) -> str: - """将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*') - - 支持: - - C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8' - - 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*' - - 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*' - 无法识别返回空字符串。 - """ - s: str = type_str.strip() - ptr_count: int = 0 - while s.endswith('*'): - ptr_count += 1 - s = s[:-1].strip() - base_llvm: str = '' - if s in ('void', 'CVoid'): - base_llvm = 'void' - else: - base_llvm = CTypeRegistry.NameToLLVM(s) - if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'): - base_llvm = s - if not base_llvm: - return '' - if ptr_count > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * ptr_count - return base_llvm - - def _resolve_name(self, node: ast.Name) -> str: - """解析 ast.Name 节点""" - id_map: dict[str, str] = { - 'str': 'i8*', 'int': 'i32', 'bool': 'i8', - 'float': 'double', 'None': 'void', - 'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*', - 'UINT16PTR': 'i16*', 'INT16PTR': 'i16*', - 'UINT32PTR': 'i32*', 'INT32PTR': 'i32*', - 'UINT64PTR': 'i64*', 'INT64PTR': 'i64*', - } - if node.id in id_map: - return id_map[node.id] - # 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名 - builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id) - if builtin_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = builtin_entry - base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass) - if base_ptr > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * base_ptr - return base_llvm if base_llvm else 'i32' - # 查找 SymbolTable 中的 typedef - if node.id in self._symtab: - entry: CTypeInfo = self._symtab[node.id] - if entry and entry.IsTypedef: - # 优先用 OriginalType 解析 - if entry.OriginalType: - if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: - return 'i8*' - elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: - # 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString() - resolved: str = self._ctype_to_llvm_str(entry.OriginalType) - if resolved: - return resolved - return entry.OriginalType.ToString() - elif isinstance(entry.OriginalType, str): - # 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串 - llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType) - if llvm_str: - return llvm_str - # OriginalType 为空或字符串无法转换时,回退到 BaseType - if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0): - resolved = self._ctype_to_llvm_str(entry) - if resolved: - return resolved - self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32") - return 'i32' - - def _resolve_attribute(self, node: ast.Attribute) -> str: - """解析 ast.Attribute 节点""" - attr_name: str = node.attr if hasattr(node, 'attr') else '' - llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name) - if llvm_str is not None: - return llvm_str - if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'): - return '' - if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'): - return 'i8*' - if attr_name == 'CVoidPtr': - return 'i8*' - if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class: - return f'%struct.{attr_name}*' - if attr_name and attr_name not in CTypeRegistry._name_to_class: - return f'%struct.{attr_name}*' - self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32") - return 'i32' - - def _resolve_subscript(self, node: ast.Subscript) -> str: - """解析 ast.Subscript 节点""" - if isinstance(node.value, ast.Name) and node.value.id == 'tuple': - slice_node: ast.AST = node.slice - elem_types: list[str] = [] - if isinstance(slice_node, ast.Tuple): - elt: ast.AST - for elt in slice_node.elts: - elem_types.append(self.get_llvm_type_str(elt)) - else: - elem_types.append(self.get_llvm_type_str(slice_node)) - if elem_types: - return '{ ' + ', '.join(elem_types) + ' }' - if IsListAnnotation(node): - slice_node: ast.AST = node.slice - elem_type: str - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: - elem_type = self.get_llvm_type_str(slice_node.elts[0]) - else: - elem_type = self.get_llvm_type_str(slice_node) - return elem_type + '*' - self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32") - return 'i32' - - def _resolve_bitor(self, node: ast.BinOp) -> str: - """解析 ast.BinOp(BitOr) 节点""" - left: str = self.get_llvm_type_str(node.left) - right: str = self.get_llvm_type_str(node.right) - if right and right.endswith('*'): - return right - if left and left.endswith('*'): - return left - if left and left not in ('i32', 'void', 'i64'): - return left - if right and right not in ('i32', 'void', 'i64'): - return right - return left if left else right - - def _resolve_call(self, node: ast.Call) -> str: - """解析 ast.Call 节点""" - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id): - return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) - self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32") - return 'i32' diff --git a/App/lib/core/LlvmCodeGenerator.py b/App/lib/core/LlvmCodeGenerator.py deleted file mode 100644 index b09db65..0000000 --- a/App/lib/core/LlvmCodeGenerator.py +++ /dev/null @@ -1,45 +0,0 @@ -# LLVM 代码生成器主类 -# 通过 Mixin 模式组合各功能模块,保持向后兼容的导入路径 -# -# 拆分后的模块位于 lib/core/LLVMCG/ 目录下: -# - BaseGen.py: __init__、平台解析、名称修饰、函数查找 -# - TypeConvert.py: 类型转换(CType -> LLVM IR) -# - StructGen.py: 结构体生成(struct/vtable) -# - MemoryOps.py: 内存操作(alloca/Load/store) -# - ExprGen.py: 表达式生成(常量、二元运算、返回) -# - FuncGen.py: 函数处理(参数调整、成员偏移) -# - VaArg.py: 变长参数处理 -from __future__ import annotations - -from lib.core.LLVMCG.BaseGen import BaseGenMixin -from lib.core.LLVMCG.TypeConvert import TypeConvertMixin -from lib.core.LLVMCG.StructGen import StructGenMixin -from lib.core.LLVMCG.MemoryOps import MemoryOpsMixin -from lib.core.LLVMCG.ExprGen import ExprGenMixin -from lib.core.LLVMCG.FuncGen import FuncGenMixin -from lib.core.LLVMCG.VaArg import VaArgMixin - -# from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin - - -class LlvmCodeGenerator( - BaseGenMixin, - TypeConvertMixin, - StructGenMixin, - MemoryOpsMixin, - ExprGenMixin, - FuncGenMixin, - VaArgMixin, -): - """LLVM IR 代码生成器 - - 通过 Mixin 模式组合各功能模块。 - 实际方法实现分布在 lib/core/LLVMCG/ 下的各模块中。 - """ - #builder: ir.IRBuilder = None - #_Trans: LlvmGeneratorMixin = None - pass - - -# 向后兼容:重新导出常量和辅助类 -__all__: list[str] = ['LlvmCodeGenerator', 'VaArgInstruction'] diff --git a/App/lib/core/Phase1.py b/App/lib/core/Phase1.py index 2d88870..e226eca 100644 --- a/App/lib/core/Phase1.py +++ b/App/lib/core/Phase1.py @@ -18,6 +18,7 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.Handles.HandlesImports as HandlesImports import lib.core.IncludesScanner as IncludesScanner import lib.core.StubMerger as StubMerger +import lib.core.BuildPipeline as BuildPipeline import lib.Projectrans.Config as Config import lib.StubGen.Converter as StubConverter @@ -53,6 +54,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdio.printf("[Phase1] includes_dir 或 temp_dir 为空,跳过\n") return 1 + # 确保 temp 目录存在(build_dir/temp 可能尚未创建) + BuildPipeline.ensure_dir(temp_dir) + if log is not None: log.banner("Phase1: 扫描 includes(按需翻译)") @@ -178,9 +182,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 生成 .deps.txt(记录依赖模块名,供依赖图按需翻译使用) td_len_a: t.CSizeT = string.strlen(temp_dir) - deps_path_a: bytes = stdlib.malloc(td_len_a + 32) + deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt") if deps_path_a is not None: - viperlib.snprintf(deps_path_a, td_len_a + 32, "%s/%s.deps.txt", temp_dir, sha1_a) df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) if not df_a.closed: if tr_a._imported_modules is not None: @@ -356,20 +359,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 构造 stub 路径: {temp_dir}/{sha1}.stub.ll dir_len: t.CSizeT = string.strlen(temp_dir) sha1_len: t.CSizeT = string.strlen(sha1) - stub_path: bytes = stdlib.malloc(dir_len + sha1_len + 16) + stub_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "stub.ll") if stub_path is None: failed += 1 continue - viperlib.snprintf(stub_path, dir_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, sha1) # 检查 stub 是否已存在(按需翻译:跳过已存在的) sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) if not sf.closed: sf.close() # 检查 text.ll 是否也存在(虚表扫描需要 text.ll) - text_path: bytes = stdlib.malloc(dir_len + sha1_len + 16) + text_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "text.ll") if text_path is not None: - viperlib.snprintf(text_path, dir_len + sha1_len + 16, "%s/%s.text.ll", temp_dir, sha1) tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) if not tf.closed: tf.close() @@ -442,9 +443,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, if pyi_buf is not None: pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE) if pyi_pos > 0: - pyi_path: bytes = stdlib.malloc(dir_len + 32) + pyi_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "pyi") if pyi_path is not None: - viperlib.snprintf(pyi_path, dir_len + 32, "%s/%s.pyi", temp_dir, sha1) pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W) if not pf.closed: pf.write(pyi_buf, pyi_pos) @@ -490,9 +490,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # save stub.ll dir_len_p1: t.CSizeT = string.strlen(temp_dir) - stub_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + stub_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll") if stub_path_p1 is not None: - viperlib.snprintf(stub_path_p1, dir_len_p1 + 32, "%s/%s.stub.ll", temp_dir, sha1) sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W) if not sf_p1.closed: sf_p1.write(stub_buf, stub_len) @@ -514,9 +513,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, text_len: t.CSizeT = string.strlen(text_buf) # save text.ll - text_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + text_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll") if text_path_p1 is not None: - viperlib.snprintf(text_path_p1, dir_len_p1 + 32, "%s/%s.text.ll", temp_dir, sha1) tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W) if not tf_p1.closed: tf_p1.write(text_buf, text_len) @@ -525,9 +523,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(text_buf) # save dependencies (_imported_modules) for Phase B - deps_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + deps_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt") if deps_path_p1 is not None: - viperlib.snprintf(deps_path_p1, dir_len_p1 + 32, "%s/%s.deps.txt", temp_dir, sha1) df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W) if not df_p1.closed: if tr._imported_modules is not None: diff --git a/App/lib/core/Phase2.py b/App/lib/core/Phase2.py index d3e18d4..ab6bb64 100644 --- a/App/lib/core/Phase2.py +++ b/App/lib/core/Phase2.py @@ -313,10 +313,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB) stub_len_a: t.CSizeT = string.strlen(stub_buf_a) - # save stub.ll - stub_path_a: bytes = stdlib.malloc(td_len_pa + 32) + # save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll) + stub_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll") if stub_path_a is not None: - viperlib.snprintf(stub_path_a, td_len_pa + 32, "%s/%s.stub.ll", temp_dir, ent.Sha1) sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W) if not sf_a.closed: sf_a.write(stub_buf_a, stub_len_a) @@ -331,10 +330,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT) text_len_a: t.CSizeT = string.strlen(text_buf_a) - # save text.ll - text_path_a: bytes = stdlib.malloc(td_len_pa + 32) + # save text.ll (切片路径) + text_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll") if text_path_a is not None: - viperlib.snprintf(text_path_a, td_len_pa + 32, "%s/%s.text.ll", temp_dir, ent.Sha1) tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W) if not tf_a.closed: tf_a.write(text_buf_a, text_len_a) @@ -342,10 +340,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, stdlib.free(text_path_a) stdlib.free(text_buf_a) - # save dependencies (_imported_modules) for Phase B - deps_path_a: bytes = stdlib.malloc(td_len_pa + 32) + # save dependencies (_imported_modules) for Phase B (切片路径) + deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt") if deps_path_a is not None: - viperlib.snprintf(deps_path_a, td_len_pa + 32, "%s/%s.deps.txt", temp_dir, ent.Sha1) df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) if not df_a.closed: if tr_a._imported_modules is not None: @@ -412,26 +409,34 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # 构造 .obj 路径,检测是否是 main 模块(test_main.py 或 main.py) od_len: t.CSizeT = string.strlen(output_dir) - sha1_len: t.CSizeT = string.strlen(ent.Sha1) - need: t.CSizeT = od_len + 1 + sha1_len + 6 is_main_mod: int = 0 if string.strstr(ent.Path, "test_main.py") is not None: is_main_mod = 1 elif string.strstr(ent.Path, "main.py") is not None: is_main_mod = 1 - if is_main_mod != 0: - viperlib.snprintf(main_obj_path, 512, "%s/%s.obj", output_dir, ent.Sha1) - else: - if obj_pos + need < OBJ_PATHS_SIZE: - if obj_pos > 0: - obj_paths[obj_pos] = ' ' - obj_pos += 1 - viperlib.snprintf(obj_paths + obj_pos, need, "%s/%s.obj", output_dir, ent.Sha1) - obj_pos += od_len + 1 + sha1_len + 4 - obj_paths[obj_pos] = '\0' + # 切片路径: output_dir/{sha1前缀}/{sha1}.obj + obj_path_sliced: str = StubMerger._sliced_path(output_dir, od_len, ent.Sha1, "obj") + if obj_path_sliced is not None: + op_sliced_len: t.CSizeT = string.strlen(obj_path_sliced) + if is_main_mod != 0: + # main 模块: 复制到 main_obj_path(确保链接时 main 在最前) + if op_sliced_len < 512: + string.strcpy(main_obj_path, obj_path_sliced) + else: + stdio.printf("[Phase B] 警告: main_obj_path 缓冲区不足\n") else: - stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n") + # 其他模块: 追加到 obj_paths + if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + string.strcpy(obj_paths + obj_pos, obj_path_sliced) + obj_pos += op_sliced_len + obj_paths[obj_pos] = '\0' + else: + stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n") + stdlib.free(obj_path_sliced) stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count) @@ -518,9 +523,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # 检查是否为声明文件(只有 declare 没有实质 define) # 判断方法: text.ll 中若有混淆函数 define(含 @\")则为实现文件 is_decl_mi: int = -1 - tpath_mi: bytes = stdlib.malloc(td_len_mi + 32) + tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") if tpath_mi is not None: - viperlib.snprintf(tpath_mi, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi) tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R) if not tf_mi.closed: is_decl_mi = 1 @@ -574,28 +578,26 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi) if tr_mi is not None: PBP_IR_SIZE: t.CSizeT = 262144 - # 保存 stub.ll + # 保存 stub.ll (切片路径) inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE) if inc_stub_buf is not None: tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB) inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf) - inc_stub_path: bytes = stdlib.malloc(td_len_mi + 32) + inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll") if inc_stub_path is not None: - viperlib.snprintf(inc_stub_path, td_len_mi + 32, "%s/%s.stub.ll", temp_dir, inc_sha1_mi) isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W) if not isf.closed: isf.write(inc_stub_buf, inc_stub_len) isf.close() stdlib.free(inc_stub_path) stdlib.free(inc_stub_buf) - # 保存 text.ll + # 保存 text.ll (切片路径) inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE) if inc_text_buf is not None: tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT) inc_text_len: t.CSizeT = string.strlen(inc_text_buf) - inc_text_path: bytes = stdlib.malloc(td_len_mi + 32) + inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") if inc_text_path is not None: - viperlib.snprintf(inc_text_path, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi) itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W) if not itf.closed: itf.write(inc_text_buf, inc_text_len) @@ -622,17 +624,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, inc_compiled += 1 - # 添加到 obj_paths + # 添加到 obj_paths (切片路径) od_len_mi: t.CSizeT = string.strlen(output_dir) - sha1_len_mi: t.CSizeT = 16 - need_mi: t.CSizeT = od_len_mi + 1 + sha1_len_mi + 6 - if obj_pos + need_mi < OBJ_PATHS_SIZE: - if obj_pos > 0: - obj_paths[obj_pos] = ' ' - obj_pos += 1 - viperlib.snprintf(obj_paths + obj_pos, need_mi, "%s/%s.obj", output_dir, inc_sha1_mi) - obj_pos += od_len_mi + 1 + sha1_len_mi + 4 - obj_paths[obj_pos] = '\0' + inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj") + if inc_obj_sliced is not None: + inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced) + if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + string.strcpy(obj_paths + obj_pos, inc_obj_sliced) + obj_pos += inc_obj_len + obj_paths[obj_pos] = '\0' + stdlib.free(inc_obj_sliced) stdio.printf("[Phase B+] 编译缺失 includes: %d 个\n", inc_compiled) diff --git a/App/lib/core/StubMerger.py b/App/lib/core/StubMerger.py index fe6a424..bfd12c0 100644 --- a/App/lib/core/StubMerger.py +++ b/App/lib/core/StubMerger.py @@ -15,6 +15,8 @@ import lib.core.IncludesScanner as IncludesScanner import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesImports as HandlesImports import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.BuildPipeline as BuildPipeline +import lib.Projectrans.Config as Config # ============================================================ @@ -42,6 +44,178 @@ STUB_READ_BUF_SIZE: t.CDefine = 262144 MAX_INCLUDES: t.CDefine = 256 +# ============================================================ +# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free) +# +# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录: +# level=0 → {temp_dir}/{sha1}.{ext} +# level=1 → {temp_dir}/b7/{sha1}.{ext} +# level=2 → {temp_dir}/b7/90/{sha1}.{ext} +# +# 自动调用 BuildPipeline.ensure_dir 创建子目录(level>0 时)。 +# +# Args: +# temp_dir: 基础目录 +# td_len: temp_dir 长度(避免重复 strlen) +# sha1: SHA1 字符串 +# ext: 文件扩展名(如 "stub.ll") +# +# Returns: +# 完整路径(stdlib.malloc 分配,需 stdlib.free),None 失败 +# ============================================================ +def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str: + """构建切片路径(stdlib.malloc 分配,调用者负责 free) + + level>0 时自动调用 ensure_dir 创建子目录。 + """ + if temp_dir is None or sha1 is None or ext is None: + return None + sha1_len: t.CSizeT = string.strlen(sha1) + ext_len: t.CSizeT = string.strlen(ext) + + # 子目录前缀缓冲区(最多 3 层 = 8 字节 + null = 16 足够) + SUBDIR_BUF_SIZE: t.CSizeT = 16 + subdir_buf: bytes = stdlib.malloc(SUBDIR_BUF_SIZE) + if subdir_buf is None: + return None + subdir_buf[0] = '\0' + sub_len: t.CSizeT = 0 + level: int = Config.Sha1SliceLevel + if level > 0: + li: int = 0 + while li < level: + if li > 0: + subdir_buf[sub_len] = '/' + sub_len += 1 + idx: int = li * 2 + subdir_buf[sub_len] = sha1[idx] + subdir_buf[sub_len + 1] = sha1[idx + 1] + sub_len += 2 + li += 1 + subdir_buf[sub_len] = '\0' + + # 确保子目录存在: {temp_dir}/{subdir} + # 不创建目录会导致 fileio.File(MODE.W) 静默失败(file.closed==True), + # 进而 BuildCombinedIR 读不到文件返回 0("BuildCombinedIR 失败")。 + dir_path_len: t.CSizeT = td_len + sub_len + 2 + dir_path: bytes = stdlib.malloc(dir_path_len) + if dir_path is not None: + viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf) + BuildPipeline.ensure_dir(dir_path) + stdlib.free(dir_path) + + # 构建完整路径 + path: str = None + path_len: t.CSizeT = 0 + if sub_len > 0: + path_len = td_len + sub_len + sha1_len + ext_len + 4 + path = stdlib.malloc(path_len) + if path is not None: + viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext) + else: + path_len = td_len + sha1_len + ext_len + 3 + path = stdlib.malloc(path_len) + if path is not None: + viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext) + + stdlib.free(subdir_buf) + return path + + +# ============================================================ +# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1 +# +# 根据 level 递归扫描子目录: +# level=0 → 扫描 {base_dir}/*.stub.ll,从文件名提取 SHA1 +# level>0 → 扫描 {base_dir}/* 的子目录,对每个子目录递归调用 +# +# Args: +# base_dir: 当前扫描目录 +# bd_len: base_dir 长度 +# level: 剩余递归层数 +# out_arr: 输出数组(每个 SHA1 17 字节 = 16字符 + null) +# out_count: 当前已收集数量 +# max_count: 最大数量 +# +# Returns: +# 收集后的总数量 +# ============================================================ +def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int, + out_arr: str, out_count: int, max_count: int) -> int: + """递归扫描子目录,收集 .stub.ll 文件的 SHA1""" + if base_dir is None or out_arr is None: + return out_count + if out_count >= max_count: + return out_count + + find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + return out_count + string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) + + if level <= 0: + # 扫描 {base_dir}/*.stub.ll + pattern: bytes = stdlib.malloc(bd_len + 16) + if pattern is None: + stdlib.free(find_data) + return out_count + viperlib.snprintf(pattern, bd_len + 16, "%s/*.stub.ll", base_dir) + handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) + stdlib.free(pattern) + if handle != win32base.INVALID_HANDLE_VALUE: + while 1: + if out_count >= max_count: + break + fname: str = find_data.cFileName + if fname is not None: + if fname[0] != '\0': + # 从文件名提取 SHA1(前 16 字符) + string.strncpy(out_arr + out_count * 17, fname, 16) + out_arr[out_count * 17 + 16] = '\0' + out_count += 1 + if win32file.FindNextFileA(handle, find_data) == 0: + break + win32file.FindClose(handle) + else: + # 扫描 {base_dir}/* 的子目录 + pattern = stdlib.malloc(bd_len + 4) + if pattern is None: + stdlib.free(find_data) + return out_count + viperlib.snprintf(pattern, bd_len + 4, "%s/*", base_dir) + handle = win32file.FindFirstFileA(pattern, find_data) + stdlib.free(pattern) + if handle != win32base.INVALID_HANDLE_VALUE: + while 1: + # 检查是否是目录(FILE_ATTRIBUTE_DIRECTORY = 0x10 = 16) + attrs: t.CUInt32T = find_data.dwFileAttributes + if (attrs & 16) != 0: + fname = find_data.cFileName + if fname is not None: + # 跳过 "." 和 ".." + is_dot: int = 0 + if fname[0] == '.': + if fname[1] == '\0': + is_dot = 1 + elif fname[1] == '.' and fname[2] == '\0': + is_dot = 1 + if is_dot == 0: + # 构建子目录路径并递归扫描 + fname_len: t.CSizeT = string.strlen(fname) + sub_dir: str = stdlib.malloc(bd_len + fname_len + 2) + if sub_dir is not None: + viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname) + sub_dir_len: t.CSizeT = string.strlen(sub_dir) + out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count) + stdlib.free(sub_dir) + if win32file.FindNextFileA(handle, find_data) == 0: + break + win32file.FindClose(handle) + + stdlib.free(find_data) + return out_count + + # ============================================================ # _load_includes_sha1_set - 读取 _sha1_map.txt,收集 includes/ 开头的 SHA1 # @@ -381,11 +555,9 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: return out_pos - sha1_len: t.CSizeT = string.strlen(dep_sha1) - dep_path: bytes = stdlib.malloc(td_len + sha1_len + 16) + dep_path: str = _sliced_path(temp_dir, td_len, dep_sha1, "stub.ll") if dep_path is None: return out_pos - viperlib.snprintf(dep_path, td_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, dep_sha1) df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R) if df_ls.closed: stdlib.free(dep_path) @@ -541,11 +713,9 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: return out_pos - sha1_len_lt: t.CSizeT = string.strlen(dep_sha1) - text_path: bytes = stdlib.malloc(td_len + sha1_len_lt + 16) + text_path: str = _sliced_path(temp_dir, td_len, dep_sha1, "text.ll") if text_path is None: return out_pos - viperlib.snprintf(text_path, td_len + sha1_len_lt + 16, "%s/%s.text.ll", temp_dir, dep_sha1) tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) if tf_lt.closed: stdlib.free(text_path) @@ -1106,9 +1276,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1) # 读取 .deps.txt 追加到 worklist - deps_path: bytes = stdlib.malloc(td_len_r + 33) + deps_path: str = _sliced_path(temp_dir, td_len_r, found_sha1, "deps.txt") if deps_path is not None: - viperlib.snprintf(deps_path, td_len_r + 33, "%s/%s.deps.txt", temp_dir, found_sha1) df: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) if not df.closed: deps_buf: bytes = stdlib.malloc(2048) @@ -1162,10 +1331,9 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, out_pos: t.CSizeT = 0 # 1. 读取并追加本地 stub.ll(含 header) - stub_path: bytes = stdlib.malloc(td_len + 32) + stub_path: str = _sliced_path(temp_dir, td_len, local_sha1, "stub.ll") if stub_path is None: return 0 - viperlib.snprintf(stub_path, td_len + 32, "%s/%s.stub.ll", temp_dir, local_sha1) sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) if sf.closed: stdlib.free(stub_path) @@ -1229,9 +1397,8 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, # 2b. 读取 deps.txt 获取导入模块名集合 deps_buf: str = None deps_loaded: int = 0 - deps_path: bytes = stdlib.malloc(td_len + 32) + deps_path: str = _sliced_path(temp_dir, td_len, local_sha1, "deps.txt") if deps_path is not None: - viperlib.snprintf(deps_path, td_len + 32, "%s/%s.deps.txt", temp_dir, local_sha1) df_deps: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) if not df_deps.closed: deps_buf = stdlib.malloc(4096) @@ -1246,52 +1413,41 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, df_deps.close() stdlib.free(deps_path) - # 2c. 扫描 temp_dir 中所有 .stub.ll,按需加载 - pattern: bytes = stdlib.malloc(td_len + 16) - if pattern is not None: - viperlib.snprintf(pattern, td_len + 16, "%s/*.stub.ll", temp_dir) - find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) - if find_data is not None: - string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) - handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) - if handle != win32base.INVALID_HANDLE_VALUE: - dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) - if dep_buf is not None: - while 1: - fname: str = find_data.cFileName - if fname is not None: - dep_sha1: str = stdlib.malloc(17) - if dep_sha1 is not None: - string.strncpy(dep_sha1, fname, 16) - dep_sha1[16] = '\0' - if string.strcmp(dep_sha1, local_sha1) != 0: - should_load: int = 0 - # 检查是否在 includes 映射中 - is_include: int = 0 - if inc_count > 0: - for ii in range(inc_count): - idx_ii: t.CSizeT = t.CSizeT(ii) * 17 - if string.strcmp(sha1_arr + idx_ii, dep_sha1) == 0: - is_include = 1 - if deps_loaded != 0: - idx_mi: t.CSizeT = t.CSizeT(ii) * 64 - if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0: - should_load = 1 - break - if is_include == 0: - # 非 includes stub(用户文件),总是加载 - should_load = 1 - if should_load != 0: - out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) - out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) - stdlib.free(dep_sha1) - if win32file.FindNextFileA(handle, find_data) == 0: - break - if dep_buf is not None: - stdlib.free(dep_buf) - win32file.FindClose(handle) - stdlib.free(find_data) - stdlib.free(pattern) + # 2c. 递归扫描 temp_dir 中所有 .stub.ll,按需加载 + all_sha1_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17) + all_count: int = 0 + if all_sha1_arr is not None: + string.memset(all_sha1_arr, 0, MAX_INCLUDES_SHA1 * 17) + all_count = _collect_stub_sha1s(temp_dir, td_len, Config.Sha1SliceLevel, all_sha1_arr, 0, MAX_INCLUDES_SHA1) + if all_count > 0: + dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if dep_buf is not None: + si: int = 0 + while si < all_count: + dep_sha1: str = all_sha1_arr + t.CSizeT(si) * 17 + if string.strcmp(dep_sha1, local_sha1) != 0: + should_load: int = 0 + # 检查是否在 includes 映射中 + is_include: int = 0 + if inc_count > 0: + for ii in range(inc_count): + idx_ii: t.CSizeT = t.CSizeT(ii) * 17 + if string.strcmp(sha1_arr + idx_ii, dep_sha1) == 0: + is_include = 1 + if deps_loaded != 0: + idx_mi: t.CSizeT = t.CSizeT(ii) * 64 + if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0: + should_load = 1 + break + if is_include == 0: + # 非 includes stub(用户文件),总是加载 + should_load = 1 + if should_load != 0: + out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + si += 1 + stdlib.free(dep_buf) + stdlib.free(all_sha1_arr) # 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在(fail-fast) # 避免到 llc 才报 undefined value 错误。 @@ -1332,9 +1488,8 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, break if found_s is not None: # 检查 stub 文件是否存在 - chk_path: bytes = stdlib.malloc(td_len + 32) + chk_path: str = _sliced_path(temp_dir, td_len, found_s, "stub.ll") if chk_path is not None: - viperlib.snprintf(chk_path, td_len + 32, "%s/%s.stub.ll", temp_dir, found_s) chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R) if chk_f.closed: stdio.printf("[FATAL][BuildCombinedIR] 依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译\n", mod_nm, found_s, chk_path) @@ -1344,10 +1499,9 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str, stdlib.free(mod_nm) # 3. 读取并追加本地 text.ll(行级去重,跳过 stub.ll 中已存在的定义) - text_path: bytes = stdlib.malloc(td_len + 32) + text_path: str = _sliced_path(temp_dir, td_len, local_sha1, "text.ll") if text_path is None: return out_pos - viperlib.snprintf(text_path, td_len + 32, "%s/%s.text.ll", temp_dir, local_sha1) tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) if tf.closed: stdlib.free(text_path) diff --git a/App/lib/core/SymbolData.py b/App/lib/core/SymbolData.py deleted file mode 100644 index c422de0..0000000 --- a/App/lib/core/SymbolData.py +++ /dev/null @@ -1,85 +0,0 @@ -"""符号表处理的数据结构:四阶段管线中传递的中间数据""" -from __future__ import annotations -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING -import ast - -if TYPE_CHECKING: - from lib.core.Handles.HandlesBase import CTypeInfo - - -@dataclass -class ClassSymbolData: - """从 AST 提取的类符号数据""" - name: str - type_kind: str # 'struct', 'union', 'enum', 'exception' - lineno: int - members: Dict[str, CTypeInfo] - is_cpython_object: bool = False - is_packed: bool = False - enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno) - - -@dataclass -class TypedefSymbolData: - """Typedef 符号数据(含原始注解和解析结果)""" - name: str - lineno: int - # 原始注解数据(由 Extractor 设置,Resolver 使用) - annotation: ast.expr | None = None - value: ast.expr | int | str | float | None = None - has_cdefine: bool = False - has_postdef: bool = False - has_ctypedef: bool = False - # 解析结果(由 Resolver 设置,Inserter 使用) - original_type_kind: Optional[str] = None - original_class: type | None = None - members: Optional[Dict] = None - - -@dataclass -class FuncSymbolData: - """函数符号数据(含原始注解和解析结果)""" - name: str - lineno: int - # 原始数据(由 Extractor 设置) - returns_node: ast.expr | None = None - params: List = field(default_factory=list) # [(name, annotation_node), ...] - is_variadic: bool = False - is_inline: bool = False - # 解析结果(由 Resolver 设置) - ret_type: str | None = None - param_types: List = field(default_factory=list) # [str, ...] - # 解析结果(CTypeInfo,保留符号性,由 Resolver 设置) - ret_ctype: Optional[CTypeInfo] = None - - -@dataclass -class DefineSymbolData: - """Define 符号数据(含原始值和解析结果)""" - name: str - lineno: int - # 原始数据(由 Extractor 设置) - value_node: ast.expr | None = None - # 解析结果(由 Resolver 设置) - value: int | str | float | None = None - - -@dataclass -class AnonymousTypeData: - """匿名类型数据""" - name: str - is_union: bool - members: Dict[str, CTypeInfo] - lineno: int - - -@dataclass -class ModuleSymbols: - """从模块提取的完整符号数据,在四阶段管线中传递""" - file_path: str - classes: List[ClassSymbolData] = field(default_factory=list) - typedefs: List[TypedefSymbolData] = field(default_factory=list) - functions: List[FuncSymbolData] = field(default_factory=list) - defines: List[DefineSymbolData] = field(default_factory=list) - anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict) diff --git a/App/lib/core/SymbolExtractor.py b/App/lib/core/SymbolExtractor.py deleted file mode 100644 index f3fba6a..0000000 --- a/App/lib/core/SymbolExtractor.py +++ /dev/null @@ -1,307 +0,0 @@ -"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息""" -from __future__ import annotations -import ast -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ( - ModuleSymbols, ClassSymbolData, TypedefSymbolData, - FuncSymbolData, DefineSymbolData, AnonymousTypeData -) -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName -from lib.includes import t - - -class ASTSymbolExtractor: - """从 Python 源文件的 AST 中提取所有符号信息""" - - def __init__(self, symbol_table: SymbolTable) -> None: - self._symtab: SymbolTable = symbol_table - - def extract(self, file_path: str) -> ModuleSymbols: - """提取文件中的所有符号信息""" - with open(file_path, 'r', encoding='utf-8') as f: - code: str = f.read() - tree: ast.Module = ast.parse(code) - - result: ModuleSymbols = ModuleSymbols(file_path=file_path) - - # 第一步:收集所有类的成员和匿名类型 - class_members: dict[str, dict[str, CTypeInfo]] = {} - for node in tree.body: - if isinstance(node, ast.ClassDef): - members: dict[str, CTypeInfo] = {} - self._collect_members(node, members, result.anonymous_types) - class_members[node.name] = members - - # 第二步:从每个顶层节点提取符号信息 - for node in tree.body: - if isinstance(node, ast.ClassDef): - members_info: dict[str, CTypeInfo] = class_members.get(node.name, {}) - result.classes.append(self._extract_class(node, members_info)) - elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - self._extract_ann_assign(node, result) - elif isinstance(node, ast.FunctionDef): - result.functions.append(self._extract_function(node)) - - return result - - # ------------------------------------------------------------------ - # 成员收集(递归处理嵌套匿名类) - # ------------------------------------------------------------------ - - def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None: - """递归收集类成员,包括嵌套匿名类型""" - for item in class_node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - member_name: str = item.target.id - full_name: str = f'{prefix}{member_name}' if prefix else member_name - member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab) - if member_type is None: - member_type = CTypeInfo() - member_type.BaseType = t.CInt() - is_ptr: bool = member_type.IsPtr - if isinstance(item.annotation, ast.BinOp): - if AnnotationContainsName(item.annotation, 'CPtr'): - is_ptr = True - members[full_name] = member_type.Copy() - - elif isinstance(item, ast.ClassDef): - is_anonymous: bool = any( - any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases) - ) if item.bases else False - - if is_anonymous: - is_union: bool = any( - any(AnnotationContainsTType(base, 'CUnion') for base in item.bases) - ) - # 也检查装饰器形式 @t.CUnion - if not is_union and hasattr(item, 'decorator_list') and item.decorator_list: - for deco in item.decorator_list: - if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion': - is_union = True - break - elif isinstance(deco, ast.Name): - cls2: type | None = getattr(t, deco.id, None) - if cls2 is None and hasattr(self._symtab, '_t_type_symbols'): - cls2 = self._symtab._t_type_symbols.get(deco.id) - if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion): - is_union = True - break - - nested_name: str = f'{prefix}{item.name}' if prefix else item.name - members[nested_name] = CTypeInfo() - members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}' - members[nested_name].PtrCount = 0 - members[nested_name].ArrayDims = [] - - new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.' - self._collect_members(item, members, anonymous_types, new_prefix) - - anonymous_members: dict[str, CTypeInfo] = {} - for full_name, member_info in members.items(): - if full_name.startswith(f"{nested_name}."): - member_name: str = full_name[len(nested_name) + 1:] - anonymous_members[member_name] = member_info - - if item.name not in anonymous_types: - anonymous_types[item.name] = AnonymousTypeData( - name=item.name, - is_union=is_union, - members=anonymous_members, - lineno=item.lineno - ) - - # ------------------------------------------------------------------ - # 类符号提取 - # ------------------------------------------------------------------ - - def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData: - """从 ClassDef 节点提取类符号数据""" - type_kind: str = 'struct' - is_cpython_object: bool = False - is_packed: bool = False - - # 检查装饰器 - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if (hasattr(decorator.value, 'id') and - IsTModule(decorator.value.id, self._symtab)): - if decorator.attr == 'Object': - is_cpython_object = True - elif decorator.attr == 'CUnion': - type_kind = 'union' - elif decorator.attr == 'CEnum': - type_kind = 'enum' - elif decorator.attr == 'REnum': - type_kind = 'renum' - elif decorator.attr == 'CStruct': - type_kind = 'struct' - elif isinstance(decorator, ast.Name): - # from t import CStruct / CUnion / CEnum / REnum - cls: type | None = getattr(t, decorator.id, None) - if cls is None and hasattr(self._symtab, '_t_type_symbols'): - cls = self._symtab._t_type_symbols.get(decorator.id) - if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): - if issubclass(cls, t.CUnion): - type_kind = 'union' - elif issubclass(cls, t.REnum): - type_kind = 'renum' - elif issubclass(cls, t.CEnum): - type_kind = 'enum' - elif issubclass(cls, t.CStruct): - type_kind = 'struct' - elif decorator.id == 'Object': - is_cpython_object = True - elif isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute': - for arg in decorator.args: - if isinstance(arg, ast.Attribute): - if isinstance(arg.value, ast.Attribute): - if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed': - is_packed = True - - # 检查基类 - for base in node.bases: - if AnnotationContainsTType(base, 'CUnion'): - type_kind = 'union' - break - elif AnnotationContainsTType(base, 'CEnum'): - type_kind = 'enum' - break - elif AnnotationContainsTType(base, 'REnum'): - type_kind = 'renum' - break - elif AnnotationContainsTType(base, 'CStruct'): - type_kind = 'struct' - break - elif AnnotationContainsTType(base, 'Object'): - is_cpython_object = True - type_kind = 'struct' - break - elif isinstance(base, ast.Name) and base.id == 'Exception': - type_kind = 'exception' - break - elif isinstance(base, ast.Name): - base_entry: CTypeInfo | None = self._symtab.get(base.id) - if base_entry and base_entry.IsExceptionClass: - type_kind = 'exception' - break - - # 提取枚举成员 - enum_members: list[tuple[str, int, int]] = [] - if type_kind == 'enum': - next_enum_value: int = 0 - for item in node.body: - if isinstance(item, ast.Assign): - if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): - member_name: str = item.targets[0].id - if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - next_enum_value = item.value.value + 1 - else: - next_enum_value += 1 - enum_members.append((member_name, next_enum_value - 1, item.lineno)) - elif isinstance(item, ast.AnnAssign): - if isinstance(item.target, ast.Name): - member_name: str = item.target.id - if item.value: - if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - next_enum_value = item.value.value + 1 - else: - next_enum_value += 1 - else: - next_enum_value += 1 - enum_members.append((member_name, next_enum_value - 1, item.lineno)) - - # REnum 变体提取(嵌套 ClassDef + Assign 显式值) - # 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐: - # - 先收集 Assign 显式值 - # - ClassDef 变体从 max(explicit)+1 开始顺序编号 - # - Assign 无显式值时用独立计数器 variant_index - if type_kind == 'renum': - explicit_values: dict[str, int] = {} - for item in node.body: - if isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name): - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - explicit_values[target.id] = item.value.value - next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0 - variant_index: int = 0 - for item in node.body: - if isinstance(item, ast.ClassDef): - variant_name_r: str = item.name - tag: int = next_class_tag - next_class_tag += 1 - enum_members.append((variant_name_r, tag, item.lineno)) - elif isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name): - var_name: str = target.id - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - value: int = item.value.value - else: - value = variant_index - variant_index += 1 - enum_members.append((var_name, value, item.lineno)) - - return ClassSymbolData( - name=node.name, - type_kind=type_kind, - lineno=node.lineno, - members=members_info, - is_cpython_object=is_cpython_object, - is_packed=is_packed, - enum_members=enum_members, - ) - - # ------------------------------------------------------------------ - # AnnAssign 提取(typedef / define) - # ------------------------------------------------------------------ - - def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None: - """从 AnnAssign 节点提取 typedef 或 define 数据""" - var_name: str = node.target.id - has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False - has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False - has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False - - if has_cdefine: - result.defines.append(DefineSymbolData( - name=var_name, - lineno=node.lineno, - value_node=node.value, - )) - else: - result.typedefs.append(TypedefSymbolData( - name=var_name, - lineno=node.lineno, - annotation=node.annotation, - value=node.value, - has_cdefine=has_cdefine, - has_postdef=has_postdef, - has_ctypedef=has_ctypedef, - )) - - # ------------------------------------------------------------------ - # 函数提取 - # ------------------------------------------------------------------ - - def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData: - """从 FunctionDef 节点提取函数符号数据""" - params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args] - is_variadic: bool = node.args.vararg is not None - is_inline: bool = CheckAnnotationHasCInline(node.returns) - - return FuncSymbolData( - name=node.name, - lineno=node.lineno, - returns_node=node.returns, - params=params, - is_variadic=is_variadic, - is_inline=is_inline, - ) diff --git a/App/lib/core/SymbolInserter.py b/App/lib/core/SymbolInserter.py deleted file mode 100644 index 01dc3a1..0000000 --- a/App/lib/core/SymbolInserter.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Pass 3: SymbolInserter — 将解析后的符号插入 SymbolTable(主命名空间)""" -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ModuleSymbols - - -class SymbolInserter: - """将解析后的符号插入 SymbolTable 的主命名空间(无前缀)""" - - def __init__(self, symbol_table: SymbolTable) -> None: - self._symtab: SymbolTable = symbol_table - self._namespace: str | None = None - - def set_namespace(self, namespace: str) -> None: - """设置当前模块的命名空间""" - self._namespace = namespace - self._symtab.register_namespace(namespace) - - def insert(self, module_symbols: ModuleSymbols) -> list[str]: - """插入所有符号到主命名空间,返回已加载的符号名列表""" - loaded: list[str] = [] - file_path: str = module_symbols.file_path - ns: dict[str, object] = self._symtab._namespaces.get(self._namespace, {}) if self._namespace else {} - - # 插入类符号 - for cls in module_symbols.classes: - self._symtab._InsertClassSymbol( - cls.name, cls.type_kind, cls.lineno, file_path, - cls.members, cls.is_cpython_object, cls.is_packed - ) - loaded.append(cls.name) - if self._namespace: - ns[cls.name] = self._symtab._symbols[cls.name] - - # 插入枚举成员(短名 + 类名.成员名)—— CEnum 和 REnum 共用 - if cls.type_kind in ('enum', 'renum'): - for member_name, member_value, member_lineno in cls.enum_members: - self._symtab._InsertEnumMemberSymbol(member_name, cls.name, member_lineno, file_path, value=member_value) - loaded.append(member_name) - class_member_name: str = f"{cls.name}.{member_name}" - self._symtab._InsertEnumMemberSymbol(class_member_name, cls.name, member_lineno, file_path, value=member_value) - loaded.append(class_member_name) - # REnum: 记录变体名列表到类符号(供 HandlesExprCall 跨模块变体构造识别) - if cls.type_kind == 'renum': - renum_info = self._symtab._symbols[cls.name] - renum_info.RenumVariants = [m[0] for m in cls.enum_members] - - # 插入 typedef 符号 - for td in module_symbols.typedefs: - self._symtab._InsertTypedefSymbol( - td.name, td.original_type_kind, td.original_class, - td.lineno, file_path, td.members - ) - loaded.append(td.name) - if self._namespace: - ns[td.name] = self._symtab._symbols[td.name] - - # 插入函数符号 - for func in module_symbols.functions: - # 优先使用 CTypeInfo(保留符号性),回退到 LLVM 类型字符串 - ret_type = func.ret_ctype if func.ret_ctype else func.ret_type - self._symtab._InsertFuncSymbol( - func.name, ret_type, func.param_types, - func.lineno, file_path, func.is_variadic, func.is_inline - ) - loaded.append(func.name) - if self._namespace: - ns[func.name] = self._symtab._symbols[func.name] - - # 插入 define 符号 - for define in module_symbols.defines: - self._symtab._InsertDefineSymbol( - define.name, define.value, define.lineno, file_path - ) - loaded.append(define.name) - if self._namespace: - ns[define.name] = self._symtab._symbols[define.name] - - # 插入匿名类型符号(短名) - for anon_name, anon_data in module_symbols.anonymous_types.items(): - self._symtab._InsertAnonymousSymbol( - anon_name, anon_data.is_union, anon_data.members, - anon_data.lineno, file_path - ) - - return loaded diff --git a/App/lib/core/SymbolNode.py b/App/lib/core/SymbolNode.py deleted file mode 100644 index f1aa0ef..0000000 --- a/App/lib/core/SymbolNode.py +++ /dev/null @@ -1,224 +0,0 @@ -from __future__ import annotations -from typing import Any, Dict, Optional - -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.includes import t - - -class SymbolNode: - """符号表节点,类似 AST 节点的树形结构 - - attributes 存储 CTypeInfo 对象,不再使用 TypeInfo - """ - - def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None): - self.name: str = name - self.type: str = NodeType - self.lineno: int = lineno - self.file: str = file - self.parent: SymbolNode | None = parent - self.children: Dict[str, SymbolNode] = {} - self.attributes: CTypeInfo = CTypeInfo() - self.attributes.Name = name - self.attributes.Lineno = lineno - - def get(self, key: str, default: Any = None) -> Any: - """获取属性值""" - if hasattr(self.attributes, key): - return getattr(self.attributes, key) - return self.attributes._extra.get(key, default) - - def set(self, key: str, value: Any) -> None: - """设置属性值""" - if hasattr(self.attributes, key): - attr: Any = getattr(type(self.attributes), key, None) - if isinstance(attr, property) and attr.fset is None: - return - setattr(self.attributes, key, value) - else: - self.attributes._extra[key] = value - - def HasChild(self, name: str) -> bool: - """检查是否有子节点""" - return name in self.children - - def GetChild(self, name: str) -> Optional[SymbolNode]: - """获取子节点""" - return self.children.get(name) - - def AddChild(self, node: SymbolNode): - """添加子节点""" - node.parent = self - self.children[node.name] = node - - def RemoveChild(self, name: str) -> bool: - """删除子节点""" - if name in self.children: - del self.children[name] - return True - return False - - def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]: - """根据路径查找节点,如 'test.ClassA'""" - parts: list[str] = path.split(separator) - current: SymbolNode = self - - for part in parts: - if current.HasChild(part): - current = current.GetChild(part) - else: - return None - - return current - - def ToDict(self) -> Dict[str, Any]: - """转换为字典格式""" - result: dict[str, Any] = { - 'type': self.type, - 'lineno': self.lineno, - 'file': self.file, - } - # 序列化 CTypeInfo 属性 - attrs: CTypeInfo = self.attributes - if attrs.BaseType: - result['BaseType'] = str(attrs.BaseType) - if attrs.PtrCount: - result['PtrCount'] = attrs.PtrCount - if attrs.IsTypedef: - result['IsTypedef'] = True - if attrs.IsStruct: - result['IsStruct'] = True - if attrs.IsEnum: - result['IsEnum'] = True - if attrs.IsUnion: - result['IsUnion'] = True - if attrs.IsFunction: - result['IsFunction'] = True - if attrs.IsVariable: - result['IsVariable'] = True - if attrs.IsDefine: - result['IsDefine'] = True - if attrs.OriginalType: - result['OriginalType'] = str(attrs.OriginalType) - if attrs._sm._extra: - result.update(attrs._sm._extra) - - if self.children: - result['children'] = {name: child.ToDict() for name, child in self.children.items()} - - return result - - @classmethod - def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode: - """从字典创建节点(兼容性)""" - node = cls(name=name, NodeType=data.get('type', 'unknown')) - node.lineno = data.get('lineno', 0) - node.file = data.get('file', '') - - for key, value in data.items(): - if key not in ('type', 'lineno', 'file', 'children'): - node.set(key, value) - - if 'children' in data: - for ChildName, ChildData in data['children'].items(): - node.AddChild(cls.FromDict(ChildName, ChildData)) - - return node - - @classmethod - def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode: - """创建成员节点(工厂函数)""" - node = cls(name=name, NodeType='member', lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - if TypeInfo is not None: - node.attributes = TypeInfo - node.attributes.Name = name - node.attributes.Lineno = lineno - else: - if TypeName is not None: - node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName) - if IsPtr: - node.attributes.PtrCount = 1 - if dims: - node.attributes.ArrayDims = list(dims) - return node - - @classmethod - def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode: - """创建类节点(工厂函数)""" - node: SymbolNode = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsCpythonObject = IsCpythonObject - node.attributes.IsPacked = IsPacked - if members: - for MemberName, MemberInfo in members.items(): - if isinstance(MemberInfo, CTypeInfo): - node.attributes.Members[MemberName] = MemberInfo - elif isinstance(MemberInfo, dict): - CTypeMember: CTypeInfo = CTypeInfo() - type_str: str = MemberInfo.get('type', 'int') - IsPtr: bool = MemberInfo.get('IsPtr', False) - if isinstance(type_str, str): - try: - resolved: CTypeInfo | None = CTypeInfo.FromTypeName(type_str) - if resolved and resolved.BaseType: - CTypeMember = resolved - else: - CTypeMember.BaseType = t.CInt() - except Exception: - CTypeMember.BaseType = t.CInt() - else: - CTypeMember.BaseType = t.CInt() - if IsPtr and not CTypeMember.IsPtr: - CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1) - node.attributes.Members[MemberName] = CTypeMember - if TypeKind == 'struct': - node.attributes.IsStruct = True - elif TypeKind == 'enum': - node.attributes.IsEnum = True - elif TypeKind == 'union': - node.attributes.IsUnion = True - elif TypeKind == 'typedef': - node.attributes.IsTypedef = True - elif TypeKind == 'exception': - node.attributes.IsExceptionClass = True - return node - - @classmethod - def CreateTypedef(cls, name: str, OriginalType: CTypeInfo | str | None, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode: - node: SymbolNode = cls(name=name, NodeType='typedef', lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsTypedef = True - if isinstance(OriginalType, CTypeInfo): - node.attributes.OriginalType = OriginalType - elif isinstance(OriginalType, str): - node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None - else: - node.attributes.OriginalType = OriginalType - return node - - @classmethod - def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode: - """创建匿名类型节点(工厂函数)""" - NodeType: type = t.CUnion if IsUnion else t.CStruct - node: SymbolNode = cls(name=name, NodeType=NodeType, lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsAnonymous = True - if IsUnion: - node.attributes.IsUnion = True - else: - node.attributes.IsStruct = True - return node - - @classmethod - def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode: - """创建模块节点(工厂函数)""" - return cls(name=name, NodeType='module', lineno=lineno, file=file) diff --git a/App/lib/core/SymbolReexporter.py b/App/lib/core/SymbolReexporter.py deleted file mode 100644 index ae86b80..0000000 --- a/App/lib/core/SymbolReexporter.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Pass 4: PackageReexporter — 将符号重新导出到命名空间前缀下""" -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ModuleSymbols - - -class PackageReexporter: - """将已解析的符号重新导出到命名空间前缀下(如 memhub.MemPool)""" - - def __init__(self, symbol_table: SymbolTable) -> None: - self._symtab: SymbolTable = symbol_table - self._namespace: str | None = None - - def set_namespace(self, namespace: str) -> None: - """设置当前模块的命名空间""" - self._namespace = namespace - - def reexport(self, module_symbols: ModuleSymbols, prefixes: list[str], lineno: int = 0) -> list[str]: - """将符号重新导出到所有命名空间前缀下,返回新增的符号名列表""" - loaded: list[str] = [] - file_path: str = module_symbols.file_path - ns: dict[str, object] = self._symtab._namespaces.get(self._namespace, {}) if self._namespace else {} - - for prefix in prefixes: - # 插入类符号(前缀.类名) - for cls in module_symbols.classes: - full_name: str = f"{prefix}.{cls.name}" - self._symtab._InsertClassSymbol( - full_name, cls.type_kind, cls.lineno, file_path, - cls.members, cls.is_cpython_object, cls.is_packed - ) - loaded.append(full_name) - if self._namespace: - ns[full_name] = self._symtab._symbols[full_name] - - # 插入枚举成员(前缀.成员名 + 前缀.类名.成员名)—— CEnum 和 REnum 共用 - if cls.type_kind in ('enum', 'renum'): - for member_name, member_value, member_lineno in cls.enum_members: - full_member_name: str = f"{prefix}.{member_name}" - self._symtab._InsertEnumMemberSymbol(full_member_name, cls.name, member_lineno, file_path, value=member_value) - loaded.append(full_member_name) - # 同时注册 prefix.ClassName.member_name,以支持 module.Class.MEMBER 三层访问 - qualified_member_name: str = f"{prefix}.{cls.name}.{member_name}" - self._symtab._InsertEnumMemberSymbol(qualified_member_name, cls.name, member_lineno, file_path, value=member_value) - loaded.append(qualified_member_name) - # REnum: 记录变体名列表到前缀类符号 - if cls.type_kind == 'renum': - renum_info = self._symtab._symbols[full_name] - renum_info.RenumVariants = [m[0] for m in cls.enum_members] - - # 插入 typedef 符号(前缀.名称) - for td in module_symbols.typedefs: - full_name: str = f"{prefix}.{td.name}" - self._symtab._InsertTypedefSymbol( - full_name, td.original_type_kind, td.original_class, - td.lineno, file_path, td.members - ) - loaded.append(full_name) - if self._namespace: - ns[full_name] = self._symtab._symbols[full_name] - - # 插入函数符号(前缀.名称) - for func in module_symbols.functions: - full_name: str = f"{prefix}.{func.name}" - # 优先使用 CTypeInfo(保留符号性),回退到 LLVM 类型字符串 - ret_type = func.ret_ctype if func.ret_ctype else func.ret_type - self._symtab._InsertFuncSymbol( - full_name, ret_type, func.param_types, - func.lineno, file_path, func.is_variadic, func.is_inline - ) - loaded.append(full_name) - if self._namespace: - ns[full_name] = self._symtab._symbols[full_name] - - # 插入 define 符号(前缀.名称) - for define in module_symbols.defines: - full_name: str = f"{prefix}.{define.name}" - self._symtab._InsertDefineSymbol( - full_name, define.value, define.lineno, file_path - ) - loaded.append(full_name) - if self._namespace: - ns[full_name] = self._symtab._symbols[full_name] - - # 插入模块别名 - self._symtab._InsertModuleSymbol(prefix, lineno, file_path) - - # 插入匿名类型符号(前缀.名称) - for anon_name, anon_data in module_symbols.anonymous_types.items(): - full_type_name: str = f"{prefix}.{anon_name}" - self._symtab._InsertAnonymousSymbol( - full_type_name, anon_data.is_union, anon_data.members, - anon_data.lineno, file_path - ) - - return loaded diff --git a/App/lib/core/SymbolTable.py b/App/lib/core/SymbolTable.py deleted file mode 100644 index 9646b54..0000000 --- a/App/lib/core/SymbolTable.py +++ /dev/null @@ -1,531 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any, Iterator -if TYPE_CHECKING: - from lib.core.translator import Translator - -import ast -import traceback - -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.includes import t -from lib.core.VLogger import get_logger as _vlog -from lib.core.DiagnosticCollector import DiagnosticCollector -from lib.core.LLVMTypeMapper import LLVMTypeMapper -from lib.core.SymbolExtractor import ASTSymbolExtractor -from lib.core.SymbolTypeResolver import TypeResolver -from lib.core.SymbolInserter import SymbolInserter -from lib.core.SymbolReexporter import PackageReexporter -from lib.core.ConstEvaluator import ConstEvaluator -from lib.core.SymbolData import ModuleSymbols - -# 从 SymbolUtils 重导出,保持向后兼容 -from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline - - -class SymbolTable: - def __init__(self, translator: Translator) -> None: - self.translator: Translator = translator - self._symbols: dict[str, CTypeInfo] = {} - self._namespaces: dict[str, dict[str, CTypeInfo]] = {} # 模块名 -> 符号字典 - self._t_type_symbols: dict[str, type] = {} # 别名 -> t.CType 子类 (from t import CEnum as en) - self.diagnostics: DiagnosticCollector = DiagnosticCollector() - self._type_mapper: LLVMTypeMapper = LLVMTypeMapper(self) - self.import_aliases: dict[str, str] = {} # 别名 -> 模块路径 - - def __getstate__(self) -> dict: - """pickle 序列化:排除不可序列化的字段(translator/_type_mapper/diagnostics)""" - state: dict = self.__dict__.copy() - state.pop('translator', None) - state.pop('_type_mapper', None) - state.pop('diagnostics', None) - return state - - def __setstate__(self, state: dict) -> None: - """pickle 反序列化:重建可序列化的字段,translator 由调用方后续设置""" - self.__dict__.update(state) - self.translator = None # 由调用方赋值 - self.diagnostics = DiagnosticCollector() - self._type_mapper = LLVMTypeMapper(self) - - def clear(self) -> None: - self._symbols.clear() - self._namespaces.clear() - self._t_type_symbols.clear() - self.import_aliases.clear() - - def get(self, name: str, default: CTypeInfo | None = None) -> CTypeInfo | None: - return self._symbols.get(name, default) - - def set(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: - if isinstance(value, CTypeInfo): - self._symbols[name] = value - else: - # 兼容旧代码传入 dict 的情况 - info: CTypeInfo = self._CTypeInfoFromDict(name, value) - self._symbols[name] = info - - def update(self, symbols: dict[str, CTypeInfo | dict[str, Any]]) -> None: - for name, value in symbols.items(): - self.set(name, value) - - def keys(self) -> Iterator[str]: - return iter(self._symbols.keys()) - - def values(self) -> Iterator[CTypeInfo]: - return iter(self._symbols.values()) - - def items(self) -> Iterator[tuple[str, CTypeInfo]]: - return iter(self._symbols.items()) - - def pop(self, name: str, *args: Any) -> CTypeInfo: - return self._symbols.pop(name, *args) - - def __getitem__(self, name: str) -> CTypeInfo: - if name in self._symbols: - return self._symbols[name] - raise KeyError(name) - - def __setitem__(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: - self.set(name, value) - - def __delitem__(self, name: str) -> None: - del self._symbols[name] - - def __contains__(self, name: str) -> bool: - return name in self._symbols - - def __len__(self) -> int: - return len(self._symbols) - - def __iter__(self) -> Iterator[str]: - return iter(self._symbols) - - # ================================================================== - # 服务接口 — 语义化的符号查询与操作方法 - # ================================================================== - - def lookup(self, name: str) -> CTypeInfo | None: - """查找符号,支持别名解析和 dotted name - - 解析顺序: - 1. 直接匹配 _symbols - 2. 如果包含 '.',解析第一个段为别名后查找剩余路径 - 3. 查 _t_type_symbols(t/c 类型别名,返回模拟 CTypeInfo) - """ - if name in self._symbols: - return self._symbols[name] - - if '.' not in name: - return self._lookup_t_type(name) - - # dotted name: 尝试解析第一个段为别名 - parts: list[str] = name.split('.', 1) - first: str = parts[0] - rest: str = parts[1] - - # 1) 别名解析:import X as Y → Y.Symbol → X.Symbol - resolved: str | None = self.import_aliases.get(first) - if resolved: - alias_name: str = f"{resolved}.{rest}" - if alias_name in self._symbols: - return self._symbols[alias_name] - - # 2) 纯路径查找:module.ClassName - # (已在 line 100 检查过,此处为兜底,保留注释说明路径查找语义) - - return None - - def _lookup_t_type(self, name: str) -> CTypeInfo | None: - """在 _t_type_symbols 中查找 t/c 类型别名,返回模拟 CTypeInfo""" - cls: type | None = self._t_type_symbols.get(name) - if cls is None: - return None - info: CTypeInfo = CTypeInfo() - info.Name = name - info.BaseType = cls() - if issubclass(cls, (t.CEnum, t.REnum)): - info.IsEnum = True - elif issubclass(cls, t.CUnion): - info.IsUnion = True - elif issubclass(cls, t.CStruct): - info.IsStruct = True - return info - - def register_namespace(self, module_name: str) -> None: - """注册一个模块命名空间""" - if module_name not in self._namespaces: - self._namespaces[module_name] = {} - - def has(self, name: str) -> bool: - """检查符号是否存在(替代 `name in SymbolTable`)""" - return name in self._symbols - - def is_struct(self, name: str) -> bool: - """检查名称是否为结构体""" - entry: CTypeInfo | None = self._symbols.get(name) - return entry is not None and (entry.IsStruct or entry.IsCpythonObject) - - def is_define(self, name: str) -> bool: - """检查名称是否为常量定义""" - entry: CTypeInfo | None = self._symbols.get(name) - return entry is not None and entry.IsDefine - - def insert(self, name: str, info: CTypeInfo) -> None: - """插入符号(替代 `SymbolTable[name] = info`)""" - self._symbols[name] = info - - def resolve_alias(self, module_path: str) -> str: - """解析 import 别名,无别名返回原路径""" - return self.import_aliases.get(module_path, module_path) - - def ToDict(self) -> dict[str, Any]: - """序列化为字典格式,BaseType 使用可重建的 dict 格式 - - 返回的 dict 包含: - - 符号条目:{name: {attrs}}(与旧格式兼容) - - '__namespaces__': {namespace: [symbol_names]} 命名空间索引 - - '__import_aliases__': {alias: module_path} 导入别名 - """ - result: dict[str, Any] = {} - for name, info in self._symbols.items(): - entry: dict[str, Any] = {'name': name} - if info.BaseType: - entry['BaseType'] = self._SerializeBaseType(info.BaseType) - if info.PtrCount: - entry['PtrCount'] = info.PtrCount - if info.IsTypedef: - entry['IsTypedef'] = True - if info.IsStruct: - entry['IsStruct'] = True - if info.IsEnum: - entry['IsEnum'] = True - if info.IsUnion: - entry['IsUnion'] = True - if info.IsFunction: - entry['IsFunction'] = True - if info.IsVariable: - entry['IsVariable'] = True - if info.IsDefine: - entry['IsDefine'] = True - if info.OriginalType: - entry['OriginalType'] = str(info.OriginalType) - if info.Lineno: - entry['lineno'] = info.Lineno - if info.file: - entry['file'] = info.file - if info.Members: - entry['members'] = info.Members - extra: dict[str, Any] = info._sm._extra - if extra: - entry.update(extra) - result[name] = entry - - # 序列化命名空间信息 - if self._namespaces: - result['__namespaces__'] = { - ns: list(symbols.keys()) for ns, symbols in self._namespaces.items() - } - if self.import_aliases: - result['__import_aliases__'] = dict(self.import_aliases) - if self._t_type_symbols: - result['__t_type_symbols__'] = { - name: cls.__name__ for name, cls in self._t_type_symbols.items() - } - - return result - - @staticmethod - def _SerializeBaseType(base_type: t.CType | tuple | list | str | None) -> dict | str: - """将 BaseType 序列化为可重建的格式""" - if isinstance(base_type, t.CType): - return {'class': type(base_type).__name__} - if isinstance(base_type, (tuple, list)): - return {'classes': [type(b).__name__ for b in base_type if isinstance(b, t.CType)]} - return str(base_type) - - @staticmethod - def _DeserializeBaseType(data: Any) -> Any: - """从序列化格式恢复 BaseType""" - if isinstance(data, dict): - if 'class' in data: - cls: type | None = getattr(t, data['class'], None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - return cls() - elif 'classes' in data: - types: list[t.CType] = [] - for cname in data['classes']: - cls: type | None = getattr(t, cname, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - types.append(cls()) - if types: - return tuple(types) - elif isinstance(data, str): - cls: type | None = getattr(t, data, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - return cls() - return None - - def FromDict(self, symbols: dict[str, Any]) -> None: - """从字典格式反序列化(兼容带/不带命名空间信息的两种格式)""" - self._symbols.clear() - self._namespaces.clear() - self.import_aliases.clear() - self._t_type_symbols.clear() - - _SPECIAL_KEYS: frozenset[str] = frozenset({'__namespaces__', '__import_aliases__', '__t_type_symbols__'}) - - for name, attrs in symbols.items(): - if name in _SPECIAL_KEYS: - continue - if isinstance(attrs, dict): - info: CTypeInfo = self._CTypeInfoFromDict(name, attrs) - self._symbols[name] = info - elif isinstance(attrs, CTypeInfo): - self._symbols[name] = attrs - - # 恢复命名空间信息 - ns_data: dict[str, list[str]] | None = symbols.get('__namespaces__') - if ns_data: - for ns, sym_names in ns_data.items(): - self._namespaces[ns] = {} - for sym_name in sym_names: - if sym_name in self._symbols: - self._namespaces[ns][sym_name] = self._symbols[sym_name] - aliases_data: dict[str, str] | None = symbols.get('__import_aliases__') - if aliases_data: - self.import_aliases.update(aliases_data) - - # 恢复 t 类型别名 - t_type_data: dict[str, str] | None = symbols.get('__t_type_symbols__') - if t_type_data: - for name, cls_name in t_type_data.items(): - cls: type | None = getattr(t, cls_name, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - self._t_type_symbols[name] = cls - - def _CTypeInfoFromDict(self, name: str, attrs: dict[str, Any]) -> CTypeInfo: - """从旧 dict 格式创建 CTypeInfo(兼容旧代码)""" - info: CTypeInfo = CTypeInfo() - info.Name = name - node_type: str = attrs.get('type', '') - - if node_type == 'struct' or attrs.get('IsStruct'): - info.IsStruct = True - elif node_type == 'enum' or attrs.get('IsEnum'): - info.IsEnum = True - elif node_type == 'union' or attrs.get('IsUnion'): - info.IsUnion = True - elif node_type == 'typedef' or attrs.get('IsTypedef'): - info.IsTypedef = True - elif node_type == 'function' or attrs.get('IsFunction'): - info.IsFunction = True - elif node_type == 'variable' or attrs.get('IsVariable'): - info.IsVariable = True - elif node_type == 'define' or attrs.get('IsDefine'): - info.IsDefine = True - elif node_type == 'enum_member' or attrs.get('IsEnumMember'): - info.IsEnumMember = True - - if 'PtrCount' in attrs: - info.PtrCount = attrs['PtrCount'] - if 'OriginalType' in attrs: - info.OriginalType = attrs['OriginalType'] - if 'lineno' in attrs: - info.Lineno = attrs['lineno'] - if 'file' in attrs: - info.file = attrs['file'] - if 'members' in attrs: - info.Members = attrs['members'] - if 'IsPtr' in attrs: - info.IsPtr = attrs['IsPtr'] - if 'dims' in attrs: - info.ArrayDims = attrs['dims'] - if 'IsCpythonObject' in attrs: - info.IsCpythonObject = attrs['IsCpythonObject'] - if 'IsAnonymous' in attrs: - info.IsAnonymous = attrs['IsAnonymous'] - if 'IsPacked' in attrs: - info.IsPacked = attrs['IsPacked'] - if 'EnumName' in attrs: - info.EnumName = attrs['EnumName'] - if 'DefineValue' in attrs: - info.DefineValue = attrs['DefineValue'] - if 'BaseType' in attrs: - info.BaseType = self._DeserializeBaseType(attrs['BaseType']) - if 'name' in attrs and attrs['name'] != name: - info.Name = attrs['name'] - - # 其他属性存入 _extra - skip_keys: frozenset[str] = frozenset({'type', 'name', 'PtrCount', 'OriginalType', 'lineno', 'file', - 'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous', - 'IsPacked', 'EnumName', 'DefineValue', 'BaseType', - 'IsStruct', 'IsEnum', 'IsUnion', 'IsTypedef', - 'IsFunction', 'IsVariable', 'IsDefine', 'IsEnumMember'}) - for key, value in attrs.items(): - if key not in skip_keys: - info.set(key, value) - - return info - - # ================================================================== - # 模块符号加载:四阶段管线 - # ================================================================== - - def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: - return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) - - def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: - try: - # 提取模块名作为命名空间 - module_name: str = namespace_prefix[0] if isinstance(namespace_prefix, list) else namespace_prefix - - # Pass 1: 从 AST 提取原始符号信息 - extractor: ASTSymbolExtractor = ASTSymbolExtractor(self) - module_symbols: ModuleSymbols = extractor.extract(FilePath) - - # Pass 2: 解析类型信息(typedef、函数签名、define 值) - resolver: TypeResolver = TypeResolver(self) - resolver.resolve(module_symbols) - - # Pass 3: 插入符号到主命名空间(无前缀) - inserter: SymbolInserter = SymbolInserter(self) - inserter.set_namespace(module_name) - loaded: list[str] = inserter.insert(module_symbols) - - # Pass 4: 重新导出到命名空间前缀下 - prefixes: list[str] = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix - reexporter: PackageReexporter = PackageReexporter(self) - reexporter.set_namespace(module_name) - loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno)) - - return loaded - - except Exception as e: - _vlog().error(traceback.format_exc()) - self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}") - return [] - - # ================================================================== - # 类型解析辅助方法(委托到 LLVMTypeMapper) - # ================================================================== - - @staticmethod - def _CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: - return _CheckAnnotationHasCInline(annotation_node) - - # ================================================================== - # 符号插入方法(供 SymbolInserter / PackageReexporter 调用) - # ================================================================== - - def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict[str, CTypeInfo], IsCpythonObject: bool, IsPacked: bool = False) -> None: - info: CTypeInfo = CTypeInfo() - info.Lineno = lineno - info.file = FilePath - info.Members = members if members else {} - - if TypeKind == 'struct': - info.IsStruct = True - elif TypeKind == 'union': - info.IsUnion = True - elif TypeKind == 'enum': - info.IsEnum = True - elif TypeKind == 'renum': - info.IsStruct = True - info.IsRenum = True - info.IsEnum = True - elif TypeKind == 'exception': - info.IsStruct = True - info.IsExceptionClass = True - - if IsCpythonObject: - info.IsCpythonObject = True - if IsPacked: - info.IsPacked = True - - self._symbols[FullName] = info - - def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str, value: int | None = None) -> None: - info: CTypeInfo = CTypeInfo() - info.IsEnumMember = True - info.EnumName = EnumName - info.Lineno = lineno - info.file = FilePath - if value is not None: - info.value = value - self._symbols[FullName] = info - - def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass: CTypeInfo | str | None, lineno: int, FilePath: str, members: dict[str, CTypeInfo] | None = None) -> None: - info: CTypeInfo = CTypeInfo() - info.IsTypedef = True - info.Name = FullName - info.Lineno = lineno - info.file = FilePath - if members: - info.Members = members - - if isinstance(OriginalClass, CTypeInfo): - info.OriginalType = OriginalClass - elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): - OriginalType: str = OriginalClass - if OriginalType == 'CVoid *': - OriginalType = 'void *' - info.OriginalType = OriginalType - elif OriginalType_kind == 'typedef' and OriginalClass == 'void': - info.OriginalType = 'void *' - elif OriginalType_kind == 'typedef' and OriginalClass: - info.OriginalType = OriginalClass - elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): - info.OriginalType = f'{OriginalType_kind} {OriginalClass}' - else: - info.OriginalType = OriginalClass - - self._symbols[FullName] = info - - def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - info.IsModuleAlias = True - info.Lineno = lineno - info.file = FilePath - self._symbols[name] = info - - def _InsertFuncSymbol(self, FullName: str, RetType: str | CTypeInfo | None, ParamTypes: list[str], lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False) -> None: - info: CTypeInfo = CTypeInfo() - info.IsFunction = True - if isinstance(RetType, str): - info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() - elif isinstance(RetType, CTypeInfo): - info.FuncPtrReturn = RetType - else: - info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] - info.IsVariadic = IsVariadic - info.IsInline = IsInline - if IsInline: - info.Storage = t.CInline() - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _InsertDefineSymbol(self, FullName: str, DefineValue: int | str | float | bool | None, lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - info.IsDefine = True - info.DefineValue = DefineValue - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _eval_const_expr(self, node: ast.AST) -> int | float | str | None: - """计算常量表达式的值(委托到 ConstEvaluator)""" - return ConstEvaluator.eval_with_symtab(node, self) - - def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict[str, CTypeInfo], lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - if IsUnion: - info.IsUnion = True - else: - info.IsStruct = True - info.IsAnonymous = True - info.Members = members if members else {} - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info diff --git a/App/lib/core/SymbolTypeResolver.py b/App/lib/core/SymbolTypeResolver.py deleted file mode 100644 index deb567c..0000000 --- a/App/lib/core/SymbolTypeResolver.py +++ /dev/null @@ -1,272 +0,0 @@ -"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值""" -from __future__ import annotations -import ast -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ( - ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData -) -from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper -from lib.core.LLVMTypeMapper import LLVMTypeMapper -from lib.core.SymbolUtils import IsTModule -from lib.includes import t - - -class TypeResolver: - """解析从 AST 提取的原始符号中的类型信息""" - - def __init__(self, symbol_table: SymbolTable): - self._symtab = symbol_table - self._type_mapper = LLVMTypeMapper(symbol_table) - # 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析) - self._resolved_typedefs: dict[str, str | None] = {} - - def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols: - """解析所有类型信息,就地更新 ModuleSymbols""" - # 构建 class_members 查找表(typedef Postdefinition 需要) - class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes} - - # 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef) - td: TypedefSymbolData - for td in module_symbols.typedefs: - self._resolve_typedef(td, class_members) - self._resolved_typedefs[td.name] = td.original_class - - # 解析函数签名 - func: FuncSymbolData - for func in module_symbols.functions: - self._resolve_function(func) - - # 解析 define 值 - define: DefineSymbolData - for define in module_symbols.defines: - self._resolve_define(define) - - return module_symbols - - # ------------------------------------------------------------------ - # Typedef 解析 - # ------------------------------------------------------------------ - - def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): - """解析单个 typedef 的类型信息""" - is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef - - if is_postdef_with_typedef: - self._resolve_postdef_typedef(td, class_members) - elif td.has_ctypedef: - self._resolve_ctypedef_typedef(td) - else: - # 无特殊注解的 typedef - td.original_type_kind = None - td.original_class = None - - def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): - """解析 Postdefinition + CTypedef 组合注解""" - original_class: str | None = self._find_postdef_arg(td.annotation) - if original_class and original_class in class_members: - members_info: dict[str, CTypeInfo] = class_members[original_class] - original_type_kind: str = 'struct' - if original_class in self._symtab: - orig_type_info: CTypeInfo = self._symtab[original_class] - if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion): - if orig_type_info.type_cls is t.CStruct: - original_type_kind = 'struct' - elif orig_type_info.type_cls is t.CEnum: - original_type_kind = 'enum' - elif orig_type_info.type_cls is t.CUnion: - original_type_kind = 'union' - td.original_type_kind = original_type_kind - td.original_class = original_class - td.members = members_info - else: - td.original_type_kind = None - td.original_class = None - - def _resolve_ctypedef_typedef(self, td: TypedefSymbolData): - """解析 CTypedef 注解""" - base_type_name: str | None = self._find_base_type(td.annotation) - _TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'}) - - if base_type_name == 'Callable': - original_type: CTypeInfo = CTypeInfo() - original_type.IsFuncPtr = True - original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - original_type.FuncPtrParams = [] - td.original_type_kind = 'typedef' - td.original_class = original_type - elif base_type_name and base_type_name not in _TYPE_QUALIFIERS: - cname: str | None = CTypeHelper.GetCName(base_type_name) - if cname: - td.original_class = cname - else: - td.original_class = base_type_name - td.original_type_kind = 'typedef' - else: - # 尝试从值表达式解析 - self._resolve_typedef_from_value(td) - - def _resolve_typedef_from_value(self, td: TypedefSymbolData): - """从值表达式解析 typedef 类型 - - BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理, - 因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。 - """ - if not td.value: - td.original_type_kind = None - td.original_class = None - return - - # 优先处理 BinOp(_find_base_type 无法解析 Name 引用) - if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr): - left_type: str = self._resolve_type_expr(td.value.left) - right_type: str = self._resolve_type_expr(td.value.right) - is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr' - if is_ptr_type: - base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '') - original_type: str = (base_name + ' *') if base_name else 'void *' - td.original_class = original_type - td.original_type_kind = 'typedef' - elif left_type: - td.original_class = left_type - td.original_type_kind = 'typedef' - elif right_type: - td.original_class = right_type - td.original_type_kind = 'typedef' - else: - td.original_type_kind = None - td.original_class = None - return - - # 非 BinOp:使用 _find_base_type - value_base_type: str | None = self._find_base_type(td.value) - _PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'}) - - if value_base_type and value_base_type not in _PTR_MODIFIERS: - cname: str | None = CTypeHelper.GetCName(value_base_type) - if cname: - td.original_class = cname - else: - td.original_class = value_base_type - td.original_type_kind = 'typedef' - return - - if isinstance(td.value, ast.Name): - ref_name: str = td.value.id - # 先查本模块已解析的 typedef - if ref_name in self._resolved_typedefs: - ref_class: str | None = self._resolved_typedefs[ref_name] - if ref_class: - td.original_class = ref_class - td.original_type_kind = 'typedef' - return - # 再查 symtab(跨模块) - if ref_name in self._symtab: - ref_info: CTypeInfo = self._symtab[ref_name] - if ref_info and ref_info.IsTypedef and ref_info.OriginalType: - td.original_class = ref_info.OriginalType - td.original_type_kind = 'typedef' - return - - td.original_type_kind = None - td.original_class = None - - def _resolve_type_expr(self, node: ast.AST) -> str: - """解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef - - 解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT) - 在 TypeResolver 阶段尚未插入 symtab 的问题。 - """ - if isinstance(node, ast.Name): - if node.id in self._resolved_typedefs: - return self._resolved_typedefs[node.id] or '' - return self._type_mapper.resolve_typedef_value_type(node) - - # ------------------------------------------------------------------ - # 函数签名解析 - # ------------------------------------------------------------------ - - def _resolve_function(self, func: FuncSymbolData): - """解析函数的返回类型和参数类型""" - func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node) - # 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号) - if func.returns_node is not None: - try: - func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab) - except Exception: - func.ret_ctype = None - func.param_types = [] - _arg_name: str - annotation: ast.expr | None - for _arg_name, annotation in func.params: - if annotation: - func.param_types.append(self._type_mapper.get_func_param_type_str(annotation)) - else: - func.param_types.append('i8*') - - # ------------------------------------------------------------------ - # Define 值解析 - # ------------------------------------------------------------------ - - def _resolve_define(self, define: DefineSymbolData): - """解析 define 常量值""" - if define.value_node: - define.value = self._symtab._eval_const_expr(define.value_node) - - # ------------------------------------------------------------------ - # 静态工具方法(原 _LoadSymbolsFromFile 中的闭包) - # ------------------------------------------------------------------ - - @staticmethod - def _find_base_type(node: ast.AST | None) -> str | None: - """从注解 AST 节点中查找基础类型名称""" - if isinstance(node, ast.Attribute): - if hasattr(node.value, 'id') and IsTModule(node.value.id): - if node.attr == 'CPtr': - return 'ptr' - return node.attr - elif isinstance(node, ast.Subscript): - if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable': - return 'Callable' - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_result: str | None = TypeResolver._find_base_type(node.left) - if left_result == 'ptr': - right_result: str | None = TypeResolver._find_base_type(node.right) - return (right_result if right_result and right_result != 'ptr' else 'void') + ' *' - if left_result == 'Callable': - return 'Callable' - right_result: str | None = TypeResolver._find_base_type(node.right) - if right_result == 'ptr': - return (left_result if left_result and left_result != 'ptr' else 'void') + ' *' - if right_result == 'Callable': - return 'Callable' - # 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong - long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'}) - if left_result in long_types and right_result in long_types: - if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong': - return 'CUnsignedLongLong' - return 'CLongLong' - if left_result: - return left_result - if right_result: - return right_result - return None - - @staticmethod - def _find_postdef_arg(node: ast.AST | None) -> str | None: - """从注解 AST 节点中查找 Postdefinition 参数""" - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition': - if node.args and isinstance(node.args[0], ast.Name): - return node.args[0].id - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_result: str | None = TypeResolver._find_postdef_arg(node.left) - if left_result: - return left_result - right_result: str | None = TypeResolver._find_postdef_arg(node.right) - if right_result: - return right_result - return None diff --git a/App/lib/core/SymbolUtils.py b/App/lib/core/SymbolUtils.py deleted file mode 100644 index e85f4ec..0000000 --- a/App/lib/core/SymbolUtils.py +++ /dev/null @@ -1,214 +0,0 @@ -"""共享工具函数:符号表处理中使用的 AST 分析工具""" -from __future__ import annotations -import ast -from lib.includes import t - -_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__}) - - -def IsTModule(module_id: str, symtable: object | None = None) -> bool: - """检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)""" - if module_id in _T_MODULE_NAMES: - return True - if symtable is not None and hasattr(symtable, 'import_aliases'): - resolved: str = symtable.import_aliases.get(module_id, module_id) - if resolved in _T_MODULE_NAMES: - return True - return False - - -def IsTModulePath(module_path: str) -> bool: - """检查模块路径是否指向 t 类型模块""" - if module_path in _T_MODULE_NAMES: - return True - if module_path: - t_name: str - for t_name in _T_MODULE_NAMES: - if module_path == t_name or module_path.startswith(t_name + '.'): - return True - return False - - -def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool: - """检测 AST 节点中是否包含指定名称的 t 模块类型""" - if isinstance(node, ast.Attribute): - if (hasattr(node.value, 'id') and IsTModule(node.value.id) and - node.attr == TypeName): - return True - elif isinstance(node, ast.BinOp): - return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName) - elif isinstance(node, ast.Call): - if AnnotationContainsTType(node.func, TypeName): - return True - for arg in node.args: - if AnnotationContainsTType(arg, TypeName): - return True - elif isinstance(node, ast.Subscript): - if AnnotationContainsTType(node.value, TypeName): - return True - if AnnotationContainsTType(node.slice, TypeName): - return True - return False - - -def IsListAnnotation(annotation: ast.AST) -> bool: - """检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])""" - if not isinstance(annotation, ast.Subscript): - return False - value = annotation.value - # t.CArray[...] - if (isinstance(value, ast.Attribute) - and isinstance(value.value, ast.Name) - and value.value.id == 't' - and value.attr == 'CArray'): - return True - # list[type, count] — 仅匹配双参数 Tuple 切片(固定数组), - # 单参数 list[type] 不匹配(走泛型类 list[T] 路径) - if (isinstance(value, ast.Name) - and value.id == 'list' - and isinstance(annotation.slice, ast.Tuple) - and len(annotation.slice.elts) == 2): - return True - return False - - -def ExtractListFromBinOp(annotation: ast.AST) -> ast.Subscript | None: - """从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr""" - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - for side in (annotation.left, annotation.right): - if IsListAnnotation(side): - return side - return None - - -class ListAnnotationParseResult: - """list[...] 注解解析结果。 - - is_pointer=True 表示单参数 list[type] → 指针模式; - is_pointer=False 表示 Tuple(2) 模式 list[type, count]。 - """ - __slots__ = ('elem_type_node', 'count_node', 'is_pointer') - - def __init__(self, elem_type_node: ast.AST, count_node: ast.AST | None, is_pointer: bool) -> None: - self.elem_type_node: ast.AST = elem_type_node - self.count_node: ast.AST | None = count_node - self.is_pointer: bool = is_pointer - - -def ParseListAnnotation(annotation: ast.AST) -> ListAnnotationParseResult | None: - """解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。 - - 自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。 - 返回 None 表示不是 list 注解。 - """ - list_node: ast.AST = annotation - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - extracted: ast.Subscript | None = ExtractListFromBinOp(annotation) - if extracted is None: - return None - list_node = extracted - if not IsListAnnotation(list_node): - return None - slice_node: ast.AST = list_node.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False) - # 单参数 list[type] → 指针模式 - return ListAnnotationParseResult(slice_node, None, is_pointer=True) - - -def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: - """检测注解节点中是否包含 CInline""" - if annotation_node is None: - return False - if isinstance(annotation_node, ast.Attribute): - if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline': - return True - if isinstance(annotation_node, ast.Name): - if annotation_node.id == 'CInline': - return True - if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right) - return False - - -def ExtractTypeNameFromBinOp(annotation: ast.AST) -> str | None: - """从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。 - - 返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。 - """ - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - left: ast.AST = annotation.left - if isinstance(left, ast.Name): - return left.id - if isinstance(left, ast.Attribute): - return left.attr - return None - - -def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None: - """递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。 - - 检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。 - 支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。 - """ - if isinstance(node, ast.Name) and node.id in struct_names: - return node.id - if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names: - return node.value - if isinstance(node, ast.Attribute) and node.attr in struct_names: - return node.attr - if isinstance(node, ast.Subscript): - base_name: str | None = None - if isinstance(node.value, ast.Name): - base_name = node.value.id - elif isinstance(node.value, ast.Attribute): - base_name = node.value.attr - if base_name: - slice_node: ast.AST = node.slice - if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): - slice_node = slice_node.value - type_args: list[str] = [] - if isinstance(slice_node, ast.Name): - type_args.append(slice_node.id) - elif isinstance(slice_node, ast.Attribute): - type_args.append(slice_node.attr) - elif isinstance(slice_node, ast.Tuple): - for elt in slice_node.elts: - if isinstance(elt, ast.Name): - type_args.append(elt.id) - elif isinstance(elt, ast.Attribute): - type_args.append(elt.attr) - if type_args: - spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args) - if spec_name in struct_names: - return spec_name - if base_name in struct_names: - return base_name - if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - result: str | None = FindStructNameInAnnotation(node.left, struct_names) - if result: - return result - return FindStructNameInAnnotation(node.right, struct_names) - return None - - -def AnnotationContainsName(annotation: ast.AST, name: str) -> bool: - """检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。 - - 同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。 - """ - if isinstance(annotation, ast.Attribute): - return annotation.attr == name - if isinstance(annotation, ast.Name): - return annotation.id == name - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name) - return False - - -def IsCPtrNode(node: ast.AST) -> bool: - """检查节点是否为 t.CPtr 属性引用。""" - return (isinstance(node, ast.Attribute) - and isinstance(node.value, ast.Name) - and node.value.id == 't' - and node.attr == 'CPtr') diff --git a/App/lib/core/Translator/AnnotationLoader.py b/App/lib/core/Translator/AnnotationLoader.py deleted file mode 100644 index 3e64d43..0000000 --- a/App/lib/core/Translator/AnnotationLoader.py +++ /dev/null @@ -1,381 +0,0 @@ -from __future__ import annotations - -import ast -import os -import importlib -import types -from typing import Any - -import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes) - -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolUtils import IsTModule, AnnotationContainsName -from lib.includes import t -from lib.includes.t import CType, CEnum -from lib.constants.config import mode as _config_mode -from lib.core.VLogger import get_logger as _vlog - - -class AnnotationLoaderMixin: - """注解模块加载 Mixin - - 提供注解模块/文件的加载与符号表注册能力。 - """ - - def _LoadAnnotationModule(self, ModuleName: str, library_name: str | None = None, parse_method: str = 'auto') -> int: - """加载注解模块并将 CType 子类注册为 typedef - - 支持两种模式: - 1. AST 模式:如果 ModuleName 是文件路径,解析文件提取 CType - 2. importlib 模式:如果 ModuleName 是模块名,导入模块提取 CType - - Args: - ModuleName: 模块名或文件路径 - library_name: 手动指定的库名称,用于注册到符号表。如果为 None,则从 ModuleName 推断 - parse_method: 解析方法,可选值: - - 'auto': 自动检测(默认) - - 'file': 强制使用 AST 模式(文件路径) - - 'module': 强制使用 importlib 模式(模块名) - """ - def register_to_symboltable(module: types.ModuleType, lib_name: str | None = None, source_file: str | None = None) -> int: - """将模块中的 CType 子类和 CEnum 类注册到符号表""" - count: int = 0 - for AttrName in dir(module): - attr: type = getattr(module, AttrName) - # 优先检查是否是 CEnum 子类(枚举) - if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum: - # 注册枚举类型 - EnumNode: CTypeInfo = CTypeInfo() - EnumNode.Name = AttrName - EnumNode.BaseType = t.CEnum() - EnumNode.IsEnum = True - EnumNode.set('enum_class', attr) - EnumNode.set('source', 'annotation_module') - EnumNode.library_name = lib_name - EnumNode.file = source_file - self.SymbolTable.insert(AttrName, EnumNode) - if lib_name: - FullName: str = f'{lib_name}.{AttrName}' - full_EnumNode: CTypeInfo = CTypeInfo() - full_EnumNode.Name = FullName - full_EnumNode.IsEnum = True - full_EnumNode.set('enum_class', attr) - full_EnumNode.set('source', 'annotation_module') - full_EnumNode.library_name = lib_name - full_EnumNode.file = source_file - self.SymbolTable.insert(FullName, full_EnumNode) - # 枚举成员也需要注册 - for MemberName in dir(attr): - if not MemberName.startswith('_'): - member: int = getattr(attr, MemberName, None) - if isinstance(member, int): - MemberNode: CTypeInfo = CTypeInfo() - MemberNode.Name = MemberName - MemberNode.BaseType = t.CEnum(AttrName) - MemberNode.value = member - MemberNode.EnumName = AttrName - MemberNode.library_name = lib_name - MemberNode.IsEnumMember = True - self.SymbolTable.insert(MemberName, MemberNode) - self.SymbolTable.insert(f"{AttrName}.{MemberName}", MemberNode) - self.SymbolTable.insert(f"{AttrName}_{MemberName}", MemberNode) - if lib_name: - self.SymbolTable.insert(f"{lib_name}.{AttrName}.{MemberName}", MemberNode) - self.SymbolTable.insert(f"{lib_name}_{AttrName}_{MemberName}", MemberNode) - count += 1 - # 检查是否是 CType 子类(typedef 别名) - elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: - # 继承 CType 的类是类型别名(typedef),不是结构体 - # 使用手动指定的库名称作为前缀 - if lib_name: - FullName: str = f'{lib_name}.{AttrName}' - else: - FullName = AttrName - # 同时注册带前缀和不带前缀的名称(都是 typedef 别名) - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = AttrName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = attr.__name__ - TypedefNode.set('source', 'annotation_module') - TypedefNode.library_name = lib_name - TypedefNode.file = source_file - self.SymbolTable.insert(AttrName, TypedefNode) - if lib_name and FullName != AttrName: - FullTypedef_node: CTypeInfo = CTypeInfo() - FullTypedef_node.Name = FullName - FullTypedef_node.IsTypedef = True - FullTypedef_node.OriginalType = attr.__name__ - FullTypedef_node.set('source', 'annotation_module') - FullTypedef_node.library_name = lib_name - FullTypedef_node.file = source_file - self.SymbolTable.insert(FullName, FullTypedef_node) - count += 1 - # 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef) - elif AttrName.startswith('_') and len(AttrName) > 1: - PublicName: str = AttrName[1:] - PublicAttr: type | None = getattr(module, PublicName, None) - if PublicAttr is not None and not isinstance(attr, type): - continue - if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: - if not self.SymbolTable.has(PublicName): - if lib_name: - FullName: str = f'{lib_name}.{PublicName}' - else: - FullName = PublicName - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = PublicName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = attr.__name__ - TypedefNode.set('source', 'annotation_module') - TypedefNode.library_name = lib_name - TypedefNode.file = source_file - self.SymbolTable.insert(PublicName, TypedefNode) - if lib_name and FullName != PublicName: - FullTypedef_node: CTypeInfo = CTypeInfo() - FullTypedef_node.Name = FullName - FullTypedef_node.IsTypedef = True - FullTypedef_node.OriginalType = attr.__name__ - FullTypedef_node.set('source', 'annotation_module') - FullTypedef_node.library_name = lib_name - FullTypedef_node.file = source_file - self.SymbolTable.insert(FullName, FullTypedef_node) - count += 1 - return count - - # 确定解析方法 - use_file_mode: bool = False - if parse_method == 'file': - use_file_mode = True - elif parse_method == 'module': - use_file_mode = False - else: # auto - use_file_mode = os.path.isfile(ModuleName) - - # 确定库名称 - lib_name: str | None = library_name - if lib_name is None: - if use_file_mode: - # 从文件路径推断库名称 - lib_name = os.path.splitext(os.path.basename(ModuleName))[0] - else: - # 模块名就是库名称 - lib_name = ModuleName - - # 根据解析方法加载模块 - if use_file_mode: - # AST 模式:使用 AST 解析文件,不执行代码 - try: - # 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments - saved_embedded: dict = self.EmbeddedAssignments.copy() - saved_typedef: dict = self.TypedefAssignments.copy() - - # 清空 PD 收集(注解文件不应该收集 PD 语句) - self.EmbeddedAssignments = {} - self.TypedefAssignments = {} - - # 直接调用 ParsePythonFile 解析文件提取类型信息 - # 注意:这不会执行任何 Python 代码,只是解析 AST - # UpdateCurrentFile=False 表示不修改 CurrentFile - self.ParsePythonFile(ModuleName, UpdateCurrentFile=False) - - # 恢复主代码文件的 PD 收集 - self.EmbeddedAssignments = saved_embedded - self.TypedefAssignments = saved_typedef - - # 从文件名推断类型前缀(如 test_t -> test_t.xxx) - TypePrefix: str = lib_name - count: int = 0 - - # 检查符号表中新增的类型(注解文件解析后的所有 struct 类型) - # 需要检查这些类型是否继承自 CType,如果是则是 typedef 别名 - new_types: list[str] = [] - for TypeName, TypeInfo in self.SymbolTable.items(): - if TypeInfo.IsStruct: - new_types.append(TypeName) - - # 再次遍历 AST,检测继承自 CType 的类 - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content: str = f.read() - ann_tree: ast.Module = ast.parse(ann_content) - for node in ann_tree.body: - if isinstance(node, ast.ClassDef): - ClassName: str = node.name - # 检查是否有基类 - for base in node.bases: - if isinstance(base, ast.Name) and base.id == 'CType': - # 这个类继承自 CType,是 typedef 别名 - # 更新符号表中的类型为 typedef - if self.SymbolTable.has(ClassName): - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = ClassName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}') - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('is_ctype_subclass', True) - self.SymbolTable.insert(ClassName, TypedefNode) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception") - - # 为所有新增的类型添加库前缀和 source 标记 - for TypeName in new_types: - # 添加带前缀的类型名 - FullName: str = f'{TypePrefix}.{TypeName}' - TypeInfo: CTypeInfo | dict[str, Any] = self.SymbolTable[TypeName].copy() - TypeInfo['source'] = 'annotation_module' - TypeInfo['original_name'] = TypeName - self.SymbolTable.insert(FullName, TypeInfo) - count += 1 - - # 再次遍历 AST,查找注解文件中的 typedef 语句(AnnAssign with t.CTypedef) - # 注意:必须在类定义处理完之后再处理 typedef - typedef_annots: list[tuple[str, str]] = [] - # 查找 CEnum 成员变量(AnnAssign with t.CEnum | t.State 或 t.CEnum) - cEnumMembers: list[tuple[str, int | None]] = [] - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content: str = f.read() - ann_tree: ast.Module = ast.parse(ann_content) - for node in ann_tree.body: - # 检测 xxx: t.CEnum 形式的枚举成员变量 - if isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name) and node.annotation: - TargetName: str = node.target.id - # 检查注解是否是 BinOp (Union) 或直接是 Attribute - IsCenum: bool = False - if isinstance(node.annotation, ast.BinOp): - # 检查是否包含 CEnum - if AnnotationContainsName(node.annotation, 'CEnum'): - IsCenum = True - elif isinstance(node.annotation, ast.Attribute): - # 直接是 t.CEnum - if node.annotation.attr == t.CEnum.__name__: - IsCenum = True - - if IsCenum: - # 检查值是否是 Constant (枚举成员值) - if node.value and isinstance(node.value, ast.Constant): - value: int | str | float | None = node.value.value - else: - value = None - cEnumMembers.append((TargetName, value)) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception") - - # 处理 CEnum 成员变量 - for TargetName, value in cEnumMembers: - # 注册枚举成员 - MemberNode: CTypeInfo = CTypeInfo() - MemberNode.Name = TargetName - MemberNode.BaseType = t.CEnum(TypePrefix) - MemberNode.value = value - MemberNode.EnumName = TypePrefix - MemberNode.library_name = TypePrefix - MemberNode.IsEnumMember = True - self.SymbolTable.insert(TargetName, MemberNode) - self.SymbolTable.insert(f"{TypePrefix}.{TargetName}", MemberNode) - self.SymbolTable.insert(f"{TypePrefix}_{TargetName}", MemberNode) - - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content: str = f.read() - ann_tree: ast.Module = ast.parse(ann_content) - for node in ann_tree.body: - # 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句 - if isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name) and node.annotation and node.value: - TargetName: str = node.target.id - # 检查注解是否是 t.CTypedef - if isinstance(node.annotation, ast.Attribute): - if isinstance(node.annotation.value, ast.Name): - if IsTModule(node.annotation.value.id) and node.annotation.attr == 'CTypedef': - # 检查值是否是 Name - if isinstance(node.value, ast.Name): - original_name: str = node.value.id - typedef_annots.append((TargetName, original_name)) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception") - - # 处理 typedef 注解 - for TargetName, original_name in typedef_annots: - # 检查原始类型是否在符号表中(带前缀或不带前缀) - orig_with_prefix: str = f'{TypePrefix}.{original_name}' - if self.SymbolTable.has(orig_with_prefix): - # 添加带前缀的 typedef 别名 - FullTypedef_name: str = f'{TypePrefix}.{TargetName}' - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = FullTypedef_name - TypedefNode.IsTypedef = True - orig_entry: CTypeInfo | dict[str, Any] = self.SymbolTable.lookup(orig_with_prefix) - orig_type_str: str = f'struct {original_name}' - if isinstance(orig_entry, dict): - if orig_entry.get('type') == 'typedef': - orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}') - elif orig_entry.get('type') == 'enum': - orig_type_str = f'enum {original_name}' - elif orig_entry.IsTypedef: - orig_type_str = orig_entry.OriginalType or f'struct {original_name}' - elif orig_entry.IsEnum: - orig_type_str = f'enum {original_name}' - TypedefNode.OriginalType = orig_type_str - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('original_name', TargetName) - self.SymbolTable.insert(FullTypedef_name, TypedefNode) - count += 1 - - self.AnnotationModules.add(lib_name) - return count - except Exception as e: - # 恢复 PD 收集 - self.EmbeddedAssignments = saved_embedded - self.TypedefAssignments = saved_typedef - self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}") - return 0 - else: - # importlib 模式:导入模块 - try: - module: types.ModuleType = importlib.import_module(ModuleName) - count: int = register_to_symboltable(module, lib_name, None) - self.AnnotationModules.add(lib_name) - return count - except ImportError: - self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}") - return 0 - except Exception as e: - self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}") - return 0 - - def _LoadAnnotationFiles(self, FilePaths: list[str | tuple]) -> None: - """加载多个注解文件并注册到符号表 - - Args: - FilePaths: 文件路径列表,每个元素可以是: - - str: 文件路径或模块名 - - tuple: (path, options) 或 (path, library_name, parse_method) - """ - for item in FilePaths: - if isinstance(item, tuple): - if len(item) >= 3: - path: str - library_name: str - parse_method: str - path, library_name, parse_method = item[:3] - count: int = self._LoadAnnotationModule(path, library_name, parse_method) - elif len(item) == 2: - path: str - library_name: str - path, library_name = item - count: int = self._LoadAnnotationModule(path, library_name, 'auto') - else: - count: int = self._LoadAnnotationModule(item) - else: - count: int = self._LoadAnnotationModule(item) - - # 别名,保持向后兼容 - LoadAnnotationFiles = _LoadAnnotationFiles diff --git a/App/lib/core/Translator/BaseTranslator.py b/App/lib/core/Translator/BaseTranslator.py deleted file mode 100644 index 03f8537..0000000 --- a/App/lib/core/Translator/BaseTranslator.py +++ /dev/null @@ -1,157 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Any, Callable, Dict, TYPE_CHECKING - -from lib.core.Exportable import Exportable - -if TYPE_CHECKING: - import llvmlite.ir as ir - -from lib.core.Handles import ( - IfHandle, ForHandle, WhileHandle, - AnnAssignHandle, - HandlesTypeMerge, ExprHandle, BodyHandle, - ReturnHandle, AssignHandle, AugAssignHandle, DeleteHandle, - WithHandle, TryHandle, AssertHandle, RaiseHandle, MatchHandle, - ExprUtils, ExprOpsHandle, ExprAttrHandle, ExprBuiltinHandle, - ExprAsmHandle, ExprFormatHandle, ExprLambdaHandle, ExprCallHandle, - CSpecialCallHandle, TSpecialCallHandle, - ClassHandle, - FunctionHandle, - ImportHandle -) -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolTable import SymbolTable -from lib.core.SymbolNode import SymbolNode -from lib.constants.config import mode as _ConfigMode -from lib.core.VLogger import get_logger as _vlog - - -def _StrictLog(logger: Callable[[str], None], msg: str) -> None: - """在 strict 模式下记录异常日志""" - if _ConfigMode == "strict": - logger(msg) - - -class BaseTranslatorMixin: - """代码转换器基础 Mixin - - 提供 __init__、日志、调试输出与表达式处理等基础能力。 - """ - - def __init__(self) -> None: - self.VarScopes: list[Dict[str, SymbolNode]] = [{}] # 跟踪变量作用域,第一个是全局作用域 - self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型 - self.CurrentCReturnTypes: list[CTypeInfo] | None = None # 当前函数的 CReturn 类型列表 - self._CurrentCpythonObjectClass: str | None = None # 当前正在处理的 CPython 对象类名 - self.FunctionDefCache: dict = {} # 函数定义缓存 - self.OriginalLines: list[str] = [] # 原始代码行 - self.Content: str = '' - self.DebugFile: str | None = None # 调试输出文件路径 - self.IsHeader: bool = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体) - self.AnnotationModules: set[str] = set() # 注解模块集合,用于识别类型定义模块 - self.Warnings: list[str] = [] # 警告日志 - self._ErrorStack: list[tuple[str, str, str]] = [] # 错误栈,按顺序收集错误位置 - self.Errors: list[dict[str, str | None]] = [] # 错误日志 - self.SliceCount: int = 0 # 切片计数 - self.SliceInfos: list = [] # 切片信息列表 - self.SliceLevel: int = 3 # 切片优化级别 - self.GeneratedTypes: set[str] = set() # 在当前代码中生成的类型(struct/typedef) - self.EmbeddedAssignments: dict[str, list] = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量 - self.TypedefAssignments: dict[str, list] = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量 - self.ChainAssignmentArrays: list = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...] - self.tree: ast.AST | None = None # 保存解析后的 AST 树 - self.LibraryPaths: list[str] = ['.'] # 库搜索路径列表,默认包含当前目录 - self.InClass: bool = False # 是否正在处理 class 定义 - self._UserTypeModules: dict = {} - self._source_module_sig_files: dict = {} - self._global_function_default_args: dict = {} - self._global_function_param_names: dict = {} - self.exception_registry: dict = {} - self.exception_parents: dict = {} - self._next_exception_code: int = 100 - # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 - self.config: Any = None - self._ImportedModules: set[str] | None = None - self._t_c_imported_names: dict = {} - - # 导出表 - self.Exportable = Exportable(filename='') - - self.SymbolTable = SymbolTable(self) - self.IfHandler = IfHandle(self) - self.ForHandler = ForHandle(self) - self.WhileHandler = WhileHandle(self) - self.AnnAssignHandler = AnnAssignHandle(self) - self.TypeMergeHandler = HandlesTypeMerge(self) - self.ExprHandler = ExprHandle(self) - self.ExprUtils = ExprUtils(self) - self.ExprOpsHandle = ExprOpsHandle(self) - self.ExprAttrHandle = ExprAttrHandle(self) - self.ExprBuiltinHandle = ExprBuiltinHandle(self) - self.ExprAsmHandle = ExprAsmHandle(self) - self.ExprFormatHandle = ExprFormatHandle(self) - self.ExprLambdaHandle = ExprLambdaHandle(self) - self.ExprCallHandle = ExprCallHandle(self) - self.CSpecialCallHandle = CSpecialCallHandle(self) - self.TSpecialCallHandle = TSpecialCallHandle(self) - self.ClassHandler = ClassHandle(self) - self.FunctionHandler = FunctionHandle(self) - self.ImportHandler = ImportHandle(self) - self.BodyHandler = BodyHandle(self) - self.ReturnHandler = ReturnHandle(self) - self.AssignHandler = AssignHandle(self) - self.AugAssignHandler = AugAssignHandle(self) - self.DeleteHandler = DeleteHandle(self) - self.WithHandler = WithHandle(self) - self.TryHandler = TryHandle(self) - self.AssertHandler = AssertHandle(self) - self.RaiseHandler = RaiseHandle(self) - self.MatchHandler = MatchHandle(self) - - def LogWarning(self, message: str, LineNum: int | None = None) -> None: - """记录警告 - - Args: - message: 警告消息 - LineNum: 行号(可选) - """ - warning = f"Warning: {message}" - if LineNum is not None: - warning += f" (line {LineNum})" - self.Warnings.append(warning) - - def LogError(self, message: str, LineNum: int | None = None) -> None: - """记录错误 - - Args: - message: 错误消息 - LineNum: 行号 - """ - _vlog().error(message) - entry: dict[str, str | int | None] = {'message': message, 'line': LineNum} - self.Errors.append(entry) - - # 检查 config 中是否有 debug 文件 - DebugFile: str | None = None - if hasattr(self, 'config') and self.config: - DebugFile = getattr(self.config, 'debug', None) - - if DebugFile: - with open(DebugFile, 'a', encoding='utf-8') as f: - LineInfo: str = f' line {LineNum}' if LineNum else '' - f.write(f'[ERROR]{LineInfo}: {message}\n') - - def SetDebugFile(self, FilePath: str) -> None: - """设置调试输出文件""" - self.DebugFile = FilePath - - def DebugPrint(self, *args: Any, **kwargs: Any) -> None: - """输出调试信息到文件""" - if self.DebugFile: - with open(self.DebugFile, 'a', encoding='utf-8') as f: - print(*args, file=f, **kwargs) - - def HandleExpr(self, Node: ast.AST, UseSingleQuote: bool = False, VarType: ir.Type | None = None) -> Any: - return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType) diff --git a/App/lib/core/Translator/ConstEval.py b/App/lib/core/Translator/ConstEval.py deleted file mode 100644 index 8785365..0000000 --- a/App/lib/core/Translator/ConstEval.py +++ /dev/null @@ -1,305 +0,0 @@ -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING -import llvmlite.ir as ir - -from lib.core.ConstEvaluator import ConstEvaluator - -if TYPE_CHECKING: - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - - -class ConstEvalMixin: - """常量表达式求值 Mixin - - 提供数组初始化常量构建与常量表达式求值能力。 - """ - - @staticmethod - def _bswap_constant_value(val: int, width: int) -> int: - """编译期字节序交换""" - if width == 16: - return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF) - elif width == 32: - return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF) - elif width == 64: - return ((val & 0xFF) << 56) | ((val & 0xFF00) << 40) | ((val & 0xFF0000) << 24) | ((val & 0xFF000000) << 8) | ((val >> 8) & 0xFF000000) | ((val >> 24) & 0xFF0000) | ((val >> 40) & 0xFF00) | ((val >> 56) & 0xFF) - return val - - def _BuildArrayInitConstants(self, value_node: ast.AST, ElemType: ir.Type, elem_type_node: ast.AST, ArrayCount: int, Gen: LlvmCodeGenerator, byte_order: str = '') -> list[ir.Constant] | None: - _zv: ir.Constant | None = Gen._zero_value_for_type(ElemType) - _fallback: ir.Constant = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined) - if not isinstance(value_node, (ast.List, ast.Set)): - return None - if isinstance(ElemType, ir.ArrayType): - constants: list[ir.Constant] = [] - for elt in value_node.elts: - if isinstance(elt, (ast.List, ast.Set)): - inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen) - if inner_consts: - try: - constants.append(ir.Constant(ElemType, inner_consts)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < ArrayCount: - constants.append(_fallback) - return constants[:ArrayCount] - StructName: str | None = None - if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: - StructName = elem_type_node.id - constants = [] - for elt in value_node.elts: - if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName: - const: ir.Constant | None = self.ClassHandler._BuildStructConstant(elt, StructName, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Constant): - # 字符串常量:根据引号类型决定 i8 或 i8* - if isinstance(elt.value, str): - const: ir.Constant | None = self._BuildStringLiteralConstant(elt, ElemType, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - else: - const = self._BuildScalarConstantUnified(elt, ElemType, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.UnaryOp): - const = self._BuildScalarConstantUnified(elt, ElemType, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr': - if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int): - try: - constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord': - if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1: - try: - constants.append(ir.Constant(ElemType, ord(elt.args[0].value))) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - else: - const_val: int | float | str | None = self._try_eval_const_call(elt, Gen) - if const_val is not None: - try: - constants.append(ir.Constant(ElemType, const_val)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < ArrayCount: - constants.append(_fallback) - if byte_order == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64): - swapped: list[ir.Constant] = [] - for c in constants: - if isinstance(c, ir.Constant) and isinstance(c.type, ir.IntType) and isinstance(c.constant, int): - swapped_val: int = self._bswap_constant_value(int(c.constant), ElemType.width) - swapped.append(ir.Constant(ElemType, swapped_val)) - else: - swapped.append(c) - constants = swapped - return constants[:ArrayCount] - - def _BuildStringLiteralConstant(self, node: ast.Constant, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None: - """根据引号类型决定字符串常量的类型: - - - 单引号单字符 → i8 (char 值) - - 双引号/单引号多字符/三重引号 → i8* (C 字符串指针) - - 空字符串 → 0 (None),传入 ptr 目标自动隐式转换 - """ - if not isinstance(node.value, str): - return None - s: str = node.value - # 空字符串 → 0 (None) - if len(s) == 0: - try: - return ir.Constant(target_type, 0) - except Exception: - return None - # 获取源代码以判断引号类型 - quote_char: str | None = None - is_triple: bool = False - col_offset: int = getattr(node, 'col_offset', 0) - node_lineno: int = getattr(node, 'lineno', 0) - # AST 的 lineno 可能不准确(常量节点可能指向下一行), - # 因此在 lineno 和 lineno-1 两行中查找引号 - for try_lineno in (node_lineno, node_lineno - 1): - source_line: str | None = Gen._get_source_line(try_lineno) - if source_line and col_offset < len(source_line): - ch: str = source_line[col_offset] - if ch in ("'", '"'): - quote_char = ch - if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'): - is_triple = True - break - # 判断是否为 char (i8):单引号、非三重、单字符 - is_char: bool = (not is_triple) and (quote_char == "'") and (len(s) == 1) - if is_char: - # 单引号单字符 → i8 - if isinstance(target_type, ir.IntType): - try: - return ir.Constant(target_type, ord(s)) - except Exception: - return None - # 目标类型不是整数 → 类型不匹配 - return None - else: - # 双引号/多字符/三重 → i8* (C 字符串) - if isinstance(target_type, ir.PointerType): - 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 = f"str_const_{id(node)}" - gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, arr_type, name=gv_name) - gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) - gv.linkage = 'internal' - return ir.Constant(target_type, gv.get_reference()) - # 目标类型不是指针 → 类型不匹配 - return None - - def _BuildScalarConstantUnified(self, node: ast.AST, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None: - """统一的标量常量构建方法。 - - 合并原 HandlesClassDef._BuildScalarConstant 与 HandlesImports._BuildScalarConstant 的特性: - - 支持 bool/int/float/str/ast.UnaryOp(USub)/ast.Name(True/False) - - 字符串处理委托给 _BuildStringLiteralConstant - - 显式拒绝 BaseStructType - - 全部 try/except 保护 - """ - # 显式拒绝结构体类型 - if isinstance(target_type, ir.BaseStructType): - return None - # 处理常量节点 - if isinstance(node, ast.Constant): - # bool 必须在 int 之前判断(bool 是 int 的子类) - if isinstance(node.value, bool): - try: - return ir.Constant(target_type, 1 if node.value else 0) - except Exception: - return None - elif isinstance(node.value, int): - try: - return ir.Constant(target_type, node.value) - except Exception: - return None - elif isinstance(node.value, float): - try: - return ir.Constant(target_type, node.value) - except Exception: - return None - elif isinstance(node.value, str): - # 字符串处理委托给 _BuildStringLiteralConstant - const: ir.Constant | None = self._BuildStringLiteralConstant(node, target_type, Gen) - if const is not None: - return const - # 回退:直接创建字符串全局变量(i8*) - try: - return Gen._create_string_global(node.value) - except Exception: - return None - # 处理一元负号 - elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub): - if isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int): - try: - return ir.Constant(target_type, -node.operand.value) - except Exception: - return None - # 处理 True/False 名称节点 - elif isinstance(node, ast.Name): - if node.id == 'True': - try: - return ir.Constant(target_type, 1) - except Exception: - return None - elif node.id == 'False': - try: - if isinstance(target_type, ir.PointerType): - return ir.Constant(target_type, None) - return ir.Constant(target_type, 0) - except Exception: - return None - return None - - def _try_eval_const_call(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | None: - if isinstance(node, ast.Call): - func_name: str | None = None - if isinstance(node.func, ast.Name): - func_name = node.func.id - elif isinstance(node.func, ast.Attribute): - func_name = node.func.attr - if func_name: - arg_vals: list[int | float | str | None] = [] - for arg in node.args: - v: int | float | str | None = self._try_eval_const_expr(arg, Gen) - if v is None: - return None - arg_vals.append(v) - if func_name == 'COLOR_RGB' and len(arg_vals) == 3: - r: int | float | str | None - g: int | float | str | None - b: int | float | str | None - r, g, b = arg_vals - return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r) - if func_name in Gen._DefineConstants: - return Gen._DefineConstants[func_name] - for key in Gen.functions: - if key.endswith(f'__{func_name}'): - return None - return None - return self._try_eval_const_expr(node, Gen) - - def _try_eval_const_expr(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | float | str | None: - return ConstEvaluator.eval_with_symtab(node, self.SymbolTable) - - def _BuildMultiDimArrayInitConstants(self, value_node: ast.AST, ArrayType: ir.ArrayType, Gen: LlvmCodeGenerator) -> list[ir.Constant] | None: - inner_type: ir.Type = ArrayType.element - count: int = ArrayType.count - elts: list[ast.AST] = list(value_node.elts) if hasattr(value_node, 'elts') else [] - _zv: ir.Constant | None = Gen._zero_value_for_type(inner_type) - _fallback: ir.Constant = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined) - constants: list[ir.Constant] = [] - for elt in elts: - if isinstance(inner_type, ir.ArrayType): - if isinstance(elt, (ast.List, ast.Set)): - inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen) - if inner_consts: - constants.append(ir.Constant(inner_type, inner_consts)) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Constant): - const: ir.Constant | None = self._BuildScalarConstantUnified(elt, inner_type, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.UnaryOp): - const = self._BuildScalarConstantUnified(elt, inner_type, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < count: - constants.append(_fallback) - return constants[:count] diff --git a/App/lib/core/Translator/LlvmGenerator.py b/App/lib/core/Translator/LlvmGenerator.py deleted file mode 100644 index 4ae3d90..0000000 --- a/App/lib/core/Translator/LlvmGenerator.py +++ /dev/null @@ -1,642 +0,0 @@ -from __future__ import annotations - -import ast -import re -import llvmlite.ir as ir - -from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, CTypeHelper -from lib.includes import t -from lib.constants.config import mode as _config_mode -from lib.core.VLogger import get_logger as _vlog -from lib.core.DecoratorPass import run as _run_decorator_pass -from lib.core.SymbolUtils import IsTModule, AnnotationContainsName - - -class LlvmGeneratorMixin: - """LLVM IR 生成 Mixin - - 提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。 - """ - - def GenerateLlvmDirect(self, Tree: ast.Module) -> str: - Gen: LlvmCodeGenerator = self.LlvmGen - - # === 新增:轻量 AST 遍历,收集类图信息,解决前向引用 === - Gen._class_graph: dict[str, dict[str, bool | list[str]]] = {} - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.ClassDef): - bases: list[str] = [] - for base in Node.bases: - if hasattr(base, 'id'): - bases.append(base.id) - elif hasattr(base, 'attr'): - bases.append(base.attr) - has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in Node.body) - # 检测 @t.NoVTable 装饰器(非多态继承基类标记) - has_novtable: bool = False - if hasattr(Node, 'decorator_list') and Node.decorator_list: - for decorator in Node.decorator_list: - if isinstance(decorator, ast.Attribute): - if getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable': - has_novtable = True - elif isinstance(decorator, ast.Name): - if decorator.id == 'NoVTable': - has_novtable = True - Gen._class_graph[Node.name] = { - 'bases': bases, - 'has_methods': has_methods, - 'has_novtable': has_novtable, - } - # === 结束新增 === - - # 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8* - # 这样在类方法中调用这些函数时,前向声明会使用正确的类型 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str': - Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8)) - - # 首先收集所有 CDefine 常量,确保类定义中可以引用 - def _extract_call_const_val(node: ast.AST) -> int | str | float | None: - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if getattr(node.func.value, 'id', None) == 't': - if node.args and isinstance(node.args[0], ast.Constant): - return node.args[0].value - elif isinstance(node.func, ast.Name): - if node.args and isinstance(node.args[0], ast.Constant): - return node.args[0].value - return None - - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value: - TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) - if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)): - val: int | str | float | None = None - if isinstance(Node.value, ast.Constant): - val = Node.value.value - else: - val = _extract_call_const_val(Node.value) - if val is not None: - if not hasattr(Gen, '_define_constants'): - Gen._define_constants: dict[str, int | str | float | bool] = {} - Gen._define_constants[Node.target.id] = val - existing = self.SymbolTable.lookup(Node.target.id) - if not (existing and existing.IsTypedef and existing.OriginalType): - sym_info: _CTypeInfo = _CTypeInfo() - sym_info.IsDefine = True - sym_info.DefineValue = val - self.SymbolTable.insert(Node.target.id, sym_info) - elif isinstance(Node, ast.Assign): - for target in Node.targets: - if isinstance(target, ast.Name): - TypeInfo: CTypeInfo | None = None - if Node.type_comment: - try: - tc_ast: ast.Expression = ast.parse(Node.type_comment, mode='eval') - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析类型注释失败: {_e}", "Exception") - if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)): - val: int | str | float | None = None - if isinstance(Node.value, ast.Constant): - val = Node.value.value - else: - val = _extract_call_const_val(Node.value) - if val is not None: - if not hasattr(Gen, '_define_constants'): - Gen._define_constants: dict[str, int | str | float | bool] = {} - Gen._define_constants[target.id] = val - sym_info: _CTypeInfo = _CTypeInfo() - sym_info.IsDefine = True - sym_info.DefineValue = val - self.SymbolTable.insert(target.id, sym_info) - - # 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明) - # 这样类方法编译时遇到未声明的函数可以按需前向声明 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - FuncName: str = Node.name - if FuncName not in self.FunctionDefCache: - self.FunctionDefCache[FuncName] = Node - - # 首先处理所有导入语句,确保模块在类型解析前被加载 - for Node in ast.iter_child_nodes(Tree): - Gen._set_node_info(Node) - try: - if isinstance(Node, ast.Import): - self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen) - elif isinstance(Node, ast.ImportFrom): - self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen) - except Exception as e: - lineno: int = getattr(Node, 'lineno', 0) - source_line: str | None = Gen._get_source_line(lineno) - src_file: str = getattr(Gen, '_current_source_file', '') - src_path: str = src_file if src_file else 'unknown' - line_info: str = "源代码 (%s, line %d)" % (src_path, lineno) - if source_line: - line_info += ":\n %d | %s" % (lineno, source_line) - self._ErrorStack.append((type(e).__name__, str(e), line_info)) - - # 前向声明所有顶层函数,确保全局变量初始化时能引用函数指针 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - Gen._set_node_info(Node) - self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen) - - # 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等 - Gen._current_tree: ast.Module = Tree - for Node in ast.iter_child_nodes(Tree): - Gen._set_node_info(Node) - if isinstance(Node, ast.AnnAssign): - self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) - elif isinstance(Node, ast.Assign): - self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) - - # 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.ClassDef): - Gen._set_node_info(Node) - self.ClassHandler._EmitClassLlvm(Node, Gen) - - Gen._generate_structs() - Gen._create_Vtable_globals() - - for Node in ast.iter_child_nodes(Tree): - Gen._set_node_info(Node) - try: - if isinstance(Node, ast.Import): - continue - elif isinstance(Node, ast.ImportFrom): - continue - elif isinstance(Node, ast.ClassDef): - continue - elif isinstance(Node, ast.FunctionDef): - self.FunctionHandler._EmitFunctionLlvm(Node, Gen) - elif isinstance(Node, ast.AnnAssign): - self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) - elif isinstance(Node, ast.Assign): - self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) - elif isinstance(Node, ast.If): - pass - elif isinstance(Node, ast.Expr): - self._HandleModuleLevelExprLlvm(Node, Gen) - except Exception as e: - lineno: int = getattr(Node, 'lineno', 0) - source_line: str | None = Gen._get_source_line(lineno) - src_file: str = getattr(Gen, '_current_source_file', '') - src_path: str = src_file if src_file else 'unknown' - line_info: str = "源代码 (%s, line %d)" % (src_path, lineno) - if source_line: - line_info += ":\n %d | %s" % (lineno, source_line) - self._ErrorStack.append((type(e).__name__, str(e), line_info)) - raise - Gen._set_Vtable_initializers() - # 执行 DecoratorPass:为带自定义装饰器的函数生成 wrapper - _run_decorator_pass(Gen) - ir_code: str = Gen.finalize() - return ir_code - - def _HandleModuleLevelExprLlvm(self, Node: ast.Expr, Gen: LlvmCodeGenerator) -> None: - if not isinstance(Node.value, ast.Call): - return - call: ast.Call = Node.value - if not isinstance(call.func, ast.Attribute): - return - if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c': - return - func_name: str = call.func.attr - if func_name == 'LLVMIR': - self._HandleModuleLevelLLVMIR(call, Gen) - - def _HandleModuleLevelLLVMIR(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> None: - if not Node.args: - return - first_arg: ast.expr = Node.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - ir_text: str = first_arg.value - elif isinstance(first_arg, ast.JoinedStr): - parts: list[str] = [] - for value in first_arg.values: - if isinstance(value, ast.Constant) and isinstance(value.value, str): - parts.append(value.value) - elif isinstance(value, ast.FormattedValue): - parts.append('') - ir_text = ''.join(parts) - else: - return - self._InsertModuleLevelLLVMIR(Gen, ir_text) - - def _InsertModuleLevelLLVMIR(self, Gen: LlvmCodeGenerator, ir_text: str) -> None: - for line in ir_text.strip().split('\n'): - line = line.strip() - if not line: - continue - module_flags_match: re.Match[str] | None = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line) - if module_flags_match: - ref: str = module_flags_match.group(1) - if not hasattr(Gen, '_pending_module_flags'): - Gen._pending_module_flags: list = [] - Gen._pending_module_flags_refs: str = ref - continue - metadata_match: re.Match[str] | None = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line) - if metadata_match: - md_id: str = metadata_match.group(1) - md_body: str = metadata_match.group(2) - fields: list[ir.Constant | ir.MetaDataString | str] = [] - for field_str in re.split(r',\s*', md_body): - field_str = field_str.strip() - if not field_str: - continue - int_m: re.Match[str] | None = re.match(r'^i32\s+(\d+)$', field_str) - if int_m: - fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1)))) - continue - str_m: re.Match[str] | None = re.match(r'^"([^"]*)"$', field_str) - if str_m: - fields.append(ir.MetaDataString(Gen.module, str_m.group(1))) - continue - mdstr_m: re.Match[str] | None = re.match(r'^!"([^"]*)"$', field_str) - if mdstr_m: - fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1))) - continue - int_m2: re.Match[str] | None = re.match(r'^(\d+)$', field_str) - if int_m2: - fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1)))) - continue - ref_m: re.Match[str] | None = re.match(r'^(!\d+)$', field_str) - if ref_m: - fields.append(ref_m.group(1)) - continue - if fields: - if not hasattr(Gen, '_pending_metadata'): - Gen._pending_metadata: list[tuple[str, list]] = [] - Gen._pending_metadata.append((md_id, fields)) - continue - self._FlushModuleMetadata(Gen) - - def _FlushModuleMetadata(self, Gen: LlvmCodeGenerator) -> None: - if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata: - return - md_map: dict[str, ir.MetaDataString] = {} - for md_id, fields in Gen._pending_metadata: - resolved: list[ir.Constant | ir.MetaDataString] = [] - for f in fields: - if isinstance(f, str) and f.startswith('!'): - ref: ir.MetaDataString | None = md_map.get(f) - if ref: - resolved.append(ref) - else: - resolved.append(f) - md_value: ir.MetaDataString = Gen.module.add_metadata(resolved) - md_map[md_id] = md_value - if hasattr(Gen, '_pending_module_flags_refs'): - ref: str = Gen._pending_module_flags_refs - md_node: ir.MetaDataString | None = md_map.get(ref) - if md_node: - Gen.module.add_named_metadata('llvm.module.flags', md_node) - Gen._pending_metadata = [] - Gen._pending_module_flags_refs = None - - def GenerateCCode(self, Tree: ast.Module, target: str = 'llvm') -> str: - """生成代码 - - Args: - Tree: Python AST 树 - target: 目标代码类型,仅支持 'llvm' - - Returns: - 生成的代码字符串 - """ - self._generated_vars: set[str] = set() - self.VarScopes = [{}] # 全局作用域 - - # 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名 - if not getattr(self, '_ImportedModules', None): - self._ImportedModules: set[str] = set() - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.Import): - for alias in Node.names: - name: str = alias.name - if name in ('c', 't'): - continue - self._ImportedModules.add(name) - if alias.asname: - self.SymbolTable.import_aliases[alias.asname] = name - elif isinstance(Node, ast.ImportFrom): - module_name: str | None = Node.module - if module_name and module_name not in ('c', 't'): - self._ImportedModules.add(module_name) - for alias in Node.names: - if alias.asname: - self.SymbolTable.import_aliases[alias.asname] = f"{module_name}.{alias.name}" - - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.ClassDef): - ClassName: str = Node.name - - # 检查是否是特殊类型(枚举或联合体) - IsSpecialType: bool = False - if Node.bases: - for base in Node.bases: - if hasattr(base, 'attr'): - if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']: - IsSpecialType = True - break - elif hasattr(base, 'id'): - if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']: - IsSpecialType = True - break - - # 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理) - if IsSpecialType: - continue - - members: dict[str, CTypeInfo] = {} - IsTypedef: bool = False - TypedefName: str | None = None - - if hasattr(Node, 'annotation') and Node.annotation: - try: - if AnnotationContainsName(Node.annotation, 'CTypedef'): - IsTypedef = True - if isinstance(Node.annotation, ast.Call): - if Node.annotation.args: - if isinstance(Node.annotation.args[0], ast.Constant): - TypedefName = Node.annotation.args[0].value - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"解析 typedef 注解失败: {_e}", "Exception") - - if not IsTypedef: - for item in Node.body: - if isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name) and target.id == '__annotations__': - if isinstance(item.value, ast.Dict): - for key, value in zip(item.value.keys, item.value.values): - if isinstance(key, ast.Constant) and key.value == '__type__': - if AnnotationContainsName(value, 'CTypedef'): - IsTypedef = True - - if IsTypedef: - TypedefKey: str = TypedefName if TypedefName else ClassName - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = TypedefKey - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = f'struct {ClassName}' - TypedefNode.set('IsComplete', True) - TypedefNode.file = '' - self.SymbolTable.insert(TypedefKey, TypedefNode) - - for item in Node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - VarName: str = item.target.id - try: - TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation) - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - IsPtr: bool = TypeInfo.IsPtr - if not IsPtr: - if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): - if AnnotationContainsName(item.annotation, 'CPtr'): - IsPtr = True - dims: list[int] = [] - if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): - if isinstance(item.annotation.value, ast.Name): - if IsTModule(item.annotation.value.id, self.SymbolTable): - if hasattr(item.annotation, 'slice'): - try: - dims.append(int(item.annotation.slice.value)) - except Exception as _e: - if _config_mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - MemberInfo: CTypeInfo = TypeInfo.Copy() - if dims: - MemberInfo.ArrayDims = [str(d) for d in dims] - members[VarName] = MemberInfo - except Exception as _e: - if _config_mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - - if not IsTypedef: - StructNode: CTypeInfo = CTypeInfo() - StructNode.Name = ClassName - StructNode.IsStruct = True - StructNode.Members = members or {} - StructNode.file = '' - existing: CTypeInfo | None = self.SymbolTable.lookup(ClassName) - if existing: - if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: - StructNode.IsCpythonObject = True - self.SymbolTable.insert(ClassName, StructNode) - elif isinstance(Node, ast.FunctionDef): - FuncName: str = Node.name - if not self.SymbolTable.has(FuncName): - FuncNode: CTypeInfo = CTypeInfo() - FuncNode.Name = FuncName - FuncNode.IsFunction = True - FuncNode.file = '' - self.SymbolTable.insert(FuncName, FuncNode) - elif isinstance(Node, ast.AnnAssign): - if isinstance(Node.target, ast.Name): - VarName: str = Node.target.id - - VarType: str = 'unknown' - IsPtr: bool = False - IsTypedef_assignment: bool = False - - if Node.annotation: - try: - if AnnotationContainsName(Node.annotation, 'CTypedef'): - IsTypedef_assignment = True - except Exception as _e: - if _config_mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - - if IsTypedef_assignment and Node.value: - if isinstance(Node.value, ast.Name): - OriginalType: str = Node.value.id - if OriginalType in self.GeneratedTypes: - OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType) - if OriginalInfo: - if isinstance(OriginalInfo, dict): - actual_type: str = OriginalInfo.get('type', 'struct') - elif isinstance(OriginalInfo, CTypeInfo): - if OriginalInfo.IsEnum: - actual_type = 'enum' - elif OriginalInfo.IsTypedef: - actual_type = 'typedef' - elif OriginalInfo.IsStruct: - actual_type = 'struct' - else: - actual_type = 'struct' - else: - actual_type = 'struct' - if actual_type == 'enum': - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = f'enum {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - elif actual_type == 'typedef': - TypedefNode = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - if isinstance(OriginalInfo, dict): - TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}') - elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: - TypedefNode.OriginalType = OriginalInfo.OriginalType - else: - TypedefNode.OriginalType = f'struct {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - else: - TypedefNode = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = f'struct {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - self.GeneratedTypes.add(VarName) - continue - else: - OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType) - if OriginalInfo: - if isinstance(OriginalInfo, dict): - actual_type: str = OriginalInfo.get('type', 'struct') - elif isinstance(OriginalInfo, CTypeInfo): - if OriginalInfo.IsEnum: - actual_type = 'enum' - elif OriginalInfo.IsTypedef: - actual_type = 'typedef' - elif OriginalInfo.IsStruct: - actual_type = 'struct' - else: - actual_type = 'struct' - else: - actual_type = 'struct' - if actual_type == 'typedef': - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - if isinstance(OriginalInfo, dict): - TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}') - elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: - TypedefNode.OriginalType = OriginalInfo.OriginalType - else: - TypedefNode.OriginalType = f'struct {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif actual_type == 'struct': - TypedefNode = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = f'struct {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif actual_type == 'enum': - TypedefNode = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = f'enum {OriginalType}' - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif isinstance(Node.value, ast.Attribute): - CName: str | None = CTypeHelper.GetCName(Node.value.attr) - if CName: - TypedefNode: CTypeInfo = CTypeInfo() - TypedefNode.Name = VarName - TypedefNode.IsTypedef = True - TypedefNode.OriginalType = CName - TypedefNode.file = '' - self.SymbolTable.insert(VarName, TypedefNode) - self.GeneratedTypes.add(VarName) - continue - - if Node.annotation: - try: - TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) - IsPtr = TypeInfo.IsPtr if TypeInfo else False - except Exception as _e: - if _config_mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - # 如果符号已经存在且是 typedef,不要覆盖它 - existing = self.SymbolTable.lookup(VarName) - if existing and existing.IsTypedef and existing.OriginalType: - # typedef 已正确插入,保持现有条目不覆盖 - pass - else: - var_node: CTypeInfo = CTypeInfo() - var_node.Name = VarName - var_node.IsVariable = True - var_node.PtrCount = 1 if IsPtr else 0 - var_node.file = '' - self.SymbolTable.insert(VarName, var_node) - - self.LlvmGen: LlvmCodeGenerator = LlvmCodeGenerator( - triple=getattr(self, 'triple', None), - datalayout=getattr(self, 'datalayout', None), - ) - self.LlvmGen._Trans = self - self.LlvmGen._import_handler_ref = self.ImportHandler - if hasattr(self, '_module_sha1'): - self.LlvmGen.module_sha1 = self._module_sha1 - if hasattr(self, '_ModuleSha1Map'): - self.LlvmGen.ModuleSha1Map = self._ModuleSha1Map - if hasattr(self, '_struct_sha1_map'): - self.LlvmGen._struct_sha1_map = self._struct_sha1_map - if hasattr(self, '_temp_dir'): - self.LlvmGen._temp_dir = self._temp_dir - if hasattr(self, '_export_extern_funcs'): - self.LlvmGen._export_extern_funcs = self._export_extern_funcs - self.LlvmGen.setup_from_symbol_table(self.SymbolTable) - if hasattr(self, 'CurrentFile') and self.CurrentFile: - self.LlvmGen._set_source_info(self.CurrentFile) - - # --- 修复:共享 vtable 状态跨模块 --- - # 根因:LlvmGen 每模块重新创建,class_vtable/class_methods 等是实例级属性, - # 不跨模块共享。导致模块 B 编译时 _specialize_generic_class 触发的 - # pool.alloc(48) 找不到 MemManager 的虚表状态,直接调用 stub 返回 NULL → 段错误。 - # 修复:将 vtable 状态存储在 Translator 对象上并赋值给每个新 Gen。 - if not hasattr(self, '_shared_class_vtable'): - self._shared_class_vtable: set[str] = set() - self._shared_cross_module_vtable: set[str] = set() - self._shared_class_methods: dict[str, list[str]] = {} - self._shared_cross_module_novtable: set[str] = set() - # 合并 setup_from_symbol_table 创建的实例级 class_methods 到共享 dict - # (仅添加新类,不覆盖已有方法列表) - for _cls_name, _methods in self.LlvmGen.class_methods.items(): - if _cls_name not in self._shared_class_methods: - self._shared_class_methods[_cls_name] = _methods - else: - for _m in _methods: - if _m not in self._shared_class_methods[_cls_name]: - self._shared_class_methods[_cls_name].append(_m) - # 替换为共享状态 - self.LlvmGen.class_vtable = self._shared_class_vtable - self.LlvmGen._cross_module_vtable_classes = self._shared_cross_module_vtable - self.LlvmGen.class_methods = self._shared_class_methods - self.LlvmGen._cross_module_novtable = self._shared_cross_module_novtable - # --- 修复结束 --- - - return self.GenerateLlvmDirect(Tree) diff --git a/App/lib/core/Translator/PythonParser.py b/App/lib/core/Translator/PythonParser.py deleted file mode 100644 index 9bcabcc..0000000 --- a/App/lib/core/Translator/PythonParser.py +++ /dev/null @@ -1,452 +0,0 @@ -from __future__ import annotations - -import ast -import json -import struct - -from lib.utils.helpers import DetectFileType -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolUtils import IsTModule, AnnotationContainsName -from lib.includes import t -from lib.constants.config import mode as _ConfigMode -from lib.core.VLogger import get_logger as _vlog - - -class PythonParserMixin: - """Python 文件解析 Mixin - - 提供辅助文件解析、symbin 文件加载与 Python 源文件解析能力。 - """ - - def ParseHelperFiles(self, HelperFiles: list[str], encoding: str = 'utf-8') -> None: - """解析辅助文件,提取符号信息 - - 支持 .py, .c, .h 和 .symbin 文件 - """ - for FilePath in HelperFiles: - ext: str = DetectFileType(FilePath) - if ext == '.py': - self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False) - elif ext == '.c': - pass # .c 文件解析已移除,不再使用旧的正则解析路径 - elif FilePath.endswith('.symbin'): - self.LoadSymbinFile(FilePath) - - def LoadSymbinFile(self, FilePath: str) -> None: - """从.symbin文件加载符号表 - - Args: - FilePath: .symbin文件路径 - """ - try: - with open(FilePath, 'rb') as f: - data: bytes = f.read() - - # 导入序列化函数(避免循环导入) - # 解析二进制格式 - if len(data) < 4: - _vlog().warning(f"无效的 symbin 文件 (太短): {FilePath}") - return - - # 解析4字节长度头(小端序) - length: int = struct.unpack(' None: - """解析Python文件,提取类、函数、变量信息 - - Args: - FilePath: 要解析的文件路径 - encoding: 文件编码 - UpdateCurrentFile: 是否更新 CurrentFile(默认为 True,处理导入时设为 False) - """ - try: - with open(FilePath, 'r', encoding=encoding) as f: - content: str = f.read() - - # 保存当前处理的文件路径(仅在主文件处理时更新) - if UpdateCurrentFile: - self.CurrentFile = FilePath - - # 解析Python代码为AST - tree: ast.Module = ast.parse(content) - - # 保存 AST 树供后续使用 - self.tree = tree - - # 第一遍:检测特殊赋值语句,收集跟在 class 后面的 - # 遍历 tree.body,找到所有 ClassDef,然后收集紧随其后的赋值语句 - i: int = 0 - while i < len(tree.body): - node: ast.stmt = tree.body[i] - - # 检测 ClassDef - if isinstance(node, ast.ClassDef): - ClassName: str = node.name - # 使用类名_行号作为唯一 key - ClassKey: str = f"{ClassName}_{node.lineno}" - - # 检查后面的语句,收集特殊赋值 - j: int = i + 1 - while j < len(tree.body): - NextNode: ast.stmt = tree.body[j] - - if isinstance(NextNode, ast.Assign): - # 检测 xxx = xxx 或 xxx = yyy - if len(NextNode.targets) == 1 and isinstance(NextNode.targets[0], ast.Name): - TargetName: str = NextNode.targets[0].id - if isinstance(NextNode.value, ast.Name): - ValueName: str = NextNode.value.id - if ValueName == ClassName: - # 这是 class 的实例化 - if ClassKey not in self.EmbeddedAssignments: - self.EmbeddedAssignments[ClassKey] = [] - self.EmbeddedAssignments[ClassKey].append(TargetName) - j += 1 - continue - elif isinstance(NextNode, ast.AnnAssign): - # 检测 xxx: t.Postdefinition(yyy) 或 xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx - if isinstance(NextNode.target, ast.Name): - TargetName: str = NextNode.target.id - # 先处理新格式:t.Postdefinition(...) - annotation: ast.expr | None = NextNode.annotation - PostdefNode: ast.Call | None = None - - # 递归搜索整个注解树,找到 t.Postdefinition(...) 调用 - def find_PostdefNode(node: ast.AST) -> ast.Call | None: - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id, self.SymbolTable) and node.func.attr == 'Postdefinition': - return node - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - LeftResult: ast.Call | None = find_PostdefNode(node.left) - if LeftResult: - return LeftResult - RightResult: ast.Call | None = find_PostdefNode(node.right) - if RightResult: - return RightResult - return None - - PostdefNode = find_PostdefNode(annotation) - # 检查是否找到 t.Postdefinition(...) 调用 - if PostdefNode: - if (isinstance(PostdefNode.func, ast.Attribute) and - hasattr(PostdefNode.func, 'value') and - hasattr(PostdefNode.func.value, 'id') and - IsTModule(PostdefNode.func.value.id, self.SymbolTable) and - PostdefNode.func.attr == 'Postdefinition' and - PostdefNode.args): - # 检查第一个参数是否是当前类名 - arg: ast.expr = PostdefNode.args[0] - if isinstance(arg, ast.Name) and arg.id == ClassName: - # 检查是否包含 CTypedef 或 CPtr - HasCtypedef: bool = AnnotationContainsName(NextNode.annotation, 'CTypedef') - IsPtr: bool = AnnotationContainsName(NextNode.annotation, 'CPtr') - - # 解析维度列表(第二个参数) - dimensions: list[ast.expr] = [] - if len(PostdefNode.args) > 1: - # 第二个参数应该是一个列表 - dim_arg: ast.expr = PostdefNode.args[1] - if isinstance(dim_arg, ast.List): - for DimExpr in dim_arg.elts: - dimensions.append(DimExpr) - - # 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取 - # 例如:memory_block_t[MAX_ORDER + 1] | t.CPtr - if not dimensions: - def extract_subscript_dims(node: ast.AST) -> list[ast.expr]: - """递归提取 Subscript 节点的维度""" - dims: list[ast.expr] = [] - if isinstance(node, ast.Subscript): - # 提取当前维度 - if isinstance(node.slice, ast.Constant): - dims.append(ast.Constant(value=node.slice.value)) - elif isinstance(node.slice, ast.Name): - dims.append(ast.Name(id=node.slice.id, ctx=ast.Load())) - elif isinstance(node.slice, ast.BinOp): - dims.append(node.slice) - # 递归提取更外层的维度 - dims.extend(extract_subscript_dims(node.value)) - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - # 处理 Type | t.CPtr 的情况,检查左侧 - dims.extend(extract_subscript_dims(node.left)) - return dims - - # 从注解中提取维度 - subscript_dims: list[ast.expr] = extract_subscript_dims(annotation) - if subscript_dims: - # 反转维度顺序(从内到外) - dimensions = list(reversed(subscript_dims)) - - # 获取赋值值 - value: ast.expr | None = None - if hasattr(NextNode, 'value') and NextNode.value is not None: - value = NextNode.value - - # 添加到对应的 assignments - # 对于 t.Postdefinition(...),只有包含 CTypedef 或 CPtr 时才视为 typedef 类型 - if HasCtypedef or IsPtr: - if ClassKey not in self.TypedefAssignments: - self.TypedefAssignments[ClassKey] = [] - # 如果有维度信息,使用字典存储 - if dimensions: - self.TypedefAssignments[ClassKey].append({ - 'name': TargetName, - 'IsPtr': IsPtr, - 'dimensions': dimensions, - 'value': value - }) - else: - self.TypedefAssignments[ClassKey].append((TargetName, IsPtr)) - else: - if ClassKey not in self.EmbeddedAssignments: - self.EmbeddedAssignments[ClassKey] = [] - # 如果有维度信息,使用字典存储 - if dimensions: - self.EmbeddedAssignments[ClassKey].append({ - 'name': TargetName, - 'dimensions': dimensions, - 'value': value - }) - else: - self.EmbeddedAssignments[ClassKey].append(TargetName) - - # 检查是否有 __set_default__ 初始化 - if AnnotationContainsName(NextNode.annotation, '__set_default__'): - self._handle_set_default_in_parse(ClassKey, TargetName, ClassName, NextNode) - j += 1 - continue - # 再处理旧格式:xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx - # 注意:这种格式的 typedef 不应该被合并到结构体定义中, - # 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments - elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute): - if isinstance(NextNode.annotation.value, ast.Name): - annot_id: str = NextNode.annotation.value.id - annot_attr: str = NextNode.annotation.attr - if annot_id == 't' and NextNode.value: - if isinstance(NextNode.value, ast.Name): - ValueName: str = NextNode.value.id - if ValueName == ClassName: - # 检查是 CTypedef 还是 CPtr - if annot_attr == t.CPtr.__name__: - # t.CPtr 表示指针变量,加入 TypedefAssignments,设置 IsPtr=True - if ClassKey not in self.TypedefAssignments: - self.TypedefAssignments[ClassKey] = [] - self.TypedefAssignments[ClassKey].append((TargetName, True)) - j += 1 - continue - # 注意:t.CTypedef 不在这里处理,由 HandlesAnnAssign 生成独立的 typedef 语句 - # 如果不是特殊赋值,停止收集 - break - - i = j - continue - - i += 1 - - # 提取类定义(作为结构体) - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - ClassName: str = node.name - # 先把类名加入 GeneratedTypes,这样 GetTypeName 可以正确识别 - self.GeneratedTypes.add(ClassName) - - # 检测是否是 CEnum - IsCenum: bool = False - for base in node.bases: - if isinstance(base, ast.Attribute): - if base.attr in ('CEnum', 'REnum'): - IsCenum = True - break - elif isinstance(base, ast.Name): - if base.id in ('CEnum', 'REnum'): - IsCenum = True - break - - # 检测是否有 @t.Object 装饰器或继承自 t.Object - IsCpythonObject: bool = False - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if (hasattr(decorator.value, 'id') and - IsTModule(decorator.value.id, self.SymbolTable) and - decorator.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if (hasattr(decorator.func.value, 'id') and - IsTModule(decorator.func.value.id, self.SymbolTable) and - decorator.func.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(decorator.func, ast.Name): - if decorator.func.id == 'Object': - IsCpythonObject = True - break - elif isinstance(decorator, ast.Name): - if decorator.id == 'Object': - IsCpythonObject = True - break - if not IsCpythonObject and hasattr(node, 'bases') and node.bases: - for base in node.bases: - if isinstance(base, ast.Attribute): - if (hasattr(base.value, 'id') and - IsTModule(base.value.id, self.SymbolTable) and - base.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(base, ast.Name): - if base.id == 'Object': - IsCpythonObject = True - break - - if IsCenum: - # 注册为 enum 类型 - EnumNode: CTypeInfo = CTypeInfo() - EnumNode.Name = ClassName - EnumNode.IsEnum = True - EnumNode.set('file', '') - self.SymbolTable.insert(ClassName, EnumNode) - - # 注册 enum 成员(提取枚举值,与 SymbolExtractor 逻辑一致) - next_enum_value: int = 0 - for item in node.body: - MemberName: str | None = None - ItemValue: object | None = None - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - MemberName = item.target.id - ItemValue = item.value - elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): - MemberName = item.targets[0].id - ItemValue = item.value - if MemberName is None: - continue - MemberNode: CTypeInfo = CTypeInfo() - MemberNode.Name = MemberName - MemberNode.BaseType = t.CEnum(ClassName) - # 提取枚举值:优先用显式赋值,否则自动编号 - if ItemValue is not None and isinstance(ItemValue, ast.Constant) and isinstance(ItemValue.value, int): - MemberNode.value = ItemValue.value - next_enum_value = ItemValue.value + 1 - else: - MemberNode.value = next_enum_value - next_enum_value += 1 - MemberNode.EnumName = ClassName - MemberNode.library_name = None - MemberNode.IsEnumMember = True - self.SymbolTable.insert(MemberName, MemberNode) - self.SymbolTable.insert(f"{ClassName}.{MemberName}", MemberNode) - self.SymbolTable.insert(f"{ClassName}_{MemberName}", MemberNode) - - continue - - # 检测是否是 Anonymous - IsAnonymous: bool = False - - # 提取结构体成员信息 - members: dict[str, CTypeInfo] = {} - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - VarName: str = item.target.id - try: - TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation) - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - IsPtr: bool = TypeInfo.IsPtr - if not IsPtr: - if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): - if AnnotationContainsName(item.annotation, 'CPtr'): - IsPtr = True - dims: list[int] = [] - if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): - if isinstance(item.annotation.value, ast.Name): - if IsTModule(item.annotation.value.id, self.SymbolTable): - if hasattr(item.annotation, 'slice'): - try: - dims.append(int(item.annotation.slice.value)) - except Exception as _e: - if _ConfigMode == "strict": - raise - _vlog().warning(f"解析数组维度失败: {_e}", "Exception") - MemberInfo: CTypeInfo = TypeInfo.Copy() - if dims: - MemberInfo.ArrayDims = [str(d) for d in dims] - members[VarName] = MemberInfo - except Exception as _e: - if _ConfigMode == "strict": - raise - _vlog().warning(f"解析结构体成员失败: {_e}", "Exception") - StructNode: CTypeInfo = CTypeInfo() - StructNode.Name = ClassName - StructNode.IsStruct = True - StructNode.Members = members or {} - StructNode.set('file', '') - StructNode.set('IsAnonymous', IsAnonymous) - StructNode.set('IsCpythonObject', IsCpythonObject) - self.SymbolTable.insert(ClassName, StructNode) - elif isinstance(node, ast.FunctionDef): - FuncName: str = node.name - if not self.SymbolTable.has(FuncName): - FuncNode: CTypeInfo = CTypeInfo() - FuncNode.Name = FuncName - FuncNode.IsFunction = True - FuncNode.set('file', '') - self.SymbolTable.insert(FuncName, FuncNode) - elif isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name): - VarName: str = node.target.id - # 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理) - is_ctypedef: bool = False - if node.annotation: - if isinstance(node.annotation, ast.Attribute): - if isinstance(node.annotation.value, ast.Name): - if IsTModule(node.annotation.value.id, self.SymbolTable) and node.annotation.attr == 'CTypedef': - is_ctypedef = True - elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr): - def _has_ctype(ann: ast.AST) -> bool: - if isinstance(ann, ast.Attribute): - return hasattr(ann.value, 'id') and IsTModule(ann.value.id) and ann.attr == 'CTypedef' - if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): - return _has_ctype(ann.left) or _has_ctype(ann.right) - if isinstance(ann, ast.Subscript): - return _has_ctype(ann.value) - return False - if _has_ctype(node.annotation): - is_ctypedef = True - if not is_ctypedef: - # 如果符号已经存在且是 typedef,不要覆盖它 - existing = self.SymbolTable.lookup(VarName) - if existing and existing.IsTypedef and existing.OriginalType: - pass - else: - IsPtr: bool = False - if node.annotation: - try: - TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(node.annotation) - IsPtr = TypeInfo.IsPtr if TypeInfo else False - except Exception as _e: - if _ConfigMode == "strict": - raise - _vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception") - var_node: CTypeInfo = CTypeInfo() - var_node.Name = VarName - var_node.IsVariable = True - var_node.set('IsPtr', IsPtr) - var_node.set('file', '') - self.SymbolTable.insert(VarName, var_node) - except Exception as e: - _vlog().warning(f'解析 Python 文件失败 {FilePath}: {e}') - - # ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用 - # 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式 diff --git a/App/lib/core/Translator/__init__.py b/App/lib/core/Translator/__init__.py deleted file mode 100644 index 84114dc..0000000 --- a/App/lib/core/Translator/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Translator 包 - 代码转换器模块""" -from lib.core.Translator.BaseTranslator import BaseTranslatorMixin, _StrictLog -from lib.core.Translator.AnnotationLoader import AnnotationLoaderMixin -from lib.core.Translator.PythonParser import PythonParserMixin -from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -from lib.core.Translator.ConstEval import ConstEvalMixin - -__all__ = [ - 'BaseTranslatorMixin', 'AnnotationLoaderMixin', 'PythonParserMixin', - 'LlvmGeneratorMixin', 'ConstEvalMixin', '_StrictLog' -] diff --git a/App/lib/core/TypeAnnotationResolver.py b/App/lib/core/TypeAnnotationResolver.py deleted file mode 100644 index 9ebcad1..0000000 --- a/App/lib/core/TypeAnnotationResolver.py +++ /dev/null @@ -1,736 +0,0 @@ -from __future__ import annotations -import ast -import warnings -from typing import TYPE_CHECKING - -from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper -from lib.core.ConstEvaluator import ConstEvaluator -from lib.core.SymbolUtils import IsTModule, IsTModulePath, IsListAnnotation -from lib.includes import t -from lib.constants.config import mode as _config_mode - -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - - -class TypeAnnotationResolver: - """从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。""" - - @staticmethod - def from_type_name(TypeName: str) -> CTypeInfo: - """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" - # Handle pointer types like 'CUInt32T *', 'void *', etc. - ptr_count: int = 0 - base_name: str = TypeName - while base_name.endswith(' *') or base_name.endswith('*'): - ptr_count += 1 - base_name = base_name.rstrip(' *').rstrip() - - entry: tuple[type, int] | None = BuiltinTypeMap.Get(base_name) - if entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = entry - info: CTypeInfo = CTypeInfo() - info.BaseType = TypeClass - info.PtrCount = base_ptr + ptr_count - return info - # Handle LLVM primitive type names (e.g., 'i64', 'double' from generic type inference) - llvm_map: dict = CTypeInfo._get_llvm_primitive_map() - llvm_entry: tuple[type, int] | None = llvm_map.get(base_name) - if llvm_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = llvm_entry - info: CTypeInfo = CTypeInfo() - info.BaseType = TypeClass - info.PtrCount = base_ptr + ptr_count - return info - # Fallback with pointer count - info: CTypeInfo = CTypeInfo.CreateFromTypeName(TypeName) - if ptr_count > 0: - info.PtrCount = ptr_count - return info - - @staticmethod - def try_eval_const_expr(node: ast.AST, SymbolTable: SymbolTable) -> int | float | str | None: - return ConstEvaluator.eval_with_symtab(node, SymbolTable) - - @staticmethod - def from_node(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """从 AST 节点解析 CTypeInfo - - Args: - Node: AST 节点(如 ast.Name, ast.Attribute 等) - SymbolTable: 符号表字典 - """ - if isinstance(Node, ast.Constant): - return TypeAnnotationResolver._from_node_constant(Node, SymbolTable) - if isinstance(Node, ast.Name): - return TypeAnnotationResolver._from_node_name(Node, SymbolTable) - if isinstance(Node, ast.Call): - return TypeAnnotationResolver._from_node_call(Node, SymbolTable) - if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): - return TypeAnnotationResolver._from_node_binop(Node, SymbolTable) - if isinstance(Node, ast.Subscript): - return TypeAnnotationResolver._from_node_subscript(Node, SymbolTable) - if isinstance(Node, ast.Attribute): - return TypeAnnotationResolver._from_node_attribute(Node, SymbolTable) - return CTypeInfo() - - @staticmethod - def _from_node_constant(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Constant 节点""" - TypeName: str = Node.value - return TypeAnnotationResolver.from_type_name(TypeName) - - @staticmethod - def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Name 节点""" - TypeName: str = Node.id - TypeObj: type | None = CTypeHelper.GetTModuleCType(TypeName) - if TypeObj is None: - TypeObj = getattr(t, TypeName, None) - if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType) and TypeObj is not t.CType: - if TypeObj == t.CPtr: - Result: CTypeInfo = CTypeInfo() - Result.PtrCount = 1 - Result.BaseType = t.CVoid() - return Result - if TypeObj == t.State: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - Result.BaseType = t.CVoid() - return Result - Inst: t.CType = TypeObj() - Result: CTypeInfo = CTypeInfo() - Result.Name = type(Inst).__name__ - # 存储类修饰符(CExtern, CExport, CInline, CThreadLocal 等): - # position 含 STORAGE_CLASS 且不含 BASE → 纯修饰符,无实际类型 - if t.CType.STORAGE_CLASS in TypeObj.position and t.CType.BASE not in TypeObj.position: - Result.BaseType = t.CVoid() - Result.Storage = Inst - return Result - # 类型限定符(CConst, CVolatile 等) - if t.CType.TYPE_QUALIFIER in TypeObj.position and t.CType.BASE not in TypeObj.position: - Result.BaseType = t.CVoid() - if TypeObj == t.CConst: - Result.DataConst = True - elif TypeObj == t.CVolatile: - Result.DataVolatile = True - return Result - Result.BaseType = TypeObj - if hasattr(Inst, 'IsSigned'): - Result.IsSigned = Inst.IsSigned - return Result - # 检查 BuiltinTypeMap(覆盖 VOIDPTR, BYTEPTR 等指针别名) - builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(TypeName) - if builtin_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = builtin_entry - Result: CTypeInfo = CTypeInfo() - Result.BaseType = TypeClass - Result.PtrCount = base_ptr - return Result - if TypeName in SymbolTable: - Entry: CTypeInfo | dict = SymbolTable[TypeName] - if Entry: - if isinstance(Entry, CTypeInfo): - if Entry.IsTypedef: - if Entry.BaseType and (not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0): - Result = Entry.Copy() - Result.IsTypedef = True - Result.Name = TypeName - return Result - if Entry.OriginalType: - if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, CTypeInfo): - Resolved = Entry.OriginalType.Copy() - elif isinstance(Entry.OriginalType, str) and Entry.OriginalType == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, str): - Resolved = TypeAnnotationResolver.from_type_name(Entry.OriginalType) - else: - Resolved = Entry.OriginalType - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - TypeEntry = BuiltinTypeMap.Get(TypeName) - if TypeEntry: - Result = CTypeInfo() - Result.BaseType = TypeEntry[0]() - Result.PtrCount = TypeEntry[1] - Result.IsTypedef = True - Result.Name = TypeName - return Result - return Entry - if Entry.IsEnum: - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsEnum = True - Result.Name = TypeName - return Result - if Entry.IsExceptionClass: - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsExceptionClass = True - Result.Name = TypeName - return Result - if Entry.BaseType is None and (Entry.IsStruct or Entry.Name): - Entry.BaseType = t.CStruct(name=TypeName) - Entry.IsStruct = True - return Entry - elif isinstance(Entry, dict): - if Entry.get('type') == 'typedef': - OriginalType = Entry.get('OriginalType', '') - if OriginalType: - if OriginalType == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - Resolved = TypeAnnotationResolver.from_type_name(OriginalType) - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - TypeEntry = BuiltinTypeMap.Get(TypeName) - if TypeEntry: - Result = CTypeInfo() - Result.BaseType = TypeEntry[0]() - Result.PtrCount = TypeEntry[1] - Result.IsTypedef = True - Result.Name = TypeName - return Result - Result = CTypeInfo() - Result.BaseType = t._CTypedef(TypeName) - Result.IsTypedef = True - Result.Name = TypeName - return Result - # 检查 t 类型别名(from t import CInt as myint) - if hasattr(SymbolTable, '_t_type_symbols'): - t_cls = SymbolTable._t_type_symbols.get(TypeName) - if t_cls is not None: - Result = CTypeInfo() - Result.BaseType = t_cls - return Result - # 特殊处理 str 类型,它应该是 char*(指针) - if TypeName in ('str', 'bytes'): - Result = CTypeInfo() - Result.BaseType = t.CChar() - Result.PtrCount = 1 - return Result - return TypeAnnotationResolver.from_type_name(TypeName) - - @staticmethod - def _from_node_call(Node: ast.Call, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Call 节点""" - if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': - Result: CTypeInfo = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - try: - if len(Node.args) > 0: - RetInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.args[0], SymbolTable) - if RetInfo: - Result.FuncPtrReturn = RetInfo - kw: ast.keyword - for kw in Node.keywords: - ParamInfo: CTypeInfo = TypeAnnotationResolver.from_node(kw.value, SymbolTable) - if ParamInfo: - Result.FuncPtrParams.append((kw.arg or '', ParamInfo)) - except Exception as _e: - if _config_mode == "strict": - warnings.warn(f"异常被忽略: {_e}") - return Result - if isinstance(Node.func, ast.Attribute): - if isinstance(Node.func.value, ast.Name) and IsTModule(Node.func.value.id, SymbolTable): - if Node.func.attr == 'Bit' and len(Node.args) > 0: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsBitField = True - if isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, int): - Result.BitWidth = Node.args[0].value - else: - Result.BitWidth = 1 - return Result - return CTypeInfo() - - @staticmethod - def _from_node_binop(Node: ast.BinOp, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.BinOp (BitOr) 节点""" - LeftInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.left, SymbolTable) - RightInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.right, SymbolTable) - - if LeftInfo.IsState or RightInfo.IsState: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - NonStateInfo: CTypeInfo = LeftInfo if not LeftInfo.IsState else RightInfo - StateInfo: CTypeInfo = LeftInfo if LeftInfo.IsState else RightInfo - if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): - Result.BaseType = NonStateInfo.BaseType - elif NonStateInfo.IsTypedef and NonStateInfo.Name: - if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): - Result.BaseType = NonStateInfo.BaseType - Result.PtrCount = NonStateInfo.PtrCount - Result.IsTypedef = True - Result.Name = NonStateInfo.Name - if NonStateInfo.OriginalType: - Result.OriginalType = NonStateInfo.OriginalType - else: - Result.BaseType = t.CStruct(name=NonStateInfo.Name) - Result.IsStruct = True - Result.IsTypedef = True - Result.Name = NonStateInfo.Name - if NonStateInfo.OriginalType: - Result.OriginalType = NonStateInfo.OriginalType - else: - Result.BaseType = t.CVoid() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if not Result.Storage: - Result.Storage = t.CExport() - if LeftInfo.Storage and not isinstance(LeftInfo.Storage, t.CExport): - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage and not isinstance(RightInfo.Storage, t.CExport): - Result.Storage = RightInfo.Storage - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - return Result - - if LeftInfo.IsPtr or RightInfo.IsPtr: - Result = CTypeInfo() - # 当双方都是指针时(如 (AST | t.CPtr) | t.CPtr),PtrCount 应相加 - # 而非取 max,否则 AST** 会被折叠为 AST*,导致对象切片问题 - if LeftInfo.IsPtr and RightInfo.IsPtr: - Result.PtrCount = LeftInfo.PtrCount + RightInfo.PtrCount - # BaseType 优先取非 void 侧(如 AST),而非 t.CPtr 的 void - if LeftInfo.BaseType and not isinstance(LeftInfo.BaseType, t.CVoid): - Result.BaseType = LeftInfo.BaseType - elif RightInfo.BaseType and not isinstance(RightInfo.BaseType, t.CVoid): - Result.BaseType = RightInfo.BaseType - else: - Result.BaseType = t.CUnsignedChar() - else: - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo - PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo - if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): - Result.BaseType = NonPtrInfo.BaseType - elif NonPtrInfo.IsTypedef and NonPtrInfo.Name: - if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): - Result.BaseType = NonPtrInfo.BaseType - Result.IsTypedef = True - Result.Name = NonPtrInfo.Name - if NonPtrInfo.OriginalType: - Result.OriginalType = NonPtrInfo.OriginalType - else: - Result.BaseType = t.CStruct(name=NonPtrInfo.Name) - Result.IsStruct = True - elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (t._CTypedef,)) or PtrInfo.PtrCount > 0): - Result.BaseType = PtrInfo.BaseType - else: - Result.BaseType = t.CUnsignedChar() - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result.DataVolatile = True - if LeftInfo.VarVolatile or RightInfo.VarVolatile: - Result.VarVolatile = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.DataConst or RightInfo.DataConst: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo - QualSide = LeftInfo if LeftInfo.DataConst else RightInfo - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.DataConst = True - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result.DataVolatile = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo - QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.DataVolatile = True - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.Storage or RightInfo.Storage: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo - StorageSide = LeftInfo if LeftInfo.Storage else RightInfo - # CExtern | CExport 等价于 t.State:两边都有 Storage 时设置 IsState - if BaseTypeSide.IsState or StorageSide.IsState or (LeftInfo.Storage and RightInfo.Storage): - Result.IsState = True - Result.BaseType = t.CVoid() - Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage - return Result - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - return Result - - # 检查是否有位域类型 (t.Bit) - if LeftInfo.IsBitField: - Result = CTypeInfo() - Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt() - Result.IsBitField = True - Result.BitWidth = LeftInfo.BitWidth - return Result - if RightInfo.IsBitField: - Result = CTypeInfo() - Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt() - Result.IsBitField = True - Result.BitWidth = RightInfo.BitWidth - return Result - - # 处理字节序类型 (t.BigEndian, t.LittleEndian) - # 合并两侧:保留非字节序侧的实际类型(如 CUInt64T),取字节序侧的 ByteOrder - if LeftInfo.ByteOrder or RightInfo.ByteOrder: - Result = CTypeInfo() - ByteOrderSide: CTypeInfo = LeftInfo if LeftInfo.ByteOrder else RightInfo - OtherSide: CTypeInfo = RightInfo if LeftInfo.ByteOrder else LeftInfo - if OtherSide.BaseType and (not isinstance(OtherSide.BaseType, (t._CTypedef,)) or OtherSide.PtrCount > 0): - Result.BaseType = OtherSide.BaseType - elif ByteOrderSide.BaseType and (not isinstance(ByteOrderSide.BaseType, (t._CTypedef,)) or ByteOrderSide.PtrCount > 0): - Result.BaseType = ByteOrderSide.BaseType - else: - Result.BaseType = t.CInt() - Result.ByteOrder = LeftInfo.ByteOrder or RightInfo.ByteOrder - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - return Result - - if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr: - Result = CTypeInfo() - FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo - Result.IsFuncPtr = True - Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams) - Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.IsTypedef and RightInfo.BaseType: - if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (t._CTypedef,)) or LeftInfo.PtrCount > 0): - Result = LeftInfo.Copy() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - return RightInfo - if RightInfo.IsTypedef and LeftInfo.BaseType: - if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (t._CTypedef,)) or RightInfo.PtrCount > 0): - Result = RightInfo.Copy() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - return Result - return LeftInfo - - if LeftInfo.BaseType: - return LeftInfo - elif RightInfo.BaseType: - return RightInfo - return CTypeInfo() - - @staticmethod - def _from_node_subscript(Node: ast.Subscript, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Subscript 节点""" - base: ast.AST = Node.value - if isinstance(base, ast.Attribute): - if isinstance(base.value, ast.Name) and IsTModule(base.value.id, SymbolTable) and base.attr == 'Bit': - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsBitField = True - if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): - Result.BitWidth = Node.slice.value - else: - Result.BitWidth = 1 - return Result - if IsListAnnotation(Node): - slice_node: ast.AST = Node.slice - elts: list[ast.AST] = [] - if isinstance(slice_node, ast.Tuple): - elts = slice_node.elts - elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): - elts = [slice_node] - if elts: - ElemInfo: CTypeInfo = TypeAnnotationResolver.from_node(elts[0], SymbolTable) - if ElemInfo and ElemInfo.BaseType: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = ElemInfo.BaseType - Result.PtrCount = ElemInfo.PtrCount - Result.ArrayDims = list(ElemInfo.ArrayDims) - if len(elts) >= 2: - count_val: int | None = TypeAnnotationResolver.try_eval_const_expr(elts[1], SymbolTable) - if count_val is not None and isinstance(count_val, int) and count_val > 0: - Result.ArrayDims.insert(0, str(count_val)) - else: - Result.PtrCount += 1 - if ElemInfo.IsPtr and not ElemInfo.ArrayDims: - Result.PtrCount = max(Result.PtrCount, 1) - return Result - if isinstance(base, ast.Attribute): - parts: list[str] = [] - current: ast.AST = base - while isinstance(current, ast.Attribute): - parts.insert(0, current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.insert(0, current.id) - if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == t.CPtr.__name__: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CVoid() - Result.PtrCount = 1 - slice_node: ast.AST = Node.slice - if isinstance(slice_node, ast.Subscript): - InnerInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if InnerInfo: - if InnerInfo.PtrCount > 0: - Result.PtrCount += InnerInfo.PtrCount - if InnerInfo.BaseType and not isinstance(InnerInfo.BaseType, t.CVoid): - Result.BaseType = InnerInfo.BaseType - elif isinstance(slice_node, ast.Attribute): - SliceInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if SliceInfo: - if SliceInfo.IsPtr: - Result.PtrCount += SliceInfo.PtrCount - elif SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): - Result.BaseType = SliceInfo.BaseType - elif isinstance(slice_node, ast.Name): - SliceType: type | None = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - Result.PtrCount += 1 - else: - SliceInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): - Result.BaseType = SliceInfo.BaseType - return Result - if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - slice_node = Node.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - params_list = slice_node.elts[0] - return_node = slice_node.elts[1] - ParamTypes = [] - if isinstance(params_list, ast.List): - for elt in params_list.elts: - ParamTypeInfo = TypeAnnotationResolver.from_node(elt, SymbolTable) - if ParamTypeInfo: - ParamTypes.append(('', ParamTypeInfo)) - if not ParamTypes: - ParamTypes.append(('', TypeAnnotationResolver.from_type_name('void'))) - Result.FuncPtrParams = ParamTypes - ReturnTypeInfo = TypeAnnotationResolver.from_node(return_node, SymbolTable) - Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo() - return Result - return CTypeInfo() - - @staticmethod - def _from_node_attribute(Node: ast.Attribute, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Attribute 节点""" - ModuleParts: list[str] = [] - Current: ast.AST = Node - while isinstance(Current, ast.Attribute): - ModuleParts.insert(0, Current.attr) - Current = Current.value - - if isinstance(Current, ast.Name): - ModuleParts.insert(0, Current.id) - - TypeName: str - ModulePath: str | None - if len(ModuleParts) >= 2: - TypeName = ModuleParts[-1] - ModulePath = '.'.join(ModuleParts[:-1]) - elif len(ModuleParts) == 1: - TypeName = ModuleParts[0] - ModulePath = None - else: - return CTypeInfo() - - # 解析 import 别名: 如 import vpsdk.window as window -> window -> vpsdk.window - if ModulePath: - resolved: bool = False - import_aliases: dict = SymbolTable.import_aliases - if ModulePath in import_aliases: - ModulePath = import_aliases[ModulePath] - resolved = True - if not resolved and ModulePath in SymbolTable: - entry: CTypeInfo = SymbolTable[ModulePath] - if isinstance(entry, CTypeInfo) and entry.IsModuleAlias: - resolved_name = entry.ResolvedModule - if resolved_name: - ModulePath = resolved_name - - if ModulePath and IsTModulePath(ModulePath): - TypeClass: type | None = CTypeHelper.GetTModuleCType(TypeName) - if TypeClass is None: - TypeClass = getattr(t, TypeName, None) - if TypeClass is not None and TypeClass.HasPosition(t.CType.POINTER): - Info: CTypeInfo = CTypeInfo() - Info.PtrCount = 1 - if TypeClass == t.CArrayPtr: - Info.IsArrayPtr = True - Info.BaseType = t.CVoid - return Info - if TypeClass is not None and TypeClass.IsStorageClass(): - Info: CTypeInfo = CTypeInfo() - Info.Storage = TypeClass() - if TypeClass == t.State: - Info.IsState = True - Info.BaseType = t.CVoid() - return Info - if TypeClass is not None and TypeClass.IsTypeQualifier(): - Info: CTypeInfo = CTypeInfo() - if TypeClass == t.CConst: - Info.DataConst = True - elif TypeClass == t.CVolatile: - Info.DataVolatile = True - return Info - if TypeClass is not None and TypeClass in (t.BigEndian, t.LittleEndian): - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little' - return Result - if (TypeClass is not None - and isinstance(TypeClass, type) - and issubclass(TypeClass, t.CType) - and TypeClass is not t.CType - and TypeClass.HasPosition(t.CType.BASE)): - if TypeClass == t.State: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - Result.BaseType = t.CVoid() - return Result - Inst: t.CType = TypeClass() - Result: CTypeInfo = CTypeInfo() - Result.BaseType = TypeClass - Result.Name = type(Inst).__name__ - if hasattr(Inst, 'IsSigned'): - Result.IsSigned = Inst.IsSigned - return Result - CNAME: str | None = CTypeHelper.GetCName(TypeName) - if CNAME: - return TypeAnnotationResolver.from_type_name(CNAME) - - # 处理字节序类型 - if TypeName == 'BigEndian': - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'big' - return Result - if TypeName == 'LittleEndian': - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'little' - return Result - - FullName: str = f"{ModulePath}.{TypeName}" if ModulePath else TypeName - - if TypeName in SymbolTable: - Entry: CTypeInfo = SymbolTable[TypeName] - if Entry and Entry.IsTypedef: - Resolved: CTypeInfo = Entry.Copy() - if Resolved.BaseType is None: - Resolved.BaseType = t._CTypedef(TypeName) - return Resolved - if Entry and Entry.IsEnum: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsEnum = True - Result.Name = TypeName - return Result - if Entry and Entry.IsExceptionClass: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsExceptionClass = True - Result.Name = TypeName - return Result - if Entry: - Result: CTypeInfo = Entry.Copy() - if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - return Result - return CTypeInfo() - - if FullName in SymbolTable: - Info: CTypeInfo = SymbolTable[FullName] - if Info and Info.IsTypedef: - OriginalType: str = Info.get('OriginalType', '') - if OriginalType and 'typedef' in OriginalType: - parts: list[str] = OriginalType.split() - if len(parts) >= 2: - BaseType_name: str = parts[1] - if not BaseType_name.startswith('C'): - BaseType_name = 'C' + BaseType_name - CNAME: str | None = CTypeHelper.GetCName(BaseType_name) - if CNAME: - return TypeAnnotationResolver.from_type_name(CNAME) - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t._CTypedef(TypeName) - Result.IsTypedef = True - return Result - if Info: - Result: CTypeInfo = Info.Copy() - if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - return Result - return CTypeInfo() - - return CTypeInfo() diff --git a/App/lib/core/TypeSpec.py b/App/lib/core/TypeSpec.py deleted file mode 100644 index 1b28bf5..0000000 --- a/App/lib/core/TypeSpec.py +++ /dev/null @@ -1,332 +0,0 @@ -"""TypeSpec, SymbolMeta, SymbolKind — CTypeInfo 的拆分类型 - -Phase 1 重构:将 CTypeInfo 的 40+ 平铺字段拆分为三个聚焦的类型: -- TypeSpec: 纯类型描述(BaseType + 指针 + 限定符 + 数组维度等) -- SymbolMeta: 符号表元数据(名称、行号、文件、类型种类、成员等) -- SymbolKind: 枚举类型种类(从 is_xxx bool 字段派生,供新代码使用) - -设计原则: -- CTypeInfo 内部组合 TypeSpec + SymbolMeta -- 旧 property 委托到新字段,外部代码零修改 -- 渐进式迁移:先加新字段,后删旧字段 -- 类型种类 bool 保持独立(因为 IsTypedef 和 IsStruct 可以同时为 True) -- SymbolKind 从 is_xxx bool 字段派生,供新代码使用 -""" -from __future__ import annotations - -import enum -from typing import TYPE_CHECKING, List, Dict, Tuple, Any, Optional - -if TYPE_CHECKING: - from lib.core.Handles.HandlesBase import CTypeInfo - -from lib.includes import t - - -class SymbolKind(enum.Enum): - """符号类型种类 — 从 is_xxx bool 字段派生的主类型 - - 注意:IsTypedef 与 IsStruct/IsEnum/IsUnion 正交(可以同时为 True), - 因此 SymbolKind 只反映"主类型",IsTypedef 需要单独查询。 - """ - UNKNOWN = 0 - VARIABLE = 1 - FUNCTION = 2 - STRUCT = 3 - UNION = 4 - ENUM = 5 - DEFINE = 6 - ENUM_MEMBER = 7 - MODULE = 8 - EXCEPTION = 9 - RENUM = 10 - FUNC_PTR = 11 - STATE = 12 - CPYTHON_OBJECT = 13 - - -# CTypeInfo 旧字段 → (目标, 新字段名) 的路由表 -# 目标: 'ts' = TypeSpec, 'sm' = SymbolMeta -FIELD_ROUTES = { - # --- TypeSpec 字段 --- - 'PtrCount': ('ts', 'ptr_count'), - 'VarConst': ('ts', 'var_const'), - 'VarVolatile': ('ts', 'var_volatile'), - 'DataConst': ('ts', 'data_const'), - 'DataVolatile': ('ts', 'data_volatile'), - 'ArrayDims': ('ts', 'array_dims'), - 'Storage': ('ts', 'storage'), - 'IsFuncPtr': ('ts', 'is_func_ptr'), - 'FuncPtrParams': ('ts', 'func_ptr_params'), - 'FuncParamNames': ('ts', 'func_param_names'), - 'FuncPtrReturn': ('ts', 'func_ptr_return'), - 'IsVariadic': ('ts', 'is_variadic'), - 'IsBitField': ('ts', 'is_bitfield'), - 'BitWidth': ('ts', 'bit_width'), - 'ByteOrder': ('ts', 'byte_order'), - 'IsArrayPtr': ('ts', 'is_array_ptr'), - 'ArrayPtr': ('ts', 'array_ptr'), - 'IsState': ('ts', 'is_state'), - 'OriginalType': ('ts', 'original_type'), - 'IsSigned': ('ts', 'is_signed'), - - # --- SymbolMeta 字段 --- - 'Name': ('sm', 'name'), - 'Lineno': ('sm', 'lineno'), - 'file': ('sm', 'file'), - 'ModuleName': ('sm', 'module_name'), - 'Members': ('sm', 'members'), - 'IsCpythonObject':('sm', 'is_cpython_object'), - 'IsPacked': ('sm', 'is_packed'), - 'IsAnonymous': ('sm', 'is_anonymous'), - 'IsInline': ('sm', 'is_inline'), - 'InlineBody': ('sm', 'inline_body'), - 'InlineParams': ('sm', 'inline_params'), - 'RenumVariants': ('sm', 'renum_variants'), - 'DeclaredType': ('sm', 'declared_type'), - 'CreturnTypes': ('sm', 'creturn_types'), - 'MetaList': ('sm', 'meta_list'), - 'IsModuleAlias': ('sm', 'is_module_alias'), - 'ResolvedModule': ('sm', 'resolved_module'), - 'DefineValue': ('sm', 'define_value'), - 'EnumName': ('sm', 'enum_name'), - 'value': ('sm', 'enum_value'), - - # --- 类型种类 bool(直接存储在 SymbolMeta 的 __slots__ 字段)--- - 'IsStruct': ('sm', 'is_struct'), - 'IsEnum': ('sm', 'is_enum'), - 'IsUnion': ('sm', 'is_union'), - 'IsTypedef': ('sm', 'is_typedef'), - 'IsVariable': ('sm', 'is_variable'), - 'IsFunction': ('sm', 'is_function'), - 'IsDefine': ('sm', 'is_define'), - 'IsEnumMember': ('sm', 'is_enum_member'), - 'IsRenum': ('sm', 'is_renum'), - 'IsExceptionClass': ('sm', 'is_exception_class'), - - # --- _extra(CTypeInfo 旧 _extra 字典,迁移到 SymbolMeta)--- - '_extra': ('sm', '_extra'), -} - - -class TypeSpec: - """纯类型描述 — 不包含符号表元数据 - - 职责:描述一个 C 类型的结构(基础类型、指针层数、限定符、数组维度等) - 不包含:名称、行号、文件路径、符号种类等元数据(这些归 SymbolMeta) - - 注意:当前阶段保持与 CTypeInfo 旧字段的兼容性, - PtrCount/VarConst/DataConst 等仍然使用扁平字段。 - 未来 Phase 2 会将指针改为嵌套 PointerLayer 表示。 - """ - - __slots__ = ( - '_base_type', 'ptr_count', - 'var_const', 'var_volatile', 'data_const', 'data_volatile', - 'array_dims', 'storage', - 'is_func_ptr', 'func_ptr_params', 'func_param_names', 'func_ptr_return', - 'is_variadic', - 'is_bitfield', 'bit_width', - 'byte_order', - 'is_array_ptr', 'array_ptr', - 'is_state', - 'original_type', - 'is_signed', - ) - - def __init__(self): - self._base_type: t.CType | tuple | None = None # t.CType 实例或 tuple - self.ptr_count: int = 0 - self.var_const: bool = False - self.var_volatile: bool = False - self.data_const: bool = False - self.data_volatile: bool = False - self.array_dims: List[str] = [] - self.storage: t.CType | None = None # t.CType (CStatic/CExtern/CExport 等) - self.is_func_ptr: bool = False - self.func_ptr_params: List[Tuple[str, CTypeInfo]] = [] # (参数名, CTypeInfo) - self.func_param_names: List[str] = [] - self.func_ptr_return: CTypeInfo | None = None # CTypeInfo - self.is_variadic: bool = False - self.is_bitfield: bool = False - self.bit_width: int = 0 - self.byte_order: str = "" # "big", "little", or "" - self.is_array_ptr: bool = False - self.array_ptr: CTypeInfo | None = None # CTypeInfo - self.is_state: bool = False - self.original_type: CTypeInfo | str | None = None # CTypeInfo | str | None (typedef 原始类型) - self.is_signed: Optional[bool] = None # None = 未设置, True/False = 有符号/无符号 - - @property - def base_type(self) -> t.CType | tuple | None: - return self._base_type - - @base_type.setter - def base_type(self, value: t.CType | tuple | None): - """设置 BaseType,与 CTypeInfo.BaseType setter 逻辑一致(不含 kind 副作用)""" - if value is None: - self._base_type = None - return - - if isinstance(value, (tuple, list)): - self._base_type = tuple(value) - return - - if isinstance(value, type) and issubclass(value, t.CType): - self._base_type = value() - return - - if isinstance(value, t.CType): - self._base_type = value - return - - raise TypeError( - f"base_type must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}" - ) - - def copy(self) -> TypeSpec: - """深拷贝""" - new: TypeSpec = TypeSpec() - new._base_type = self._base_type - new.ptr_count = self.ptr_count - new.var_const = self.var_const - new.var_volatile = self.var_volatile - new.data_const = self.data_const - new.data_volatile = self.data_volatile - new.array_dims = list(self.array_dims) - new.storage = self.storage - new.is_func_ptr = self.is_func_ptr - new.func_ptr_params = list(self.func_ptr_params) - new.func_param_names = list(self.func_param_names) - new.func_ptr_return = self.func_ptr_return - new.is_variadic = self.is_variadic - new.is_bitfield = self.is_bitfield - new.bit_width = self.bit_width - new.byte_order = self.byte_order - new.is_array_ptr = self.is_array_ptr - new.array_ptr = self.array_ptr - new.is_state = self.is_state - new.original_type = self.original_type - new.is_signed = self.is_signed - return new - - -class SymbolMeta: - """符号表条目的元数据 — 与类型描述无关 - - 职责:记录符号的名称、位置、种类、成员等元数据 - 不包含:类型结构(BaseType、指针、限定符等,这些归 TypeSpec) - - is_struct/is_enum/is_union/is_typedef/is_variable/is_function/is_define/ - is_enum_member/is_renum/is_exception_class: 独立 bool 字段,存储类型种类。 - 这些 flag 不是互斥的(IsTypedef 和 IsStruct 可以同时为 True)。 - SymbolKind 从这些 bool 字段派生,供新代码使用。 - """ - - __slots__ = ( - 'name', 'lineno', 'file', 'module_name', - 'members', - 'is_cpython_object', 'is_packed', - 'define_value', - 'enum_name', 'enum_value', - 'is_inline', 'inline_body', 'inline_params', - 'is_anonymous', - 'renum_variants', - 'declared_type', 'creturn_types', - 'meta_list', - 'is_module_alias', 'resolved_module', - 'is_struct', 'is_enum', 'is_union', 'is_typedef', - 'is_variable', 'is_function', 'is_define', - 'is_enum_member', 'is_renum', 'is_exception_class', - '_extra', - ) - - def __init__(self): - self.name: str = "" - self.lineno: int = 0 - self.file: str = "" - self.module_name: str = "" - self.members: Dict[str, CTypeInfo] = {} # 成员名 -> CTypeInfo - self.is_cpython_object: bool = False - self.is_packed: bool = False - self.define_value: int | str | float | bool | None = None - self.enum_name: str = "" # 枚举成员所属的枚举类名 - self.enum_value: int | None = None # 枚举成员的值 - self.is_inline: bool = False - self.inline_body: list | None = None - self.inline_params: list | None = None - self.is_anonymous: bool = False - self.renum_variants: list = [] - self.declared_type: str = "" - self.creturn_types: list = [] - self.meta_list: Any = None # FuncMeta - self.is_module_alias: bool = False - self.resolved_module: str | None = None - self.is_struct: bool = False - self.is_enum: bool = False - self.is_union: bool = False - self.is_typedef: bool = False - self.is_variable: bool = False - self.is_function: bool = False - self.is_define: bool = False - self.is_enum_member: bool = False - self.is_renum: bool = False - self.is_exception_class: bool = False - self._extra: dict = {} - - @property - def kind(self) -> SymbolKind: - """从 is_xxx bool 字段派生主类型种类""" - if self.is_struct or self.is_cpython_object: - return SymbolKind.STRUCT if not self.is_cpython_object else SymbolKind.CPYTHON_OBJECT - if self.is_enum: - return SymbolKind.RENUM if self.is_renum else SymbolKind.ENUM - if self.is_union: - return SymbolKind.UNION - if self.is_function: - return SymbolKind.FUNCTION - if self.is_variable: - return SymbolKind.VARIABLE - if self.is_define: - return SymbolKind.DEFINE - if self.is_enum_member: - return SymbolKind.ENUM_MEMBER - if self.is_exception_class: - return SymbolKind.EXCEPTION - return SymbolKind.UNKNOWN - - def copy(self) -> SymbolMeta: - """深拷贝""" - new: SymbolMeta = SymbolMeta() - new.name = self.name - new.lineno = self.lineno - new.file = self.file - new.module_name = self.module_name - new.members = dict(self.members) - new.is_cpython_object = self.is_cpython_object - new.is_packed = self.is_packed - new.define_value = self.define_value - new.enum_name = self.enum_name - new.enum_value = self.enum_value - new.is_inline = self.is_inline - new.inline_body = self.inline_body - new.inline_params = list(self.inline_params) if self.inline_params else None - new.is_anonymous = self.is_anonymous - new.renum_variants = list(self.renum_variants) - new.declared_type = self.declared_type - new.creturn_types = list(self.creturn_types) - new.meta_list = self.meta_list - new.is_module_alias = self.is_module_alias - new.resolved_module = self.resolved_module - new.is_struct = self.is_struct - new.is_enum = self.is_enum - new.is_union = self.is_union - new.is_typedef = self.is_typedef - new.is_variable = self.is_variable - new.is_function = self.is_function - new.is_define = self.is_define - new.is_enum_member = self.is_enum_member - new.is_renum = self.is_renum - new.is_exception_class = self.is_exception_class - new._extra = dict(self._extra) - return new diff --git a/App/lib/core/stub_generator.py b/App/lib/core/stub_generator.py deleted file mode 100644 index 5b60618..0000000 --- a/App/lib/core/stub_generator.py +++ /dev/null @@ -1,761 +0,0 @@ -#!/usr/bin/env python3 -""" -C/H 文件到 Python 存根文件生成器 - -将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.pyi) -生成的 Python 代码使用 TransPyC 语法,包含类型注解 -""" -from __future__ import annotations - -import os -import re -import sys -from typing import Any -from lib.core.VLogger import get_logger as _vlog - - -class CTypeMapper: - - # 硬编码 C 类型名 → Python 类型映射表 - # 这是 stub 生成器(C 头文件 → Python stub)专用的固定映射, - # 不再依赖运行时 CTypeRegistry._cname_to_class(该映射已删除)。 - _CNAME_TO_PY: dict[str, str] = { - # 基本类型 - 'char': 't.CChar', 'int': 't.CInt', 'short': 't.CShort', - 'long': 't.CLong', 'long long': 't.CLongLong', - 'float': 't.CFloat', 'double': 't.CDouble', 'void': 't.CVoid', - # unsigned / signed 变体 - 'unsigned': 't.CUnsigned', 'unsigned char': 't.CUnsignedChar', - 'unsigned int': 't.CUnsignedInt', 'unsigned short': 't.CUnsignedShort', - 'unsigned long': 't.CUnsignedLong', - 'unsigned long long': 't.CUnsignedLongLong', - 'signed char': 't.CSignedChar', - # bool / size_t - 'bool': 't.CBool', '_Bool': 't.CBool', 'size_t': 't.CSizeT', - 'ssize_t': 't.CLong', - # stdint 固定宽度类型 - 'int8_t': 't.CInt8T', 'int16_t': 't.CInt16T', - 'int32_t': 't.CInt32T', 'int64_t': 't.CInt64T', - 'uint8_t': 't.CUInt8T', 'uint16_t': 't.CUInt16T', - 'uint32_t': 't.CUInt32T', 'uint64_t': 't.CUInt64T', - 'intptr_t': 't.CIntPtrT', 'uintptr_t': 't.CUIntPtrT', - 'ptrdiff_t': 't.CPtrDiffT', - # 宽字符 / 字符类型 - 'wchar_t': 't.CWCharT', 'char8_t': 't.CChar8T', - 'char16_t': 't.CChar16T', 'char32_t': 't.CChar32T', - # 浮点特化类型 - 'float8_t': 't.CFloat8T', 'float16_t': 't.CFloat16T', - 'float32_t': 't.CFloat32T', 'float64_t': 't.CFloat64T', - 'float128_t': 't.CFloat128T', - # signed 速记 - 'signed': 't.CInt', 'signed int': 't.CInt', - 'signed short': 't.CShort', 'signed long': 't.CLong', - } - - @classmethod - def _ResolveCNameToPyType(cls, c_type: str) -> str: - """将 C 类型名解析为 Python 类型字符串(如 'int' → 't.CInt') - - 使用硬编码映射表,不再依赖 CTypeRegistry._cname_to_class。 - 未识别的类型原样返回(用于 struct/union/enum/typedef 用户自定义名)。 - """ - py: str | None = cls._CNAME_TO_PY.get(c_type) - if py is not None: - return py - return c_type - - @classmethod - def MapType(cls, c_type: str, IsPtr: bool = False, IsArray: bool = False) -> str: - c_type = c_type.strip() - - IsConst: bool = 'const ' in c_type - c_type = c_type.replace('const ', '').replace('const', '').strip() - IsVolatile: bool = 'volatile ' in c_type - c_type = c_type.replace('volatile ', '').replace('volatile', '').strip() - IsStatic: bool = 'static ' in c_type - c_type = c_type.replace('static ', '').replace('static', '').strip() - IsExtern: bool = 'extern ' in c_type - c_type = c_type.replace('extern ', '').replace('extern', '').strip() - IsRegister: bool = 'register ' in c_type - c_type = c_type.replace('register ', '').replace('register', '').strip() - IsInline: bool = 'inline ' in c_type - c_type = c_type.replace('inline ', '').replace('inline', '').strip() - - PtrSuffix: str = '' - if IsPtr or c_type.endswith('*'): - PtrSuffix = ' | t.CPtr' - c_type = c_type.rstrip('*').strip() - - if c_type.startswith('struct '): - c_type = c_type[7:].strip() - elif c_type.startswith('union '): - c_type = c_type[6:].strip() - elif c_type.startswith('enum '): - c_type = c_type[5:].strip() - - PyType: str = cls._ResolveCNameToPyType(c_type) - - result: str = PyType + PtrSuffix - - if IsArray: - result += ' | t.CArrayPtr' - - return result - - -def _find_matching_brace(text: str, start: int) -> int: - depth: int = 0 - i: int = start - while i < len(text): - if text[i] == '{': - depth += 1 - elif text[i] == '}': - depth -= 1 - if depth == 0: - return i - elif text[i] == '"' or text[i] == "'": - quote: str = text[i] - i += 1 - while i < len(text) and text[i] != quote: - if text[i] == '\\': - i += 1 - i += 1 - elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '/': - while i < len(text) and text[i] != '\n': - i += 1 - continue - elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '*': - i += 2 - while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'): - i += 1 - i += 1 - i += 1 - return -1 - - -def _strip_comments(content: str) -> str: - result: list[str] = [] - i: int = 0 - while i < len(content): - if content[i] == '/' and i + 1 < len(content) and content[i + 1] == '/': - while i < len(content) and content[i] != '\n': - i += 1 - elif content[i] == '/' and i + 1 < len(content) and content[i + 1] == '*': - i += 2 - while i + 1 < len(content) and not (content[i] == '*' and content[i + 1] == '/'): - i += 1 - i += 2 - elif content[i] == '"' or content[i] == "'": - quote: str = content[i] - result.append(content[i]) - i += 1 - while i < len(content) and content[i] != quote: - if content[i] == '\\' and i + 1 < len(content): - result.append(content[i]) - i += 1 - result.append(content[i]) - i += 1 - if i < len(content): - result.append(content[i]) - i += 1 - else: - result.append(content[i]) - i += 1 - return ''.join(result) - - -def _strip_preprocessor_guards(content: str) -> str: - lines: list[str] = content.split('\n') - filtered: list[str] = [] - for line in lines: - stripped: str = line.strip() - if stripped.startswith('#ifndef') and '_H' in stripped.upper(): - continue - if stripped.startswith('#define') and '_H' in stripped.upper(): - continue - if stripped == '#endif': - continue - filtered.append(line) - return '\n'.join(filtered) - - -class CHeaderParser: - """C 头文件解析器""" - - def __init__(self) -> None: - self.defines: list[dict[str, str | None]] = [] - self.structs: dict[str, dict[str, Any]] = {} - self.enums: dict[str, dict[str, Any]] = {} - self.typedefs: list[dict[str, str]] = [] - self.functions: dict[str, dict[str, Any]] = {} - self.variables: dict[str, dict[str, Any]] = {} - self.unions: dict[str, dict[str, Any]] = {} - self.func_ptr_typedefs: dict[str, dict[str, Any]] = {} - self._typedef_struct_map: dict[str, str] = {} - self._typedef_enum_map: dict[str, str] = {} - self._typedef_union_map: dict[str, str] = {} - - def ParseFile(self, FilePath: str) -> None: - with open(FilePath, 'r', encoding='utf-8') as f: - content: str = f.read() - self.ParseContent(content) - - def ParseContent(self, content: str) -> None: - content = _strip_comments(content) - content = _strip_preprocessor_guards(content) - self._ParseDefines(content) - self._ParseTypedefStructs(content) - self._ParseTypedefEnums(content) - self._ParseTypedefUnions(content) - self._ParseFuncPtrTypedefs(content) - self._ParseSimpleTypedefs(content) - self._ParseStandaloneStructs(content) - self._ParseStandaloneEnums(content) - self._ParseStandaloneUnions(content) - stripped: str = self._StripBodies(content) - self._ParseFunctions(stripped) - self._ParseVariables(stripped) - - def _StripBodies(self, content: str) -> str: - result: str = content - while True: - pos: int = result.find('{') - if pos < 0: - break - end: int = _find_matching_brace(result, pos) - if end < 0: - break - result = result[:pos] + result[end + 1:] - return result - - def _ParseDefines(self, content: str) -> None: - for match in re.finditer(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', content, re.MULTILINE): - Name: str = match.group(1) - Value: str | None = match.group(2) - if Name.startswith('_') and Name.endswith('_'): - continue - if Name.startswith('__'): - continue - self.defines.append({ - 'name': Name, - 'value': Value.strip() if Value else None, - }) - - def _ParseTypedefStructs(self, content: str) -> None: - pattern: str = r'typedef\s+struct\s*(\w*)\s*\{' - for match in re.finditer(pattern, content): - brace_start: int = content.index('{', match.start()) - brace_end: int = _find_matching_brace(content, brace_start) - if brace_end < 0: - continue - body: str = content[brace_start + 1:brace_end] - rest: str = content[brace_end + 1:].lstrip() - AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest) - if not AliasMatch: - continue - AliasName: str = AliasMatch.group(1) - TagName: str | None = match.group(1) if match.group(1) else None - members: list[dict[str, Any]] = self._ParseStructMembers(body) - self.structs[AliasName] = { - 'name': AliasName, - 'tag': TagName, - 'members': members, - } - if TagName: - self._typedef_struct_map[TagName] = AliasName - - def _ParseTypedefEnums(self, content: str) -> None: - pattern: str = r'typedef\s+enum\s*(\w*)\s*\{' - for match in re.finditer(pattern, content): - brace_start: int = content.index('{', match.start()) - brace_end: int = _find_matching_brace(content, brace_start) - if brace_end < 0: - continue - body: str = content[brace_start + 1:brace_end] - rest: str = content[brace_end + 1:].lstrip() - AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest) - if not AliasMatch: - continue - AliasName: str = AliasMatch.group(1) - TagName: str | None = match.group(1) if match.group(1) else None - values: list[dict[str, str | None]] = self._ParseEnumValues(body) - self.enums[AliasName] = { - 'name': AliasName, - 'tag': TagName, - 'values': values, - } - if TagName: - self._typedef_enum_map[TagName] = AliasName - - def _ParseTypedefUnions(self, content: str) -> None: - pattern: str = r'typedef\s+union\s*(\w*)\s*\{' - for match in re.finditer(pattern, content): - brace_start: int = content.index('{', match.start()) - brace_end: int = _find_matching_brace(content, brace_start) - if brace_end < 0: - continue - body: str = content[brace_start + 1:brace_end] - rest: str = content[brace_end + 1:].lstrip() - AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest) - if not AliasMatch: - continue - AliasName: str = AliasMatch.group(1) - TagName: str | None = match.group(1) if match.group(1) else None - members: list[dict[str, Any]] = self._ParseStructMembers(body) - self.unions[AliasName] = { - 'name': AliasName, - 'tag': TagName, - 'members': members, - } - if TagName: - self._typedef_union_map[TagName] = AliasName - - def _ParseFuncPtrTypedefs(self, content: str) -> None: - pattern: str = r'typedef\s+([\w\s\*]+?)\s*\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*;' - for match in re.finditer(pattern, content): - ReturnType: str = match.group(1).strip() - Name: str = match.group(2) - ParamsStr: str = match.group(3).strip() - params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr) - self.func_ptr_typedefs[Name] = { - 'name': Name, - 'return_type': ReturnType, - 'params': params, - } - - def _ParseSimpleTypedefs(self, content: str) -> None: - stripped: str = self._StripBodies(content) - pattern: str = r'typedef\s+([\w\s\*]+?)\s+(\w+)\s*;' - for match in re.finditer(pattern, stripped): - BaseType: str = match.group(1).strip() - AliasName: str = match.group(2) - if AliasName in self.structs: - continue - if AliasName in self.enums: - continue - if AliasName in self.unions: - continue - if AliasName in self.func_ptr_typedefs: - continue - if BaseType.startswith('typedef'): - continue - self.typedefs.append({'name': AliasName, 'base': BaseType}) - - def _ParseStandaloneStructs(self, content: str) -> None: - pattern: str = r'(? None: - pattern: str = r'(? None: - pattern: str = r'(? None: - pattern: str = r'(?:(?:static|extern|inline)\s+)*([\w][\w\s\*]*?)\b(\w+)\s*\(([^)]*)\)\s*;' - for match in re.finditer(pattern, content): - ReturnType: str = match.group(1).strip() - FuncName: str = match.group(2) - ParamsStr: str = match.group(3).strip() - if FuncName in self.structs or FuncName in self.enums or FuncName in self.unions: - continue - if FuncName in self.func_ptr_typedefs: - continue - if FuncName in self.defines: - continue - if ReturnType in ('struct', 'union', 'enum', 'typedef'): - continue - if re.match(r'^\d', ReturnType): - continue - if not re.match(r'^[A-Za-z_]', FuncName): - continue - params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr) - self.functions[FuncName] = { - 'name': FuncName, - 'return_type': ReturnType, - 'params': params, - } - - def _ParseVariables(self, content: str) -> None: - pattern: str = r'(?:(?:static|extern|volatile|const)\s+)*([\w][\w\s\*]*?)\s+(\w+)\s*(?:\[(\d*)\])?\s*;' - for match in re.finditer(pattern, content): - TypeStr: str = match.group(1).strip() - VarName: str = match.group(2) - ArraySize: str | None = match.group(3) - if VarName in self.functions or VarName in self.structs or VarName in self.enums: - continue - if VarName in self.unions or VarName in self.func_ptr_typedefs: - continue - if VarName in self.defines: - continue - if TypeStr.startswith('typedef'): - continue - if TypeStr in ('struct', 'union', 'enum', 'typedef'): - continue - if re.match(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$', VarName): - continue - if not re.match(r'^[A-Za-z_]', VarName): - continue - IsPtr: bool = '*' in TypeStr - IsArray: bool = ArraySize is not None - self.variables[VarName] = { - 'name': VarName, - 'type': TypeStr, - 'IsPtr': IsPtr, - 'is_array': IsArray, - 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, - } - - def _ParseStructMembers(self, body: str) -> list[dict[str, Any]]: - members: list[dict[str, Any]] = [] - for line in body.split(';'): - line = line.strip() - if not line: - continue - arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]', line) - if arr_match: - MemberType: str = arr_match.group(1).strip() - MemberName: str = arr_match.group(2) - ArraySize: str = arr_match.group(3) - members.append({ - 'name': MemberName, - 'type': MemberType, - 'is_array': True, - 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, - }) - continue - ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\*\s*(\w+)', line) - if ptr_match: - MemberType: str = ptr_match.group(1).strip() + ' *' - MemberName: str = ptr_match.group(2) - members.append({ - 'name': MemberName, - 'type': MemberType, - 'IsPtr': True, - }) - continue - simple_match: re.Match[str] | None = re.match(r'([\w\s]+?)\s+(\w+)', line) - if simple_match: - MemberType: str = simple_match.group(1).strip() - MemberName: str = simple_match.group(2) - members.append({ - 'name': MemberName, - 'type': MemberType, - }) - return members - - def _ParseEnumValues(self, body: str) -> list[dict[str, str | None]]: - values: list[dict[str, str | None]] = [] - for item in body.split(','): - item = item.strip() - if not item: - continue - eq_pos: int = item.find('=') - if eq_pos >= 0: - Name: str = item[:eq_pos].strip() - Value: str | None = item[eq_pos + 1:].strip() - else: - Name = item.strip() - Value = None - if Name and re.match(r'^[A-Za-z_]\w*$', Name): - values.append({'name': Name, 'value': Value}) - return values - - def _ParseFuncParams(self, params_str: str) -> list[dict[str, Any]]: - params: list[dict[str, Any]] = [] - if not params_str or params_str.strip() == 'void' or params_str.strip() == '': - return params - for param in params_str.split(','): - param = param.strip() - if not param: - continue - func_ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)', param) - if func_ptr_match: - RetType: str = func_ptr_match.group(1).strip() - ParamName: str = func_ptr_match.group(2) or 'callback' - params.append({ - 'name': ParamName, - 'type': RetType + ' (*)', - 'is_func_ptr': True, - }) - continue - arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]', param) - if arr_match: - ParamType: str = arr_match.group(1).strip() - ParamName: str = arr_match.group(2) - params.append({ - 'name': ParamName, - 'type': ParamType, - 'is_array': True, - }) - continue - tokens: list[str] = param.split() - if len(tokens) >= 2: - LastToken: str = tokens[-1] - PtrCount: int = 0 - while LastToken.startswith('*'): - PtrCount += 1 - LastToken = LastToken[1:] - TypeTokens: list[str] = tokens[:-1] - for _ in range(PtrCount): - TypeTokens.append('*') - ParamName: str = LastToken - ParamType: str = ' '.join(TypeTokens) - if not ParamName: - ParamName = 'arg' - ParamType = param - params.append({ - 'name': ParamName, - 'type': ParamType, - }) - elif len(tokens) == 1: - params.append({ - 'name': 'arg', - 'type': tokens[0], - }) - return params - - -class PythonStubGenerator: - """Python 存根文件生成器""" - - def __init__(self, parser: CHeaderParser) -> None: - self.parser: CHeaderParser = parser - self.OutputLines: list[str] = [] - - def generate(self, ModuleName: str | None = None) -> str: - self.OutputLines = [] - self._AddHeader(ModuleName) - self._GenerateImports() - self._GenerateDefines() - self._GenerateFuncPtrTypedefs() - self._GenerateSimpleTypedefs() - self._GenerateStructs() - self._GenerateUnions() - self._GenerateEnums() - self._GenerateVariables() - self._GenerateFunctions() - return '\n'.join(self.OutputLines) - - def _AddHeader(self, ModuleName: str | None = None) -> None: - self.OutputLines.append('"""') - self.OutputLines.append('Auto-generated Python stub file from C header') - if ModuleName: - self.OutputLines.append(f'Module: {ModuleName}') - self.OutputLines.append('"""') - self.OutputLines.append('') - - def _GenerateImports(self) -> None: - self.OutputLines.append('import t') - self.OutputLines.append('import c') - self.OutputLines.append('') - - def _GenerateDefines(self) -> None: - if not self.parser.defines: - return - for define in self.parser.defines: - Name: str = define['name'] - Value: str | None = define['value'] - if Value is not None: - self.OutputLines.append(f'{Name}: t.CDefine = {Value}') - else: - self.OutputLines.append(f'{Name}: t.CDefine') - self.OutputLines.append('') - - def _GenerateFuncPtrTypedefs(self) -> None: - if not self.parser.func_ptr_typedefs: - return - for Name, Info in self.parser.func_ptr_typedefs.items(): - RetType: str = CTypeMapper.MapType(Info['return_type']) - ParamTypes: list[str] = [] - for p in Info['params']: - ParamTypes.append(CTypeMapper.MapType(p['type'])) - ParamStr: str = ', '.join(ParamTypes) if ParamTypes else '' - self.OutputLines.append(f'{Name}: t.CTypedef = t.Callable[[{ParamStr}], {RetType}]') - self.OutputLines.append('') - - def _GenerateSimpleTypedefs(self) -> None: - if not self.parser.typedefs: - return - for td in self.parser.typedefs: - AliasName: str = td['name'] - BaseType: str = td['base'] - PyType: str = CTypeMapper.MapType(BaseType) - self.OutputLines.append(f'{AliasName}: t.CTypedef | {PyType}') - self.OutputLines.append('') - - def _GenerateStructs(self) -> None: - if not self.parser.structs: - return - for StructName, StructInfo in self.parser.structs.items(): - self.OutputLines.append(f'@c.Attribute(t.attr.packed)') - self.OutputLines.append(f'class {StructName}(t.CStruct):') - if StructInfo['members']: - for member in StructInfo['members']: - MemberName: str = member['name'] - IsPtr: bool = member.get('IsPtr', False) - IsArray: bool = member.get('is_array', False) - ArraySize: int | None = member.get('array_size') - PyType: str = CTypeMapper.MapType(member['type'], IsPtr=IsPtr) - if IsArray and ArraySize is not None: - self.OutputLines.append(f' {MemberName}: list[{PyType}, {ArraySize}]') - elif IsArray: - self.OutputLines.append(f' {MemberName}: {PyType} | t.CArrayPtr') - else: - self.OutputLines.append(f' {MemberName}: {PyType}') - else: - self.OutputLines.append(' pass') - self.OutputLines.append('') - - def _GenerateUnions(self) -> None: - if not self.parser.unions: - return - for UnionName, UnionInfo in self.parser.unions.items(): - self.OutputLines.append(f'@c.Attribute(t.attr.packed)') - self.OutputLines.append(f'class {UnionName}(t.CUnion):') - if UnionInfo['members']: - for member in UnionInfo['members']: - PyType: str = CTypeMapper.MapType(member['type'], IsPtr=member.get('IsPtr', False)) - self.OutputLines.append(f' {member["name"]}: {PyType}') - else: - self.OutputLines.append(' pass') - self.OutputLines.append('') - - def _GenerateEnums(self) -> None: - if not self.parser.enums: - return - for EnumName, EnumInfo in self.parser.enums.items(): - self.OutputLines.append(f'class __{EnumName.lower()}(t.CEnum):') - if EnumInfo['values']: - for value in EnumInfo['values']: - if value['value'] is not None: - self.OutputLines.append(f' {value["name"]}: t.CDefine = {value["value"]}') - else: - self.OutputLines.append(f' {value["name"]}: t.CDefine') - else: - self.OutputLines.append(' pass') - self.OutputLines.append(f'{EnumName}: t.CTypedef = __{EnumName.lower()}') - self.OutputLines.append('') - - def _GenerateVariables(self) -> None: - if not self.parser.variables: - return - for VarName, VarInfo in self.parser.variables.items(): - PyType: str = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr'], IsArray=VarInfo['is_array']) - self.OutputLines.append(f'{VarName}: {PyType}') - self.OutputLines.append('') - - def _GenerateFunctions(self) -> None: - if not self.parser.functions: - return - for FuncName, FuncInfo in self.parser.functions.items(): - params: list[str] = [] - for param in FuncInfo['params']: - if param.get('is_func_ptr'): - PyType: str = CTypeMapper.MapType(param['type']) - elif param.get('is_array'): - PyType: str = CTypeMapper.MapType(param['type'], IsPtr=True) - else: - PyType: str = CTypeMapper.MapType(param['type']) - params.append(f'{param["name"]}: {PyType}') - ParamStr: str = ', '.join(params) if params else '' - ReturnType: str = CTypeMapper.MapType(FuncInfo['return_type']) - self.OutputLines.append(f'def {FuncName}({ParamStr}) -> {ReturnType}: pass') - self.OutputLines.append('') - - -def GenerateStubFromC(InputFile: str, OutputFile: str | None = None) -> str: - parser: CHeaderParser = CHeaderParser() - parser.ParseFile(InputFile) - generator: PythonStubGenerator = PythonStubGenerator(parser) - ModuleName: str = os.path.splitext(os.path.basename(InputFile))[0] - content: str = generator.generate(ModuleName) - if OutputFile: - with open(OutputFile, 'w', encoding='utf-8') as f: - f.write(content) - _vlog().success(f"生成: {OutputFile}") - return content - - -if __name__ == '__main__': - if len(sys.argv) >= 3: - GenerateStubFromC(sys.argv[1], sys.argv[2]) - elif len(sys.argv) == 2: - _vlog().info(GenerateStubFromC(sys.argv[1])) - else: - test_code: str = ''' -struct memory_block { - uint64_t size; - uint8_t state; - uint8_t order; - struct memory_block *next; - struct memory_block *prev; -}; - -typedef struct memory_block memory_block_t; - -enum color_format { - COLOR_FORMAT_BGRA, - COLOR_FORMAT_RGBA, - COLOR_FORMAT_BGR, - COLOR_FORMAT_RGB -}; - -void *malloc(size_t size); -void free(void *ptr); -void *memcpy(void *dest, const void *src, size_t n); -''' - parser: CHeaderParser = CHeaderParser() - parser.ParseContent(test_code) - generator: PythonStubGenerator = PythonStubGenerator(parser) - _vlog().info(generator.generate("test_header")) diff --git a/App/lib/core/translator.py b/App/lib/core/translator.py deleted file mode 100644 index 219684d..0000000 --- a/App/lib/core/translator.py +++ /dev/null @@ -1,34 +0,0 @@ -# 核心转换逻辑 -# 通过 Mixin 模式组合各功能模块 -# -# 拆分后的模块位于 lib/core/Translator/ 目录下: -# - BaseTranslator.py: __init__、日志、Handle 实例化 -# - AnnotationLoader.py: 注解模块加载 -# - PythonParser.py: Python 文件解析 -# - LlvmGenerator.py: LLVM IR 生成 -# - ConstEval.py: 常量表达式求值 -from __future__ import annotations - -from lib.core.Translator.BaseTranslator import BaseTranslatorMixin, _StrictLog -from lib.core.Translator.AnnotationLoader import AnnotationLoaderMixin -from lib.core.Translator.PythonParser import PythonParserMixin -from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -from lib.core.Translator.ConstEval import ConstEvalMixin - - -class Translator( - BaseTranslatorMixin, - AnnotationLoaderMixin, - PythonParserMixin, - LlvmGeneratorMixin, - ConstEvalMixin, -): - """代码转换器 - - 通过 Mixin 模式组合各功能模块。 - 实际方法实现分布在 lib/core/Translator/ 下的各模块中。 - """ - pass - - -__all__: list[str] = ['Translator', '_StrictLog'] diff --git a/App/lib/includes/__init__.py b/App/lib/includes/__init__.py deleted file mode 100644 index 6129c5d..0000000 --- a/App/lib/includes/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""类型系统与 C 语法定义 (t.py / c.py)""" diff --git a/App/lib/utils/__init__.py b/App/lib/utils/__init__.py deleted file mode 100644 index f68d323..0000000 --- a/App/lib/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""通用工具函数""" diff --git a/App/lib/utils/helpers.py b/App/lib/utils/helpers.py deleted file mode 100644 index 225a19a..0000000 --- a/App/lib/utils/helpers.py +++ /dev/null @@ -1,47 +0,0 @@ -# 工具函数 -from __future__ import annotations - -import os -import subprocess - -from lib.core.VLogger import get_logger as _vlog - - -def DetectFileType(FilePath: str) -> str: - """检测文件类型""" - _: str - ext: str - _, ext = os.path.splitext(FilePath) - return ext.lower() - - -def ExecuteCommand(command: list[str], shell: bool = False, CaptureOutput: bool = True, text: bool = True) -> subprocess.CompletedProcess[str] | None: - """执行命令 - command 应该是列表形式(如 ['gcc', 'file.c', '-o', 'file.exe']) - 避免字符串拼接以防止 shell 注入""" - try: - result: subprocess.CompletedProcess[str] = subprocess.run( - command, - shell=shell, - check=True, - capture_output=CaptureOutput, - text=text - ) - return result - except subprocess.CalledProcessError as e: - _vlog().error(f'编译失败: {e}') - if e.stderr: - _vlog().error(f'错误输出: {e.stderr}') - return None - - -def AppendFileContent(FilePath: str, content: str) -> bool: - """追加文件内容""" - try: - with open(FilePath, 'a', encoding='utf-8') as f: - f.write(content) - f.write('\n') - return True - except Exception as e: - _vlog().error(f'写入文件失败 {FilePath}: {e}') - return False diff --git a/App/main.py b/App/main.py index a3c08ed..fbc4b27 100644 --- a/App/main.py +++ b/App/main.py @@ -425,9 +425,8 @@ def main() -> int: if sf_stub_buf is not None: tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB) sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf) - sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32) + sf_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll") if sf_stub_path is not None: - viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name) sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W) if not sf_f.closed: sf_f.write(sf_stub_buf, sf_stub_len) @@ -439,9 +438,8 @@ def main() -> int: if sf_text_buf is not None: tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT) sf_text_len: t.CSizeT = string.strlen(sf_text_buf) - sf_text_path: bytes = stdlib.malloc(td_len_sf + 32) + sf_text_path: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "text.ll") if sf_text_path is not None: - viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name) sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W) if not sf_tf.closed: sf_tf.write(sf_text_buf, sf_text_len) diff --git a/Test/NegativeTest/project.vpj b/Test/NegativeTest/project.vpj index 6064058..78326f3 100644 --- a/Test/NegativeTest/project.vpj +++ b/Test/NegativeTest/project.vpj @@ -3,8 +3,7 @@ "name": "NegativeTest", "version": "1.0.0", "source_dir": "./App", - "temp_dir": "./temp", - "output_dir": "./output", + "build_dir": "./.tpv_build", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-relocation-model=pic"] @@ -23,6 +22,7 @@ }, "options": { "slice_level": 3, + "sha1_slice_level": 3, "target": "llvm", "strict_mode": true } diff --git a/Test/Sha1Test/project.vpj b/Test/Sha1Test/project.vpj index f3e807d..abe83ce 100644 --- a/Test/Sha1Test/project.vpj +++ b/Test/Sha1Test/project.vpj @@ -2,8 +2,7 @@ "name": "Sha1Test", "version": "1.0.0", "source_dir": "./App", - "temp_dir": "./temp", - "output_dir": "./output", + "build_dir": "./.tpv_build", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-relocation-model=pic"] @@ -22,6 +21,7 @@ }, "options": { "slice_level": 3, + "sha1_slice_level": 3, "target": "llvm", "strict_mode": true } diff --git a/Test/build.log b/Test/build.log deleted file mode 100644 index 6aa0c89..0000000 Binary files a/Test/build.log and /dev/null differ diff --git a/Test/crash_log.txt b/Test/crash_log.txt deleted file mode 100644 index 6a4bc5a..0000000 --- a/Test/crash_log.txt +++ /dev/null @@ -1,1169 +0,0 @@ -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D148 -[INFO] TransPyV 启动 -DBG MemBuddy.alloc: size=131 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=3 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D248 -DBG MemBuddy.alloc: size=1048 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=6 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D948 -DBG MemBuddy.alloc: size=40 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D188 -DBG MemBuddy.alloc: size=2048 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=7 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000E148 -DBG MemBuddy.alloc: size=16 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D1C8 -DBG MemBuddy.alloc: size=48 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D208 -DBG MemBuddy.alloc: size=384 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=4 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D348 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D1E8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D548 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D568 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D588 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D5A8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D5C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D5E8 - -=== TransPyV 参数解析结果 === - - --project: project.vpj - --src: (未指定) - --temp: (未指定) - --output: (未指定) - --phase: (未指定,默认 all) - --cc: (未指定) - --clean: True - --run: False - --rebuild-includes: True - --clear-cache: True - -参数解析完成。 - -=== 工程配置 === - -DBG MemBuddy.alloc: size=8192 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=9 max_order=24 -DBG MemBuddy.alloc: block=0000021A00011148 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D648 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D608 -DBG MemBuddy.alloc: size=87 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D6C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D748 -DBG MemBuddy.alloc: size=87 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D7C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D628 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D848 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D868 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D8C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D888 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000D8A8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F148 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F168 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F1C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F188 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F1A8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F248 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F268 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F2C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F288 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F2A8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F348 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F368 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F3C8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F388 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F3A8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F448 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F468 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F4C8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F488 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F4A8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F548 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F5C8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F568 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F588 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F648 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F5A8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F6C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F6E8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F748 -DBG MemBuddy.alloc: size=14 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F708 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F7C8 -DBG MemBuddy.alloc: size=14 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F728 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F848 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F8C8 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F868 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F888 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F8A8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F948 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F9C8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F968 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F988 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FA48 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000F9A8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FAC8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FAE8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FB48 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FB08 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FBC8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FB28 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FC48 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FCC8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FC68 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FC88 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FD48 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FCA8 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FDC8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FE48 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FDE8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FE08 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FEC8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FE28 -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FF48 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FFC8 -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A0000FF88 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010048 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010068 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010088 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000100C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000100A8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010148 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010168 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010188 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000101C8 -DBG MemBuddy.alloc: size=15 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000101A8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010248 -DBG MemBuddy.alloc: size=15 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000102C8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000102E8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010308 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010348 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010328 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000103C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010448 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000103E8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010408 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010428 -DBG MemBuddy.alloc: size=71 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000104C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010548 -DBG MemBuddy.alloc: size=71 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000105C8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010648 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010668 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010688 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000106C8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000106A8 -DBG MemBuddy.alloc: size=2 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010748 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A000107C8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010768 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010788 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000107A8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010848 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000108C8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000108E8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010908 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010948 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010928 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000021A000109C8 -DBG MemBuddy.alloc: size=37 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010A08 -DBG MemBuddy.alloc: size=80 -DBG MemBuddy.alloc: usable=0000021A0000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000021A00010A48 - project: AstTest v1.0.0 - source_dir: App - temp_dir: temp - output_dir: output - compiler: llc - linker: clang++ -> app.exe - includes: ../../includes - -[clean] 清理临时目录... -[clean] temp: 删除 1 个文件 -[clean] output: 删除 0 个文件 -[phase] 模式: all (phase1=1 phase2=1) - -=== Phase1: 扫描 includes(按需翻译) === - -[Phase1] 扫描 includes 目录: ../../includes -[DBG add_file_entry] Count=0 entry_addr=0x21a545d94e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d34a0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d34d0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d34f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3460 -[DBG add_file_entry] Count incremented to 1 - [scan] argparse.py -> aba439b7882ad9d6 -[DBG add_file_entry] Count=1 entry_addr=0x21a545d9500 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3530 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3550 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3570 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3430 -[DBG add_file_entry] Count incremented to 2 - [scan] asm.py -> 3487a256b250bb74 -[DBG add_file_entry] Count=2 entry_addr=0x21a545d9520 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3b80 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3b40 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d38a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d39c0 -[DBG add_file_entry] Count incremented to 3 - [scan] ast/astaux.py -> 4337fb260448bbe2 -[DBG add_file_entry] Count=3 entry_addr=0x21a545d9540 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3710 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3b20 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3940 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d39a0 -[DBG add_file_entry] Count incremented to 4 - [scan] ast/base.py -> 5dab8cb390496d22 -[DBG add_file_entry] Count=4 entry_addr=0x21a545d9560 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3740 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3a20 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3840 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3820 -[DBG add_file_entry] Count incremented to 5 - [scan] ast/exprs.py -> 47767b5026a8ee15 -[DBG add_file_entry] Count=5 entry_addr=0x21a545d9580 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3bb0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3a40 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3a60 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3860 -[DBG add_file_entry] Count incremented to 6 - [scan] ast/lexer.py -> 0c212981c180e7fb -[DBG add_file_entry] Count=6 entry_addr=0x21a545d95a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3be0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d38c0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3a00 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d37c0 -[DBG add_file_entry] Count incremented to 7 - [scan] ast/match.py -> 4dd6b3f1427d1cc5 -[DBG add_file_entry] Count=7 entry_addr=0x21a545d95c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3c10 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d37e0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3960 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d39e0 -[DBG add_file_entry] Count incremented to 8 - [scan] ast/parser.py -> ee52c08239684346 -[DBG add_file_entry] Count=8 entry_addr=0x21a545d95e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3c40 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3b00 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3980 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3880 -[DBG add_file_entry] Count incremented to 9 - [scan] ast/stmts.py -> 657e182b27c2a022 -[DBG add_file_entry] Count=9 entry_addr=0x21a545d9600 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545db8f0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3900 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3920 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3aa0 -[DBG add_file_entry] Count incremented to 10 - [scan] ast/tokens.py -> b547ac4f380bddb6 -[DBG add_file_entry] Count=10 entry_addr=0x21a545d9620 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545db920 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545d3800 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d38e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3ae0 -[DBG add_file_entry] Count incremented to 11 - [scan] ast/__init__.py -> 34548789d646f432 -[DBG add_file_entry] Count=11 entry_addr=0x21a545d9640 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546004c0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600680 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3410 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3480 -[DBG add_file_entry] Count incremented to 12 - [scan] atom.py -> 271ea3decb810db2 -[DBG add_file_entry] Count=12 entry_addr=0x21a545d9660 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d35c0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546001c0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600860 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600200 -[DBG add_file_entry] Count incremented to 13 - [scan] base64.py -> 971e24c228377a9b -[DBG add_file_entry] Count=13 entry_addr=0x21a545d9680 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d35f0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600140 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546004e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600600 -[DBG add_file_entry] Count incremented to 14 - [scan] binascii.py -> 257e074b935c33b4 -[DBG add_file_entry] Count=14 entry_addr=0x21a545d96a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3620 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600240 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600620 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600500 -[DBG add_file_entry] Count incremented to 15 - [scan] builtins.py -> ea80a4a724accbda -[DBG add_file_entry] Count=15 entry_addr=0x21a545d96c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d3650 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600540 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600740 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600660 -[DBG add_file_entry] Count incremented to 16 - [scan] condition.py -> ad6c853acfc0c146 -[DBG add_file_entry] Count=16 entry_addr=0x21a545d96e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600440 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600220 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546006a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546001e0 -[DBG add_file_entry] Count incremented to 17 - [scan] event.py -> 9d8626a10208b8de -[DBG add_file_entry] Count=17 entry_addr=0x21a545d9700 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545d36b0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600280 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546006c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546003a0 -[DBG add_file_entry] Count incremented to 18 - [scan] hashlib/__init__.py -> 96837bcc64032444 -[DBG add_file_entry] Count=18 entry_addr=0x21a545d9720 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600ce0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600720 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600560 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600700 -[DBG add_file_entry] Count incremented to 19 - [scan] hashlib/__md5.py -> 19f8024d10c828e8 -[DBG add_file_entry] Count=19 entry_addr=0x21a545d9740 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600b90 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546005a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546002c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546002a0 -[DBG add_file_entry] Count incremented to 20 - [scan] hashlib/__sha1.py -> 0df65b8ed15664b0 -[DBG add_file_entry] Count=20 entry_addr=0x21a545d9760 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600aa0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600520 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546002e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600840 -[DBG add_file_entry] Count incremented to 21 - [scan] hashlib/__sha256.py -> c9d54a4158f7f5a8 -[DBG add_file_entry] Count=21 entry_addr=0x21a545d9780 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600c50 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600180 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546005c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600580 -[DBG add_file_entry] Count incremented to 22 - [scan] hashlib/__sha512.py -> 6ff26590374ae6fc -[DBG add_file_entry] Count=22 entry_addr=0x21a545d97a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600a70 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600780 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546005e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600640 -[DBG add_file_entry] Count incremented to 23 - [scan] hashtable.py -> b8c66c8ff44eb874 -[DBG add_file_entry] Count=23 entry_addr=0x21a545d97c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546004a0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546007a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600480 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600260 -[DBG add_file_entry] Count incremented to 24 - [scan] hello.py -> 6166aecc7fa7ad65 -[DBG add_file_entry] Count=24 entry_addr=0x21a545d97e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600ad0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600320 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600400 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600300 -[DBG add_file_entry] Count incremented to 25 - [scan] json/__init__.py -> 57288496f7c2d1ad -[DBG add_file_entry] Count=25 entry_addr=0x21a545d9800 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600bf0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600800 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546006e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546003c0 -[DBG add_file_entry] Count incremented to 26 - [scan] json/__parser.py -> 240a9a4157959a9f -[DBG add_file_entry] Count=26 entry_addr=0x21a545d9820 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600bc0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600360 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600820 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600760 -[DBG add_file_entry] Count incremented to 27 - [scan] json/__writer.py -> 20cd49775c100a38 -[DBG add_file_entry] Count=27 entry_addr=0x21a545d9840 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600d10 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600380 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546001a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546007c0 -[DBG add_file_entry] Count incremented to 28 - [scan] linkedlist.py -> 2d39c6c7d3557b3e -[DBG add_file_entry] Count=28 entry_addr=0x21a545d9860 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600c80 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600460 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600160 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600420 -[DBG add_file_entry] Count incremented to 29 - [scan] llvmlite/__builder.py -> 946e087da91aaada -[DBG add_file_entry] Count=29 entry_addr=0x21a545d9880 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600cb0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600120 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3a80 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600100 -[DBG add_file_entry] Count incremented to 30 - [scan] llvmlite/__function.py -> 89b3965176cd2407 -[DBG add_file_entry] Count=30 entry_addr=0x21a545d98a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600d40 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601490 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601090 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546003e0 -[DBG add_file_entry] Count incremented to 31 - [scan] llvmlite/__init__.py -> 95394ca8da0f655a -[DBG add_file_entry] Count=31 entry_addr=0x21a545d98c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600da0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600e90 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601290 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601370 -[DBG add_file_entry] Count incremented to 32 - [scan] llvmlite/__module.py -> 21a7fcfc665f75ef -[DBG add_file_entry] Count=32 entry_addr=0x21a545d98e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600d70 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600ed0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601330 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546015d0 -[DBG add_file_entry] Count incremented to 33 - [scan] llvmlite/__types.py -> 15f1ded02f3aa5bc -[DBG add_file_entry] Count=33 entry_addr=0x21a545d9900 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600b00 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601550 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601450 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601510 -[DBG add_file_entry] Count incremented to 34 - [scan] llvmlite/__values.py -> f9e36e2cd6fa659f -[DBG add_file_entry] Count=34 entry_addr=0x21a545d9920 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600b30 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600f10 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601110 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600ef0 -[DBG add_file_entry] Count incremented to 35 - [scan] llvmlite/__verify.py -> 6b3bc463fd044545 -[DBG add_file_entry] Count=35 entry_addr=0x21a545d9940 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601590 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546013d0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3c70 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3510 -[DBG add_file_entry] Count incremented to 36 - [scan] lock.py -> 56d07ea7e30ef631 -[DBG add_file_entry] Count=36 entry_addr=0x21a545d9960 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600b60 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600f50 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546015b0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546014b0 -[DBG add_file_entry] Count incremented to 37 - [scan] memhub.py -> 754640ce30cfebcc -[DBG add_file_entry] Count=37 entry_addr=0x21a545d9980 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600c20 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601390 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546012b0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600f90 -[DBG add_file_entry] Count incremented to 38 - [scan] numpy/__init__.py -> c3a6aed1f1fb8b1e -[DBG add_file_entry] Count=38 entry_addr=0x21a545d99a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601d80 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600e50 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601130 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546013f0 -[DBG add_file_entry] Count incremented to 39 - [scan] os/path.py -> 13110effbb0bb06c -[DBG add_file_entry] Count=39 entry_addr=0x21a545d99c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601780 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546013b0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601150 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546011d0 -[DBG add_file_entry] Count incremented to 40 - [scan] os/_posix.py -> d152115b49e50218 -[DBG add_file_entry] Count=40 entry_addr=0x21a545d99e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601c00 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601530 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601470 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601430 -[DBG add_file_entry] Count incremented to 41 - [scan] os/_win32.py -> a68b70f233541a7f -[DBG add_file_entry] Count=41 entry_addr=0x21a545d9a00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601c60 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546014f0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546012d0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546014d0 -[DBG add_file_entry] Count incremented to 42 - [scan] os/__init__.py -> 76dd6c275aa72b3b -[DBG add_file_entry] Count=42 entry_addr=0x21a545d9a20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601930 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601010 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601210 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601250 -[DBG add_file_entry] Count incremented to 43 - [scan] platmacro.py -> 93c1d18e35d188d6 -[DBG add_file_entry] Count=43 entry_addr=0x21a545d9a40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600e70 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600fd0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601270 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601230 -[DBG add_file_entry] Count incremented to 44 - [scan] plist.py -> e0f1d864a10b2e4d -[DBG add_file_entry] Count=44 entry_addr=0x21a545d9a60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601350 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600f70 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601410 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601310 -[DBG add_file_entry] Count incremented to 45 - [scan] posix.py -> 6503c97dde0c79c4 -[DBG add_file_entry] Count=45 entry_addr=0x21a545d9a80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601b40 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601030 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600fb0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600eb0 -[DBG add_file_entry] Count incremented to 46 - [scan] requests.py -> b558d8d8f01f4825 -[DBG add_file_entry] Count=46 entry_addr=0x21a545d9aa0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546019c0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54600ff0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601050 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54600f30 -[DBG add_file_entry] Count incremented to 47 - [scan] rwlock.py -> da44924f0777c67a -[DBG add_file_entry] Count=47 entry_addr=0x21a545d9ac0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601720 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a54601190 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546010b0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546011f0 -[DBG add_file_entry] Count incremented to 48 - [scan] shutil.py -> abbcbd92436cc16a -[DBG add_file_entry] Count=48 entry_addr=0x21a545d9ae0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601db0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546010d0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a546010f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601070 -[DBG add_file_entry] Count incremented to 49 - [scan] socket.py -> d7e3386b828acb66 -[DBG add_file_entry] Count=49 entry_addr=0x21a545d9b00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546019f0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546011b0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54600340 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a54601570 -[DBG add_file_entry] Count incremented to 50 - [scan] spinlock.py -> b19a9e500f677f2e -[DBG add_file_entry] Count=50 entry_addr=0x21a545d9b20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601a50 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546000e0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d3ac0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a546012f0 -[DBG add_file_entry] Count incremented to 51 - [scan] stdarg.py -> 71e0a3ffcb3ebfad -[DBG add_file_entry] Count=51 entry_addr=0x21a545d9b40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601900 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbe80 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbb80 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbe00 -[DBG add_file_entry] Count incremented to 52 - [scan] stdint.py -> f5522571bcce7bcb -[DBG add_file_entry] Count=52 entry_addr=0x21a545d9b60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545dbea0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbb60 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbfa0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbd60 -[DBG add_file_entry] Count incremented to 53 - [scan] stdio.py -> 6f62fe05c5ea1ceb -[DBG add_file_entry] Count=53 entry_addr=0x21a545d9b80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601c30 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbfe0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbbe0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbe20 -[DBG add_file_entry] Count incremented to 54 - [scan] stdlib.py -> 90c53dd6db8d41cf -[DBG add_file_entry] Count=54 entry_addr=0x21a545d9ba0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601690 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbde0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbba0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbce0 -[DBG add_file_entry] Count incremented to 55 - [scan] string.py -> 9474791561654346 -[DBG add_file_entry] Count=55 entry_addr=0x21a545d9bc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546016c0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbec0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbf60 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbe40 -[DBG add_file_entry] Count incremented to 56 - [scan] subprocess.py -> 2da636c61863c815 -[DBG add_file_entry] Count=56 entry_addr=0x21a545d9be0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545dbb40 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc0a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545d36e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3680 -[DBG add_file_entry] Count incremented to 57 - [scan] sys.py -> b5a965302cded36b -[DBG add_file_entry] Count=57 entry_addr=0x21a545d9c00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601a20 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dba40 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbc60 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dba20 -[DBG add_file_entry] Count incremented to 58 - [scan] testcheck.py -> 14d33679f7fadf1f -[DBG add_file_entry] Count=58 entry_addr=0x21a545d9c20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545dc0c0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbf20 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc2f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545d3590 -[DBG add_file_entry] Count incremented to 59 - [scan] this.py -> a7bc8c01684c0001 -[DBG add_file_entry] Count=59 entry_addr=0x21a545d9c40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601b70 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbf00 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbf40 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbaa0 -[DBG add_file_entry] Count incremented to 60 - [scan] vector.py -> 285a822aa26bfbda -[DBG add_file_entry] Count=60 entry_addr=0x21a545d9c60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601c90 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbf80 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbee0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbd80 -[DBG add_file_entry] Count incremented to 61 - [scan] viperio.py -> c9f4be41ca1cc2b4 -[DBG add_file_entry] Count=61 entry_addr=0x21a545d9c80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546017b0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dba60 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc000 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dba00 -[DBG add_file_entry] Count incremented to 62 - [scan] viperlib.py -> c3b259b4059f8668 -[DBG add_file_entry] Count=62 entry_addr=0x21a545d9ca0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546016f0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc020 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc040 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbac0 -[DBG add_file_entry] Count incremented to 63 - [scan] vipermath.py -> 3f7c5e78d8652535 -[DBG add_file_entry] Count=63 entry_addr=0x21a545d9cc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601cc0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc0e0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbfc0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbda0 -[DBG add_file_entry] Count incremented to 64 - [scan] vipersimd.py -> c24f25b14b4bbd0a -[DBG add_file_entry] Count=64 entry_addr=0x21a545d9ce0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601cf0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbae0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbb00 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dba80 -[DBG add_file_entry] Count incremented to 65 - [scan] viperstring.py -> 3624cfde3c5cb6cb -[DBG add_file_entry] Count=65 entry_addr=0x21a545d9d00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601750 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbdc0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbb20 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc060 -[DBG add_file_entry] Count incremented to 66 - [scan] vrandom.py -> 62cc01c2bb770ca3 -[DBG add_file_entry] Count=66 entry_addr=0x21a545d9d20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601ba0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbd00 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc120 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbbc0 -[DBG add_file_entry] Count incremented to 67 - [scan] vthreading.py -> 87274c2b0190fb33 -[DBG add_file_entry] Count=67 entry_addr=0x21a545d9d40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601960 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbe60 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbd20 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545db9e0 -[DBG add_file_entry] Count incremented to 68 - [scan] w32/fileio.py -> 0035c95a18d4f8e8 -[DBG add_file_entry] Count=68 entry_addr=0x21a545d9d60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601d20 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545db9a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545db9c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbc20 -[DBG add_file_entry] Count incremented to 69 - [scan] w32/win32base.py -> 7e529fe7a078cfef -[DBG add_file_entry] Count=69 entry_addr=0x21a545d9d80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601d50 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dbca0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dbcc0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbc40 -[DBG add_file_entry] Count incremented to 70 - [scan] w32/win32console.py -> bbdf3bbd4c3bc28c -[DBG add_file_entry] Count=70 entry_addr=0x21a545d9da0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601a80 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a546007e0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a54601170 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dbc80 -[DBG add_file_entry] Count incremented to 71 - [scan] w32/win32file.py -> f6b51804a0ba8ff0 -[DBG add_file_entry] Count=71 entry_addr=0x21a545d9dc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601810 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc460 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dca40 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc4e0 -[DBG add_file_entry] Count incremented to 72 - [scan] w32/win32memory.py -> 72e2d5ccb7cedcf1 -[DBG add_file_entry] Count=72 entry_addr=0x21a545d9de0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601de0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc6a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc780 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc980 -[DBG add_file_entry] Count incremented to 73 - [scan] w32/win32process.py -> 067c78e9f121dce3 -[DBG add_file_entry] Count=73 entry_addr=0x21a545d9e00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546018a0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dca00 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc860 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc400 -[DBG add_file_entry] Count incremented to 74 - [scan] w32/win32sync.py -> 06f53cc594b4ac6c -[DBG add_file_entry] Count=74 entry_addr=0x21a545d9e20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601840 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dca20 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc6c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc8a0 -[DBG add_file_entry] Count incremented to 75 - [scan] w32/winsock2.py -> 6446627d4f07a1b5 -[DBG add_file_entry] Count=75 entry_addr=0x21a545d9e40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546017e0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc8c0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc520 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc7e0 -[DBG add_file_entry] Count incremented to 76 - [scan] zlib/pyzlib.py -> 1c46d554b3a3f9f3 -[DBG add_file_entry] Count=76 entry_addr=0x21a545d9e60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601bd0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc4c0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dca60 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc6e0 -[DBG add_file_entry] Count incremented to 77 - [scan] zlib/zchecksum.py -> 8ebed83a7817fa0c -[DBG add_file_entry] Count=77 entry_addr=0x21a545d9e80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601870 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dcaa0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dcac0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dca80 -[DBG add_file_entry] Count incremented to 78 - [scan] zlib/zdef.py -> 213348433fb01cc6 -[DBG add_file_entry] Count=78 entry_addr=0x21a545d9ea0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a546018d0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc720 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc5c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc640 -[DBG add_file_entry] Count incremented to 79 - [scan] zlib/zdeflate.py -> 90921d009fdd674c -[DBG add_file_entry] Count=79 entry_addr=0x21a545d9ec0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601990 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc840 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc440 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc7c0 -[DBG add_file_entry] Count incremented to 80 - [scan] zlib/zhuff.py -> d541ade6afb689a5 -[DBG add_file_entry] Count=80 entry_addr=0x21a545d9ee0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601ae0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc680 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc8e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc540 -[DBG add_file_entry] Count incremented to 81 - [scan] zlib/zinflate.py -> 451745df21e598af -[DBG add_file_entry] Count=81 entry_addr=0x21a545d9f00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601b10 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc7a0 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc900 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dcae0 -[DBG add_file_entry] Count incremented to 82 - [scan] zlib/__init__.py -> d63d2c2a2bd9bd2a -[DBG add_file_entry] Count=82 entry_addr=0x21a545d9f20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545dc5a0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc820 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc9a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc880 -[DBG add_file_entry] Count incremented to 83 - [scan] _dict.py -> e3e7b6de8d7d8b03 -[DBG add_file_entry] Count=83 entry_addr=0x21a545d9f40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54601ab0 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc700 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc420 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dc620 -[DBG add_file_entry] Count incremented to 84 - [scan] _fakeduck.py -> 79b337e5ea8951e2 -[DBG add_file_entry] Count=84 entry_addr=0x21a545d9f60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a545dc920 -[DBG add_file_entry] Sha1 set, sha1_buf=0x21a545dc480 -[DBG add_file_entry] RelPath set, rel_buf=0x21a545dc940 -[DBG add_file_entry] ModuleName set, mod_buf=0x21a545dcb40 -[DBG add_file_entry] Count incremented to 85 - [scan] _list.py -> 668790e6c9efdbae -[DBG add_file_entry] Count=85 entry_addr=0x21a545d9f80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x21a54600a40 -[DBG add_file_entry] Sha1 diff --git a/Test/crash_log2.txt b/Test/crash_log2.txt deleted file mode 100644 index 7829bec..0000000 --- a/Test/crash_log2.txt +++ /dev/null @@ -1,1636 +0,0 @@ -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=000001618000D148 -[INFO] TransPyV 启动 -DBG MemBuddy.alloc: size=131 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=3 max_order=24 -DBG MemBuddy.alloc: block=000001618000D248 -DBG MemBuddy.alloc: size=1048 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=6 max_order=24 -DBG MemBuddy.alloc: block=000001618000D948 -DBG MemBuddy.alloc: size=40 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=000001618000D188 -DBG MemBuddy.alloc: size=2048 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=7 max_order=24 -DBG MemBuddy.alloc: block=000001618000E148 -DBG MemBuddy.alloc: size=16 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D1C8 -DBG MemBuddy.alloc: size=48 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=000001618000D208 -DBG MemBuddy.alloc: size=384 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=4 max_order=24 -DBG MemBuddy.alloc: block=000001618000D348 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D1E8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D548 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D568 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D588 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D5A8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D5C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D5E8 - -=== TransPyV 参数解析结果 === - - --project: project.vpj - --src: (未指定) - --temp: (未指定) - --output: (未指定) - --phase: (未指定,默认 all) - --cc: (未指定) - --clean: True - --run: False - --rebuild-includes: True - --clear-cache: True - -参数解析完成。 - -=== 工程配置 === - -DBG MemBuddy.alloc: size=8192 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=9 max_order=24 -DBG MemBuddy.alloc: block=0000016180011148 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000D648 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D608 -DBG MemBuddy.alloc: size=87 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000D6C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000D748 -DBG MemBuddy.alloc: size=87 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000D7C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D628 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D848 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D868 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000D8C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D888 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000D8A8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F148 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F168 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F1C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F188 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F1A8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F248 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F268 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F2C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F288 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F2A8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F348 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F368 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F3C8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F388 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F3A8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F448 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F468 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F4C8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F488 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F4A8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F548 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F5C8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F568 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F588 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F648 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F5A8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F6C8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F6E8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F748 -DBG MemBuddy.alloc: size=14 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F708 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F7C8 -DBG MemBuddy.alloc: size=14 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F728 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F848 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F8C8 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F868 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F888 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F8A8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F948 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000F9C8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F968 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F988 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FA48 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000F9A8 -DBG MemBuddy.alloc: size=4 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FAC8 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FAE8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FB48 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FB08 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FBC8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FB28 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FC48 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FCC8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FC68 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FC88 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FD48 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FCA8 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FDC8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FE48 -DBG MemBuddy.alloc: size=10 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FDE8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FE08 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FEC8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=000001618000FE28 -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=000001618000FF48 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=000001618000FFC8 -DBG MemBuddy.alloc: size=32 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=000001618000FF88 -DBG MemBuddy.alloc: size=6 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010048 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010068 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010088 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800100C8 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800100A8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010148 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010168 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010188 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800101C8 -DBG MemBuddy.alloc: size=15 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800101A8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010248 -DBG MemBuddy.alloc: size=15 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800102C8 -DBG MemBuddy.alloc: size=9 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800102E8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010308 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010348 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010328 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800103C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010448 -DBG MemBuddy.alloc: size=22 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800103E8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010408 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010428 -DBG MemBuddy.alloc: size=71 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800104C8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010548 -DBG MemBuddy.alloc: size=71 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800105C8 -DBG MemBuddy.alloc: size=11 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010648 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010668 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010688 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800106C8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800106A8 -DBG MemBuddy.alloc: size=2 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010748 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=00000161800107C8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010768 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010788 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800107A8 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010848 -DBG MemBuddy.alloc: size=5 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800108C8 -DBG MemBuddy.alloc: size=7 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800108E8 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010908 -DBG MemBuddy.alloc: size=64 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010948 -DBG MemBuddy.alloc: size=12 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=0000016180010928 -DBG MemBuddy.alloc: size=8 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=0 max_order=24 -DBG MemBuddy.alloc: block=00000161800109C8 -DBG MemBuddy.alloc: size=37 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=1 max_order=24 -DBG MemBuddy.alloc: block=0000016180010A08 -DBG MemBuddy.alloc: size=80 -DBG MemBuddy.alloc: usable=000001618000D148 -DBG MemBuddy.alloc: order=2 max_order=24 -DBG MemBuddy.alloc: block=0000016180010A48 - project: AstTest v1.0.0 - source_dir: App - temp_dir: temp - output_dir: output - compiler: llc - linker: clang++ -> app.exe - includes: ../../includes - -[clean] 清理临时目录... -[clean] temp: 删除 1 个文件 -[clean] output: 删除 0 个文件 -[phase] 模式: all (phase1=1 phase2=1) - -=== Phase1: 扫描 includes(按需翻译) === - -[Phase1] 扫描 includes 目录: ../../includes -[DBG add_file_entry] Count=0 entry_addr=0x161e6d394e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d334a0 -[DBG sha1] before malloc(17), sha1=0x161e6d33480 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d334d0 -[DBG sha1] before strcpy, sha1[0]=a -[DBG sha1] after strcpy, sha1_buf[0]=a -[DBG sha1] before store entry.Sha1, entry=0x161e6d394e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d334d0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d334f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33460 -[DBG add_file_entry] Count incremented to 1 - [scan] argparse.py -> aba439b7882ad9d6 -[DBG add_file_entry] Count=1 entry_addr=0x161e6d39500 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33530 -[DBG sha1] before malloc(17), sha1=0x161e6d33510 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33550 -[DBG sha1] before strcpy, sha1[0]=3 -[DBG sha1] after strcpy, sha1_buf[0]=3 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39500 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33550 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33570 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33430 -[DBG add_file_entry] Count incremented to 2 - [scan] asm.py -> 3487a256b250bb74 -[DBG add_file_entry] Count=2 entry_addr=0x161e6d39520 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33b80 -[DBG sha1] before malloc(17), sha1=0x161e6d33750 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33a20 -[DBG sha1] before strcpy, sha1[0]=4 -[DBG sha1] after strcpy, sha1_buf[0]=4 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39520 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33a20 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33a40 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33a00 -[DBG add_file_entry] Count incremented to 3 - [scan] ast/astaux.py -> 4337fb260448bbe2 -[DBG add_file_entry] Count=3 entry_addr=0x161e6d39540 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33710 -[DBG sha1] before malloc(17), sha1=0x161e6d33900 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33840 -[DBG sha1] before strcpy, sha1[0]=5 -[DBG sha1] after strcpy, sha1_buf[0]=5 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39540 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33840 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33860 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d339e0 -[DBG add_file_entry] Count incremented to 4 - [scan] ast/base.py -> 5dab8cb390496d22 -[DBG add_file_entry] Count=4 entry_addr=0x161e6d39560 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33740 -[DBG sha1] before malloc(17), sha1=0x161e6d338e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33a60 -[DBG sha1] before strcpy, sha1[0]=4 -[DBG sha1] after strcpy, sha1_buf[0]=4 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39560 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33a60 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d339c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33880 -[DBG add_file_entry] Count incremented to 5 - [scan] ast/exprs.py -> 47767b5026a8ee15 -[DBG add_file_entry] Count=5 entry_addr=0x161e6d39580 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33bb0 -[DBG sha1] before malloc(17), sha1=0x161e6d33920 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33800 -[DBG sha1] before strcpy, sha1[0]=0 -[DBG sha1] after strcpy, sha1_buf[0]=0 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39580 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33800 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33a80 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d338e0 -[DBG add_file_entry] Count incremented to 6 - [scan] ast/lexer.py -> 0c212981c180e7fb -[DBG add_file_entry] Count=6 entry_addr=0x161e6d395a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33be0 -[DBG sha1] before malloc(17), sha1=0x161e6d33aa0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33ae0 -[DBG sha1] before strcpy, sha1[0]=4 -[DBG sha1] after strcpy, sha1_buf[0]=4 -[DBG sha1] before store entry.Sha1, entry=0x161e6d395a0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33ae0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33b00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33ac0 -[DBG add_file_entry] Count incremented to 7 - [scan] ast/match.py -> 4dd6b3f1427d1cc5 -[DBG add_file_entry] Count=7 entry_addr=0x161e6d395c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33c10 -[DBG sha1] before malloc(17), sha1=0x161e6d33b40 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33820 -[DBG sha1] before strcpy, sha1[0]=e -[DBG sha1] after strcpy, sha1_buf[0]=e -[DBG sha1] before store entry.Sha1, entry=0x161e6d395c0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33820 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d338a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33900 -[DBG add_file_entry] Count incremented to 8 - [scan] ast/parser.py -> ee52c08239684346 -[DBG add_file_entry] Count=8 entry_addr=0x161e6d395e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33c40 -[DBG sha1] before malloc(17), sha1=0x161e6d338c0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33920 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d395e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33920 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33b40 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33b20 -[DBG add_file_entry] Count incremented to 9 - [scan] ast/stmts.py -> 657e182b27c2a022 -[DBG add_file_entry] Count=9 entry_addr=0x161e6d39600 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d3b8f0 -[DBG sha1] before malloc(17), sha1=0x161e6d337e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d33aa0 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d39600 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d33aa0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d338c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33960 -[DBG add_file_entry] Count incremented to 10 - [scan] ast/tokens.py -> b547ac4f380bddb6 -[DBG add_file_entry] Count=10 entry_addr=0x161e6d39620 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d3b920 -[DBG sha1] before malloc(17), sha1=0x161e6d33980 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d337c0 -[DBG sha1] before strcpy, sha1[0]=3 -[DBG sha1] after strcpy, sha1_buf[0]=3 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39620 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d337c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d337e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d339a0 -[DBG add_file_entry] Count incremented to 11 - [scan] ast/__init__.py -> 34548789d646f432 -[DBG add_file_entry] Count=11 entry_addr=0x161e6d39640 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50840 -[DBG sha1] before malloc(17), sha1=0x161e6c50640 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c503a0 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39640 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c503a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33410 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33480 -[DBG add_file_entry] Count incremented to 12 - [scan] atom.py -> 271ea3decb810db2 -[DBG add_file_entry] Count=12 entry_addr=0x161e6d39660 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d335c0 -[DBG sha1] before malloc(17), sha1=0x161e6c50220 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50400 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39660 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50400 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c502a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c505e0 -[DBG add_file_entry] Count incremented to 13 - [scan] base64.py -> 971e24c228377a9b -[DBG add_file_entry] Count=13 entry_addr=0x161e6d39680 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d335f0 -[DBG sha1] before malloc(17), sha1=0x161e6c504a0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c505a0 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39680 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c505a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50860 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50100 -[DBG add_file_entry] Count incremented to 14 - [scan] binascii.py -> 257e074b935c33b4 -[DBG add_file_entry] Count=14 entry_addr=0x161e6d396a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33620 -[DBG sha1] before malloc(17), sha1=0x161e6c50440 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c502c0 -[DBG sha1] before strcpy, sha1[0]=e -[DBG sha1] after strcpy, sha1_buf[0]=e -[DBG sha1] before store entry.Sha1, entry=0x161e6d396a0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c502c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c506e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50720 -[DBG add_file_entry] Count incremented to 15 - [scan] builtins.py -> ea80a4a724accbda -[DBG add_file_entry] Count=15 entry_addr=0x161e6d396c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d33650 -[DBG sha1] before malloc(17), sha1=0x161e6c50560 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c503c0 -[DBG sha1] before strcpy, sha1[0]=a -[DBG sha1] after strcpy, sha1_buf[0]=a -[DBG sha1] before store entry.Sha1, entry=0x161e6d396c0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c503c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c502e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c504a0 -[DBG add_file_entry] Count incremented to 16 - [scan] condition.py -> ad6c853acfc0c146 -[DBG add_file_entry] Count=16 entry_addr=0x161e6d396e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50600 -[DBG sha1] before malloc(17), sha1=0x161e6c50120 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50820 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d396e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50820 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50620 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c500e0 -[DBG add_file_entry] Count incremented to 17 - [scan] event.py -> 9d8626a10208b8de -[DBG add_file_entry] Count=17 entry_addr=0x161e6d39700 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d336b0 -[DBG sha1] before malloc(17), sha1=0x161e6c50700 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50380 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39700 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50380 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50220 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50300 -[DBG add_file_entry] Count incremented to 18 - [scan] hashlib/__init__.py -> 96837bcc64032444 -[DBG add_file_entry] Count=18 entry_addr=0x161e6d39720 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50ad0 -[DBG sha1] before malloc(17), sha1=0x161e6c50180 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50700 -[DBG sha1] before strcpy, sha1[0]=1 -[DBG sha1] after strcpy, sha1_buf[0]=1 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39720 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50700 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50340 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50260 -[DBG add_file_entry] Count incremented to 19 - [scan] hashlib/__md5.py -> 19f8024d10c828e8 -[DBG add_file_entry] Count=19 entry_addr=0x161e6d39740 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50d10 -[DBG sha1] before malloc(17), sha1=0x161e6c50200 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50360 -[DBG sha1] before strcpy, sha1[0]=0 -[DBG sha1] after strcpy, sha1_buf[0]=0 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39740 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50360 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c501c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50120 -[DBG add_file_entry] Count incremented to 20 - [scan] hashlib/__sha1.py -> 0df65b8ed15664b0 -[DBG add_file_entry] Count=20 entry_addr=0x161e6d39760 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50ce0 -[DBG sha1] before malloc(17), sha1=0x161e6c50140 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50280 -[DBG sha1] before strcpy, sha1[0]=c -[DBG sha1] after strcpy, sha1_buf[0]=c -[DBG sha1] before store entry.Sha1, entry=0x161e6d39760 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50280 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50320 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c506c0 -[DBG add_file_entry] Count incremented to 21 - [scan] hashlib/__sha256.py -> c9d54a4158f7f5a8 -[DBG add_file_entry] Count=21 entry_addr=0x161e6d39780 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50c50 -[DBG sha1] before malloc(17), sha1=0x161e6c50640 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50740 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39780 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50740 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c504c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50140 -[DBG add_file_entry] Count incremented to 22 - [scan] hashlib/__sha512.py -> 6ff26590374ae6fc -[DBG add_file_entry] Count=22 entry_addr=0x161e6d397a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50d40 -[DBG sha1] before malloc(17), sha1=0x161e6c50440 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50160 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d397a0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50160 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50760 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50780 -[DBG add_file_entry] Count incremented to 23 - [scan] hashtable.py -> b8c66c8ff44eb874 -[DBG add_file_entry] Count=23 entry_addr=0x161e6d397c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c503e0 -[DBG sha1] before malloc(17), sha1=0x161e6c504e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c501e0 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d397c0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c501e0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50520 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50500 -[DBG add_file_entry] Count incremented to 24 - [scan] hello.py -> 6166aecc7fa7ad65 -[DBG add_file_entry] Count=24 entry_addr=0x161e6d397e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50c80 -[DBG sha1] before malloc(17), sha1=0x161e6c50460 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50200 -[DBG sha1] before strcpy, sha1[0]=5 -[DBG sha1] after strcpy, sha1_buf[0]=5 -[DBG sha1] before store entry.Sha1, entry=0x161e6d397e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50200 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c501a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50180 -[DBG add_file_entry] Count incremented to 25 - [scan] json/__init__.py -> 57288496f7c2d1ad -[DBG add_file_entry] Count=25 entry_addr=0x161e6d39800 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50bc0 -[DBG sha1] before malloc(17), sha1=0x161e6c50440 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50480 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39800 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50480 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c504e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50460 -[DBG add_file_entry] Count incremented to 26 - [scan] json/__parser.py -> 240a9a4157959a9f -[DBG add_file_entry] Count=26 entry_addr=0x161e6d39820 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50d70 -[DBG sha1] before malloc(17), sha1=0x161e6c50240 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c507c0 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39820 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c507c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50640 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50660 -[DBG add_file_entry] Count incremented to 27 - [scan] json/__writer.py -> 20cd49775c100a38 -[DBG add_file_entry] Count=27 entry_addr=0x161e6d39840 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50b00 -[DBG sha1] before malloc(17), sha1=0x161e6c50440 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50680 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39840 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50680 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50240 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50540 -[DBG add_file_entry] Count incremented to 28 - [scan] linkedlist.py -> 2d39c6c7d3557b3e -[DBG add_file_entry] Count=28 entry_addr=0x161e6d39860 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50da0 -[DBG sha1] before malloc(17), sha1=0x161e6c507e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50580 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39860 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50580 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50800 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50560 -[DBG add_file_entry] Count incremented to 29 - [scan] llvmlite/__builder.py -> 946e087da91aaada -[DBG add_file_entry] Count=29 entry_addr=0x161e6d39880 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50a70 -[DBG sha1] before malloc(17), sha1=0x161e6c507a0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c505c0 -[DBG sha1] before strcpy, sha1[0]=8 -[DBG sha1] after strcpy, sha1_buf[0]=8 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39880 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c505c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33940 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c507e0 -[DBG add_file_entry] Count incremented to 30 - [scan] llvmlite/__function.py -> 89b3965176cd2407 -[DBG add_file_entry] Count=30 entry_addr=0x161e6d398a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50aa0 -[DBG sha1] before malloc(17), sha1=0x161e6c507a0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51450 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d398a0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51450 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51230 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50440 -[DBG add_file_entry] Count incremented to 31 - [scan] llvmlite/__init__.py -> 95394ca8da0f655a -[DBG add_file_entry] Count=31 entry_addr=0x161e6d398c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50cb0 -[DBG sha1] before malloc(17), sha1=0x161e6c51270 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50f10 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d398c0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50f10 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c513f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51150 -[DBG add_file_entry] Count incremented to 32 - [scan] llvmlite/__module.py -> 21a7fcfc665f75ef -[DBG add_file_entry] Count=32 entry_addr=0x161e6d398e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50a40 -[DBG sha1] before malloc(17), sha1=0x161e6c51250 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51490 -[DBG sha1] before strcpy, sha1[0]=1 -[DBG sha1] after strcpy, sha1_buf[0]=1 -[DBG sha1] before store entry.Sha1, entry=0x161e6d398e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51490 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51470 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51050 -[DBG add_file_entry] Count incremented to 33 - [scan] llvmlite/__types.py -> 15f1ded02f3aa5bc -[DBG add_file_entry] Count=33 entry_addr=0x161e6d39900 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50b60 -[DBG sha1] before malloc(17), sha1=0x161e6c51110 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c510b0 -[DBG sha1] before strcpy, sha1[0]=f -[DBG sha1] after strcpy, sha1_buf[0]=f -[DBG sha1] before store entry.Sha1, entry=0x161e6d39900 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c510b0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c514b0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51590 -[DBG add_file_entry] Count incremented to 34 - [scan] llvmlite/__values.py -> f9e36e2cd6fa659f -[DBG add_file_entry] Count=34 entry_addr=0x161e6d39920 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50bf0 -[DBG sha1] before malloc(17), sha1=0x161e6c51350 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c510f0 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39920 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c510f0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50e50 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51330 -[DBG add_file_entry] Count incremented to 35 - [scan] llvmlite/__verify.py -> 6b3bc463fd044545 -[DBG add_file_entry] Count=35 entry_addr=0x161e6d39940 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51250 -[DBG sha1] before malloc(17), sha1=0x161e6c514d0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50e90 -[DBG sha1] before strcpy, sha1[0]=5 -[DBG sha1] after strcpy, sha1_buf[0]=5 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39940 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50e90 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33c70 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33510 -[DBG add_file_entry] Count incremented to 36 - [scan] lock.py -> 56d07ea7e30ef631 -[DBG add_file_entry] Count=36 entry_addr=0x161e6d39960 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50b90 -[DBG sha1] before malloc(17), sha1=0x161e6c51030 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51070 -[DBG sha1] before strcpy, sha1[0]=7 -[DBG sha1] after strcpy, sha1_buf[0]=7 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39960 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51070 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c514d0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c511d0 -[DBG add_file_entry] Count incremented to 37 - [scan] memhub.py -> 754640ce30cfebcc -[DBG add_file_entry] Count=37 entry_addr=0x161e6d39980 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50c20 -[DBG sha1] before malloc(17), sha1=0x161e6c51030 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51130 -[DBG sha1] before strcpy, sha1[0]=c -[DBG sha1] after strcpy, sha1_buf[0]=c -[DBG sha1] before store entry.Sha1, entry=0x161e6d39980 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51130 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51110 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50ed0 -[DBG add_file_entry] Count incremented to 38 - [scan] numpy/__init__.py -> c3a6aed1f1fb8b1e -[DBG add_file_entry] Count=38 entry_addr=0x161e6d399a0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51cc0 -[DBG sha1] before malloc(17), sha1=0x161e6c51550 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51370 -[DBG sha1] before strcpy, sha1[0]=1 -[DBG sha1] after strcpy, sha1_buf[0]=1 -[DBG sha1] before store entry.Sha1, entry=0x161e6d399a0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51370 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c514f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51170 -[DBG add_file_entry] Count incremented to 39 - [scan] os/path.py -> 13110effbb0bb06c -[DBG add_file_entry] Count=39 entry_addr=0x161e6d399c0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51870 -[DBG sha1] before malloc(17), sha1=0x161e6c51210 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50ef0 -[DBG sha1] before strcpy, sha1[0]=d -[DBG sha1] after strcpy, sha1_buf[0]=d -[DBG sha1] before store entry.Sha1, entry=0x161e6d399c0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50ef0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50fd0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51270 -[DBG add_file_entry] Count incremented to 40 - [scan] os/_posix.py -> d152115b49e50218 -[DBG add_file_entry] Count=40 entry_addr=0x161e6d399e0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51a50 -[DBG sha1] before malloc(17), sha1=0x161e6c50f30 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51530 -[DBG sha1] before strcpy, sha1[0]=a -[DBG sha1] after strcpy, sha1_buf[0]=a -[DBG sha1] before store entry.Sha1, entry=0x161e6d399e0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51530 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51550 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51310 -[DBG add_file_entry] Count incremented to 41 - [scan] os/_win32.py -> a68b70f233541a7f -[DBG add_file_entry] Count=41 entry_addr=0x161e6d39a00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51cf0 -[DBG sha1] before malloc(17), sha1=0x161e6c51090 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c513d0 -[DBG sha1] before strcpy, sha1[0]=7 -[DBG sha1] after strcpy, sha1_buf[0]=7 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39a00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c513d0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51190 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50f30 -[DBG add_file_entry] Count incremented to 42 - [scan] os/__init__.py -> 76dd6c275aa72b3b -[DBG add_file_entry] Count=42 entry_addr=0x161e6d39a20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c518a0 -[DBG sha1] before malloc(17), sha1=0x161e6c50ff0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51510 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39a20 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51510 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51350 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c512d0 -[DBG add_file_entry] Count incremented to 43 - [scan] platmacro.py -> 93c1d18e35d188d6 -[DBG add_file_entry] Count=43 entry_addr=0x161e6d39a40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c512b0 -[DBG sha1] before malloc(17), sha1=0x161e6c51290 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c511b0 -[DBG sha1] before strcpy, sha1[0]=e -[DBG sha1] after strcpy, sha1_buf[0]=e -[DBG sha1] before store entry.Sha1, entry=0x161e6d39a40 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c511b0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c511f0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50f70 -[DBG add_file_entry] Count incremented to 44 - [scan] plist.py -> e0f1d864a10b2e4d -[DBG add_file_entry] Count=44 entry_addr=0x161e6d39a60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c50f90 -[DBG sha1] before malloc(17), sha1=0x161e6c50e70 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c50f50 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39a60 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c50f50 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51210 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c515d0 -[DBG add_file_entry] Count incremented to 45 - [scan] posix.py -> 6503c97dde0c79c4 -[DBG add_file_entry] Count=45 entry_addr=0x161e6d39a80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51780 -[DBG sha1] before malloc(17), sha1=0x161e6c512f0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51570 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d39a80 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51570 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50ff0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c50e70 -[DBG add_file_entry] Count incremented to 46 - [scan] requests.py -> b558d8d8f01f4825 -[DBG add_file_entry] Count=46 entry_addr=0x161e6d39aa0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51a20 -[DBG sha1] before malloc(17), sha1=0x161e6c51010 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c513b0 -[DBG sha1] before strcpy, sha1[0]=d -[DBG sha1] after strcpy, sha1_buf[0]=d -[DBG sha1] before store entry.Sha1, entry=0x161e6d39aa0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c513b0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50eb0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c515b0 -[DBG add_file_entry] Count incremented to 47 - [scan] rwlock.py -> da44924f0777c67a -[DBG add_file_entry] Count=47 entry_addr=0x161e6d39ac0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51d20 -[DBG sha1] before malloc(17), sha1=0x161e6c51290 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c510d0 -[DBG sha1] before strcpy, sha1[0]=a -[DBG sha1] after strcpy, sha1_buf[0]=a -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ac0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c510d0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50fb0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c512f0 -[DBG add_file_entry] Count incremented to 48 - [scan] shutil.py -> abbcbd92436cc16a -[DBG add_file_entry] Count=48 entry_addr=0x161e6d39ae0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c517b0 -[DBG sha1] before malloc(17), sha1=0x161e6c51010 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51390 -[DBG sha1] before strcpy, sha1[0]=d -[DBG sha1] after strcpy, sha1_buf[0]=d -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ae0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51390 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51090 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51030 -[DBG add_file_entry] Count incremented to 49 - [scan] socket.py -> d7e3386b828acb66 -[DBG add_file_entry] Count=49 entry_addr=0x161e6d39b00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51c30 -[DBG sha1] before malloc(17), sha1=0x161e6c51410 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c51430 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d39b00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c51430 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c50420 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51290 -[DBG add_file_entry] Count incremented to 50 - [scan] spinlock.py -> b19a9e500f677f2e -[DBG add_file_entry] Count=50 entry_addr=0x161e6d39b20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51690 -[DBG sha1] before malloc(17), sha1=0x161e6c51010 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c506a0 -[DBG sha1] before strcpy, sha1[0]=7 -[DBG sha1] after strcpy, sha1_buf[0]=7 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39b20 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c506a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d33980 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6c51410 -[DBG add_file_entry] Count incremented to 51 - [scan] stdarg.py -> 71e0a3ffcb3ebfad -[DBG add_file_entry] Count=51 entry_addr=0x161e6d39b40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51c90 -[DBG sha1] before malloc(17), sha1=0x161e6d3b9e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bc80 -[DBG sha1] before strcpy, sha1[0]=f -[DBG sha1] after strcpy, sha1_buf[0]=f -[DBG sha1] before store entry.Sha1, entry=0x161e6d39b40 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bc80 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bca0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bf20 -[DBG add_file_entry] Count incremented to 52 - [scan] stdint.py -> f5522571bcce7bcb -[DBG add_file_entry] Count=52 entry_addr=0x161e6d39b60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d3bd40 -[DBG sha1] before malloc(17), sha1=0x161e6d3bce0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bdc0 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39b60 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bdc0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bcc0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bb40 -[DBG add_file_entry] Count incremented to 53 - [scan] stdio.py -> 6f62fe05c5ea1ceb -[DBG add_file_entry] Count=53 entry_addr=0x161e6d39b80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51a80 -[DBG sha1] before malloc(17), sha1=0x161e6d3bc40 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bba0 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39b80 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bba0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3be00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bd60 -[DBG add_file_entry] Count incremented to 54 - [scan] stdlib.py -> 90c53dd6db8d41cf -[DBG add_file_entry] Count=54 entry_addr=0x161e6d39ba0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51db0 -[DBG sha1] before malloc(17), sha1=0x161e6d3bda0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bd80 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ba0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bd80 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bc00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bc60 -[DBG add_file_entry] Count incremented to 55 - [scan] string.py -> 9474791561654346 -[DBG add_file_entry] Count=55 entry_addr=0x161e6d39bc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51b40 -[DBG sha1] before malloc(17), sha1=0x161e6d3be60 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3be80 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39bc0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3be80 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bc40 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bea0 -[DBG add_file_entry] Count incremented to 56 - [scan] subprocess.py -> 2da636c61863c815 -[DBG add_file_entry] Count=56 entry_addr=0x161e6d39be0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d3bfa0 -[DBG sha1] before malloc(17), sha1=0x161e6d3bae0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bbc0 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d39be0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bbc0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d336e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33680 -[DBG add_file_entry] Count incremented to 57 - [scan] sys.py -> b5a965302cded36b -[DBG add_file_entry] Count=57 entry_addr=0x161e6d39c00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51ba0 -[DBG sha1] before malloc(17), sha1=0x161e6d3bde0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bce0 -[DBG sha1] before strcpy, sha1[0]=1 -[DBG sha1] after strcpy, sha1_buf[0]=1 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39c00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bce0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bd00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bda0 -[DBG add_file_entry] Count incremented to 58 - [scan] testcheck.py -> 14d33679f7fadf1f -[DBG add_file_entry] Count=58 entry_addr=0x161e6d39c20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6d3bbe0 -[DBG sha1] before malloc(17), sha1=0x161e6d3bd20 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bfc0 -[DBG sha1] before strcpy, sha1[0]=a -[DBG sha1] after strcpy, sha1_buf[0]=a -[DBG sha1] before store entry.Sha1, entry=0x161e6d39c20 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bfc0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c320 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d33590 -[DBG add_file_entry] Count incremented to 59 - [scan] this.py -> a7bc8c01684c0001 -[DBG add_file_entry] Count=59 entry_addr=0x161e6d39c40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c517e0 -[DBG sha1] before malloc(17), sha1=0x161e6d3bd20 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bfe0 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39c40 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bfe0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3ba60 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3ba40 -[DBG add_file_entry] Count incremented to 60 - [scan] vector.py -> 285a822aa26bfbda -[DBG add_file_entry] Count=60 entry_addr=0x161e6d39c60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51ab0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c080 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bee0 -[DBG sha1] before strcpy, sha1[0]=c -[DBG sha1] after strcpy, sha1_buf[0]=c -[DBG sha1] before store entry.Sha1, entry=0x161e6d39c60 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bee0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bb00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3b9c0 -[DBG add_file_entry] Count incremented to 61 - [scan] viperio.py -> c9f4be41ca1cc2b4 -[DBG add_file_entry] Count=61 entry_addr=0x161e6d39c80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51d50 -[DBG sha1] before malloc(17), sha1=0x161e6d3bb80 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c100 -[DBG sha1] before strcpy, sha1[0]=c -[DBG sha1] after strcpy, sha1_buf[0]=c -[DBG sha1] before store entry.Sha1, entry=0x161e6d39c80 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c100 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3ba80 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bd20 -[DBG add_file_entry] Count incremented to 62 - [scan] viperlib.py -> c3b259b4059f8668 -[DBG add_file_entry] Count=62 entry_addr=0x161e6d39ca0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51930 -[DBG sha1] before malloc(17), sha1=0x161e6d3bf00 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c000 -[DBG sha1] before strcpy, sha1[0]=3 -[DBG sha1] after strcpy, sha1_buf[0]=3 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ca0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c000 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bae0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c120 -[DBG add_file_entry] Count incremented to 63 - [scan] vipermath.py -> 3f7c5e78d8652535 -[DBG add_file_entry] Count=63 entry_addr=0x161e6d39cc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51900 -[DBG sha1] before malloc(17), sha1=0x161e6d3bb60 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c080 -[DBG sha1] before strcpy, sha1[0]=c -[DBG sha1] after strcpy, sha1_buf[0]=c -[DBG sha1] before store entry.Sha1, entry=0x161e6d39cc0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c080 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3b9e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c040 -[DBG add_file_entry] Count incremented to 64 - [scan] vipersimd.py -> c24f25b14b4bbd0a -[DBG add_file_entry] Count=64 entry_addr=0x161e6d39ce0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51840 -[DBG sha1] before malloc(17), sha1=0x161e6d3bde0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3be20 -[DBG sha1] before strcpy, sha1[0]=3 -[DBG sha1] after strcpy, sha1_buf[0]=3 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ce0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3be20 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bb80 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c020 -[DBG add_file_entry] Count incremented to 65 - [scan] viperstring.py -> 3624cfde3c5cb6cb -[DBG add_file_entry] Count=65 entry_addr=0x161e6d39d00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51ae0 -[DBG sha1] before malloc(17), sha1=0x161e6d3ba20 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3be40 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39d00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3be40 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bf00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bde0 -[DBG add_file_entry] Count incremented to 66 - [scan] vrandom.py -> 62cc01c2bb770ca3 -[DBG add_file_entry] Count=66 entry_addr=0x161e6d39d20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51810 -[DBG sha1] before malloc(17), sha1=0x161e6d3bb20 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3bec0 -[DBG sha1] before strcpy, sha1[0]=8 -[DBG sha1] after strcpy, sha1_buf[0]=8 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39d20 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3bec0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bf40 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3bc20 -[DBG add_file_entry] Count incremented to 67 - [scan] vthreading.py -> 87274c2b0190fb33 -[DBG add_file_entry] Count=67 entry_addr=0x161e6d39d40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51b70 -[DBG sha1] before malloc(17), sha1=0x161e6d3b9a0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3be60 -[DBG sha1] before strcpy, sha1[0]=0 -[DBG sha1] after strcpy, sha1_buf[0]=0 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39d40 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3be60 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bf80 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3ba20 -[DBG add_file_entry] Count incremented to 68 - [scan] w32/fileio.py -> 0035c95a18d4f8e8 -[DBG add_file_entry] Count=68 entry_addr=0x161e6d39d60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51660 -[DBG sha1] before malloc(17), sha1=0x161e6d3ba00 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c0a0 -[DBG sha1] before strcpy, sha1[0]=7 -[DBG sha1] after strcpy, sha1_buf[0]=7 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39d60 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c0a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c0c0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c060 -[DBG add_file_entry] Count incremented to 69 - [scan] w32/win32base.py -> 7e529fe7a078cfef -[DBG add_file_entry] Count=69 entry_addr=0x161e6d39d80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51960 -[DBG sha1] before malloc(17), sha1=0x161e6d3b9a0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3baa0 -[DBG sha1] before strcpy, sha1[0]=b -[DBG sha1] after strcpy, sha1_buf[0]=b -[DBG sha1] before store entry.Sha1, entry=0x161e6d39d80 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3baa0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3bb20 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3ba00 -[DBG add_file_entry] Count incremented to 70 - [scan] w32/win32console.py -> bbdf3bbd4c3bc28c -[DBG add_file_entry] Count=70 entry_addr=0x161e6d39da0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51990 -[DBG sha1] before malloc(17), sha1=0x161e6d3bac0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6c507a0 -[DBG sha1] before strcpy, sha1[0]=f -[DBG sha1] after strcpy, sha1_buf[0]=f -[DBG sha1] before store entry.Sha1, entry=0x161e6d39da0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6c507a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6c51010 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3b9a0 -[DBG add_file_entry] Count incremented to 71 - [scan] w32/win32file.py -> f6b51804a0ba8ff0 -[DBG add_file_entry] Count=71 entry_addr=0x161e6d39dc0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c518d0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c8e0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c420 -[DBG sha1] before strcpy, sha1[0]=7 -[DBG sha1] after strcpy, sha1_buf[0]=7 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39dc0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c420 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c500 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c740 -[DBG add_file_entry] Count incremented to 72 - [scan] w32/win32memory.py -> 72e2d5ccb7cedcf1 -[DBG add_file_entry] Count=72 entry_addr=0x161e6d39de0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51b10 -[DBG sha1] before malloc(17), sha1=0x161e6d3c440 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3ca80 -[DBG sha1] before strcpy, sha1[0]=0 -[DBG sha1] after strcpy, sha1_buf[0]=0 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39de0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3ca80 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3ca60 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c860 -[DBG add_file_entry] Count incremented to 73 - [scan] w32/win32process.py -> 067c78e9f121dce3 -[DBG add_file_entry] Count=73 entry_addr=0x161e6d39e00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51d80 -[DBG sha1] before malloc(17), sha1=0x161e6d3c5c0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c920 -[DBG sha1] before strcpy, sha1[0]=0 -[DBG sha1] after strcpy, sha1_buf[0]=0 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39e00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c920 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c640 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c440 -[DBG add_file_entry] Count incremented to 74 - [scan] w32/win32sync.py -> 06f53cc594b4ac6c -[DBG add_file_entry] Count=74 entry_addr=0x161e6d39e20 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51bd0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c4c0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c5e0 -[DBG sha1] before strcpy, sha1[0]=6 -[DBG sha1] after strcpy, sha1_buf[0]=6 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39e20 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c5e0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c9a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c520 -[DBG add_file_entry] Count incremented to 75 - [scan] w32/winsock2.py -> 6446627d4f07a1b5 -[DBG add_file_entry] Count=75 entry_addr=0x161e6d39e40 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c519c0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c780 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c9e0 -[DBG sha1] before strcpy, sha1[0]=1 -[DBG sha1] after strcpy, sha1_buf[0]=1 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39e40 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c9e0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3ca40 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c680 -[DBG add_file_entry] Count incremented to 76 - [scan] zlib/pyzlib.py -> 1c46d554b3a3f9f3 -[DBG add_file_entry] Count=76 entry_addr=0x161e6d39e60 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51750 -[DBG sha1] before malloc(17), sha1=0x161e6d3cb00 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c6c0 -[DBG sha1] before strcpy, sha1[0]=8 -[DBG sha1] after strcpy, sha1_buf[0]=8 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39e60 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c6c0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c6a0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c480 -[DBG add_file_entry] Count incremented to 77 - [scan] zlib/zchecksum.py -> 8ebed83a7817fa0c -[DBG add_file_entry] Count=77 entry_addr=0x161e6d39e80 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c516c0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c560 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c4e0 -[DBG sha1] before strcpy, sha1[0]=2 -[DBG sha1] after strcpy, sha1_buf[0]=2 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39e80 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c4e0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c980 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c8a0 -[DBG add_file_entry] Count incremented to 78 - [scan] zlib/zdef.py -> 213348433fb01cc6 -[DBG add_file_entry] Count=78 entry_addr=0x161e6d39ea0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51720 -[DBG sha1] before malloc(17), sha1=0x161e6d3c400 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3caa0 -[DBG sha1] before strcpy, sha1[0]=9 -[DBG sha1] after strcpy, sha1_buf[0]=9 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ea0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3caa0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c800 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c3e0 -[DBG add_file_entry] Count incremented to 79 - [scan] zlib/zdeflate.py -> 90921d009fdd674c -[DBG add_file_entry] Count=79 entry_addr=0x161e6d39ec0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51c60 -[DBG sha1] before malloc(17), sha1=0x161e6d3c8c0 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c540 -[DBG sha1] before strcpy, sha1[0]=d -[DBG sha1] after strcpy, sha1_buf[0]=d -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ec0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c540 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c6e0 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3ca20 -[DBG add_file_entry] Count incremented to 80 - [scan] zlib/zhuff.py -> d541ade6afb689a5 -[DBG add_file_entry] Count=80 entry_addr=0x161e6d39ee0 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c51c00 -[DBG sha1] before malloc(17), sha1=0x161e6d3c600 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c4a0 -[DBG sha1] before strcpy, sha1[0]=4 -[DBG sha1] after strcpy, sha1_buf[0]=4 -[DBG sha1] before store entry.Sha1, entry=0x161e6d39ee0 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c4a0 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3ca00 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3c460 -[DBG add_file_entry] Count incremented to 81 - [scan] zlib/zinflate.py -> 451745df21e598af -[DBG add_file_entry] Count=81 entry_addr=0x161e6d39f00 entry_size=32 -[DBG add_file_entry] Path set, abs_buf=0x161e6c516f0 -[DBG sha1] before malloc(17), sha1=0x161e6d3c820 -[DBG sha1] after malloc(17), sha1_buf=0x161e6d3c600 -[DBG sha1] before strcpy, sha1[0]=d -[DBG sha1] after strcpy, sha1_buf[0]=d -[DBG sha1] before store entry.Sha1, entry=0x161e6d39f00 -[DBG sha1] after store entry.Sha1 -[DBG add_file_entry] Sha1 set, sha1_buf=0x161e6d3c600 -[DBG add_file_entry] RelPath set, rel_buf=0x161e6d3c700 -[DBG add_file_entry] ModuleName set, mod_buf=0x161e6d3cac0 -[DBG add_file_entry] Count incre diff --git a/Test/crash_out.txt b/Test/crash_out.txt deleted file mode 100644 index ab38657..0000000 --- a/Test/crash_out.txt +++ /dev/null @@ -1 +0,0 @@ -[ASM] args loop ai3=2 aval=18371664 diff --git a/Test/crash_out2.txt b/Test/crash_out2.txt deleted file mode 100644 index 2bb7585..0000000 --- a/Test/crash_out2.txt +++ /dev/null @@ -1 +0,0 @@ -DBG MemBuddy.alloc: block=000002428000F828 diff --git a/Test/crash_output.txt b/Test/crash_output.txt deleted file mode 100644 index f393c9c..0000000 --- a/Test/crash_output.txt +++ /dev/null @@ -1 +0,0 @@ -[DBG] diff --git a/Test/dbg_out.txt b/Test/dbg_out.txt deleted file mode 100644 index f91921a..0000000 --- a/Test/dbg_out.txt +++ /dev/null @@ -1 +0,0 @@ -[L] ai3=2 aval=-2129095600 检查Ty diff --git a/Test/project.vpj b/Test/project.vpj index dd18769..7dfbe2c 100644 --- a/Test/project.vpj +++ b/Test/project.vpj @@ -3,8 +3,7 @@ "name": "AstTest", "version": "1.0.0", "source_dir": "./App", - "temp_dir": "./temp", - "output_dir": "./output", + "build_dir": "./.tpv_build", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-relocation-model=pic"] @@ -23,6 +22,7 @@ }, "options": { "slice_level": 3, + "sha1_slice_level": 3, "target": "llvm", "strict_mode": true } diff --git a/project.json b/project.json index 7fe93e3..fe2a67f 100644 --- a/project.json +++ b/project.json @@ -3,8 +3,7 @@ "name": "TransPyV", "version": "1.0.0", "source_dir": "./App", - "temp_dir": "./temp", - "output_dir": "./output", + "build_dir": "./.tpv_build", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-relocation-model=pic"] @@ -22,7 +21,8 @@ "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" }, "options": { - "slice_level": 3, + "slice_level": 3, + "sha1_slice_level": 3, "target": "llvm", "strict_mode": true }