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