1915 lines
113 KiB
Python
1915 lines
113 KiB
Python
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 copy
|
||
import traceback
|
||
import llvmlite.ir as ir
|
||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||
from lib.core.SymbolUtils import IsTModule, FindStructNameInAnnotation
|
||
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
|
||
|
||
|
||
# t 模块存储类标记装饰器名称集合
|
||
_T_STORAGE_DECORATORS = frozenset({'CExport', 'CExtern', 'CStatic', 'State', 'CInline', 'TLS'})
|
||
|
||
|
||
class FunctionHandle(BaseHandle):
|
||
@staticmethod
|
||
def _ExtractFuncMeta(decorator_list: list[ast.AST]) -> FuncMeta:
|
||
meta: FuncMeta = FuncMeta.NONE
|
||
if not decorator_list:
|
||
return meta
|
||
for d in decorator_list:
|
||
if isinstance(d, ast.Name):
|
||
if d.id == 'staticmethod':
|
||
meta |= FuncMeta.STATIC_METHOD
|
||
elif d.id == 'property':
|
||
meta |= FuncMeta.PROPERTY_GETTER
|
||
elif d.id == 'classmethod':
|
||
meta |= FuncMeta.CLASS_METHOD
|
||
elif isinstance(d, ast.Attribute):
|
||
if isinstance(d.value, ast.Name):
|
||
# 支持 @property.setter 和 @propname.setter 两种形式
|
||
# @propname.setter 中 propname 是之前用 @property 定义的同名属性
|
||
if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'):
|
||
if d.attr == 'setter':
|
||
meta |= FuncMeta.PROPERTY_SETTER
|
||
elif d.attr == 'getter':
|
||
meta |= FuncMeta.PROPERTY_GETTER
|
||
elif d.attr == 'deleter':
|
||
meta |= FuncMeta.PROPERTY_DELETER
|
||
return meta
|
||
|
||
def _extract_decorator_storage_flags(self, Node: ast.FunctionDef) -> dict[str, bool]:
|
||
"""从装饰器列表中提取 t 模块存储类标记
|
||
|
||
支持 @t.CExport, @t.CExtern, @t.CStatic, @t.State, @t.CInline
|
||
也支持 from t import CExport 等别名形式
|
||
|
||
Returns:
|
||
dict with keys: 'is_export', 'is_extern', 'is_static', 'is_state', 'is_inline'
|
||
"""
|
||
flags: dict[str, bool] = {
|
||
'is_export': False, 'is_extern': False,
|
||
'is_static': False, 'is_state': False, 'is_inline': False,
|
||
}
|
||
if not Node.decorator_list:
|
||
return flags
|
||
symtab: object = self.Trans.SymbolTable
|
||
for decorator in Node.decorator_list:
|
||
attr_name: str | None = None
|
||
# @t.CExport 形式
|
||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||
if IsTModule(decorator.value.id, symtab):
|
||
attr_name = decorator.attr
|
||
# @CExport 形式 (from t import CExport)
|
||
elif isinstance(decorator, ast.Name):
|
||
cls: type | None = getattr(t, decorator.id, None)
|
||
if cls is None and hasattr(symtab, '_t_type_symbols'):
|
||
cls = symtab._t_type_symbols.get(decorator.id)
|
||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||
attr_name = cls.__name__
|
||
if attr_name and attr_name in _T_STORAGE_DECORATORS:
|
||
if attr_name == 'CExport':
|
||
flags['is_export'] = True
|
||
elif attr_name == 'CExtern':
|
||
flags['is_extern'] = True
|
||
elif attr_name == 'CStatic':
|
||
flags['is_static'] = True
|
||
elif attr_name == 'State':
|
||
flags['is_state'] = True
|
||
elif attr_name == 'CInline':
|
||
flags['is_inline'] = True
|
||
return flags
|
||
|
||
@staticmethod
|
||
def _is_t_storage_decorator(decorator: ast.AST, symtab: object) -> bool:
|
||
"""检查装饰器是否是 t 模块存储类标记(用于排除 behavior_decorators)"""
|
||
attr_name: str | None = None
|
||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||
if IsTModule(decorator.value.id, symtab):
|
||
attr_name = decorator.attr
|
||
elif isinstance(decorator, ast.Name):
|
||
cls: type | None = getattr(t, decorator.id, None)
|
||
if cls is None and hasattr(symtab, '_t_type_symbols'):
|
||
cls = symtab._t_type_symbols.get(decorator.id)
|
||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||
attr_name = cls.__name__
|
||
elif decorator.id in _T_STORAGE_DECORATORS and hasattr(t, decorator.id):
|
||
# TLS 是普通函数标记,不是 CType 子类
|
||
attr_name = decorator.id
|
||
return attr_name in _T_STORAGE_DECORATORS if attr_name else False
|
||
|
||
# ------------------------------------------------------------------
|
||
# 函数签名公共辅助:以下三个方法供 _GetFunctionSignatureLlvm 与
|
||
# _EmitFunctionLlvm 共享,避免 ~80 行重复代码。
|
||
# ------------------------------------------------------------------
|
||
|
||
def _compute_func_name_meta(self, Node: ast.FunctionDef, ClassName: str | None) -> tuple[str, str, FuncMeta]:
|
||
"""计算函数全名(含 setter/deleter 后缀)和 func_meta
|
||
|
||
Returns:
|
||
(FuncName, RawFuncName, func_meta)
|
||
"""
|
||
RawFuncName: str = Node.name
|
||
FuncName: str = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName
|
||
func_meta: FuncMeta = self._ExtractFuncMeta(Node.decorator_list)
|
||
# property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突
|
||
if FuncMeta.PROPERTY_SETTER in func_meta:
|
||
FuncName = FuncName + '$set'
|
||
elif FuncMeta.PROPERTY_DELETER in func_meta:
|
||
FuncName = FuncName + '$del'
|
||
return FuncName, RawFuncName, func_meta
|
||
|
||
def _resolve_method_class(self, Node: ast.FunctionDef, ClassName: str | None, func_meta: FuncMeta, FuncName: str, Gen: LlvmCodeGenerator) -> tuple[bool, bool, str | None]:
|
||
"""判定函数是否是实例方法 / 类方法,并解析所属类名
|
||
|
||
Returns:
|
||
(IsMethod, IsClassMethod, ResolvedClassName)
|
||
"""
|
||
RawFuncName: str = Node.name
|
||
IsMethod: bool = False
|
||
IsClassMethod: bool = False
|
||
ResolvedClassName: str | None = ClassName
|
||
if not ResolvedClassName:
|
||
for potential_class in Gen.class_methods:
|
||
if FuncName.startswith(f"{potential_class}."):
|
||
IsMethod = True
|
||
ResolvedClassName = potential_class
|
||
break
|
||
else:
|
||
IsMethod = FuncMeta.STATIC_METHOD not in func_meta and FuncMeta.CLASS_METHOD not in func_meta
|
||
IsClassMethod = FuncMeta.CLASS_METHOD in func_meta
|
||
if RawFuncName == '__init__':
|
||
IsMethod = False
|
||
return IsMethod, IsClassMethod, ResolvedClassName
|
||
|
||
def _apply_struct_self_cls_types(self, ParamTypes: list[ir.Type], ParamNames: list[str], IsMethod: bool, IsClassMethod: bool, ResolvedClassName: str | None, Gen: LlvmCodeGenerator) -> bool:
|
||
"""根据 IsMethod / IsClassMethod 调整 self/cls 参数的 LLVM 类型
|
||
|
||
- 若是实例方法且无 self 参数,自动插入一个 struct 指针类型;
|
||
此时调用方需要同步插入对应的 ParamTypeStrs(本方法不维护)。
|
||
- 若是 @classmethod,将 cls 参数覆盖为 struct 指针类型。
|
||
|
||
Returns:
|
||
True 表示为实例方法自动插入了 self 参数;False 表示未插入。
|
||
"""
|
||
if not ResolvedClassName or ResolvedClassName not in Gen.structs:
|
||
return False
|
||
# 治本修复:同名类 sha1 冲突检测。
|
||
# 当多个模块定义同名类(如 stmts.py:Module 和 __module.py:Module)时,
|
||
# Gen.structs[short_name] 可能指向错误模块的 struct(set_body 已锁定错误布局)。
|
||
# 通过 class_sha1_map 获取当前类的源模块 sha1,查找以 sha1 为前缀的完整 struct。
|
||
TargetStruct: ir.IdentifiedStructType = Gen.structs[ResolvedClassName]
|
||
ClassSha1Map: dict[str, str] = getattr(Gen, 'class_sha1_map', {})
|
||
ExpectedSha1: str | None = ClassSha1Map.get(ResolvedClassName)
|
||
if ExpectedSha1 and isinstance(TargetStruct, ir.IdentifiedStructType):
|
||
ExistingSha1: str = Gen._extract_struct_sha1(TargetStruct)
|
||
if ExistingSha1 and ExistingSha1 != ExpectedSha1:
|
||
# sha1 冲突:查找或创建正确的 struct
|
||
FullKey: str = f"{ExpectedSha1}.{ResolvedClassName}"
|
||
if FullKey in Gen.structs:
|
||
TargetStruct = Gen.structs[FullKey]
|
||
else:
|
||
# 创建新 struct 并从 stub 加载 body
|
||
TargetStruct = Gen._get_or_create_struct(ResolvedClassName, source_sha1=ExpectedSha1)
|
||
if hasattr(self.Trans, 'ImportHandler'):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ResolvedClassName, Gen, source_sha1=ExpectedSha1)
|
||
if FullKey in Gen.structs:
|
||
TargetStruct = Gen.structs[FullKey]
|
||
# 安全回退:如果新 struct 仍为 opaque(body 未加载),回退到原始短名 struct,
|
||
# 避免方法编译生成无效 GEP(访问 opaque struct 元素)导致运行时崩溃。
|
||
if isinstance(TargetStruct, ir.IdentifiedStructType):
|
||
try:
|
||
_is_opaque: bool = TargetStruct.is_opaque
|
||
except (AssertionError, AttributeError):
|
||
_is_opaque = False
|
||
if _is_opaque:
|
||
TargetStruct = Gen.structs[ResolvedClassName]
|
||
if IsMethod:
|
||
StructPtrType: ir.PointerType = ir.PointerType(TargetStruct)
|
||
SelfIdx: int = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
return False
|
||
ParamTypes.insert(0, StructPtrType)
|
||
ParamNames.insert(0, "self")
|
||
return True
|
||
# 非方法但属于类(如 staticmethod / 顶层函数位于类下)
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
StructPtrType = ir.PointerType(TargetStruct)
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
if IsClassMethod:
|
||
ClsIdx: int = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1)
|
||
if ClsIdx >= 0:
|
||
StructPtrType = ir.PointerType(TargetStruct)
|
||
ParamTypes[ClsIdx] = StructPtrType
|
||
return False
|
||
|
||
def _body_contains_raise(self, body: list[ast.AST]) -> bool:
|
||
for node in ast.walk(ast.Module(body=body, type_ignores=[])):
|
||
if isinstance(node, ast.Raise):
|
||
if node.exc:
|
||
if isinstance(node.exc, ast.Name) and node.exc.id == 'StopIteration':
|
||
continue
|
||
if isinstance(node.exc, ast.Call) and isinstance(node.exc.func, ast.Name) and node.exc.func.id == 'StopIteration':
|
||
continue
|
||
return True
|
||
if isinstance(node, ast.Call):
|
||
called_name: str | None = None
|
||
if isinstance(node.func, ast.Name):
|
||
called_name = node.func.id
|
||
elif isinstance(node.func, ast.Attribute):
|
||
called_name = node.func.attr
|
||
if called_name:
|
||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||
for prefix in ['', f'{called_name}.', f'__']:
|
||
for suffix in ['', f'.{called_name}']:
|
||
fname: str = f'{prefix}{called_name}{suffix}'
|
||
if fname in Gen.functions:
|
||
func: Any = Gen.functions[fname]
|
||
if len(func.args) > 0:
|
||
for arg in func.args:
|
||
if hasattr(arg, 'name') and arg.name in ('__eh_msg_out__', '__eh_code_out__'):
|
||
return True
|
||
break
|
||
return False
|
||
|
||
_LLVM_ATTR_NAMES = frozenset({
|
||
'nobuiltin', 'nounwind', 'noredzone', 'willreturn', 'mustprogress',
|
||
'optnone', 'noinline', 'alwaysinline', 'readnone', 'readonly',
|
||
'writeonly', 'inaccessiblememonly', 'inaccessiblemem_or_argmemonly',
|
||
})
|
||
|
||
def _ExtractLLVMAttrs(self, node: ast.AST) -> list[str]:
|
||
attrs: list[str] = []
|
||
if isinstance(node, ast.BinOp):
|
||
attrs.extend(self._ExtractLLVMAttrs(node.left))
|
||
attrs.extend(self._ExtractLLVMAttrs(node.right))
|
||
elif isinstance(node, ast.Attribute):
|
||
attr_name: str | None = self._GetAttrLLVMName(node)
|
||
if attr_name:
|
||
attrs.append(attr_name)
|
||
return attrs
|
||
|
||
def _GetAttrLLVMName(self, node: ast.AST) -> str | None:
|
||
if not isinstance(node, ast.Attribute):
|
||
return None
|
||
if node.attr not in self._LLVM_ATTR_NAMES:
|
||
return None
|
||
value: ast.AST = node.value
|
||
if not isinstance(value, ast.Attribute) or value.attr != 'llvm':
|
||
return None
|
||
inner: ast.AST = value.value
|
||
if not isinstance(inner, ast.Attribute) or inner.attr != 'attr':
|
||
return None
|
||
if not isinstance(inner.value, ast.Name) or inner.value.id != 't':
|
||
return None
|
||
return node.attr
|
||
|
||
def _infer_return_type_from_body(self, Node: ast.AST, Gen: LlvmCodeGenerator | None = None, ClassName: str | None = None) -> tuple[str, bool] | None:
|
||
local_var_types: dict[str, tuple[str, bool]] = {}
|
||
for child in ast.walk(Node):
|
||
if isinstance(child, ast.Assign) and len(child.targets) == 1:
|
||
target: ast.AST = child.targets[0]
|
||
if isinstance(target, ast.Name) and isinstance(child.value, ast.Subscript):
|
||
sub: ast.Subscript = child.value
|
||
if (isinstance(sub.value, ast.Attribute)
|
||
and isinstance(sub.value.value, ast.Name)
|
||
and sub.value.value.id == 'self'
|
||
and ClassName and ClassName in Gen.class_members):
|
||
member_name: str = sub.value.attr
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == member_name:
|
||
if isinstance(m_type, ir.ArrayType):
|
||
elem_type: ir.Type = m_type.element
|
||
if isinstance(elem_type, ir.FloatType):
|
||
local_var_types[target.id] = ('float', False)
|
||
elif isinstance(elem_type, ir.DoubleType):
|
||
local_var_types[target.id] = ('double', False)
|
||
elif isinstance(elem_type, ir.IntType):
|
||
if elem_type.width == 8:
|
||
local_var_types[target.id] = ('char', False)
|
||
else:
|
||
local_var_types[target.id] = ('int', False)
|
||
elif isinstance(elem_type, ir.PointerType):
|
||
if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8:
|
||
local_var_types[target.id] = ('char', True)
|
||
else:
|
||
local_var_types[target.id] = ('void', True)
|
||
elif isinstance(elem_type, ir.IdentifiedStructType):
|
||
struct_name: str = elem_type.name
|
||
if struct_name:
|
||
for sn, st in Gen.structs.items():
|
||
if st.name == struct_name or sn == struct_name:
|
||
local_var_types[target.id] = (sn, False)
|
||
break
|
||
else:
|
||
local_var_types[target.id] = (elem_type.name, False)
|
||
elif isinstance(m_type, ir.PointerType):
|
||
pointee: ir.Type = m_type.pointee
|
||
if isinstance(pointee, ir.FloatType):
|
||
local_var_types[target.id] = ('float', False)
|
||
elif isinstance(pointee, ir.DoubleType):
|
||
local_var_types[target.id] = ('double', False)
|
||
elif isinstance(pointee, ir.IntType):
|
||
if pointee.width == 8:
|
||
local_var_types[target.id] = ('char', False)
|
||
else:
|
||
local_var_types[target.id] = ('int', False)
|
||
elif isinstance(pointee, ir.PointerType):
|
||
local_var_types[target.id] = ('void', True)
|
||
elif isinstance(pointee, ir.IdentifiedStructType):
|
||
for sn, st in Gen.structs.items():
|
||
if st == pointee or st.name == pointee.name:
|
||
local_var_types[target.id] = (sn, True)
|
||
break
|
||
break
|
||
for child in ast.walk(Node):
|
||
if isinstance(child, ast.Return) and child.value:
|
||
val: ast.AST = child.value
|
||
if isinstance(val, ast.Name) and val.id == 'self' and ClassName:
|
||
return (ClassName, True)
|
||
if isinstance(val, ast.Call):
|
||
if isinstance(val.func, ast.Name):
|
||
callee: str = val.func.id
|
||
if callee == 'malloc':
|
||
return ('char', True)
|
||
if callee == 'chr':
|
||
return ('char', False)
|
||
if Gen and callee in Gen.functions:
|
||
func: Any = Gen.functions[callee]
|
||
if hasattr(func, 'ftype'):
|
||
ret_type: ir.Type = func.ftype.return_type
|
||
if isinstance(ret_type, ir.PointerType):
|
||
if isinstance(ret_type.pointee, ir.IntType) and ret_type.pointee.width == 8:
|
||
return ('char', True)
|
||
return ('void', True)
|
||
elif isinstance(ret_type, ir.IntType):
|
||
if ret_type.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(ret_type, ir.VoidType):
|
||
return ('void', False)
|
||
elif isinstance(val.func, ast.Attribute):
|
||
pass
|
||
callee_name: str | None = None
|
||
if isinstance(val.func, ast.Name):
|
||
callee_name = val.func.id
|
||
elif isinstance(val.func, ast.Attribute):
|
||
callee_name = getattr(val.func, 'attr', None)
|
||
if callee_name:
|
||
sym: Any = self.Trans.SymbolTable.lookup(callee_name)
|
||
if sym and isinstance(sym, dict):
|
||
ret_type_str: str = sym.get('return_type', '')
|
||
if ret_type_str and ret_type_str != 'int':
|
||
IsPtr: bool = sym.get('IsPtr', False)
|
||
return (ret_type_str, IsPtr)
|
||
elif isinstance(val, ast.Constant):
|
||
if val.value is None:
|
||
return ('char', True)
|
||
elif isinstance(val.value, str) and len(val.value) <= 1:
|
||
return ('char', True)
|
||
elif isinstance(val, ast.Name):
|
||
var_name: str = val.id
|
||
if var_name in local_var_types:
|
||
return local_var_types[var_name]
|
||
var_info: Any = self.Trans.SymbolTable.lookup(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type: str = var_info.get('type', '')
|
||
if var_type and var_type != 'int':
|
||
IsPtr: bool = var_info.get('IsPtr', False)
|
||
return (var_type, IsPtr)
|
||
elif isinstance(val, ast.Subscript):
|
||
if (isinstance(val.value, ast.Attribute)
|
||
and isinstance(val.value.value, ast.Name)
|
||
and val.value.value.id == 'self'
|
||
and ClassName):
|
||
member_name: str = val.value.attr
|
||
if ClassName in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[ClassName]:
|
||
if m_name == member_name:
|
||
if isinstance(m_type, ir.ArrayType):
|
||
elem_type: ir.Type = m_type.element
|
||
if isinstance(elem_type, ir.FloatType):
|
||
return ('float', False)
|
||
elif isinstance(elem_type, ir.DoubleType):
|
||
return ('double', False)
|
||
elif isinstance(elem_type, ir.IntType):
|
||
if elem_type.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(elem_type, ir.PointerType):
|
||
if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8:
|
||
return ('char', True)
|
||
return ('void', True)
|
||
elif isinstance(elem_type, ir.IdentifiedStructType):
|
||
struct_name: str = elem_type.name
|
||
if struct_name:
|
||
for sn, st in Gen.structs.items():
|
||
if st.name == struct_name or sn == struct_name:
|
||
return (sn, False)
|
||
return (elem_type.name, False)
|
||
elif isinstance(m_type, ir.PointerType):
|
||
pointee: ir.Type = m_type.pointee
|
||
if isinstance(pointee, ir.FloatType):
|
||
return ('float', False)
|
||
elif isinstance(pointee, ir.DoubleType):
|
||
return ('double', False)
|
||
elif isinstance(pointee, ir.IntType):
|
||
if pointee.width == 8:
|
||
return ('char', False)
|
||
return ('int', False)
|
||
elif isinstance(pointee, ir.PointerType):
|
||
return ('void', True)
|
||
elif isinstance(pointee, ir.IdentifiedStructType):
|
||
for sn, st in Gen.structs.items():
|
||
if st == pointee or st.name == pointee.name:
|
||
return (sn, True)
|
||
return (pointee.name, True)
|
||
break
|
||
if isinstance(val.value, ast.Name):
|
||
var_name: str = val.value.id
|
||
var_info: Any = self.Trans.SymbolTable.lookup(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type: str = var_info.get('type', '')
|
||
if var_type.startswith('list[') or var_type.startswith('List[') or var_type.startswith('t.CArray['):
|
||
inner: str = var_type[var_type.index('[') + 1:var_type.rindex(']')]
|
||
parts: list[str] = inner.split(',')
|
||
elem_type_str: str = parts[0].strip()
|
||
if elem_type_str and elem_type_str != 'int':
|
||
IsPtr: bool = var_info.get('IsPtr', False)
|
||
return (elem_type_str, IsPtr)
|
||
return None
|
||
|
||
def _GetFunctionSignatureLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, Any]] | None = None) -> tuple[str, ir.FunctionType, Any, list[Any], list[ast.AST], bool, str | None, bool]:
|
||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||
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:
|
||
llvm_attrs: list[str] = self._ExtractLLVMAttrs(Node.returns)
|
||
if llvm_attrs:
|
||
if not hasattr(self, '_pending_llvm_attrs'):
|
||
self._pending_llvm_attrs = {}
|
||
self._pending_llvm_attrs[FuncName] = llvm_attrs
|
||
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)
|
||
IsPtr: bool = False
|
||
ReturnTypeInfo: Any = None
|
||
if Node.returns:
|
||
if CReturnTypes:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
else:
|
||
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()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
|
||
def _FindNonVoidCTypeInfo(node: ast.AST) -> Any:
|
||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
results: list[Any] = []
|
||
for child in [node.left, node.right]:
|
||
r: Any = _FindNonVoidCTypeInfo(child)
|
||
if r and not r.IsVoid:
|
||
results.append(r)
|
||
for r in results:
|
||
if not r.IsPtr and not r.IsStruct:
|
||
return r
|
||
return results[0] if results else None
|
||
try:
|
||
SideInfo: Any = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
|
||
if SideInfo:
|
||
return SideInfo
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
return None
|
||
found: Any = _FindNonVoidCTypeInfo(Node.returns)
|
||
if found and not found.IsVoid:
|
||
ReturnTypeInfo = found
|
||
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
else:
|
||
is_str_type: bool = False
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_type = True
|
||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
if not hasattr(self, '_cdefine_funcs'):
|
||
self._cdefine_funcs = set()
|
||
self._cdefine_funcs.add(FuncName)
|
||
elif ReturnTypeInfo and ReturnTypeInfo.IsState:
|
||
if ReturnTypeInfo.PtrCount > 0 or (ReturnTypeInfo.BaseType and not isinstance(ReturnTypeInfo.BaseType, t.CVoid)):
|
||
pass
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
if is_str_type or ReturnTypeInfo.IsStr:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
# 检查泛型类返回类型 (如 list[str])
|
||
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
|
||
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 t.CVoid 实例),需额外检测 BaseType is None
|
||
if (isinstance(Node.returns, ast.Subscript)
|
||
and isinstance(Node.returns.value, ast.Name)
|
||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||
and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates
|
||
and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0):
|
||
ret_class: str = Node.returns.value.id
|
||
ret_slice: ast.AST = Node.returns.slice
|
||
ret_type_args: list[str] = []
|
||
ret_type_names: list[str] = []
|
||
if isinstance(ret_slice, ast.Tuple):
|
||
for elt in ret_slice.elts:
|
||
if isinstance(elt, ast.Name):
|
||
tn2: str = elt.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
elif isinstance(ret_slice, ast.Name):
|
||
tn2: str = ret_slice.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
# 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True
|
||
# 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册,
|
||
# 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。
|
||
# 完整特化由后续类实例化(L3688/L3753)触发 declare_only=False。
|
||
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
|
||
if spec_name2 and spec_name2 in Gen.structs:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CStruct(name=spec_name2)
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
except Exception: # 回退:设置默认返回类型为 CInt
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||
ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
if isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.PointerType):
|
||
if isinstance(ReturnType.pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
ReturnType = ir.PointerType(ReturnType.pointee.pointee)
|
||
if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8:
|
||
if RawFuncName == '__str__':
|
||
ReturnType = ir.PointerType(ir.IntType(8))
|
||
if isinstance(ReturnType, ir.VoidType) and FuncName == 'main':
|
||
ReturnType = ir.IntType(32)
|
||
IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen)
|
||
# __new__ methods should return a pointer to the struct (for heap allocation replacement)
|
||
# 修复:前向声明也必须使用正确的返回类型,否则 _replace_function_decl 可能失败,
|
||
# 导致 vtable 引用错误的函数类型(i32 而非 ClassName*)
|
||
if RawFuncName == '__new__' and ResolvedClassName:
|
||
StructType = Gen.structs.get(ResolvedClassName)
|
||
if StructType:
|
||
if isinstance(StructType, ir.PointerType):
|
||
ReturnType = StructType
|
||
else:
|
||
ReturnType = ir.PointerType(StructType)
|
||
ParamTypes: list[ir.Type] = []
|
||
ParamNames: list[str] = []
|
||
ParamTypeStrs: list[Any] = []
|
||
auto_addr_modes: list[str | None] = []
|
||
CReturnLlvmTypes: list[ir.Type] = []
|
||
if CReturnTypes:
|
||
for i, ReturnTypeNode in enumerate(CReturnTypes):
|
||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsStr:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
RetType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
CReturnLlvmTypes.append(RetType)
|
||
ReturnType = ir.LiteralStructType(CReturnLlvmTypes)
|
||
for Arg in Node.args.args:
|
||
ParamIsUnsigned: bool = False
|
||
if Arg.annotation:
|
||
try:
|
||
ParamTypeInfo: Any
|
||
ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CInt()
|
||
IsPtr = ParamTypeInfo.IsPtr
|
||
if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr:
|
||
IsPtr = True
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
if ParamTypeInfo.IsStr or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CChar()
|
||
ParamTypeInfo.PtrCount = 1
|
||
IsPtr = True
|
||
# C 语言中数组参数退化为指针:list[type, N] → type*
|
||
if ParamTypeInfo.ArrayDims:
|
||
ParamTypeInfo.ArrayDims = []
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
ParamType: ir.Type = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||
if isinstance(ParamType, ir.VoidType):
|
||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||
raise SyntaxError(
|
||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||
f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。"
|
||
)
|
||
ParamTypeStr: Any = ParamTypeInfo
|
||
except SyntaxError:
|
||
raise
|
||
except Exception as e:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeStr = CTypeInfo()
|
||
ParamTypeStr.BaseType = t.CInt()
|
||
else:
|
||
if ClassName and Arg.arg != 'self':
|
||
op_method_names: list[str] = ['__add__', '__sub__', '__mul__', '__truediv__', '__floordiv__', '__mod__', '__pow__',
|
||
'__radd__', '__rsub__', '__rmul__', '__rtruediv__', '__rfloordiv__', '__rmod__', '__rpow__',
|
||
'__iadd__', '__isub__', '__imul__', '__itruediv__', '__ifloordiv__', '__imod__', '__ipow__',
|
||
'__eq__', '__ne__', '__lt__', '__le__', '__gt__', '__ge__',
|
||
'__neg__', '__pos__', '__abs__', '__call__']
|
||
if RawFuncName in op_method_names and ClassName in Gen.structs:
|
||
ParamType = ir.PointerType(Gen.structs[ClassName])
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeStr = CTypeInfo()
|
||
ParamTypeStr.BaseType = t.CInt()
|
||
ParamTypes.append(ParamType)
|
||
ParamNames.append(Arg.arg)
|
||
ParamTypeStrs.append(ParamTypeStr)
|
||
# 检测 t.CNeedPtr / t.CAutoPtr 参数注解
|
||
auto_mode: str | None = None
|
||
if ParamTypeStr is not None and hasattr(ParamTypeStr, 'BaseType') and ParamTypeStr.BaseType is not None:
|
||
if isinstance(ParamTypeStr.BaseType, t.CAutoPtr):
|
||
auto_mode = 'always'
|
||
elif isinstance(ParamTypeStr.BaseType, t.CNeedPtr):
|
||
auto_mode = 'need'
|
||
auto_addr_modes.append(auto_mode)
|
||
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
|
||
ParamTypeStrs.insert(0, f"struct {ResolvedClassName}")
|
||
IsVariadic: bool = Node.args.vararg is not None
|
||
if extra_params:
|
||
for var_name, ptr_type in extra_params:
|
||
ParamTypes.append(ptr_type)
|
||
ParamNames.append(f'__nonlocal_{var_name}__')
|
||
if IsMethod and RawFuncName == '__next__':
|
||
ParamTypes.append(ir.PointerType(ir.IntType(1)))
|
||
ParamNames.append('__stop_iter_flag__')
|
||
HasRaise: bool = self._body_contains_raise(Node.body)
|
||
if HasRaise and RawFuncName != 'main':
|
||
ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8))))
|
||
ParamNames.append('__eh_msg_out__')
|
||
ParamTypes.append(ir.PointerType(ir.IntType(32)))
|
||
ParamNames.append('__eh_code_out__')
|
||
FuncType: ir.FunctionType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic)
|
||
# 存储 auto_addr_modes(为额外参数补 None)
|
||
total_params: int = len(ParamTypes)
|
||
while len(auto_addr_modes) < total_params:
|
||
auto_addr_modes.append(None)
|
||
Gen._auto_addr_params[FuncName] = auto_addr_modes
|
||
return FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic
|
||
|
||
def _is_generic_function(self, Node: ast.FunctionDef) -> bool:
|
||
if hasattr(Node, 'type_params') and Node.type_params:
|
||
return True
|
||
return False
|
||
|
||
def _mangle_generic_name(self, func_name: str, type_args: list[str], has_cexport: bool = False) -> str:
|
||
mangled_args: list[str] = []
|
||
for ta in type_args:
|
||
llvm_str: str | None = CTypeRegistry.NameToLLVM(ta)
|
||
if llvm_str:
|
||
if llvm_str in ('float', 'double', 'half', 'fp128'):
|
||
mangled: str = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size)
|
||
else:
|
||
mangled = llvm_str
|
||
else:
|
||
mangled = ta
|
||
mangled_args.append(mangled)
|
||
if has_cexport:
|
||
return func_name + '_T_' + '_'.join(mangled_args)
|
||
return func_name + '[' + ']['.join(mangled_args) + ']'
|
||
|
||
def _apply_type_map_to_node(self, Node: ast.FunctionDef, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
for arg in Node.args.args:
|
||
if arg.annotation:
|
||
arg.annotation = self._replace_type_in_annotation(arg.annotation, type_map, cptr_params)
|
||
if Node.returns:
|
||
Node.returns = self._replace_type_in_annotation(Node.returns, type_map, cptr_params)
|
||
self._apply_type_map_to_body(Node.body, type_map, cptr_params)
|
||
|
||
def _replace_type_in_annotation(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> ast.AST:
|
||
if isinstance(node, ast.Name):
|
||
if node.id in type_map:
|
||
replacement: str = type_map[node.id]
|
||
return self._make_replacement_node(replacement)
|
||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
if isinstance(node.left, ast.Name) and node.left.id in type_map:
|
||
replacement: str = type_map[node.left.id]
|
||
node.left = self._make_replacement_node(replacement)
|
||
return node
|
||
node.left = self._replace_type_in_annotation(node.left, type_map, cptr_params)
|
||
node.right = self._replace_type_in_annotation(node.right, type_map, cptr_params)
|
||
elif isinstance(node, ast.Attribute):
|
||
if hasattr(node, 'attr') and node.attr in type_map:
|
||
replacement: str = type_map[node.attr]
|
||
return self._make_replacement_node(replacement)
|
||
elif isinstance(node, ast.Subscript):
|
||
# 嵌套泛型(如 list[T]):递归替换 value 和 slice 中的类型参数
|
||
node.value = self._replace_type_in_annotation(node.value, type_map, cptr_params)
|
||
node.slice = self._replace_type_in_annotation(node.slice, type_map, cptr_params)
|
||
return node
|
||
|
||
def _make_replacement_node(self, replacement: str) -> ast.AST:
|
||
"""将 type_map 中的替换字符串转换为 AST 节点。
|
||
mangled 名称如 'sha1.ASTptr' 需要还原为 AST | t.CPtr 结构,
|
||
否则类型解析会丢失 PtrCount 信息。
|
||
含点号的名称(如 'sha1.AST')需解析为 ast.Attribute 链。
|
||
"""
|
||
if replacement.endswith('ptr'):
|
||
# 提取基础名称: 'sha1.ASTptr' -> 'sha1.AST'
|
||
base: str = replacement[:-3]
|
||
return ast.BinOp(
|
||
left=self._make_name_node(base),
|
||
op=ast.BitOr(),
|
||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||
)
|
||
return self._make_name_node(replacement)
|
||
|
||
@staticmethod
|
||
def _make_name_node(name: str) -> ast.AST:
|
||
"""将可能含点号的名称转换为 ast.Name 或 ast.Attribute 链。
|
||
'AST' -> ast.Name(id='AST')
|
||
'sha1.AST' -> ast.Attribute(value=ast.Name(id='sha1'), attr='AST')
|
||
"""
|
||
if '.' not in name:
|
||
return ast.Name(id=name, ctx=ast.Load())
|
||
parts: list[str] = name.split('.')
|
||
node: ast.AST = ast.Name(id=parts[0], ctx=ast.Load())
|
||
for part in parts[1:]:
|
||
node = ast.Attribute(value=node, attr=part, ctx=ast.Load())
|
||
return node
|
||
|
||
def _apply_type_map_to_body(self, body: list[ast.AST], type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
for stmt in body:
|
||
self._apply_type_map_to_stmt(stmt, type_map, cptr_params)
|
||
|
||
def _apply_type_map_to_stmt(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
if isinstance(node, ast.Return) and node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.Assign):
|
||
for t in node.targets:
|
||
self._apply_type_map_to_expr(t, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.AnnAssign):
|
||
if node.annotation:
|
||
node.annotation = self._replace_type_in_annotation(node.annotation, type_map, cptr_params)
|
||
if node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.AugAssign):
|
||
self._apply_type_map_to_expr(node.target, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.Expr):
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.If):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.For):
|
||
self._apply_type_map_to_expr(node.iter, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.While):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.Try):
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for handler in node.handlers:
|
||
for s in handler.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
for s in node.finalbody:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.With):
|
||
for item in node.items:
|
||
self._apply_type_map_to_expr(item.context_expr, type_map, cptr_params)
|
||
if item.optional_vars:
|
||
self._apply_type_map_to_expr(item.optional_vars, type_map, cptr_params)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map, cptr_params)
|
||
elif isinstance(node, ast.Raise):
|
||
if node.exc:
|
||
self._apply_type_map_to_expr(node.exc, type_map, cptr_params)
|
||
if node.cause:
|
||
self._apply_type_map_to_expr(node.cause, type_map, cptr_params)
|
||
elif isinstance(node, ast.Assert):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
if node.msg:
|
||
self._apply_type_map_to_expr(node.msg, type_map, cptr_params)
|
||
|
||
def _apply_type_map_to_expr(self, node: ast.AST | None, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None:
|
||
if node is None:
|
||
return
|
||
if isinstance(node, ast.Call):
|
||
if isinstance(node.func, ast.Name) and node.func.id in type_map:
|
||
replacement: str = type_map[node.func.id]
|
||
# 使用 _make_replacement_node 处理含点号的类型名(如 't.CUnsignedChar'),
|
||
# 避免 T(0) 替换为 CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域
|
||
# 而报 "Undefined function: 'CUnsignedChar'"
|
||
node.func = self._make_replacement_node(replacement)
|
||
elif isinstance(node.func, ast.Attribute):
|
||
if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map:
|
||
replacement: str = type_map[node.func.value.id]
|
||
# 指针类型参数(如 list[AST | t.CPtr] 中的 T)在表达式上下文中
|
||
# 需替换为 BinOp(AST | t.CPtr),使 __sizeof__ 等处理器能正确识别
|
||
# 指针语义并直接返回 8,避免触发 struct 加载和重入编译
|
||
if cptr_params and node.func.value.id in cptr_params:
|
||
node.func.value = ast.BinOp(
|
||
left=self._make_name_node(replacement),
|
||
op=ast.BitOr(),
|
||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||
)
|
||
else:
|
||
node.func.value = self._make_name_node(replacement)
|
||
else:
|
||
self._apply_type_map_to_expr(node.func.value, type_map, cptr_params)
|
||
for arg in node.args:
|
||
self._apply_type_map_to_expr(arg, type_map, cptr_params)
|
||
elif isinstance(node, ast.Attribute):
|
||
if isinstance(node.value, ast.Name) and node.value.id in type_map:
|
||
replacement: str = type_map[node.value.id]
|
||
if cptr_params and node.value.id in cptr_params:
|
||
node.value = ast.BinOp(
|
||
left=self._make_name_node(replacement),
|
||
op=ast.BitOr(),
|
||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||
)
|
||
else:
|
||
node.value = ast.Name(id=replacement, ctx=ast.Load())
|
||
else:
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
elif isinstance(node, ast.BinOp):
|
||
self._apply_type_map_to_expr(node.left, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.right, type_map, cptr_params)
|
||
elif isinstance(node, ast.UnaryOp):
|
||
self._apply_type_map_to_expr(node.operand, type_map, cptr_params)
|
||
elif isinstance(node, ast.Compare):
|
||
self._apply_type_map_to_expr(node.left, type_map, cptr_params)
|
||
for comp in node.comparators:
|
||
self._apply_type_map_to_expr(comp, type_map, cptr_params)
|
||
elif isinstance(node, ast.BoolOp):
|
||
for val in node.values:
|
||
self._apply_type_map_to_expr(val, type_map, cptr_params)
|
||
elif isinstance(node, ast.IfExp):
|
||
self._apply_type_map_to_expr(node.test, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.body, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.orelse, type_map, cptr_params)
|
||
elif isinstance(node, ast.Subscript):
|
||
self._apply_type_map_to_expr(node.value, type_map, cptr_params)
|
||
self._apply_type_map_to_expr(node.slice, type_map, cptr_params)
|
||
elif isinstance(node, ast.Name):
|
||
if node.id in type_map:
|
||
node.id = type_map[node.id]
|
||
|
||
def _infer_type_arg_from_value(self, val: ir.Value, Gen: LlvmCodeGenerator) -> str:
|
||
if val is None:
|
||
return 'int'
|
||
if isinstance(val.type, ir.IntType):
|
||
if val.type.width == 64:
|
||
return 'i64'
|
||
elif val.type.width == 16:
|
||
return 'i16'
|
||
elif val.type.width == 8:
|
||
return 'i8'
|
||
return 'int'
|
||
elif isinstance(val.type, ir.DoubleType):
|
||
return 'double'
|
||
elif isinstance(val.type, ir.FloatType):
|
||
return 'float'
|
||
elif isinstance(val.type, ir.PointerType):
|
||
return 'void*'
|
||
return 'int'
|
||
|
||
def _specialize_generic_function(self, FuncName: str, type_args: list[str], Gen: LlvmCodeGenerator) -> str | None:
|
||
if not hasattr(self, '_generic_templates') or FuncName not in self._generic_templates:
|
||
return None
|
||
template: dict[str, Any] = self._generic_templates[FuncName]
|
||
Node: ast.FunctionDef = template['node']
|
||
type_param_names: list[str] = template['type_params']
|
||
ClassName: str | None = template['class_name']
|
||
if len(type_args) != len(type_param_names):
|
||
return None
|
||
spec_key: str = FuncName + '<' + ','.join(type_args) + '>'
|
||
if not hasattr(self, '_generic_specializations'):
|
||
self._generic_specializations = {}
|
||
if spec_key in self._generic_specializations:
|
||
return self._generic_specializations[spec_key]
|
||
has_cexport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo: Any = None
|
||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||
RetTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
|
||
else:
|
||
RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport):
|
||
has_cexport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
spec_name: str = self._mangle_generic_name(FuncName, type_args, has_cexport)
|
||
type_map: dict[str, str] = {}
|
||
for i, tp_name in enumerate(type_param_names):
|
||
type_map[tp_name] = type_args[i]
|
||
SpecNode: ast.FunctionDef = copy.deepcopy(Node)
|
||
SpecNode.type_params = []
|
||
SpecNode.name = spec_name
|
||
self._apply_type_map_to_node(SpecNode, type_map)
|
||
if has_cexport:
|
||
if not hasattr(Gen, '_export_funcs'):
|
||
Gen._export_funcs = set()
|
||
Gen._export_funcs.add(spec_name)
|
||
saved_builder: Any = Gen.builder
|
||
saved_variables: dict[str, Any] = dict(Gen.variables) if Gen.variables else {}
|
||
saved_direct_values: dict[str, Any] = dict(Gen._direct_values) if Gen._direct_values else {}
|
||
saved_var_type_info: dict[str, Any] = dict(Gen.var_type_info) if Gen.var_type_info else {}
|
||
saved_var_signedness: dict[str, Any] = dict(Gen.var_signedness) if Gen.var_signedness else {}
|
||
saved_global_vars: set[str] = set(Gen.global_vars) if Gen.global_vars else set()
|
||
saved_var_scopes: list[dict[str, Any]] = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else []
|
||
saved_func: Any = Gen.func
|
||
saved_current_func_name: str | None = getattr(Gen, '_current_func_name', None)
|
||
saved_block: Any = None
|
||
if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated:
|
||
saved_block = Gen.builder.block
|
||
self._EmitFunctionForwardDeclLlvm(SpecNode, Gen, ClassName=ClassName)
|
||
self._EmitFunctionLlvm(SpecNode, Gen, ClassName=ClassName)
|
||
Gen.builder = saved_builder
|
||
if saved_block is not None and Gen.builder is not None:
|
||
Gen.builder.position_at_end(saved_block)
|
||
Gen.variables = saved_variables
|
||
Gen._direct_values = saved_direct_values
|
||
Gen.var_type_info = saved_var_type_info
|
||
Gen.var_signedness = saved_var_signedness
|
||
Gen.global_vars = saved_global_vars
|
||
Gen.func = saved_func
|
||
if saved_current_func_name is not None:
|
||
Gen._current_func_name = saved_current_func_name
|
||
self.Trans.VarScopes = saved_var_scopes
|
||
self._generic_specializations[spec_key] = spec_name
|
||
if not hasattr(self.Trans, '_generic_specializations'):
|
||
self.Trans._generic_specializations = {}
|
||
self.Trans._generic_specializations[spec_key] = spec_name
|
||
return spec_name
|
||
|
||
def _EmitFunctionForwardDeclLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None) -> None:
|
||
if self._is_generic_function(Node):
|
||
if not hasattr(self, '_generic_templates'):
|
||
self._generic_templates = {}
|
||
RawFuncName: str = Node.name
|
||
if ClassName:
|
||
FuncName: str = f"{ClassName}.{RawFuncName}"
|
||
else:
|
||
FuncName = RawFuncName
|
||
type_params: list[str] = [tp.name for tp in Node.type_params]
|
||
self._generic_templates[FuncName] = {
|
||
'node': Node,
|
||
'type_params': type_params,
|
||
'class_name': ClassName,
|
||
}
|
||
return
|
||
result: Any = self._GetFunctionSignatureLlvm(Node, Gen, ClassName)
|
||
if result is None:
|
||
return
|
||
FuncName: str
|
||
FuncType: ir.FunctionType
|
||
ReturnTypeInfo: Any
|
||
ParamTypeStrs: list[Any]
|
||
CReturnTypes: list[ast.AST]
|
||
IsMethod: bool
|
||
ResolvedClassName: str | None
|
||
IsVariadic: bool
|
||
FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic = result
|
||
IsUserMarkedExport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo: Any = None
|
||
RetTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern):
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName) # t.State 标记的函数必须保持原始名称,以便链接器解析
|
||
IsUserMarkedExport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
# 装饰器形式的存储类标记(@t.CExport / @t.CExtern / @t.State 等)
|
||
deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node)
|
||
if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
# 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查
|
||
# (_export_extern_funcs 是跨模块共享集合,包含所有 CExtern 函数名;当前模块定义的
|
||
# 同名用户函数应使用 SHA1 前缀,而非被误判为外部 C 函数返回裸名)
|
||
Gen._current_module_func_names.add(FuncName)
|
||
# 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数)
|
||
if not IsUserMarkedExport and FuncName in Gen._export_funcs:
|
||
Gen._export_funcs.discard(FuncName)
|
||
MangledName: str = Gen._mangle_func_name(FuncName)
|
||
need_new: bool = MangledName not in Gen.functions
|
||
if not need_new:
|
||
existing: Any = Gen.functions[MangledName]
|
||
if getattr(existing, 'name', MangledName) != MangledName:
|
||
need_new = True
|
||
if need_new:
|
||
try:
|
||
func: ir.Function = ir.Function(Gen.module, FuncType, name=MangledName)
|
||
func.attributes.add('noredzone')
|
||
if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs:
|
||
for attr_name in self._pending_llvm_attrs[FuncName]:
|
||
try:
|
||
func.attributes.add(attr_name)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
|
||
Gen.functions[MangledName] = func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = func
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
else:
|
||
existing = Gen.functions[MangledName]
|
||
existing_type: ir.FunctionType | None = getattr(existing, 'ftype', None)
|
||
if existing_type and existing_type != FuncType:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
elif not existing_type:
|
||
try:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
|
||
def _replace_function_decl(self, Gen: LlvmCodeGenerator, FuncName: str, NewFuncType: ir.FunctionType) -> ir.Function:
|
||
MangledName: str = Gen._mangle_func_name(FuncName)
|
||
old_func: Any = Gen.functions.get(MangledName)
|
||
if old_func is None:
|
||
try:
|
||
return ir.Function(Gen.module, NewFuncType, name=MangledName)
|
||
except Exception: # 回退:函数已存在时返回旧函数
|
||
return old_func
|
||
try:
|
||
old_name: str = old_func.name
|
||
if old_name in getattr(Gen.module, 'globals', {}):
|
||
del Gen.module.globals[old_name]
|
||
module_scope: Any = getattr(Gen.module, 'scope', None)
|
||
if getattr(module_scope, '_useset', None):
|
||
module_scope._useset.discard(old_name)
|
||
if getattr(Gen.module, '_guessed_names', None):
|
||
Gen.module._guessed_names.discard(FuncName)
|
||
new_func: ir.Function = ir.Function(Gen.module, NewFuncType, name=MangledName)
|
||
Gen.functions[MangledName] = new_func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = new_func
|
||
return new_func
|
||
except Exception as ex:
|
||
traceback.print_exc()
|
||
Gen.functions[MangledName] = old_func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = old_func
|
||
return old_func
|
||
|
||
def _EmitFunctionLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, ir.Type]] | None = None) -> ir.Function | None:
|
||
if self._is_generic_function(Node):
|
||
return
|
||
FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName)
|
||
# 保存父级 _CurrentCpythonObjectClass,防止嵌套函数发射污染父方法类上下文
|
||
# (例如 HandleImport body 内触发 list[ast.ASTptr] 方法发射,结束后会清空 _CurrentCpythonObjectClass)
|
||
saved_cpython_class: str | None = self.Trans._CurrentCpythonObjectClass
|
||
CReturnTypes = []
|
||
IsPtr = False
|
||
fn_attrs = {}
|
||
# 自定义行为装饰器列表,用于生成 wrapper 函数
|
||
# 任何 @name 或 @name(args) 只要不是内置装饰器,都视为自定义行为装饰器
|
||
behavior_decorators = []
|
||
# 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器
|
||
_BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod'}
|
||
_symtab: object = self.Trans.SymbolTable
|
||
if Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
# 跳过 t 模块存储类标记装饰器(@t.CExport / @CExport 等)
|
||
if self._is_t_storage_decorator(decorator, _symtab):
|
||
continue
|
||
# 识别自定义行为装饰器:@name(ast.Name 形式)
|
||
if isinstance(decorator, ast.Name):
|
||
if decorator.id not in _BUILTIN_DECORATORS:
|
||
behavior_decorators.append({'name': decorator.id, 'args': [], 'kwargs': {}})
|
||
continue
|
||
# 识别带参数的自定义行为装饰器:@name(arg1, key=val)(ast.Call + ast.Name 形式)
|
||
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Name):
|
||
deco_name = decorator.func.id
|
||
if deco_name not in _BUILTIN_DECORATORS:
|
||
deco_info = {'name': deco_name, 'args': [], 'kwargs': {}}
|
||
for arg in decorator.args:
|
||
if isinstance(arg, ast.Constant):
|
||
deco_info['args'].append(arg.value)
|
||
for kw in decorator.keywords:
|
||
if isinstance(kw.value, ast.Constant):
|
||
deco_info['kwargs'][kw.arg] = kw.value.value
|
||
behavior_decorators.append(deco_info)
|
||
continue
|
||
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
|
||
if decorator.func.attr == 'CReturn':
|
||
for arg in decorator.args:
|
||
CReturnTypes.append(arg)
|
||
elif decorator.func.attr == 'Attribute' and isinstance(decorator.func.value, ast.Name) and decorator.func.value.id == 'c':
|
||
for arg in decorator.args:
|
||
if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute):
|
||
if isinstance(arg.func.value, ast.Attribute) and isinstance(arg.func.value.value, ast.Name) and IsTModule(arg.func.value.value.id, self.Trans.SymbolTable) and arg.func.value.attr == 'attr':
|
||
attr_name = arg.func.attr
|
||
str_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, str)]
|
||
int_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, int)]
|
||
if attr_name == 'section' and str_args:
|
||
fn_attrs['section'] = str_args[0]
|
||
elif attr_name == 'aligned' and int_args:
|
||
fn_attrs['aligned'] = int_args[0]
|
||
elif attr_name == 'visibility' and str_args:
|
||
fn_attrs['visibility'] = str_args[0]
|
||
elif attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough'):
|
||
if not arg.args:
|
||
fn_attrs[attr_name] = True
|
||
elif isinstance(arg.func.value, ast.Attribute) and arg.func.value.attr == 'llvm' and isinstance(arg.func.value.value, ast.Attribute) and arg.func.value.value.attr == 'attr' and isinstance(arg.func.value.value.value, ast.Name) and IsTModule(arg.func.value.value.value.id, self.Trans.SymbolTable):
|
||
llvm_attr_name = arg.func.attr
|
||
if llvm_attr_name in self._LLVM_ATTR_NAMES:
|
||
fn_attrs[f'llvm.{llvm_attr_name}'] = True
|
||
elif isinstance(arg, ast.Attribute):
|
||
if isinstance(arg.value, ast.Attribute) and isinstance(arg.value.value, ast.Name) and IsTModule(arg.value.value.id, self.Trans.SymbolTable) and arg.value.attr == 'attr':
|
||
attr_name = arg.attr
|
||
if attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough', 'packed'):
|
||
fn_attrs[attr_name] = True
|
||
elif isinstance(arg.value, ast.Attribute) and arg.value.attr == 'llvm' and isinstance(arg.value.value, ast.Attribute) and arg.value.value.attr == 'attr' and isinstance(arg.value.value.value, ast.Name) and IsTModule(arg.value.value.value.id, self.Trans.SymbolTable):
|
||
llvm_attr_name = arg.attr
|
||
if llvm_attr_name in self._LLVM_ATTR_NAMES:
|
||
fn_attrs[f'llvm.{llvm_attr_name}'] = True
|
||
# 检查 @t.TLS 装饰器(一次性初始化标记)
|
||
is_tls_func: bool = False
|
||
if Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||
if IsTModule(decorator.value.id, _symtab) and decorator.attr == 'TLS':
|
||
is_tls_func = True
|
||
break
|
||
elif isinstance(decorator, ast.Name) and decorator.id == 'TLS' and hasattr(t, 'TLS'):
|
||
is_tls_func = True
|
||
break
|
||
if Node.returns:
|
||
if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple':
|
||
slice_node = Node.returns.slice
|
||
if isinstance(slice_node, ast.Tuple):
|
||
for elt in slice_node.elts:
|
||
CReturnTypes.append(elt)
|
||
else:
|
||
CReturnTypes.append(slice_node)
|
||
|
||
# 先强制检查 str 类型注解
|
||
is_str_return = False
|
||
ReturnTypeInfo = None
|
||
if Node.returns:
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_return = True
|
||
else:
|
||
try:
|
||
rt_info = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
if rt_info and rt_info.IsStr:
|
||
is_str_return = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
|
||
if is_str_return:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
elif Node.returns:
|
||
if CReturnTypes:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
else:
|
||
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()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
|
||
def _FindNonVoidCTypeInfo(node):
|
||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
results = []
|
||
for child in [node.left, node.right]:
|
||
r = _FindNonVoidCTypeInfo(child)
|
||
if r and not r.IsVoid:
|
||
results.append(r)
|
||
for r in results:
|
||
if not r.IsPtr and not r.IsStruct:
|
||
return r
|
||
return results[0] if results else None
|
||
try:
|
||
SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
|
||
if SideInfo:
|
||
return SideInfo
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
return None
|
||
found = _FindNonVoidCTypeInfo(Node.returns)
|
||
if found and not found.IsVoid:
|
||
ReturnTypeInfo = found
|
||
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
else:
|
||
is_str_type = False
|
||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||
is_str_type = True
|
||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
if not hasattr(self, '_cdefine_funcs'):
|
||
self._cdefine_funcs = set()
|
||
self._cdefine_funcs.add(FuncName)
|
||
elif ReturnTypeInfo and ReturnTypeInfo.IsState:
|
||
pass # t.State is a modifier, preserve the actual return type
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CVoid()
|
||
if is_str_type or ReturnTypeInfo.IsStr:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
# 检查泛型类返回类型 (如 list[str])
|
||
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
|
||
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 t.CVoid 实例),需额外检测 BaseType is None
|
||
if (isinstance(Node.returns, ast.Subscript)
|
||
and isinstance(Node.returns.value, ast.Name)
|
||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||
and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates
|
||
and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0):
|
||
ret_class: str = Node.returns.value.id
|
||
ret_slice: ast.AST = Node.returns.slice
|
||
ret_type_args: list[str] = []
|
||
ret_type_names: list[str] = []
|
||
if isinstance(ret_slice, ast.Tuple):
|
||
for elt in ret_slice.elts:
|
||
if isinstance(elt, ast.Name):
|
||
tn2: str = elt.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
elif isinstance(ret_slice, ast.Name):
|
||
tn2: str = ret_slice.id
|
||
ts2: str = tn2
|
||
if tn2 == 'int':
|
||
ts2, tn2 = 'int', 'CInt'
|
||
ret_type_args.append(ts2)
|
||
ret_type_names.append(tn2)
|
||
# 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True
|
||
# 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册,
|
||
# 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。
|
||
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
|
||
if spec_name2 and spec_name2 in Gen.structs:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CStruct(name=spec_name2)
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
except Exception: # 回退:设置默认返回类型为 CInt
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
else:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||
if inferred:
|
||
ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0])
|
||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||
|
||
ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
|
||
if isinstance(ReturnType, ir.VoidType) and FuncName == 'main':
|
||
ReturnType = ir.IntType(32)
|
||
IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen)
|
||
# __new__ methods should return a pointer to the struct (for heap allocation replacement)
|
||
if RawFuncName == '__new__' and ResolvedClassName:
|
||
StructType = Gen.structs.get(ResolvedClassName)
|
||
if StructType:
|
||
if isinstance(StructType, ir.PointerType):
|
||
ReturnType = StructType
|
||
else:
|
||
ReturnType = ir.PointerType(StructType)
|
||
ParamTypes = []
|
||
ParamNames = []
|
||
ParamTypeStrs = []
|
||
auto_addr_modes_emit: list[str | None] = []
|
||
self.Trans.VarScopes.append({})
|
||
for Arg in Node.args.args:
|
||
ParamIsUnsigned = False
|
||
if Arg.annotation:
|
||
try:
|
||
ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CInt()
|
||
IsPtr = ParamTypeInfo.IsPtr
|
||
if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr:
|
||
IsPtr = True
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
if ParamTypeInfo.IsStr or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CChar()
|
||
ParamTypeInfo.PtrCount = 1
|
||
IsPtr = True
|
||
# C 语言中数组参数退化为指针:list[type, N] → type*
|
||
if ParamTypeInfo.ArrayDims:
|
||
ParamTypeInfo.ArrayDims = []
|
||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||
if isinstance(ParamType, ir.VoidType):
|
||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||
raise SyntaxError(
|
||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||
f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。"
|
||
)
|
||
if ParamTypeInfo and ParamTypeInfo.IsFuncPtr:
|
||
ParamType = ir.IntType(8).as_pointer()
|
||
ParamIsUnsigned = ParamTypeInfo.IsUInt
|
||
except SyntaxError:
|
||
raise
|
||
except Exception: # 回退:参数类型解析失败时使用默认 i32
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CInt()
|
||
else:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeInfo = CTypeInfo()
|
||
ParamTypeInfo.BaseType = t.CInt()
|
||
ParamTypes.append(ParamType)
|
||
ParamNames.append(Arg.arg)
|
||
ParamTypeStrs.append(ParamTypeInfo)
|
||
# 检测 t.CNeedPtr / t.CAutoPtr 参数注解
|
||
auto_mode_emit: str | None = None
|
||
if ParamTypeInfo is not None and hasattr(ParamTypeInfo, 'BaseType') and ParamTypeInfo.BaseType is not None:
|
||
if isinstance(ParamTypeInfo.BaseType, t.CAutoPtr):
|
||
auto_mode_emit = 'always'
|
||
elif isinstance(ParamTypeInfo.BaseType, t.CNeedPtr):
|
||
auto_mode_emit = 'need'
|
||
auto_addr_modes_emit.append(auto_mode_emit)
|
||
Gen._record_var_signedness(Arg.arg, ParamIsUnsigned)
|
||
self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo
|
||
if Arg.annotation:
|
||
try:
|
||
PInfo = self.ResolveAnnotationType(Arg.annotation)
|
||
if PInfo and (PInfo.DataConst or PInfo.VarConst):
|
||
Gen.var_const_flags[Arg.arg] = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
if CReturnTypes:
|
||
CReturnLlvmTypes = []
|
||
for i, ReturnTypeNode in enumerate(CReturnTypes):
|
||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||
if ReturnTypeInfo and ReturnTypeInfo.IsStr:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CChar()
|
||
ReturnTypeInfo.PtrCount = 1
|
||
if ReturnTypeInfo is None:
|
||
ReturnTypeInfo = CTypeInfo()
|
||
ReturnTypeInfo.BaseType = t.CInt()
|
||
RetType = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
CReturnLlvmTypes.append(RetType)
|
||
ReturnType = ir.LiteralStructType(CReturnLlvmTypes)
|
||
self.Trans.CurrentCReturnTypes = CReturnTypes
|
||
else:
|
||
self.Trans.CurrentCReturnTypes = None
|
||
self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen)
|
||
IsVariadic = Node.args.vararg is not None
|
||
if extra_params:
|
||
for var_name, ptr_type in extra_params:
|
||
ParamTypes.append(ptr_type)
|
||
ParamNames.append(f'__nonlocal_{var_name}__')
|
||
HasStopIterFlag = False
|
||
if IsMethod and RawFuncName == '__next__':
|
||
ParamTypes.append(ir.PointerType(ir.IntType(1)))
|
||
ParamNames.append('__stop_iter_flag__')
|
||
HasStopIterFlag = True
|
||
HasRaise = self._body_contains_raise(Node.body)
|
||
if HasRaise and RawFuncName != 'main':
|
||
ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8))))
|
||
ParamNames.append('__eh_msg_out__')
|
||
ParamTypes.append(ir.PointerType(ir.IntType(32)))
|
||
ParamNames.append('__eh_code_out__')
|
||
FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic)
|
||
# 存储 auto_addr_modes(为额外参数补 None)
|
||
total_params_emit: int = len(ParamTypes)
|
||
while len(auto_addr_modes_emit) < total_params_emit:
|
||
auto_addr_modes_emit.append(None)
|
||
Gen._auto_addr_params[FuncName] = auto_addr_modes_emit
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
IsInlineFunc = False
|
||
IsExternFunc = False
|
||
IsStateFunc = False
|
||
IsUserMarkedExport: bool = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo = None
|
||
RetTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CInline):
|
||
IsInlineFunc = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern):
|
||
IsExternFunc = True
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
IsStateFunc = True
|
||
Gen._export_funcs.add(FuncName) # 外部 C 函数声明必须保持原始名称
|
||
IsUserMarkedExport = True
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
# 装饰器形式的存储类标记(@t.CExport / @t.CExtern / @t.CStatic / @t.State / @t.CInline)
|
||
deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node)
|
||
if deco_flags['is_inline']:
|
||
IsInlineFunc = True
|
||
if deco_flags['is_extern']:
|
||
IsExternFunc = True
|
||
if deco_flags['is_state']:
|
||
IsStateFunc = True
|
||
if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']:
|
||
Gen._export_funcs.add(FuncName)
|
||
IsUserMarkedExport = True
|
||
# 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查
|
||
Gen._current_module_func_names.add(FuncName)
|
||
# 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数)
|
||
if not IsUserMarkedExport and FuncName in Gen._export_funcs:
|
||
Gen._export_funcs.discard(FuncName)
|
||
MangledName = Gen._mangle_func_name(FuncName)
|
||
if MangledName in Gen.functions:
|
||
func = Gen.functions[MangledName]
|
||
if getattr(func, 'name', MangledName) != MangledName:
|
||
func = ir.Function(Gen.module, FuncType, name=MangledName)
|
||
Gen.functions[MangledName] = func
|
||
else:
|
||
existing_type = getattr(func, 'ftype', None)
|
||
if existing_type and existing_type != FuncType:
|
||
func = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
else:
|
||
func = ir.Function(Gen.module, FuncType, name=MangledName)
|
||
Gen.functions[MangledName] = func
|
||
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
|
||
Gen.functions[FuncName] = func
|
||
func.attributes.add('noredzone')
|
||
if IsInlineFunc:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs:
|
||
func.linkage = 'linkonce_odr'
|
||
func.attributes.add('alwaysinline')
|
||
if fn_attrs:
|
||
_LLVM_FN_ATTR_MAP = {
|
||
'noreturn': 'noreturn',
|
||
'always_inline': 'alwaysinline',
|
||
'noinline': 'noinline',
|
||
'cold': 'cold',
|
||
'hot': 'hot',
|
||
'constructor': 'constructor',
|
||
'destructor': 'destructor',
|
||
'malloc': 'malloc',
|
||
'returns_nonnull': 'returns_nonnull',
|
||
'used': 'used',
|
||
'naked': 'naked',
|
||
'no_instrument_function': 'no_instrument_function',
|
||
'warn_unused_result': 'warn_unused_result',
|
||
'fallthrough': 'fallthrough',
|
||
'pure': 'readonly',
|
||
'const': 'readnone',
|
||
}
|
||
if 'section' in fn_attrs:
|
||
func.section = fn_attrs['section']
|
||
if 'visibility' in fn_attrs:
|
||
func.linkage = 'internal'
|
||
func.attributes.add('visibility')
|
||
if fn_attrs.get('weak'):
|
||
func.linkage = 'weak'
|
||
for attr_name, llvm_name in _LLVM_FN_ATTR_MAP.items():
|
||
if fn_attrs.get(attr_name):
|
||
try:
|
||
func.attributes.add(llvm_name)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
|
||
for key in fn_attrs:
|
||
if key.startswith('llvm.'):
|
||
llvm_attr_name = key[5:]
|
||
try:
|
||
func.attributes.add(llvm_attr_name)
|
||
except Exception as _e:
|
||
# llvmlite 不支持某些较新的 LLVM 属性(如 willreturn, mustprogress)
|
||
# 记录下来,后续通过 IR 后处理添加
|
||
if not hasattr(Gen, '_pending_str_attrs'):
|
||
Gen._pending_str_attrs = {}
|
||
Gen._pending_str_attrs.setdefault(MangledName, []).append(llvm_attr_name)
|
||
if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs:
|
||
for attr_name in self._pending_llvm_attrs.pop(FuncName):
|
||
try:
|
||
func.attributes.add(attr_name)
|
||
except Exception as _e:
|
||
# llvmlite 不支持的属性,记录下来后续通过 IR 后处理添加
|
||
if not hasattr(Gen, '_pending_str_attrs'):
|
||
Gen._pending_str_attrs = {}
|
||
Gen._pending_str_attrs.setdefault(MangledName, []).append(attr_name)
|
||
# 记录自定义行为装饰器信息,供 DecoratorPass 使用
|
||
if behavior_decorators:
|
||
Gen._decorated_funcs[MangledName] = {
|
||
'decorators': behavior_decorators,
|
||
'func_name': FuncName,
|
||
'func_type': FuncType,
|
||
'return_type': FuncType.return_type,
|
||
'param_types': [p.type for p in func.args],
|
||
'param_names': ParamNames,
|
||
'is_export': FuncName in Gen._export_funcs,
|
||
}
|
||
if IsExternFunc or IsStateFunc:
|
||
return
|
||
# 治本修复:如果函数已经有 body(blocks 不为空),跳过重复编译。
|
||
# 否则会导致同一函数被追加第二个 entry block(llvmlite 自动重命名为 entry.1),
|
||
# 产生非法 IR:两个 entry block + 第二个 block 无前驱成为死代码。
|
||
# 触发场景:泛型特化路径 _EmitGenericSpecialization 先调用 _EmitFunctionForwardDeclLlvm
|
||
# 再调用 _EmitFunctionLlvm,若特化在多个调用点被重复触发(如 list[str] 在 split/upper 等多处使用),
|
||
# 同一 MangledName 会进入此函数两次,第二次会重复追加 entry block。
|
||
existing_blocks: list = getattr(func, 'blocks', [])
|
||
if existing_blocks:
|
||
return func
|
||
EntryBlock = func.append_basic_block(name="entry")
|
||
Gen.builder = ir.IRBuilder(EntryBlock)
|
||
Gen.func = func
|
||
Gen.variables = {}
|
||
Gen._reg_values = {}
|
||
Gen.global_vars = set()
|
||
if 'aligned' in fn_attrs:
|
||
Gen._emit_stack_align(fn_attrs['aligned'])
|
||
# 保存当前的 var_type_info,以便函数结束时恢复
|
||
saved_var_type_info = Gen.var_type_info.copy()
|
||
saved_var_type_assignments = Gen.var_type_assignments.copy()
|
||
# 治本修复:保存并清空 _local_heap_ptrs / _var_to_heap_ptr。
|
||
# 当 with 上下文中的代码(如 s1.split(','))触发内联编译 list[str].__new__ 时,
|
||
# 若不清空,__new__ 方法会继承外层 with 的 _local_heap_ptrs(含 %call_enter 条目),
|
||
# 方法结束时 _emit_local_heap_frees 会尝试 bitcast/free %call_enter,
|
||
# 但该值在 __new__ 作用域中不存在 → llc 报错 'use of undefined value'。
|
||
saved_local_heap_ptrs = list(Gen._local_heap_ptrs)
|
||
saved_var_to_heap_ptr = dict(Gen._var_to_heap_ptr)
|
||
Gen._local_heap_ptrs = []
|
||
Gen._var_to_heap_ptr = {}
|
||
# 治本修复:保存 var_struct_class / global_struct_class。
|
||
# 当方法调用(如 a.delete())触发 _try_complete_generic_specialization 时,
|
||
# 该路径走 _EmitFunctionLlvm 编译方法体,函数结尾会清空 var_struct_class。
|
||
# 若不保存/恢复,外层函数中已设置的 var_struct_class(如 b='ndarray[double]')
|
||
# 会被清空,导致后续方法调用 fallback 匹配 opaque 基础类型(如 ndarray),
|
||
# 生成对 stub declare(无方法体)的调用 → 链接报 undefined reference。
|
||
saved_var_struct_class = dict(Gen.var_struct_class) if Gen.var_struct_class else {}
|
||
saved_global_struct_class = dict(Gen.global_struct_class) if getattr(Gen, 'global_struct_class', None) else {}
|
||
# 函数内部定义的变量会在赋值时添加到 var_type_info 中
|
||
# 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理
|
||
for stmt in Node.body:
|
||
if isinstance(stmt, ast.Global):
|
||
self.Trans.ForHandler._RegisterGlobalNames(stmt.names, Gen)
|
||
for param, param_name in zip(func.args, ParamNames):
|
||
param.name = param_name
|
||
if param_name == '__stop_iter_flag__':
|
||
Gen._stop_iter_flag_param = param
|
||
Gen.builder.store(ir.Constant(ir.IntType(1), 0), param)
|
||
elif param_name.startswith('__nonlocal_') and param_name.endswith('__'):
|
||
var_name = param_name[len('__nonlocal_'):-2]
|
||
Gen.variables[var_name] = param
|
||
else:
|
||
if isinstance(param.type, ir.PointerType) and isinstance(param.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
var = Gen.builder.alloca(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
for CN, ST in Gen.structs.items():
|
||
if param.type.pointee == ST or (isinstance(param.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.pointee.name == ST.name):
|
||
Gen.var_struct_class[param_name] = CN
|
||
break
|
||
elif isinstance(param.type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
var = Gen.builder.alloca(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
for CN, ST in Gen.structs.items():
|
||
if param.type == ST or (isinstance(param.type, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.name == ST.name):
|
||
Gen.var_struct_class[param_name] = CN
|
||
break
|
||
else:
|
||
# 所有参数都存入 alloca,确保循环体中对参数的修改能正确反映
|
||
var = Gen._allocaEntry(param.type, name=param_name)
|
||
Gen._store(param, var)
|
||
Gen.variables[param_name] = var
|
||
# 为联合类型注解(如 Function | t.CPtr)的参数设置 var_struct_class,
|
||
# 确保编译器能正确生成 GEP 访问结构体成员(如 func.Blocks、func.Params)
|
||
for i, arg in enumerate(Node.args.args):
|
||
if arg.annotation and isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
|
||
param_name: str = ParamNames[i] if i < len(ParamNames) else arg.arg
|
||
if param_name in Gen.variables:
|
||
# 若 L1650-1657 已根据 param.type.pointee 匹配到正确的特化名
|
||
# (如 ndarray[double]),不覆盖:FindStructNameInAnnotation 对
|
||
# 泛型注解 ndarray[t.CDouble] 会构造 ndarray[CDouble](与实际
|
||
# ndarray[double] 不匹配),回退到裸模板类名 ndarray(opaque),
|
||
# 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。
|
||
if param_name in Gen.var_struct_class:
|
||
continue
|
||
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
|
||
if found_struct:
|
||
Gen.var_struct_class[param_name] = found_struct
|
||
if ResolvedClassName and (IsMethod or RawFuncName == '__init__'):
|
||
self.Trans._CurrentCpythonObjectClass = ResolvedClassName
|
||
Gen._variadic_info = None
|
||
if IsVariadic and Node.args.vararg:
|
||
vararg_name = getattr(Node.args.vararg, 'arg', 'args')
|
||
last_param_name = ParamNames[-1] if ParamNames else None
|
||
last_param_ptr = None
|
||
for param, pn in zip(func.args, ParamNames):
|
||
if pn == last_param_name:
|
||
last_param_ptr = param
|
||
break
|
||
triple = getattr(Gen, 'module_triple', '') or getattr(Gen.module, 'triple', '')
|
||
is_windows = 'windows' in triple if triple else False
|
||
ptr_size = getattr(Gen, 'ptr_size', 8)
|
||
# va_list 大小取决于 ABI:Windows x64 = 1个指针,Linux x64 = __va_list_tag[1](24字节)
|
||
# 32位平台:Windows = 4字节指针,Linux = 12字节
|
||
if ptr_size == 4:
|
||
va_list_size = 4 if is_windows else 12
|
||
va_list_align = 4
|
||
else:
|
||
va_list_size = 8 if is_windows else 24
|
||
va_list_align = 8 if is_windows else 16
|
||
va_list_type = ir.ArrayType(ir.IntType(8), va_list_size)
|
||
va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align)
|
||
va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr")
|
||
Gen._variadic_info = {
|
||
'vararg_name': vararg_name,
|
||
'va_list_ptr': va_list_ptr,
|
||
'last_param_ptr': last_param_ptr,
|
||
'va_start_called': False,
|
||
}
|
||
if last_param_ptr:
|
||
last_param_alloc = Gen._allocaEntry(last_param_ptr.type, name="last_param_copy")
|
||
Gen.builder.store(last_param_ptr, last_param_alloc)
|
||
Gen.emit_va_start(va_list_ptr)
|
||
Gen._variadic_info['va_start_called'] = True
|
||
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
|
||
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
|
||
Gen._direct_values[vararg_name] = va_list_ptr
|
||
# @t.TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回
|
||
if is_tls_func:
|
||
flag_name: str = f"__tls_init_done_{FuncName}"
|
||
flag_global = None
|
||
for gv in Gen.module.global_values:
|
||
if gv.name == flag_name:
|
||
flag_global = gv
|
||
break
|
||
if flag_global is None:
|
||
flag_global = ir.GlobalVariable(Gen.module, ir.IntType(1), name=flag_name)
|
||
flag_global.initializer = ir.Constant(ir.IntType(1), 0)
|
||
flag_global.linkage = 'internal'
|
||
flag_val = Gen.builder.load(flag_global, name="tls_flag_check")
|
||
skip_bb = func.append_basic_block("tls_skip")
|
||
cont_bb = func.append_basic_block("tls_continue")
|
||
Gen.builder.cbranch(flag_val, skip_bb, cont_bb)
|
||
Gen.builder.position_at_end(skip_bb)
|
||
ActualReturnType = func.function_type.return_type
|
||
if isinstance(ActualReturnType, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(ActualReturnType, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0))
|
||
elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0.0))
|
||
elif isinstance(ActualReturnType, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
else:
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
Gen.builder.position_at_end(cont_bb)
|
||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global)
|
||
_saved_class_name = getattr(Gen, '_current_class_name', None)
|
||
Gen._current_class_name = ClassName
|
||
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
|
||
func_body: list[ast.stmt] = Node.body
|
||
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
|
||
if (func_body and isinstance(func_body[0], ast.Expr)
|
||
and isinstance(func_body[0].value, ast.Constant)
|
||
and isinstance(func_body[0].value.value, str)):
|
||
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
|
||
func_body = func_body[1:]
|
||
else:
|
||
Gen._create_doc_global(doc_symbol, None)
|
||
try:
|
||
self.Trans.BodyHandler.HandleBodyLlvm(func_body)
|
||
except Exception as _body_exc:
|
||
# 方法体编译失败:确保 block 终止(防止 expected instruction opcode 错误),
|
||
# 然后重新抛出异常让编译立即终止(不吞掉错误)
|
||
_fn_name: str = Node.name
|
||
_cls_name: str = ClassName if ClassName else ''
|
||
import sys as _sys
|
||
import traceback as _tb
|
||
print(f"[FATAL] 方法体编译失败 ({_cls_name}.{_fn_name}): {type(_body_exc).__name__}: {_body_exc}", file=_sys.stderr)
|
||
_tb.print_exc(file=_sys.stderr)
|
||
if Gen.builder is not None:
|
||
try:
|
||
if not Gen.builder.block.is_terminated:
|
||
_ret_ty = func.function_type.return_type
|
||
if isinstance(_ret_ty, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(_ret_ty, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(_ret_ty, None))
|
||
elif isinstance(_ret_ty, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(_ret_ty, 0))
|
||
else:
|
||
Gen.builder.ret(ir.Constant(_ret_ty, None))
|
||
except Exception:
|
||
try:
|
||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||
Gen.builder.ret_void()
|
||
except Exception:
|
||
pass
|
||
raise
|
||
if not Gen.builder.block.is_terminated:
|
||
if 'naked' in fn_attrs:
|
||
Gen.builder.unreachable()
|
||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||
return
|
||
Gen._emit_local_heap_frees()
|
||
if Gen._variadic_info and Gen._variadic_info.get('va_start_called'):
|
||
va_list_ptr = Gen._variadic_info.get('va_list_ptr')
|
||
if va_list_ptr:
|
||
Gen.emit_va_end(va_list_ptr)
|
||
ActualReturnType = func.function_type.return_type
|
||
if isinstance(ActualReturnType, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
elif isinstance(ActualReturnType, ir.IntType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0))
|
||
elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, 0.0))
|
||
elif isinstance(ActualReturnType, ir.PointerType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
elif isinstance(ActualReturnType, ir.IdentifiedStructType):
|
||
if ActualReturnType.elements:
|
||
zero_val = ir.Constant(ActualReturnType, [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 ActualReturnType.elements])
|
||
else:
|
||
zero_val = ir.Constant(ActualReturnType, None)
|
||
Gen.builder.ret(zero_val)
|
||
elif isinstance(ActualReturnType, ir.ArrayType):
|
||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||
else:
|
||
Gen.builder.ret_void()
|
||
Gen.builder = None
|
||
Gen.func = None
|
||
Gen._current_class_name = _saved_class_name
|
||
Gen.variables = {}
|
||
Gen.var_signedness = {}
|
||
Gen._reg_values = {}
|
||
Gen._direct_values = {}
|
||
Gen.var_struct_class = {}
|
||
Gen.var_ptr_element = {}
|
||
Gen.var_const_flags = {}
|
||
# 恢复保存的 var_type_info
|
||
Gen.var_type_info = saved_var_type_info
|
||
Gen.var_type_assignments = saved_var_type_assignments
|
||
Gen._stop_iter_flag_param = None
|
||
# 恢复外层作用域的 _local_heap_ptrs / _var_to_heap_ptr
|
||
Gen._local_heap_ptrs = saved_local_heap_ptrs
|
||
Gen._var_to_heap_ptr = saved_var_to_heap_ptr
|
||
# 恢复外层作用域的 var_struct_class / global_struct_class
|
||
# (内层方法体编译不应污染外层函数的变量-类型映射)
|
||
Gen.var_struct_class = saved_var_struct_class
|
||
if hasattr(Gen, 'global_struct_class'):
|
||
Gen.global_struct_class = saved_global_struct_class
|
||
Gen._variadic_info = None
|
||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||
self.Trans.CurrentCReturnTypes = None
|
||
if self.Trans.VarScopes:
|
||
self.Trans.VarScopes.pop()
|
||
self.Trans.FunctionReturnTypes[FuncName] = ReturnTypeInfo
|
||
if not self.Trans.SymbolTable.has(FuncName):
|
||
FuncInfo = CTypeInfo()
|
||
FuncInfo.Name = FuncName
|
||
FuncInfo.IsFunction = True
|
||
FuncInfo.MetaList = func_meta
|
||
if IsInlineFunc:
|
||
FuncInfo.IsInline = True
|
||
FuncInfo.InlineBody = Node.body
|
||
FuncInfo.InlineParams = [arg.arg for arg in Node.args.args]
|
||
self.Trans.SymbolTable.insert(FuncName, FuncInfo)
|
||
else:
|
||
existing = self.Trans.SymbolTable[FuncName]
|
||
if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
|
||
existing.MetaList = func_meta
|
||
if IsInlineFunc:
|
||
existing.IsInline = True
|
||
existing.InlineBody = Node.body
|
||
existing.InlineParams = [arg.arg for arg in Node.args.args]
|
||
# property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList
|
||
if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
|
||
BasePropKey = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName
|
||
base_existing = self.Trans.SymbolTable.lookup(BasePropKey)
|
||
if base_existing:
|
||
if func_meta != FuncMeta.NONE:
|
||
base_existing.MetaList = base_existing.MetaList | func_meta
|
||
else:
|
||
PropInfo = CTypeInfo()
|
||
PropInfo.Name = BasePropKey
|
||
PropInfo.IsFunction = True
|
||
PropInfo.MetaList = func_meta
|
||
self.Trans.SymbolTable.insert(BasePropKey, PropInfo)
|
||
return func
|