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 from lib.includes import t import ast import llvmlite.ir as ir class AnnAssignHandle(BaseHandle): def _GetCTypeInfo(self, annotation): return self.Trans.TypeMergeHandler.GetCTypeInfo(annotation) def _StoreOrStrCopy(self, VarName, VarPtr, Value): Gen = self.Trans.LlvmGen DestPtr = Gen._load(VarPtr, name=VarName) if isinstance(DestPtr.type, ir.PointerType) and isinstance(DestPtr.type.pointee, ir.IntType) and DestPtr.type.pointee.width == 8: if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.IntType) and Value.type.pointee.width == 8: if 'llvm.memcpy' not in Gen.functions: memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)]) Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') if isinstance(DestPtr.type.pointee, ir.IntType) and not isinstance(DestPtr.type.pointee, ir.IntType(8)): DestPtr = Gen.builder.bitcast(DestPtr, ir.PointerType(ir.IntType(8)), name=f"strcpy_dst_cast_{VarName}") if isinstance(Value.type.pointee, ir.IntType) and not isinstance(Value.type.pointee, ir.IntType(8)): Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"strcpy_src_cast_{VarName}") size = ir.Constant(ir.IntType(64), 8) align = ir.Constant(ir.IntType(32), 1) isvolatile = ir.Constant(ir.IntType(1), 0) Gen.builder.call(Gen.functions['llvm.memcpy'], [DestPtr, Value, size, align, isvolatile], name=f"strcpy_call_{VarName}") return try: CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") Gen._store(CastedVal, VarPtr) except Exception: # 回退:bitcast 失败时 alloca 新变量 NewVar = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, NewVar) Gen.variables[VarName] = NewVar def _HandleAttributeStoreLlvm(self, Target, Value): Gen = self.Trans.LlvmGen AttrName = Target.attr if isinstance(Target.value, ast.Name) and Target.value.id == 'self': ClassName = self._CurrentCpythonObjectClass if not ClassName: self_var = Gen.variables.get('self') if self_var: var_type = self_var.type if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): var_type = var_type.pointee if isinstance(var_type, ir.PointerType): pointee = var_type.pointee for cn, st in Gen.structs.items(): if st == pointee: ClassName = cn break if ClassName and ClassName in Gen.structs: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") offset = Gen._get_member_offset(AttrName, ClassName) MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) elif isinstance(Target.value, ast.Name): VarName = Target.value.id ClassName = Gen.var_struct_class.get(VarName) if not ClassName: for CN in Gen.structs: if VarName == CN.lower() or VarName.startswith(CN): ClassName = CN break if not ClassName and VarName in Gen.variables: VarPtr = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): pointee = VarPtr.type.pointee if isinstance(pointee, ir.PointerType): pointee = pointee.pointee for CN, ST in Gen.structs.items(): if pointee == ST: ClassName = CN break IsUnion = False if ClassName and ClassName in self.Trans.SymbolTable: TypeInfo = self.Trans.SymbolTable[ClassName] if hasattr(TypeInfo, 'IsUnion') and TypeInfo.IsUnion: IsUnion = True if ClassName and ClassName in Gen.structs: ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal: if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IntType) and ObjVal.type.pointee.width == 8: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: if IsUnion: NestedStructName = f"{ClassName}_{AttrName}" if NestedStructName in Gen.structs: NestedStructType = Gen.structs[NestedStructName] ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") offset = Gen._get_member_offset(AttrName, NestedStructName) if offset is not None and offset < len(NestedStructType.elements): MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return offset = Gen._get_member_offset(AttrName, ClassName) MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) elif isinstance(Target.value, ast.Attribute): ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): pointee = ObjVal.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: offset = Gen._get_member_offset(AttrName, CN) MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) break def _StoreWithCoerce(self, Value, Ptr): Gen = self.Trans.LlvmGen if isinstance(Ptr.type, ir.PointerType): TargetType = Ptr.type.pointee if Value.type != TargetType: if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType): if TargetType.width < Value.type.width: Value = Gen.builder.trunc(Value, TargetType, name="trunc") else: Value = Gen.builder.zext(Value, TargetType, name="zext") elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast") elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType): Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr") elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType): Value = Gen.builder.ptrtoint(Value, TargetType, name="ptr_to_int") Gen._store(Value, Ptr) def _HandleAnnAssignLlvm(self, Node): Gen = self.Trans.LlvmGen self.Trans._current_assign_node = Node try: self._HandleAnnAssignLlvmInner(Node) finally: self.Trans._current_assign_node = None def _HandleAnnAssignLlvmInner(self, Node): Gen = self.Trans.LlvmGen if isinstance(Node.target, ast.Name): VarName = Node.target.id TypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) if TypeInfo is None: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CInt() IsPtr = TypeInfo.IsPtr if TypeInfo.IsDefine: if Node.value and isinstance(Node.value, ast.Constant): if not hasattr(Gen, '_define_constants'): Gen._define_constants = {} Gen._define_constants[VarName] = Node.value.value info = CTypeInfo() info.IsDefine = True info.DefineValue = Node.value.value self.Trans.SymbolTable[VarName] = info Gen._record_var_signedness(VarName, TypeInfo.IsUInt) return if TypeInfo.IsStr or (isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str'): TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CChar() TypeInfo.PtrCount = 1 IsPtr = True if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list': slice_node = Node.annotation.slice if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: elem_type_node = slice_node.elts[0] count_node = slice_node.elts[1] ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: ElemType = Gen.structs[elem_type_node.id] else: if isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str': ElemType = ir.PointerType(ir.IntType(8)) else: ElemType = Gen._ctype_to_llvm(ElemTypeInfo) if isinstance(ElemType, ir.VoidType): ElemType = ir.IntType(32) ArrayCount = 1 if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): ArrayCount = count_node.value else: eval_count = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable) if eval_count is not None and isinstance(eval_count, int) and eval_count > 0: ArrayCount = eval_count elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None): if Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): ArrayCount = len(Node.value.value) + 1 VarType = ir.ArrayType(ElemType, ArrayCount) var = Gen._allocaEntry(VarType, name=VarName) Gen.variables[VarName] = var Gen._record_var_signedness(VarName, False) if Node.value and isinstance(Node.value, ast.List): InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen) if InitConstants: try: InitVal = ir.Constant(VarType, InitConstants) Gen.builder.store(InitVal, var) except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): str_val = Node.value.value + '\x00' str_bytes = bytearray(str_val, 'utf-8') if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count: str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes))) try: InitVal = ir.Constant(VarType, str_bytes[:VarType.count] if isinstance(VarType, ir.ArrayType) else str_bytes) Gen.builder.store(InitVal, var) except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if self.Trans.VarScopes: self.Trans.VarScopes[-1][VarName] = ElemTypeInfo return if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp): def _find_struct_name_in_annot(node): if isinstance(node, ast.Name) and node.id in Gen.structs: return node.id if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs: return node.value if isinstance(node, ast.Attribute) and node.attr in Gen.structs: return node.attr if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): result = _find_struct_name_in_annot(node.left) if result: return result return _find_struct_name_in_annot(node.right) return None found = _find_struct_name_in_annot(Node.annotation) if found: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CStruct(name=found) TypeInfo.PtrCount = 1 IsPtr = True elif isinstance(Node.annotation.left, ast.Attribute): AttrTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left) if AttrTypeInfo and AttrTypeInfo.BaseType: TypeInfo = AttrTypeInfo TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1) IsPtr = True VarType = Gen._ctype_to_llvm(TypeInfo) if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name: stripped = TypeInfo.Name if stripped in Gen.class_vtable and stripped in Gen.structs: VarType = ir.PointerType(Gen.structs[stripped]) IsPtr = True if isinstance(VarType, ir.IdentifiedStructType): struct_name = getattr(VarType, 'name', '') if struct_name and Gen.class_vtable: for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: VarType = ir.PointerType(VarType) IsPtr = True break if isinstance(VarType, ir.VoidType): VarType = ir.IntType(32) IsUnsigned = TypeInfo.IsUInt if VarName in Gen._reg_values: OldVal = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] if Node.value: InitValue = self.HandleExprLlvm(Node.value, VarType=VarType) if InitValue: self._StoreOrStrCopy(VarName, var, InitValue) Gen._record_var_signedness(VarName, IsUnsigned) return del Gen._reg_values[VarName] InitValue = None if Node.value: InitValue = self.HandleExprLlvm(Node.value, VarType=VarType) if VarName in Gen._reg_values: del Gen._reg_values[VarName] if VarName in Gen.variables and Gen.variables[VarName] is not None: if InitValue and isinstance(InitValue.type, ir.PointerType): pointee = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name = getattr(pointee, 'name', '') is_vtable_class = False for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: is_vtable_class = True break if is_vtable_class: var = Gen._allocaEntry(InitValue.type, name=VarName) Gen._store(InitValue, var) Gen.variables[VarName] = var if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: Gen.var_struct_class[VarName] = Node.annotation.id Gen.global_struct_class[VarName] = Node.annotation.id Gen._record_var_signedness(VarName, IsUnsigned) return if InitValue: try: VarPtr = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): TargetType = VarPtr.type.pointee if InitValue.type != TargetType: if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType): if TargetType.width > InitValue.type.width: InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}") elif TargetType.width < InitValue.type.width: InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}") elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType): InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}") Gen._store(InitValue, VarPtr) except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") Gen._record_var_signedness(VarName, IsUnsigned) return if VarName in Gen.global_vars: if VarName in Gen.module.globals: GVar = Gen.module.globals[VarName] if InitValue: Gen._store(InitValue, GVar) Gen.variables[VarName] = GVar Gen._record_var_signedness(VarName, IsUnsigned) return var = Gen._allocaEntry(VarType, name=VarName) if InitValue and isinstance(InitValue.type, ir.PointerType): pointee = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name = getattr(pointee, 'name', '') is_vtable_class = False for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: is_vtable_class = True break if is_vtable_class and not isinstance(VarType, ir.PointerType): var = Gen._allocaEntry(InitValue.type, name=VarName) VarType = InitValue.type IsPtr = True Gen._store(InitValue, var) Gen.variables[VarName] = var if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: Gen.var_struct_class[VarName] = Node.annotation.id Gen.global_struct_class[VarName] = Node.annotation.id Gen._record_var_signedness(VarName, IsUnsigned) return for CN, ST in Gen.structs.items(): if pointee is ST or pointee == ST: if CN != Gen.var_struct_class.get(VarName): Gen.var_struct_class[VarName] = CN Gen.global_struct_class[VarName] = CN if isinstance(VarType, ir.PointerType) and VarType.pointee is not ST and VarType.pointee != ST: var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName) VarType = ir.PointerType(pointee) break if InitValue: try: if InitValue.type != VarType: if isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType): if VarType.width > InitValue.type.width: InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}") elif VarType.width < InitValue.type.width: InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}") elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType): InitValue = Gen.builder.bitcast(InitValue, VarType, name=f"cast_{VarName}") elif isinstance(VarType, ir.PointerType) and isinstance(InitValue.type, ir.IntType): InitValue = Gen.builder.inttoptr(InitValue, VarType, name=f"int2ptr_{VarName}") elif isinstance(VarType, ir.IntType) and isinstance(InitValue.type, ir.PointerType): InitValue = Gen.builder.ptrtoint(InitValue, VarType, name=f"ptr2int_{VarName}") Gen._store(InitValue, var) except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") Gen.variables[VarName] = var Gen._record_var_signedness(VarName, IsUnsigned) if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): def _find_struct_in_binop(node): if isinstance(node, ast.Name) and node.id in Gen.structs: return node.id if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs: return node.value if isinstance(node, ast.Attribute) and node.attr in Gen.structs: return node.attr if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): result = _find_struct_in_binop(node.left) if result: return result return _find_struct_in_binop(node.right) return None found_struct = _find_struct_in_binop(Node.annotation) if found_struct: Gen.var_struct_class[VarName] = found_struct Gen.global_struct_class[VarName] = found_struct if InitValue and isinstance(InitValue.type, ir.PointerType): pointee = InitValue.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: Gen._var_to_heap_ptr[VarName] = InitValue if CN != Gen.var_struct_class.get(VarName): Gen.var_struct_class[VarName] = CN Gen.global_struct_class[VarName] = CN break if self.Trans.VarScopes: if TypeInfo: self.Trans.VarScopes[-1][VarName] = TypeInfo else: DefaultInfo = CTypeInfo() DefaultInfo.BaseType = t.CInt self.Trans.VarScopes[-1][VarName] = DefaultInfo elif isinstance(Node.target, ast.Attribute): if isinstance(Node.target.value, ast.Name) and Node.target.value.id == 'self': if Node.value: AttrVarType = None try: if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list': slice_node = Node.annotation.slice if isinstance(slice_node, ast.Name): AttrVarType = f'list[{slice_node.id}]' elif isinstance(slice_node, ast.Tuple): elts = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts) AttrVarType = f'list[{elts}]' elif isinstance(slice_node, ast.Attribute): AttrVarType = f'list[{ast.dump(slice_node)}]' if AttrVarType is None: AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if AttrTypeInfo: AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo) 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") Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType) if Value: self._HandleAttributeStoreLlvm(Node.target, Value) AttrName = Node.target.attr len_name = f'{AttrName}__len' ClassName = self._CurrentCpythonObjectClass if not ClassName: self_var = Gen.variables.get('self') if self_var: var_type = self_var.type if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): var_type = var_type.pointee if isinstance(var_type, ir.PointerType): pointee = var_type.pointee for cn, st in Gen.structs.items(): if st == pointee: ClassName = cn break if ClassName and ClassName in Gen.class_members: for m_name, m_type in Gen.class_members[ClassName]: if m_name == len_name: list_len = None if isinstance(Node.value, ast.List): list_len = ir.Constant(ir.IntType(64), len(Node.value.elts)) if list_len is not None: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") offset = Gen._get_member_offset(len_name, ClassName) LenPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name) Gen._store(list_len, LenPtr) break