Files
TransPyC/lib/core/Handles/HandlesFunctions.py

1421 lines
80 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.lookup(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.lookup(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.lookup(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:
# 识别自定义行为装饰器:@nameast.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 大小取决于 ABIWindows 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 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
if self.Trans.SymbolTable.has(BasePropKey):
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.insert(BasePropKey, PropInfo)
return func