1421 lines
80 KiB
Python
1421 lines
80 KiB
Python
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
|
||
import ast
|
||
import llvmlite.ir as ir
|
||
|
||
|
||
class FunctionHandle(BaseHandle):
|
||
@staticmethod
|
||
def _ExtractFuncMeta(decorator_list) -> FuncMeta:
|
||
meta = 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 _body_contains_raise(self, body):
|
||
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 = 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 = self.Trans.LlvmGen
|
||
for prefix in ['', f'{called_name}.', f'__']:
|
||
for suffix in ['', f'.{called_name}']:
|
||
fname = f'{prefix}{called_name}{suffix}'
|
||
if fname in Gen.functions:
|
||
func = 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):
|
||
attrs = []
|
||
if isinstance(node, ast.BinOp):
|
||
attrs.extend(self._ExtractLLVMAttrs(node.left))
|
||
attrs.extend(self._ExtractLLVMAttrs(node.right))
|
||
elif isinstance(node, ast.Attribute):
|
||
attr_name = self._GetAttrLLVMName(node)
|
||
if attr_name:
|
||
attrs.append(attr_name)
|
||
return attrs
|
||
|
||
def _GetAttrLLVMName(self, node):
|
||
if not isinstance(node, ast.Attribute):
|
||
return None
|
||
if node.attr not in self._LLVM_ATTR_NAMES:
|
||
return None
|
||
value = node.value
|
||
if not isinstance(value, ast.Attribute) or value.attr != 'llvm':
|
||
return None
|
||
inner = 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, Gen=None, ClassName=None):
|
||
local_var_types = {}
|
||
for child in ast.walk(Node):
|
||
if isinstance(child, ast.Assign) and len(child.targets) == 1:
|
||
target = child.targets[0]
|
||
if isinstance(target, ast.Name) and isinstance(child.value, ast.Subscript):
|
||
sub = 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 = 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 = 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 = 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 = 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 = 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 = val.func.id
|
||
if callee == 'malloc':
|
||
return ('char', True)
|
||
if callee == 'chr':
|
||
return ('char', False)
|
||
if Gen and callee in Gen.functions:
|
||
func = Gen.functions[callee]
|
||
if hasattr(func, 'ftype'):
|
||
ret_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 = 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 = self.Trans.SymbolTable.get(callee_name)
|
||
if sym and isinstance(sym, dict):
|
||
ret_type_str = sym.get('return_type', '')
|
||
if ret_type_str and ret_type_str != 'int':
|
||
IsPtr = 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 = val.id
|
||
if var_name in local_var_types:
|
||
return local_var_types[var_name]
|
||
var_info = self.Trans.SymbolTable.get(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type = var_info.get('type', '')
|
||
if var_type and var_type != 'int':
|
||
IsPtr = 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 = 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 = 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 = 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 = 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 = val.value.id
|
||
var_info = self.Trans.SymbolTable.get(var_name)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type = var_info.get('type', '')
|
||
if var_type.startswith('list[') or var_type.startswith('List['):
|
||
inner = var_type[var_type.index('[') + 1:var_type.rindex(']')]
|
||
parts = inner.split(',')
|
||
elem_type_str = parts[0].strip()
|
||
if elem_type_str and elem_type_str != 'int':
|
||
IsPtr = var_info.get('IsPtr', False)
|
||
return (elem_type_str, IsPtr)
|
||
return None
|
||
|
||
def _GetFunctionSignatureLlvm(self, Node, Gen, ClassName=None, extra_params=None):
|
||
RawFuncName = Node.name
|
||
if ClassName:
|
||
FuncName = f"{ClassName}.{RawFuncName}"
|
||
else:
|
||
FuncName = RawFuncName
|
||
# property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突
|
||
func_meta = self._ExtractFuncMeta(Node.decorator_list)
|
||
if FuncMeta.PROPERTY_SETTER in func_meta:
|
||
FuncName = FuncName + '$set'
|
||
elif FuncMeta.PROPERTY_DELETER in func_meta:
|
||
FuncName = FuncName + '$del'
|
||
CReturnTypes = []
|
||
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 = 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 = Node.returns.slice
|
||
if isinstance(slice_node, ast.Tuple):
|
||
for elt in slice_node.elts:
|
||
CReturnTypes.append(elt)
|
||
else:
|
||
CReturnTypes.append(slice_node)
|
||
IsPtr = False
|
||
ReturnTypeInfo = 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):
|
||
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 __import__('lib.constants.config', fromlist=['mode']).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:
|
||
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
|
||
if ReturnTypeInfo.IsVoid 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
|
||
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||
ReturnType = 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 = False
|
||
IsClassMethod = False
|
||
ResolvedClassName = ClassName
|
||
func_meta = self._ExtractFuncMeta(Node.decorator_list)
|
||
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
|
||
ParamTypes = []
|
||
ParamNames = []
|
||
ParamTypeStrs = []
|
||
CReturnLlvmTypes = []
|
||
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 = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||
CReturnLlvmTypes.append(RetType)
|
||
ReturnType = ir.LiteralStructType(CReturnLlvmTypes)
|
||
for Arg in Node.args.args:
|
||
if Arg.annotation:
|
||
try:
|
||
if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||
ParamTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
else:
|
||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
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
|
||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
ParamTypeStr = ParamTypeInfo
|
||
except Exception as e:
|
||
ParamType = ir.IntType(32)
|
||
ParamTypeStr = CTypeInfo()
|
||
ParamTypeStr.BaseType = t.CInt()
|
||
else:
|
||
if ClassName and Arg.arg != 'self':
|
||
op_method_names = ['__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)
|
||
if IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
else:
|
||
ParamTypes.insert(0, StructPtrType)
|
||
ParamNames.insert(0, "self")
|
||
ParamTypeStrs.insert(0, f"struct {ResolvedClassName}")
|
||
elif not IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs:
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
# @classmethod: 将 cls 参数设为类指针类型
|
||
if IsClassMethod:
|
||
ClsIdx = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1)
|
||
if ClsIdx >= 0:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
ParamTypes[ClsIdx] = StructPtrType
|
||
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}__')
|
||
if IsMethod and RawFuncName == '__next__':
|
||
ParamTypes.append(ir.PointerType(ir.IntType(1)))
|
||
ParamNames.append('__stop_iter_flag__')
|
||
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)
|
||
return FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic
|
||
|
||
def _is_generic_function(self, Node):
|
||
if hasattr(Node, 'type_params') and Node.type_params:
|
||
return True
|
||
return False
|
||
|
||
def _mangle_generic_name(self, func_name, type_args, has_cexport=False):
|
||
from lib.includes.t import CTypeRegistry
|
||
mangled_args = []
|
||
for ta in type_args:
|
||
llvm_str = CTypeRegistry.NameToLLVM(ta)
|
||
if llvm_str:
|
||
if llvm_str in ('float', 'double', 'half', 'fp128'):
|
||
mangled = '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, type_map):
|
||
for arg in Node.args.args:
|
||
if arg.annotation:
|
||
arg.annotation = self._replace_type_in_annotation(arg.annotation, type_map)
|
||
if Node.returns:
|
||
Node.returns = self._replace_type_in_annotation(Node.returns, type_map)
|
||
self._apply_type_map_to_body(Node.body, type_map)
|
||
|
||
def _replace_type_in_annotation(self, node, type_map):
|
||
if isinstance(node, ast.Name):
|
||
if node.id in type_map:
|
||
replacement = type_map[node.id]
|
||
return ast.Name(id=replacement, ctx=ast.Load())
|
||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
node.left = self._replace_type_in_annotation(node.left, type_map)
|
||
node.right = self._replace_type_in_annotation(node.right, type_map)
|
||
elif isinstance(node, ast.Attribute):
|
||
if hasattr(node, 'attr') and node.attr in type_map:
|
||
replacement = type_map[node.attr]
|
||
return ast.Name(id=replacement, ctx=ast.Load())
|
||
return node
|
||
|
||
def _apply_type_map_to_body(self, body, type_map):
|
||
for stmt in body:
|
||
self._apply_type_map_to_stmt(stmt, type_map)
|
||
|
||
def _apply_type_map_to_stmt(self, node, type_map):
|
||
if isinstance(node, ast.Return) and node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map)
|
||
elif isinstance(node, ast.Assign):
|
||
for t in node.targets:
|
||
self._apply_type_map_to_expr(t, type_map)
|
||
self._apply_type_map_to_expr(node.value, type_map)
|
||
elif isinstance(node, ast.AnnAssign):
|
||
if node.annotation:
|
||
node.annotation = self._replace_type_in_annotation(node.annotation, type_map)
|
||
if node.value:
|
||
self._apply_type_map_to_expr(node.value, type_map)
|
||
elif isinstance(node, ast.AugAssign):
|
||
self._apply_type_map_to_expr(node.target, type_map)
|
||
self._apply_type_map_to_expr(node.value, type_map)
|
||
elif isinstance(node, ast.Expr):
|
||
self._apply_type_map_to_expr(node.value, type_map)
|
||
elif isinstance(node, ast.If):
|
||
self._apply_type_map_to_expr(node.test, type_map)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map)
|
||
for s in node.orelse:
|
||
self._apply_type_map_to_stmt(s, type_map)
|
||
elif isinstance(node, ast.For):
|
||
self._apply_type_map_to_expr(node.iter, type_map)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map)
|
||
elif isinstance(node, ast.While):
|
||
self._apply_type_map_to_expr(node.test, type_map)
|
||
for s in node.body:
|
||
self._apply_type_map_to_stmt(s, type_map)
|
||
|
||
def _apply_type_map_to_expr(self, node, type_map):
|
||
if node is None:
|
||
return
|
||
if isinstance(node, ast.Call):
|
||
if isinstance(node.func, ast.Name) and node.func.id in type_map:
|
||
replacement = type_map[node.func.id]
|
||
node.func = ast.Name(id=replacement, ctx=ast.Load())
|
||
elif isinstance(node.func, ast.Attribute):
|
||
if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map:
|
||
replacement = type_map[node.func.value.id]
|
||
node.func.value = ast.Name(id=replacement, ctx=ast.Load())
|
||
for arg in node.args:
|
||
self._apply_type_map_to_expr(arg, type_map)
|
||
elif isinstance(node, ast.Attribute):
|
||
if isinstance(node.value, ast.Name) and node.value.id in type_map:
|
||
replacement = type_map[node.value.id]
|
||
node.value = ast.Name(id=replacement, ctx=ast.Load())
|
||
elif isinstance(node, ast.BinOp):
|
||
self._apply_type_map_to_expr(node.left, type_map)
|
||
self._apply_type_map_to_expr(node.right, type_map)
|
||
elif isinstance(node, ast.UnaryOp):
|
||
self._apply_type_map_to_expr(node.operand, type_map)
|
||
elif isinstance(node, ast.Compare):
|
||
self._apply_type_map_to_expr(node.left, type_map)
|
||
for comp in node.comparators:
|
||
self._apply_type_map_to_expr(comp, type_map)
|
||
elif isinstance(node, ast.BoolOp):
|
||
for val in node.values:
|
||
self._apply_type_map_to_expr(val, type_map)
|
||
elif isinstance(node, ast.IfExp):
|
||
self._apply_type_map_to_expr(node.test, type_map)
|
||
self._apply_type_map_to_expr(node.body, type_map)
|
||
self._apply_type_map_to_expr(node.orelse, type_map)
|
||
|
||
def _infer_type_arg_from_value(self, val, Gen):
|
||
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, type_args, Gen):
|
||
if not hasattr(self, '_generic_templates') or FuncName not in self._generic_templates:
|
||
return None
|
||
template = self._generic_templates[FuncName]
|
||
Node = template['node']
|
||
type_param_names = template['type_params']
|
||
ClassName = template['class_name']
|
||
if len(type_args) != len(type_param_names):
|
||
return None
|
||
spec_key = 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 = False
|
||
if Node.returns:
|
||
try:
|
||
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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
spec_name = self._mangle_generic_name(FuncName, type_args, has_cexport)
|
||
type_map = {}
|
||
for i, tp_name in enumerate(type_param_names):
|
||
type_map[tp_name] = type_args[i]
|
||
import copy
|
||
SpecNode = 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 = Gen.builder
|
||
saved_variables = dict(Gen.variables) if Gen.variables else {}
|
||
saved_direct_values = dict(Gen._direct_values) if Gen._direct_values else {}
|
||
saved_var_type_info = dict(Gen.var_type_info) if Gen.var_type_info else {}
|
||
saved_var_signedness = dict(Gen.var_signedness) if Gen.var_signedness else {}
|
||
saved_global_vars = set(Gen.global_vars) if Gen.global_vars else set()
|
||
saved_var_scopes = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else []
|
||
saved_func = Gen.func
|
||
saved_current_func_name = getattr(Gen, '_current_func_name', None)
|
||
saved_block = 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, Gen, ClassName=None):
|
||
if self._is_generic_function(Node):
|
||
if not hasattr(self, '_generic_templates'):
|
||
self._generic_templates = {}
|
||
RawFuncName = Node.name
|
||
if ClassName:
|
||
FuncName = f"{ClassName}.{RawFuncName}"
|
||
else:
|
||
FuncName = RawFuncName
|
||
type_params = [tp.name for tp in Node.type_params]
|
||
self._generic_templates[FuncName] = {
|
||
'node': Node,
|
||
'type_params': type_params,
|
||
'class_name': ClassName,
|
||
}
|
||
return
|
||
result = self._GetFunctionSignatureLlvm(Node, Gen, ClassName)
|
||
if result is None:
|
||
return
|
||
FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic = result
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo = None
|
||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||
RetTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and 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) and not RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern):
|
||
Gen._export_funcs.add(FuncName)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
Gen._export_funcs.add(FuncName) # t.State 标记的函数必须保持原始名称,以便链接器解析
|
||
except Exception as _e:
|
||
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
MangledName = Gen._mangle_func_name(FuncName)
|
||
need_new = MangledName not in Gen.functions
|
||
if not need_new:
|
||
existing = Gen.functions[MangledName]
|
||
if getattr(existing, 'name', MangledName) != MangledName:
|
||
need_new = True
|
||
if need_new:
|
||
try:
|
||
func = 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:
|
||
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")
|
||
Gen.functions[MangledName] = func
|
||
Gen.functions[FuncName] = func
|
||
except Exception as _e:
|
||
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
else:
|
||
existing = Gen.functions[MangledName]
|
||
existing_type = getattr(existing, 'ftype', None)
|
||
if existing_type and existing_type != FuncType:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
elif not existing_type:
|
||
try:
|
||
Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType)
|
||
Gen.functions[FuncName] = Gen.functions[MangledName]
|
||
except Exception as _e:
|
||
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
|
||
def _replace_function_decl(self, Gen, FuncName, NewFuncType):
|
||
MangledName = Gen._mangle_func_name(FuncName)
|
||
old_func = 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 = old_func.name
|
||
if old_name in getattr(Gen.module, 'globals', {}):
|
||
del Gen.module.globals[old_name]
|
||
module_scope = 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(Gen.module, NewFuncType, name=MangledName)
|
||
Gen.functions[MangledName] = new_func
|
||
Gen.functions[FuncName] = new_func
|
||
return new_func
|
||
except Exception as ex:
|
||
import traceback
|
||
traceback.print_exc()
|
||
Gen.functions[MangledName] = old_func
|
||
Gen.functions[FuncName] = old_func
|
||
return old_func
|
||
|
||
def _EmitFunctionLlvm(self, Node, Gen, ClassName=None, extra_params=None):
|
||
if self._is_generic_function(Node):
|
||
return
|
||
RawFuncName = Node.name
|
||
if ClassName:
|
||
FuncName = f"{ClassName}.{RawFuncName}"
|
||
else:
|
||
FuncName = RawFuncName
|
||
# property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突
|
||
func_meta = self._ExtractFuncMeta(Node.decorator_list)
|
||
if FuncMeta.PROPERTY_SETTER in func_meta:
|
||
FuncName = FuncName + '$set'
|
||
elif FuncMeta.PROPERTY_DELETER in func_meta:
|
||
FuncName = FuncName + '$del'
|
||
CReturnTypes = []
|
||
IsPtr = False
|
||
fn_attrs = {}
|
||
# 自定义行为装饰器列表,用于生成 wrapper 函数
|
||
# 任何 @name 或 @name(args) 只要不是内置装饰器,都视为自定义行为装饰器
|
||
behavior_decorators = []
|
||
# 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器
|
||
_BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod'}
|
||
if Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
# 识别自定义行为装饰器:@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 arg.func.value.value.id == 't' 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 arg.func.value.value.value.id == 't':
|
||
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 arg.value.value.id == 't' 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 arg.value.value.value.id == 't':
|
||
llvm_attr_name = arg.attr
|
||
if llvm_attr_name in self._LLVM_ATTR_NAMES:
|
||
fn_attrs[f'llvm.{llvm_attr_name}'] = True
|
||
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 __import__('lib.constants.config', fromlist=['mode']).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 __import__('lib.constants.config', fromlist=['mode']).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
|
||
if ReturnTypeInfo.IsVoid 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 = False
|
||
IsClassMethod = False
|
||
ResolvedClassName = ClassName
|
||
# func_meta 已在函数开头提取(用于 setter/deleter 函数名后缀)
|
||
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
|
||
# __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 = []
|
||
self.Trans.VarScopes.append({})
|
||
for Arg in Node.args.args:
|
||
ParamIsUnsigned = False
|
||
if Arg.annotation:
|
||
try:
|
||
if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||
ParamTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation)
|
||
if ParamTypeInfo is None:
|
||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
else:
|
||
ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
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
|
||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||
if ParamTypeInfo and ParamTypeInfo.IsFuncPtr:
|
||
ParamType = ir.IntType(8).as_pointer()
|
||
ParamIsUnsigned = ParamTypeInfo.IsUInt
|
||
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)
|
||
Gen._record_var_signedness(Arg.arg, ParamIsUnsigned)
|
||
self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo
|
||
if Arg.annotation:
|
||
try:
|
||
if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||
PInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation)
|
||
if PInfo is None:
|
||
PInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
else:
|
||
PInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable)
|
||
if PInfo and (PInfo.DataConst or PInfo.VarConst):
|
||
Gen.var_const_flags[Arg.arg] = True
|
||
except Exception as _e:
|
||
if __import__('lib.constants.config', fromlist=['mode']).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
|
||
if IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
else:
|
||
ParamTypes.insert(0, StructPtrType)
|
||
ParamNames.insert(0, "self")
|
||
elif not IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs:
|
||
SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1)
|
||
if SelfIdx >= 0:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
ParamTypes[SelfIdx] = StructPtrType
|
||
# @classmethod: 将 cls 参数设为类指针类型
|
||
if IsClassMethod:
|
||
ClsIdx = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1)
|
||
if ClsIdx >= 0:
|
||
StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName])
|
||
ParamTypes[ClsIdx] = StructPtrType
|
||
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)
|
||
self.Trans.FunctionDefCache[FuncName] = Node
|
||
IsInlineFunc = False
|
||
IsExternFunc = False
|
||
IsStateFunc = False
|
||
if Node.returns:
|
||
try:
|
||
RetTypeInfo = None
|
||
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||
RetTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and 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.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)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern):
|
||
IsExternFunc = True
|
||
Gen._export_funcs.add(FuncName)
|
||
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
|
||
IsStateFunc = True
|
||
Gen._export_funcs.add(FuncName) # 外部 C 函数声明必须保持原始名称
|
||
except Exception as _e:
|
||
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
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
|
||
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:
|
||
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")
|
||
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:
|
||
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 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:
|
||
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")
|
||
# 记录自定义行为装饰器信息,供 DecoratorPass 使用
|
||
if behavior_decorators:
|
||
if not hasattr(Gen, '_decorated_funcs'):
|
||
Gen._decorated_funcs = {}
|
||
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
|
||
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()
|
||
# 函数内部定义的变量会在赋值时添加到 var_type_info 中
|
||
# 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理
|
||
for stmt in Node.body:
|
||
if isinstance(stmt, ast.Global):
|
||
for gname in stmt.names:
|
||
Gen.global_vars.add(gname)
|
||
if gname in Gen.module.globals:
|
||
Gen.variables[gname] = Gen.module.globals[gname]
|
||
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
|
||
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
|
||
Gen.variables[vararg_name] = va_list_ptr
|
||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||
if not Gen.builder.block.is_terminated:
|
||
if 'naked' in fn_attrs:
|
||
Gen.builder.unreachable()
|
||
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.variables = {}
|
||
Gen.var_signedness = {}
|
||
Gen._reg_values = {}
|
||
Gen._direct_values = {}
|
||
Gen.var_struct_class = {}
|
||
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
|
||
Gen._local_heap_ptrs = []
|
||
Gen._var_to_heap_ptr = {}
|
||
Gen._variadic_info = None
|
||
self.Trans._CurrentCpythonObjectClass = None
|
||
self.Trans.CurrentCReturnTypes = None
|
||
if self.Trans.VarScopes:
|
||
self.Trans.VarScopes.pop()
|
||
self.Trans.FunctionReturnTypes[FuncName] = ReturnTypeInfo
|
||
if FuncName not in self.Trans.SymbolTable:
|
||
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[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
|
||
if BasePropKey in self.Trans.SymbolTable:
|
||
base_existing = self.Trans.SymbolTable[BasePropKey]
|
||
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[BasePropKey] = PropInfo
|
||
return func
|