修复了大量存在的问题,增加了假鸭子类型等等机制
This commit is contained in:
@@ -2,12 +2,19 @@ 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, CTypeInfo, FuncMeta
|
||||
from lib.includes import t
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
import hashlib
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule, ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName
|
||||
|
||||
|
||||
class ImportHandle(BaseHandle):
|
||||
@@ -18,13 +25,21 @@ class ImportHandle(BaseHandle):
|
||||
_pyi_cache_dir = None
|
||||
_project_root_cache = None
|
||||
|
||||
def _reset_file_cache(self):
|
||||
def _reset_file_cache(self) -> None:
|
||||
self._struct_Load_cache.clear()
|
||||
|
||||
def _find_project_root(self):
|
||||
def _find_project_root(self) -> str:
|
||||
if self._project_root_cache is not None:
|
||||
return self._project_root_cache
|
||||
import os
|
||||
# 优先使用 translator 上显式设置的 _temp_dir(由 Phase2Translator._translate_file 传入),
|
||||
# 这样可以正确处理 include 文件——其源文件目录不在项目根目录下,
|
||||
# 从源文件目录向上搜索 temp/output 会失败并回退到错误的路径。
|
||||
temp_dir_attr = getattr(self.Trans, '_temp_dir', None)
|
||||
if temp_dir_attr and os.path.isdir(temp_dir_attr):
|
||||
project_root = os.path.dirname(os.path.abspath(temp_dir_attr))
|
||||
if os.path.isdir(os.path.join(project_root, 'temp')) and os.path.isdir(os.path.join(project_root, 'output')):
|
||||
self._project_root_cache = project_root
|
||||
return project_root
|
||||
current_file = getattr(self.Trans, 'CurrentFile', '') or ''
|
||||
if current_file:
|
||||
current_dir = os.path.dirname(os.path.abspath(current_file))
|
||||
@@ -37,17 +52,29 @@ class ImportHandle(BaseHandle):
|
||||
if parent == search_dir:
|
||||
break
|
||||
search_dir = parent
|
||||
# 回退到当前工作目录(编译运行时的项目根目录)
|
||||
cwd = os.getcwd()
|
||||
if os.path.isdir(os.path.join(cwd, 'temp')) and os.path.isdir(os.path.join(cwd, 'output')):
|
||||
self._project_root_cache = cwd
|
||||
return cwd
|
||||
if current_file:
|
||||
self._project_root_cache = current_dir
|
||||
return current_dir
|
||||
self._project_root_cache = os.getcwd()
|
||||
return os.getcwd()
|
||||
self._project_root_cache = cwd
|
||||
return cwd
|
||||
|
||||
def _EmitImportDeclarationsLlvm(self, Node, Gen):
|
||||
def _EmitImportDeclarationsLlvm(self, Node: ast.Import, Gen: LlvmGeneratorMixin) -> None:
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
for alias in Node.names:
|
||||
name = alias.name
|
||||
if name in ('c', 't'):
|
||||
if alias.asname:
|
||||
self.Trans.SymbolTable.import_aliases[alias.asname] = name
|
||||
AliasInfo = CTypeInfo()
|
||||
AliasInfo.IsModuleAlias = True
|
||||
AliasInfo.ResolvedModule = name
|
||||
self.Trans.SymbolTable.insert(alias.asname, AliasInfo)
|
||||
continue
|
||||
self.Trans._ImportedModules.add(name)
|
||||
if alias.asname:
|
||||
@@ -60,7 +87,7 @@ class ImportHandle(BaseHandle):
|
||||
current_module = self._get_current_module_name()
|
||||
self._EmitModuleDeclarationsLlvm(name, Gen, register_module_name=current_module)
|
||||
|
||||
def _RegisterFromImportAliases(self, Node, Gen, module):
|
||||
def _RegisterFromImportAliases(self, Node: ast.ImportFrom, Gen: LlvmGeneratorMixin, module: str) -> None:
|
||||
"""Register 'from module import y as z' aliases after module declarations are Loaded"""
|
||||
if not Node.names:
|
||||
return
|
||||
@@ -92,8 +119,9 @@ class ImportHandle(BaseHandle):
|
||||
Gen.functions[asname] = Gen.functions[name]
|
||||
if name in Gen.structs:
|
||||
Gen.structs[asname] = Gen.structs[name]
|
||||
if self.Trans.SymbolTable.has(name):
|
||||
self.Trans.SymbolTable.insert(asname, self.Trans.SymbolTable[name])
|
||||
info = self.Trans.SymbolTable.lookup(name)
|
||||
if info:
|
||||
self.Trans.SymbolTable.insert(asname, info)
|
||||
if name in Gen.variables:
|
||||
Gen.variables[asname] = Gen.variables[name]
|
||||
if name in Gen.global_vars:
|
||||
@@ -120,7 +148,7 @@ class ImportHandle(BaseHandle):
|
||||
if name in struct_sha1_map:
|
||||
struct_sha1_map[asname] = struct_sha1_map[name]
|
||||
|
||||
def _EmitImportFromDeclarationsLlvm(self, Node, Gen):
|
||||
def _EmitImportFromDeclarationsLlvm(self, Node: ast.ImportFrom, Gen: LlvmGeneratorMixin) -> None:
|
||||
module = Node.module if Node.module else ''
|
||||
if module in ('c', 't'):
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
@@ -128,10 +156,17 @@ class ImportHandle(BaseHandle):
|
||||
self.Trans._ImportedModules.add(module)
|
||||
if not hasattr(self.Trans, '_t_c_imported_names'):
|
||||
self.Trans._t_c_imported_names = {}
|
||||
# 注册 t/c 类型别名到 _t_type_symbols(CType 子类)
|
||||
t_type_syms = self.Trans.SymbolTable._t_type_symbols
|
||||
for alias in Node.names:
|
||||
name = alias.name
|
||||
asname = alias.asname or name
|
||||
self.Trans._t_c_imported_names[asname] = (module, name)
|
||||
# 仅注册 CType 子类(CEnum/CUnion/CStruct/REnum 等)
|
||||
if module == 't':
|
||||
cls = getattr(t, name, None)
|
||||
if isinstance(cls, type) and issubclass(cls, t.CType):
|
||||
t_type_syms[asname] = cls
|
||||
return
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -207,7 +242,7 @@ class ImportHandle(BaseHandle):
|
||||
self._EmitModuleDeclarationsLlvm(module, Gen, register_module_name=current_module)
|
||||
self._RegisterFromImportAliases(Node, Gen, module)
|
||||
|
||||
def _LoadModuleDeclarationsFromFile(self, pyi_path, Gen, module_name=None, register_module_name=None, actual_module_name=None, reexport_package=None):
|
||||
def _LoadModuleDeclarationsFromFile(self, pyi_path: str, Gen: LlvmGeneratorMixin, module_name: str | None = None, register_module_name: str | None = None, actual_module_name: str | None = None, reexport_package: str | None = None) -> None:
|
||||
if not pyi_path or not os.path.isfile(pyi_path):
|
||||
return
|
||||
try:
|
||||
@@ -323,16 +358,16 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
|
||||
except Exception as _e:
|
||||
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
|
||||
def _get_current_module_name(self):
|
||||
def _get_current_module_name(self) -> str | None:
|
||||
current_file = getattr(self.Trans, 'CurrentFile', '') or ''
|
||||
if current_file:
|
||||
return os.path.splitext(os.path.basename(current_file))[0]
|
||||
return None
|
||||
|
||||
def _RegisterSubModuleSha1(self, candidate_path, actual_module, short_module, Gen):
|
||||
def _RegisterSubModuleSha1(self, candidate_path: str, actual_module: str, short_module: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""Register a submodule's SHA1 in ModuleSha1Map so cross-module class references work"""
|
||||
try:
|
||||
with open(candidate_path, 'r', encoding='utf-8') as f:
|
||||
@@ -343,13 +378,11 @@ class ImportHandle(BaseHandle):
|
||||
if short_module and short_module not in Gen.ModuleSha1Map:
|
||||
Gen.ModuleSha1Map[short_module] = sub_sha1
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
|
||||
def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name):
|
||||
def _LoadPackageInitForRelativeImport(self, mod_dir: str, Gen: LlvmGeneratorMixin, register_module_name: str | None) -> str:
|
||||
"""Load __init__.py from the package directory for 'from . import name' resolution.
|
||||
This makes package-level names (functions, classes, constants) available.
|
||||
Returns the package name."""
|
||||
@@ -383,14 +416,13 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
return pkg_name
|
||||
|
||||
def _EmitModuleDeclarationsLlvm(self, module_name, Gen, register_module_name=None):
|
||||
def _EmitModuleDeclarationsLlvm(self, module_name: str, Gen: LlvmGeneratorMixin, register_module_name: str | None = None) -> None:
|
||||
if module_name in ('pyzlib',):
|
||||
source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
|
||||
ModulePath = module_name.replace('.', os.sep) + '.pyi'
|
||||
PackageInitPath = module_name.replace('.', os.sep) + os.sep + '__init__.pyi'
|
||||
ProjectRoot = os.path.dirname(os.path.abspath(getattr(self.Trans, 'CurrentFile', '') or '')) or os.getcwd()
|
||||
|
||||
import inspect
|
||||
|
||||
HandlesFile = os.path.abspath(inspect.getfile(self.__class__))
|
||||
TransPyCRoot = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(HandlesFile))))
|
||||
|
||||
@@ -592,6 +624,7 @@ class ImportHandle(BaseHandle):
|
||||
if module_name == 'pyzlib':
|
||||
node_type = type(node).__name__
|
||||
name = getattr(node, 'name', getattr(node, 'attr', '?'))
|
||||
_vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
|
||||
continue
|
||||
if not has_functions_or_classes and module_name:
|
||||
self._LoadDeclarationsFromStubLlvm(module_name, Gen)
|
||||
@@ -601,7 +634,7 @@ class ImportHandle(BaseHandle):
|
||||
if module_name:
|
||||
self._LoadDeclarationsFromStubLlvm(module_name, Gen)
|
||||
|
||||
def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, ModulePath=None):
|
||||
def _EmitExternalGlobalDeclLlvm(self, Node: ast.AnnAssign | ast.Assign, Gen: LlvmGeneratorMixin, module_name: str | None = None, ModulePath: str | None = None) -> None:
|
||||
"""Emit external global variable declaration from imported module"""
|
||||
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name):
|
||||
VarName = Node.target.id
|
||||
@@ -609,66 +642,29 @@ class ImportHandle(BaseHandle):
|
||||
var_type = ir.IntType(32)
|
||||
IsPtr = False
|
||||
is_string_val = False
|
||||
TypeInfo = None
|
||||
if VarName in Gen.module.globals:
|
||||
existing = Gen.module.globals[VarName]
|
||||
if isinstance(existing, ir.GlobalVariable):
|
||||
old_pointee = existing.type.pointee if isinstance(existing.type, ir.PointerType) else None
|
||||
if isinstance(old_pointee, ir.IdentifiedStructType):
|
||||
if old_pointee.elements is not None and len(old_pointee.elements) > 0:
|
||||
return
|
||||
elif isinstance(old_pointee, ir.ArrayType):
|
||||
return
|
||||
return
|
||||
if Node.annotation:
|
||||
if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list':
|
||||
slice_node = Node.annotation.slice
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
|
||||
elem_type_node = slice_node.elts[0]
|
||||
count_node = slice_node.elts[1]
|
||||
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
|
||||
if ElemTypeInfo:
|
||||
elem_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
if isinstance(elem_type, ir.VoidType):
|
||||
elem_type = ir.IntType(8)
|
||||
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
|
||||
var_type = ir.ArrayType(elem_type, count_node.value)
|
||||
elif isinstance(count_node, ast.Constant) and count_node.value is None:
|
||||
var_type = ir.ArrayType(elem_type, 0)
|
||||
else:
|
||||
var_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
IsPtr = False
|
||||
else:
|
||||
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
|
||||
if TypeInfo:
|
||||
var_type = Gen._ctype_to_llvm(TypeInfo)
|
||||
IsPtr = TypeInfo.IsPtr
|
||||
elif isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||||
list_node = None
|
||||
for side in (Node.annotation.left, Node.annotation.right):
|
||||
if isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list':
|
||||
list_node = side
|
||||
break
|
||||
if list_node:
|
||||
slice_node = list_node.slice
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
|
||||
elem_type_node = slice_node.elts[0]
|
||||
count_node = slice_node.elts[1]
|
||||
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
|
||||
if ElemTypeInfo:
|
||||
elem_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
if isinstance(elem_type, ir.VoidType):
|
||||
elem_type = ir.IntType(8)
|
||||
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
|
||||
var_type = ir.ArrayType(elem_type, count_node.value)
|
||||
elif isinstance(count_node, ast.Constant) and count_node.value is None:
|
||||
var_type = ir.ArrayType(elem_type, 0)
|
||||
else:
|
||||
var_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
IsPtr = False
|
||||
else:
|
||||
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
|
||||
if TypeInfo:
|
||||
var_type = Gen._ctype_to_llvm(TypeInfo)
|
||||
IsPtr = TypeInfo.IsPtr
|
||||
parse_result = ParseListAnnotation(Node.annotation)
|
||||
if parse_result and not parse_result.is_pointer:
|
||||
# list[type, count] 数组声明
|
||||
elem_type_node = parse_result.elem_type_node
|
||||
count_node = parse_result.count_node
|
||||
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
|
||||
if ElemTypeInfo:
|
||||
elem_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
if isinstance(elem_type, ir.VoidType):
|
||||
elem_type = ir.IntType(8)
|
||||
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
|
||||
var_type = ir.ArrayType(elem_type, count_node.value)
|
||||
elif isinstance(count_node, ast.Constant) and count_node.value is None:
|
||||
var_type = ir.ArrayType(elem_type, 0)
|
||||
else:
|
||||
var_type = Gen._ctype_to_llvm(ElemTypeInfo)
|
||||
IsPtr = False
|
||||
else:
|
||||
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
|
||||
if TypeInfo:
|
||||
@@ -710,6 +706,10 @@ class ImportHandle(BaseHandle):
|
||||
IsCTypedef = True
|
||||
|
||||
if IsCTypedef:
|
||||
# 检查符号是否已存在且已正确解析(OriginalType 已设置),避免覆盖
|
||||
existing_sym = self.Trans.SymbolTable.lookup(VarName) if hasattr(self.Trans.SymbolTable, 'lookup') else None
|
||||
if existing_sym and isinstance(existing_sym, CTypeInfo) and existing_sym.IsTypedef and existing_sym.OriginalType:
|
||||
return
|
||||
if Node.value:
|
||||
ValueTypeInfo = None
|
||||
if isinstance(Node.value, ast.BinOp) and isinstance(Node.value.op, ast.BitOr):
|
||||
@@ -757,16 +757,8 @@ class ImportHandle(BaseHandle):
|
||||
return
|
||||
|
||||
gv = ir.GlobalVariable(Gen.module, var_type, name=VarName)
|
||||
|
||||
if Node.value:
|
||||
InitVal = self._ExtractValue(Node.value, var_type, VarName)
|
||||
if InitVal is not None:
|
||||
gv.initializer = InitVal
|
||||
gv.linkage = 'available_externally'
|
||||
else:
|
||||
gv.linkage = 'external'
|
||||
else:
|
||||
gv.linkage = 'external'
|
||||
# 外部全局变量声明:只声明不定义(external linkage),避免多重定义
|
||||
gv.linkage = 'external'
|
||||
elif isinstance(node, ast.Assign) and Node.targets and isinstance(Node.targets[0], ast.Name):
|
||||
VarName = Node.targets[0].id
|
||||
if VarName.startswith('_'):
|
||||
@@ -774,17 +766,9 @@ class ImportHandle(BaseHandle):
|
||||
if VarName in Gen.module.globals:
|
||||
return
|
||||
gv = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName)
|
||||
if Node.value and ModulePath:
|
||||
InitVal = self._ExtractValue(Node.value, ir.IntType(32), VarName)
|
||||
if InitVal is not None:
|
||||
gv.initializer = InitVal
|
||||
gv.linkage = 'available_externally'
|
||||
else:
|
||||
gv.linkage = 'external'
|
||||
else:
|
||||
gv.linkage = 'external'
|
||||
gv.linkage = 'external'
|
||||
|
||||
def _ExtractValue(self, value_node, target_type, var_name=None):
|
||||
def _ExtractValue(self, value_node: ast.AST, target_type: ir.Type, var_name: str | None = None) -> ir.Constant | None:
|
||||
"""Extract constant value from AST node for global variable initializer"""
|
||||
# 处理负号
|
||||
if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub):
|
||||
@@ -837,12 +821,10 @@ class ImportHandle(BaseHandle):
|
||||
return ir.Constant(target_type, 0)
|
||||
return None
|
||||
|
||||
def _ExtractConstValue(self, value_node):
|
||||
def _ExtractConstValue(self, value_node: ast.AST) -> object:
|
||||
"""Extract constant value from AST node for SymbolTable registration
|
||||
支持常量、一元运算符、二元运算符和常量引用
|
||||
"""
|
||||
import ast
|
||||
|
||||
if isinstance(value_node, ast.Constant):
|
||||
return value_node.value
|
||||
elif isinstance(value_node, ast.BinOp):
|
||||
@@ -899,9 +881,7 @@ class ImportHandle(BaseHandle):
|
||||
return self._ExtractConstValue(value_node.args[0])
|
||||
return None
|
||||
|
||||
def _ExtractTypedefOriginalType(self, value_node):
|
||||
import ast
|
||||
from lib.includes.t import CTypeRegistry
|
||||
def _ExtractTypedefOriginalType(self, value_node: ast.AST) -> str | None:
|
||||
if isinstance(value_node, ast.Attribute):
|
||||
if getattr(value_node.value, 'id', None) == 't':
|
||||
llvm_str = CTypeRegistry.NameToLLVM(value_node.attr)
|
||||
@@ -933,9 +913,8 @@ class ImportHandle(BaseHandle):
|
||||
return llvm_str
|
||||
return None
|
||||
|
||||
def _RegisterCDefineSymbol(self, FullName, DefineValue, lineno, FilePath):
|
||||
def _RegisterCDefineSymbol(self, FullName: str, DefineValue: object, lineno: int, FilePath: str) -> None:
|
||||
"""Register CDefine constant to SymbolTable"""
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
info = CTypeInfo()
|
||||
info.IsDefine = True
|
||||
info.DefineValue = DefineValue
|
||||
@@ -944,20 +923,12 @@ class ImportHandle(BaseHandle):
|
||||
# 直接添加到 SymbolTable 字典
|
||||
self.Trans.SymbolTable.insert(FullName, info)
|
||||
|
||||
def _check_annotation_for_state(self, annotation) -> bool:
|
||||
import ast
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'):
|
||||
return True
|
||||
if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State':
|
||||
return True
|
||||
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right)
|
||||
elif isinstance(annotation, ast.Name):
|
||||
return annotation.id in ('CExport', 'CExtern', 'State')
|
||||
return False
|
||||
def _check_annotation_for_state(self, annotation: ast.AST) -> bool:
|
||||
return (AnnotationContainsName(annotation, 'CExport') or
|
||||
AnnotationContainsName(annotation, 'CExtern') or
|
||||
AnnotationContainsName(annotation, 'State'))
|
||||
|
||||
def _EmitExternalFuncDeclLlvm(self, Node, Gen, is_class_method=False, source_module_name=None, register_module_name=None, reexport_module_names=None):
|
||||
def _EmitExternalFuncDeclLlvm(self, Node: ast.FunctionDef, Gen: LlvmGeneratorMixin, is_class_method: bool = False, source_module_name: str | None = None, register_module_name: str | None = None, reexport_module_names: list[str] | None = None) -> None:
|
||||
FuncName = Node.name
|
||||
if Node.returns and self._check_annotation_for_state(Node.returns):
|
||||
Gen._export_funcs.add(FuncName) # t.State 标记的外部 C 函数必须保持原始名称,以便链接器解析
|
||||
@@ -974,12 +945,7 @@ class ImportHandle(BaseHandle):
|
||||
ReturnTypeInfo = None
|
||||
if Node.returns:
|
||||
try:
|
||||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||||
ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
|
||||
if not isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||||
else:
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsStr:
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = t.CChar()
|
||||
@@ -988,7 +954,8 @@ class ImportHandle(BaseHandle):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = t.CInt()
|
||||
IsPtr = ReturnTypeInfo.IsPtr
|
||||
except Exception: # 回退:返回类型解析失败时使用默认 CInt
|
||||
except Exception as e: # 回退:返回类型解析失败时使用默认 CInt
|
||||
_vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = t.CInt()
|
||||
else:
|
||||
@@ -1021,12 +988,7 @@ class ImportHandle(BaseHandle):
|
||||
ParamType = ir.PointerType(Gen.structs.get(class_name_for_method or FuncName.split('.')[0], ir.IntType(8)))
|
||||
elif Arg.annotation:
|
||||
try:
|
||||
if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||||
ParamTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation)
|
||||
if ParamTypeInfo is None or not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||||
else:
|
||||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||||
ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
|
||||
if ParamTypeInfo is None:
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
ParamTypeInfo.BaseType = t.CInt()
|
||||
@@ -1039,8 +1001,13 @@ class ImportHandle(BaseHandle):
|
||||
ParamTypeInfo.BaseType = t.CChar()
|
||||
ParamTypeInfo.PtrCount = 1
|
||||
ParamIsPtr = True
|
||||
# C 语言中数组参数退化为指针:list[type, N] → type*
|
||||
if ParamTypeInfo.ArrayDims:
|
||||
ParamTypeInfo.ArrayDims = []
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||||
except Exception: # 回退:参数类型解析失败时使用默认 i32
|
||||
except Exception as e: # 回退:参数类型解析失败时使用默认 i32
|
||||
_vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
|
||||
ParamType = ir.IntType(32)
|
||||
if isinstance(ParamType, ir.VoidType) or (isinstance(ParamType, ir.PointerType) and isinstance(ParamType.pointee, ir.VoidType)):
|
||||
AnnName = None
|
||||
@@ -1049,11 +1016,7 @@ class ImportHandle(BaseHandle):
|
||||
elif isinstance(Arg.annotation, ast.Attribute):
|
||||
AnnName = Arg.annotation.attr
|
||||
elif isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||||
left = Arg.annotation.left
|
||||
if isinstance(left, ast.Name):
|
||||
AnnName = left.id
|
||||
elif isinstance(left, ast.Attribute):
|
||||
AnnName = left.attr
|
||||
AnnName = ExtractTypeNameFromBinOp(Arg.annotation)
|
||||
if AnnName and AnnName in Gen.structs:
|
||||
ParamType = ir.PointerType(Gen.structs[AnnName])
|
||||
else:
|
||||
@@ -1123,8 +1086,8 @@ class ImportHandle(BaseHandle):
|
||||
# property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList
|
||||
if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
|
||||
BasePropKey = FuncName.replace('$set', '').replace('$del', '')
|
||||
if self.Trans.SymbolTable.has(BasePropKey):
|
||||
base_existing = self.Trans.SymbolTable[BasePropKey]
|
||||
base_existing = self.Trans.SymbolTable.lookup(BasePropKey)
|
||||
if base_existing:
|
||||
if func_meta != FuncMeta.NONE:
|
||||
base_existing.MetaList = base_existing.MetaList | func_meta
|
||||
else:
|
||||
@@ -1143,7 +1106,7 @@ class ImportHandle(BaseHandle):
|
||||
if ReexportName2 not in Gen.functions:
|
||||
Gen.functions[ReexportName2] = func
|
||||
|
||||
def _EmitExternalClassDeclLlvm(self, Node, Gen, module_name=None, actual_module_name=None):
|
||||
def _EmitExternalClassDeclLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, module_name: str | None = None, actual_module_name: str | None = None) -> None:
|
||||
ClassName = Node.name
|
||||
if hasattr(Node, 'type_params') and Node.type_params:
|
||||
return
|
||||
@@ -1180,7 +1143,7 @@ class ImportHandle(BaseHandle):
|
||||
IsCpythonObject = True
|
||||
elif decorator.func.id == 'CVTable':
|
||||
IsCVTable = True
|
||||
if ClassName.startswith('_') and not IsCpythonObject and not IsCenum:
|
||||
if ClassName.startswith('__') and not IsCpythonObject and not IsCenum:
|
||||
return
|
||||
IsPacked = False
|
||||
if getattr(Node, 'decorator_list', None):
|
||||
@@ -1260,23 +1223,46 @@ class ImportHandle(BaseHandle):
|
||||
if ClassName not in Gen.class_member_bitoffsets:
|
||||
Gen.class_member_bitoffsets[ClassName] = {}
|
||||
has_methods = False
|
||||
# 解析 __provides__/__requires__/__require_must__ 编译期元数据(跨模块加载)
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
VarName = item.target.id
|
||||
try:
|
||||
TypeInfo = CTypeInfo.FromNode(item.annotation, self.Trans.SymbolTable)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
MemberType = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(MemberType, ir.VoidType):
|
||||
MemberType = ir.PointerType(ir.IntType(8))
|
||||
if TypeInfo and TypeInfo.IsBitField:
|
||||
field_name: str = item.target.id
|
||||
if field_name in ('__provides__', '__requires__', '__require_must__') and item.value:
|
||||
values: list[str] = []
|
||||
if isinstance(item.value, ast.List):
|
||||
for elt in item.value.elts:
|
||||
if isinstance(elt, ast.Constant) and isinstance(elt.value, str):
|
||||
values.append(elt.value)
|
||||
if field_name == '__provides__':
|
||||
Gen.class_provides[ClassName] = values
|
||||
elif field_name == '__requires__':
|
||||
Gen.class_requires[ClassName] = values
|
||||
elif field_name == '__require_must__':
|
||||
Gen.class_require_must[ClassName] = values
|
||||
_existing_member_names = {m[0] for m in Gen.class_members[ClassName]}
|
||||
for item in Node.body:
|
||||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||||
continue
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
if TypeInfo is None:
|
||||
if VarName not in _existing_member_names:
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
_existing_member_names.add(VarName)
|
||||
Gen.class_member_signeds[ClassName][VarName] = None
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
else:
|
||||
if TypeInfo.IsBitField:
|
||||
Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth
|
||||
else:
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
if VarName not in _existing_member_names:
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
_existing_member_names.add(VarName)
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
if TypeInfo and TypeInfo.ByteOrder:
|
||||
if TypeInfo.ByteOrder:
|
||||
Gen.class_member_byteorders[ClassName][VarName] = TypeInfo.ByteOrder
|
||||
else:
|
||||
Gen.class_member_byteorders[ClassName][VarName] = ""
|
||||
@@ -1284,10 +1270,6 @@ class ImportHandle(BaseHandle):
|
||||
const = self._BuildScalarConstant(item.value, MemberType, Gen)
|
||||
if const:
|
||||
Gen.class_member_defaults[ClassName][VarName] = const
|
||||
except Exception: # 回退:类成员类型解析失败时使用默认 i32
|
||||
Gen.class_members[ClassName].append((VarName, ir.IntType(32)))
|
||||
Gen.class_member_signeds[ClassName][VarName] = None
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
elif isinstance(item, ast.FunctionDef):
|
||||
has_methods = True
|
||||
MethodName = item.name
|
||||
@@ -1340,8 +1322,8 @@ class ImportHandle(BaseHandle):
|
||||
existing.MetaList = func_meta
|
||||
# setter/deleter: 同时在原始 PropKey(不带后缀)下注册 MetaList
|
||||
if is_item_prop_setter or is_item_prop_deleter:
|
||||
if self.Trans.SymbolTable.has(FuncFullName):
|
||||
base_existing = self.Trans.SymbolTable[FuncFullName]
|
||||
base_existing = self.Trans.SymbolTable.lookup(FuncFullName)
|
||||
if base_existing:
|
||||
if func_meta != FuncMeta.NONE:
|
||||
base_existing.MetaList = base_existing.MetaList | func_meta
|
||||
else:
|
||||
@@ -1374,18 +1356,22 @@ class ImportHandle(BaseHandle):
|
||||
Gen.class_member_bitoffsets[ClassName][name] = current_bit_offset
|
||||
current_bit_offset += bw
|
||||
|
||||
def _TryLoadStructFromStub(self, class_name: str, Gen):
|
||||
cache_key = class_name
|
||||
def _TryLoadStructFromStub(self, class_name: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
# 缓存键包含 Gen 实例标识,确保每个模块的 Gen 都能独立加载 struct 定义,
|
||||
# 同时仍能防止同一 Gen 内的递归重入。原先使用纯 class_name 作为键会导致
|
||||
# 跨模块 struct 类型对象无法分别 set_body(每个模块有独立的 self.structs)。
|
||||
cache_key = (id(Gen), class_name)
|
||||
if cache_key in self._struct_Load_cache:
|
||||
return
|
||||
# 先设置缓存防止递归重入,但如果加载失败则清除缓存允许后续重试
|
||||
self._struct_Load_cache[cache_key] = True
|
||||
|
||||
import os, re
|
||||
|
||||
ProjectRoot = self._find_project_root()
|
||||
temp_dir = os.path.join(ProjectRoot, 'temp')
|
||||
if not os.path.isdir(temp_dir):
|
||||
del self._struct_Load_cache[cache_key]
|
||||
return
|
||||
|
||||
|
||||
if self._stub_cache_dir != temp_dir:
|
||||
self._stub_cache.clear()
|
||||
self._stub_cache_dir = temp_dir
|
||||
@@ -1408,15 +1394,14 @@ class ImportHandle(BaseHandle):
|
||||
if '.' in full_name:
|
||||
self._stub_cache.setdefault(full_name, []).append((full_name, struct_body, source_sha1))
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
|
||||
if class_name not in self._stub_cache:
|
||||
del self._struct_Load_cache[cache_key]
|
||||
return
|
||||
|
||||
|
||||
for full_name, struct_body, source_sha1 in self._stub_cache[class_name]:
|
||||
is_packed = struct_body.startswith('<{') and struct_body.endswith('}>')
|
||||
if struct_body and struct_body != 'opaque':
|
||||
@@ -1438,8 +1423,6 @@ class ImportHandle(BaseHandle):
|
||||
if is_packed:
|
||||
Gen.class_packed.add(class_name)
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
@@ -1447,8 +1430,7 @@ class ImportHandle(BaseHandle):
|
||||
self._TryLoadClassMembersFromPyi(class_name, stub_filename, Gen)
|
||||
return
|
||||
|
||||
def _TryLoadClassMembersFromPyi(self, class_name: str, stub_filename: str, Gen):
|
||||
import os
|
||||
def _TryLoadClassMembersFromPyi(self, class_name: str, stub_filename: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
ProjectRoot = self._find_project_root()
|
||||
temp_dir = os.path.join(ProjectRoot, 'temp')
|
||||
if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0:
|
||||
@@ -1467,7 +1449,8 @@ class ImportHandle(BaseHandle):
|
||||
try:
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
self._pyi_cache[pyi_path] = ast.parse(f.read())
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
_vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
|
||||
self._pyi_cache[pyi_path] = None
|
||||
return
|
||||
|
||||
@@ -1500,40 +1483,13 @@ class ImportHandle(BaseHandle):
|
||||
return
|
||||
return
|
||||
|
||||
def _BuildScalarConstant(self, value_node, target_type, Gen):
|
||||
"""Build a scalar constant value from AST node"""
|
||||
if isinstance(target_type, ir.BaseStructType):
|
||||
return None
|
||||
if isinstance(value_node, ast.Constant):
|
||||
if isinstance(value_node.value, int):
|
||||
return ir.Constant(target_type, value_node.value)
|
||||
elif isinstance(value_node.value, str):
|
||||
str_val = value_node.value + '\x00'
|
||||
str_bytes = str_val.encode('utf-8')
|
||||
arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
|
||||
gv_name = f"str_const_{id(value_node)}"
|
||||
gv = ir.GlobalVariable(Gen.module, arr_type, name=gv_name)
|
||||
gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
|
||||
gv.linkage = 'internal'
|
||||
ptr_type = ir.PointerType(ir.IntType(8))
|
||||
return ir.Constant(ptr_type, gv.reference)
|
||||
elif isinstance(value_node.value, bool):
|
||||
return ir.Constant(target_type, 1 if value_node.value else 0)
|
||||
elif isinstance(value_node, ast.Name):
|
||||
if value_node.id == 'True':
|
||||
return ir.Constant(target_type, 1)
|
||||
elif value_node.id == 'False':
|
||||
if isinstance(target_type, ir.PointerType):
|
||||
return ir.Constant(target_type, None)
|
||||
return ir.Constant(target_type, 0)
|
||||
return None
|
||||
def _BuildScalarConstant(self, value_node: ast.AST, target_type: ir.Type, Gen: LlvmGeneratorMixin) -> ir.Constant | None:
|
||||
"""Build a scalar constant value from AST node, delegated to unified method."""
|
||||
return self.Trans._BuildScalarConstantUnified(value_node, target_type, Gen)
|
||||
|
||||
def _LookupStubFuncType(self, func_name, Gen):
|
||||
def _LookupStubFuncType(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
|
||||
"""从 stub.ll 文件中查找指定函数的 LLVM 类型"""
|
||||
import os
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
if not getattr(self, '_stub_func_cache', None):
|
||||
self._stub_func_cache = {}
|
||||
|
||||
@@ -1571,8 +1527,6 @@ class ImportHandle(BaseHandle):
|
||||
stub_params = match.group(3).strip()
|
||||
self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1)
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
@@ -1613,17 +1567,15 @@ class ImportHandle(BaseHandle):
|
||||
param_types.append(ir.PointerType(ir.IntType(8)))
|
||||
return ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||||
|
||||
def _strip_llvm_param_name(self, param_str):
|
||||
def _strip_llvm_param_name(self, param_str: str) -> str:
|
||||
"""剥离 LLVM IR 参数字符串中的参数名,仅保留类型部分"""
|
||||
import re
|
||||
param_str = param_str.strip()
|
||||
result = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
|
||||
return result.strip()
|
||||
|
||||
def _parse_simple_llvm_type(self, type_str):
|
||||
def _parse_simple_llvm_type(self, type_str: str) -> ir.Type | None:
|
||||
"""解析简单的 LLVM 类型字符串(不创建结构体,避免副作用)"""
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
type_str = type_str.strip()
|
||||
|
||||
type_map = {
|
||||
@@ -1648,7 +1600,6 @@ class ImportHandle(BaseHandle):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
|
||||
if type_str.startswith('[') and ']' in type_str:
|
||||
import re
|
||||
arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
|
||||
if arr_match:
|
||||
size = int(arr_match.group(1))
|
||||
@@ -1661,20 +1612,17 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
return None
|
||||
|
||||
def _LoadDeclarationsFromStubLlvm(self, module_name: str, Gen):
|
||||
def _LoadDeclarationsFromStubLlvm(self, module_name: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""从 stub.ll 文件加载函数声明和结构体定义到 Gen"""
|
||||
import os
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
ProjectRoot = self._find_project_root()
|
||||
temp_dir = os.path.join(ProjectRoot, 'temp')
|
||||
|
||||
|
||||
if not os.path.isdir(temp_dir):
|
||||
return
|
||||
|
||||
|
||||
all_stub_files = [f for f in os.listdir(temp_dir) if f.endswith('.stub.ll')]
|
||||
|
||||
|
||||
source_sig_files = getattr(self.Trans, '_source_module_sig_files', {})
|
||||
target_sha1 = None
|
||||
if module_name:
|
||||
@@ -1685,7 +1633,7 @@ class ImportHandle(BaseHandle):
|
||||
if not target_sha1:
|
||||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||||
target_sha1 = ModuleSha1Map.get(module_name)
|
||||
|
||||
|
||||
if target_sha1:
|
||||
target_stub = f"{target_sha1}.stub.ll"
|
||||
if target_stub in all_stub_files:
|
||||
@@ -1694,7 +1642,7 @@ class ImportHandle(BaseHandle):
|
||||
stub_files = []
|
||||
else:
|
||||
stub_files = []
|
||||
|
||||
|
||||
needed_sha1s = set()
|
||||
for filename in stub_files:
|
||||
stub_path = os.path.join(temp_dir, filename)
|
||||
@@ -1710,8 +1658,6 @@ class ImportHandle(BaseHandle):
|
||||
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
|
||||
needed_sha1s.add(m.group(1))
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
@@ -1721,9 +1667,9 @@ class ImportHandle(BaseHandle):
|
||||
dep_stub = f"{sha1}.stub.ll"
|
||||
if dep_stub in all_stub_files and dep_stub not in stub_files:
|
||||
preLoad_files.append(dep_stub)
|
||||
|
||||
|
||||
Load_order = preLoad_files + stub_files
|
||||
|
||||
|
||||
for filename in Load_order:
|
||||
stub_path = os.path.join(temp_dir, filename)
|
||||
source_sha1 = filename.replace('.stub.ll', '')
|
||||
@@ -1761,12 +1707,10 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
elem_types.append(ir.IntType(32))
|
||||
st = Gen._get_or_create_struct(clean_name, source_sha1=source_sha1, packed=is_packed)
|
||||
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
|
||||
if isinstance(st, ir.IdentifiedStructType) and st.elements is None:
|
||||
try:
|
||||
st.set_body(*elem_types)
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
@@ -1806,24 +1750,93 @@ class ImportHandle(BaseHandle):
|
||||
short_name = func_name.split('.', 1)[1]
|
||||
Gen.functions[short_name] = func
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
except Exception as _e:
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
|
||||
def _parse_llvm_declare(self, declare_line: str, Gen):
|
||||
"""解析 LLVM declare 语句"""
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
def _TryLoadFuncDeclsFromOutputStub(self, struct_name: str, Gen: LlvmGeneratorMixin) -> bool:
|
||||
"""按需从 output 目录的 stub.ll 加载泛型特化方法声明。
|
||||
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', declare_line)
|
||||
当 temp stub 不包含泛型特化(如 list[str].__iter__)时,
|
||||
从 output stub(由 _split_ll 从完整 IR 生成)中按需加载。
|
||||
|
||||
struct_name: 结构体名,如 '9163064cf3eb88f4.list[str]' 或 'list[str]'
|
||||
返回 True 如果找到了并加载了新函数声明。
|
||||
"""
|
||||
ProjectRoot = self._find_project_root()
|
||||
output_dir = os.path.join(ProjectRoot, 'output')
|
||||
if not os.path.isdir(output_dir):
|
||||
return False
|
||||
|
||||
# 提取短名称和 SHA1 前缀
|
||||
sha1_prefix: str | None = None
|
||||
if '.' in struct_name:
|
||||
parts: list[str] = struct_name.split('.', 1)
|
||||
if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
|
||||
sha1_prefix = parts[0]
|
||||
short_name: str = parts[1]
|
||||
else:
|
||||
short_name = struct_name
|
||||
else:
|
||||
short_name = struct_name
|
||||
|
||||
# 确定要搜索的 stub 文件列表
|
||||
stub_files_to_search: list[str] = []
|
||||
if sha1_prefix:
|
||||
target_stub = f'{sha1_prefix}.stub.ll'
|
||||
target_path = os.path.join(output_dir, target_stub)
|
||||
if os.path.isfile(target_path):
|
||||
stub_files_to_search.append(target_stub)
|
||||
else:
|
||||
# 没有SHA1前缀,搜索所有 output stub
|
||||
for fname in os.listdir(output_dir):
|
||||
if fname.endswith('.stub.ll'):
|
||||
stub_files_to_search.append(fname)
|
||||
|
||||
loaded_any: bool = False
|
||||
for fname in stub_files_to_search:
|
||||
stub_path = os.path.join(output_dir, fname)
|
||||
try:
|
||||
with open(stub_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
for line in content.splitlines():
|
||||
stripped = line.strip()
|
||||
if not stripped.startswith('declare '):
|
||||
continue
|
||||
# 检查是否是目标结构体的方法
|
||||
if f'.{short_name}.' not in stripped:
|
||||
continue
|
||||
try:
|
||||
func_type = self._parse_llvm_declare(stripped, Gen)
|
||||
if func_type is None:
|
||||
continue
|
||||
# 提取函数名:最后一个 @ 到第一个 ( 之间的内容
|
||||
paren_pos: int = stripped.index('(')
|
||||
at_pos: int = stripped.rindex('@', 0, paren_pos)
|
||||
func_name: str = stripped[at_pos + 1:paren_pos].strip().strip('"')
|
||||
if func_name not in Gen.functions:
|
||||
func = ir.Function(Gen.module, func_type, name=func_name)
|
||||
Gen.functions[func_name] = func
|
||||
if '.' in func_name:
|
||||
short_fn = func_name.split('.', 1)[1]
|
||||
Gen.functions[short_fn] = func
|
||||
loaded_any = True
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"按需加载 output stub 失败: {_e}", "Exception")
|
||||
return loaded_any
|
||||
|
||||
def _parse_llvm_declare(self, declare_line: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
|
||||
"""解析 LLVM declare 语句"""
|
||||
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$', declare_line)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
@@ -1861,10 +1874,8 @@ class ImportHandle(BaseHandle):
|
||||
is_variadic = '...' in params_str
|
||||
return ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||||
|
||||
def _parse_llvm_type(self, type_str: str, Gen, source_sha1=None, create_structs=True):
|
||||
def _parse_llvm_type(self, type_str: str, Gen: LlvmGeneratorMixin, source_sha1: str | None = None, create_structs: bool = True) -> ir.Type | None:
|
||||
"""解析 LLVM 类型字符串"""
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
type_str = type_str.strip()
|
||||
|
||||
@@ -1926,7 +1937,7 @@ class ImportHandle(BaseHandle):
|
||||
return ir.ArrayType(elem_type, size)
|
||||
|
||||
typedef_names = {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}
|
||||
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?', type_str)
|
||||
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]]+)"?', type_str)
|
||||
if struct_match:
|
||||
raw_name = struct_match.group(1)
|
||||
actual_source_sha1 = source_sha1
|
||||
@@ -1938,6 +1949,50 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
struct_name = raw_name
|
||||
if struct_name not in typedef_names:
|
||||
# 泛型类特化(如 list[str]):触发特化创建结构体和方法声明
|
||||
# 使用 declare_only=True 避免在引用模块中生成方法体(定义由定义模块提供)
|
||||
if '[' in struct_name and actual_source_sha1:
|
||||
if struct_name in Gen.structs:
|
||||
return Gen.structs[struct_name]
|
||||
gc_base: str = struct_name.split('[')[0]
|
||||
gc_args_raw: str = struct_name[len(gc_base):]
|
||||
gc_type_args: list[str] = []
|
||||
for gc_arg_part in gc_args_raw.split(']['):
|
||||
gc_arg_part = gc_arg_part.strip('[]')
|
||||
if gc_arg_part:
|
||||
gc_type_args.append(gc_arg_part)
|
||||
if (gc_type_args
|
||||
and hasattr(self.Trans, 'ClassHandler')
|
||||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||||
and gc_base in self.Trans.ClassHandler._generic_class_templates):
|
||||
gc_type_names: list[str] = []
|
||||
for gc_ta in gc_type_args:
|
||||
gc_tn: str = gc_ta
|
||||
if gc_ta == 'int':
|
||||
gc_tn = 'CInt'
|
||||
elif gc_ta == 'double':
|
||||
gc_tn = 'CDouble'
|
||||
elif gc_ta == 'float':
|
||||
gc_tn = 'CFloat'
|
||||
elif gc_ta == 'char':
|
||||
gc_tn = 'CChar'
|
||||
elif gc_ta == 'bool':
|
||||
gc_tn = 'CBool'
|
||||
gc_type_names.append(gc_tn)
|
||||
saved_module_sha1: str | None = getattr(Gen, 'module_sha1', None)
|
||||
saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
|
||||
Gen.module_sha1 = actual_source_sha1
|
||||
self.Trans._module_sha1 = actual_source_sha1
|
||||
try:
|
||||
gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||||
gc_base, gc_type_args, Gen, type_names=gc_type_names,
|
||||
declare_only=True)
|
||||
except Exception:
|
||||
gc_spec = None
|
||||
Gen.module_sha1 = saved_module_sha1
|
||||
self.Trans._module_sha1 = saved_trans_sha1
|
||||
if gc_spec and gc_spec in Gen.structs:
|
||||
return Gen.structs[gc_spec]
|
||||
if create_structs:
|
||||
return Gen._get_or_create_struct(struct_name, source_sha1=actual_source_sha1)
|
||||
else:
|
||||
@@ -1949,13 +2004,12 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
return None
|
||||
|
||||
def _strip_param_name(self, param_str):
|
||||
def _strip_param_name(self, param_str: str) -> str:
|
||||
"""从 LLVM 参数字符串中剥离参数名,只保留类型部分
|
||||
例如: '%"sha1.struct_name"* %param_name' -> '%"sha1.struct_name"*'
|
||||
'i8* %path' -> 'i8*'
|
||||
'i32' -> 'i32'
|
||||
"""
|
||||
import re
|
||||
param_str = param_str.strip()
|
||||
stripped = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
|
||||
return stripped.strip()
|
||||
|
||||
Reference in New Issue
Block a user