from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator import ast import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode from lib.includes import t from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotation, AnnotationContainsName, IsCPtrNode class AnnAssignHandle(BaseHandle): def _StoreOrStrCopy(self, VarName: str, VarPtr: ir.Value, Value: ir.Value) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen DestPtr: ir.Value = 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.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.Constant(ir.IntType(64), 8) align: ir.Constant = ir.Constant(ir.IntType(32), 1) isvolatile: ir.Constant = 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: ir.Value = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") Gen._store(CastedVal, VarPtr) except Exception: # 回退:bitcast 失败时 alloca 新变量 NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, NewVar) Gen.variables[VarName] = NewVar def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen AttrName: str = Target.attr if isinstance(Target.value, ast.Name) and Target.value.id == 'self': ClassName: str | None = self._CurrentCpythonObjectClass if not ClassName: self_var: ir.Value | None = Gen.variables.get('self') if self_var: var_type: ir.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: ir.Type = var_type.pointee for cn, st in Gen.structs.items(): if st == pointee: ClassName = cn break if ClassName and ClassName in Gen.structs: SelfVar: ir.Value | None = Gen._get_var_ptr('self') if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") offset: int = Gen._get_member_offset(AttrName, ClassName) MemberPtr: ir.Value = 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: str = Target.value.id # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) # 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖) _fd_meta_name: str = f"{VarName}__meta__" if _fd_meta_name in Gen.variables and '_str' in Gen.structs: _fd_offset = Gen._get_member_offset(AttrName, '_str') if _fd_offset is not None: _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") self._StoreWithCoerce(Value, _fd_field_ptr) return ClassName: str | None = 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: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): pointee: ir.Type = 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: bool = False if ClassName: ClassTypeInfo: Any = self.Trans.SymbolTable.lookup(ClassName) if ClassTypeInfo: if ClassTypeInfo.IsUnion: IsUnion = True if ClassName and ClassName in Gen.structs: ObjVal: ir.Value | None = 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}") # opaque 泛型结构体 → 特化版本 bitcast # 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub), # 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者是不同的 # IdentifiedStructType,直接比较会失败。这里 bitcast 到特化版本, # 使后续 GEP 能正确访问字段。 if (isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee is not Gen.structs[ClassName] and '[' in ClassName): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_spec_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: if IsUnion: NestedStructName: str = f"{ClassName}_{AttrName}" if NestedStructName in Gen.structs: NestedStructType: ir.Type = Gen.structs[NestedStructName] ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") offset: int = Gen._get_member_offset(AttrName, NestedStructName) if offset is not None and offset < len(NestedStructType.elements): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return offset: int = Gen._get_member_offset(AttrName, ClassName) MemberPtr: ir.Value = 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: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): pointee: ir.Type = ObjVal.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: offset: int = Gen._get_member_offset(AttrName, CN) MemberPtr: ir.Value = 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: ir.Value, Ptr: ir.Value) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen if isinstance(Ptr.type, ir.PointerType): TargetType: ir.Type = 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 _HandleGenericListLiteralAssign(self, VarName: str, Node: ast.AnnAssign, Gen: LlvmCodeGenerator, list_sub: ast.Subscript) -> None: """处理 list[T] = [...] → 构造 list[T] 对象 + append 序列。 将 list 字面量翻译为: 1. 特化 list[T] 类 2. alloca + __before_init__ + __new__(pool) + __before_init__ + __init__(pool) 3. 对每个元素调用 append(elem) 4. 将堆指针存入变量 list_sub 是从注解中提取的 list[...] Subscript 节点(支持 list[T] 和 list[T] | t.CPtr) """ # 1. 解析元素类型 slice_node: ast.expr = list_sub.slice result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node) if result is None: return type_arg: str = result[0] type_name: str = result[1] # 2. 特化 list[T] 类 spec_name: str | None = self.Trans.ClassHandler._specialize_generic_class( 'list', [type_arg], Gen, type_names=[type_name]) if spec_name is None: return # 3. 获取结构体类型 StructType: ir.Type | None = Gen.structs.get(spec_name) if StructType is None: return if isinstance(StructType, ir.PointerType): StructType = StructType.pointee # 4. 查找 pool 变量(pool / _mbuddy / mbuddy / mb) pool_val: ir.Value | None = None for pool_name in ('pool', '_mbuddy', 'mbuddy', 'mb'): if pool_name in Gen.variables: pool_var: ir.Value = Gen.variables[pool_name] if isinstance(pool_var.type, ir.PointerType): pointee: ir.Type = pool_var.type.pointee if isinstance(pointee, ir.PointerType): # alloca of pointer → load pool_val = Gen._load(pool_var, name=f"pool_load_{VarName}") else: pool_val = pool_var else: pool_val = pool_var break if pool_val is None: return # 5. alloca 临时结构体 alloca_ptr: ir.AllocaInstr = Gen._allocaEntry(StructType, name=f"{VarName}_alloca") # 6. 调用 __before_init__(alloca_ptr) before_init_name: str = f'{spec_name}.__before_init__' before_init_func: ir.Function | None = None if Gen._has_function(before_init_name): before_init_func = Gen._get_function(before_init_name) Gen.builder.call(before_init_func, [alloca_ptr], name=f"before_init_{VarName}") # 7. 调用 __new__(alloca_ptr, pool_val) → heap_ptr new_method_name: str = f'{spec_name}.__new__' heap_ptr: ir.Value = alloca_ptr has_new: bool = Gen._find_function(new_method_name) is not None if has_new: new_func: ir.Function | None = Gen._find_function(new_method_name) if new_func: new_args: list[ir.Value] = [alloca_ptr, pool_val] self.Trans.ExprCallHandle._fill_default_args(new_args, new_func, new_method_name) new_args = Gen._apply_auto_addr(new_method_name, new_args) adjusted_new: list[ir.Value] = Gen._adjust_args(new_args, new_func) heap_ptr = Gen.builder.call(new_func, adjusted_new, name=f"new_{VarName}") # 转换返回指针类型 target_ptr_type: ir.PointerType = ir.PointerType(StructType) if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != target_ptr_type: heap_ptr = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{VarName}_cast") elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: if heap_ptr.type.width < 64: i64_val: ir.Value = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{VarName}_i64") heap_ptr = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{VarName}_ptr") else: heap_ptr = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{VarName}_ptr") # 对堆指针重新调用 __before_init__ if before_init_func: Gen.builder.call(before_init_func, [heap_ptr], name=f"before_init_{VarName}_heap") # 8. 调用 __init__(heap_ptr, pool_val, elem_size=0) init_name: str = f'{spec_name}.__init__' if Gen._has_function(init_name): init_func: ir.Function | None = Gen._get_function(init_name) if init_func: elem_size_val: ir.Constant = ir.Constant(ir.IntType(64), 0) init_args: list[ir.Value] = [heap_ptr, pool_val, elem_size_val] self.Trans.ExprCallHandle._fill_default_args(init_args, init_func, init_name) init_args = Gen._apply_auto_addr(init_name, init_args) adjusted_init: list[ir.Value] = Gen._adjust_args(init_args, init_func) Gen.builder.call(init_func, adjusted_init, name=f"init_{VarName}") # 9. 对每个元素调用 append(heap_ptr, elem_val) append_name: str = f'{spec_name}.append' append_func: ir.Function | None = Gen._find_function(append_name) if append_func and Node.value and isinstance(Node.value, ast.List): elts: list[ast.expr] = Node.value.elts for i, elem_node in enumerate(elts): elem_val: ir.Value | None = self.HandleExprLlvm(elem_node) if elem_val: append_args: list[ir.Value] = [heap_ptr, elem_val] self.Trans.ExprCallHandle._fill_default_args(append_args, append_func, append_name) append_args = Gen._apply_auto_addr(append_name, append_args) adjusted_append: list[ir.Value] = Gen._adjust_args(append_args, append_func) Gen.builder.call(append_func, adjusted_append, name=f"append_{VarName}_{i}") # 10. 创建变量并存储堆指针 # 判断变量类型:list[T] | t.CPtr → i8*;list[T] → Ptr(StructType) is_cptr_union: bool = isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) if is_cptr_union: # list[T] | t.CPtr → 变量类型为 i8* i8_ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) var: ir.AllocaInstr = Gen._allocaEntry(i8_ptr_type, name=VarName) # bitcast heap_ptr (Ptr(StructType)) → i8* if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != i8_ptr_type: stored_val: ir.Value = Gen.builder.bitcast(heap_ptr, i8_ptr_type, name=f"store_cast_{VarName}") else: stored_val = heap_ptr Gen._store(stored_val, var) else: # list[T] → 变量类型为 Ptr(StructType) var = Gen._allocaEntry(ir.PointerType(StructType), name=VarName) Gen._store(heap_ptr, var) Gen.variables[VarName] = var Gen.var_struct_class[VarName] = spec_name Gen.global_struct_class[VarName] = spec_name Gen._record_var_signedness(VarName, False) def _HandleAnnAssignLlvm(self, Node: ast.AnnAssign) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen self.Trans._current_assign_node = Node try: self._HandleAnnAssignLlvmInner(Node) finally: self.Trans._current_assign_node = None def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen if isinstance(Node.target, ast.Name): VarName: str = Node.target.id TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) if TypeInfo is None: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CInt() IsPtr: bool = 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 = CTypeInfo() info.IsDefine = True info.DefineValue = Node.value.value self.Trans.SymbolTable.insert(VarName, info) Gen._record_var_signedness(VarName, TypeInfo.IsUInt) elif Node.value: # 非 Constant 表达式:尝试编译期求值(如 t.CSizeT().Size // 8) from lib.core.ConstEvaluator import ConstEvaluator, EvalContext ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) eval_val = ConstEvaluator.eval_full(Node.value, ctx) if eval_val is not None and isinstance(eval_val, (int, float)): if not hasattr(Gen, '_define_constants'): Gen._define_constants = {} Gen._define_constants[VarName] = eval_val info: CTypeInfo = CTypeInfo() info.IsDefine = True info.DefineValue = eval_val self.Trans.SymbolTable.insert(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 # FakeDuck: 为 str 变量创建影子结构体 a__meta__ (栈上, per-instance) # a 保持为 char* 用于 printf; a__meta__ 存储 __data__ 和 __mbuddy__ 字段 # 仅对 str 类型创建,bytes 和 t.CChar|t.CPtr 不创建 if '_str' in Gen.structs and isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str': _meta_name: str = f"{VarName}__meta__" _meta_var: ir.AllocaInstr = Gen._allocaEntry(Gen.structs['_str'], name=_meta_name) Gen.variables[_meta_name] = _meta_var # 标记指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr) # elem_ptr[0] 应加载/存储 8 字节 (指针), 而非 1 字节 (字符) # 仅当注解包含 str 或 bytes 时设置(t.CChar | t.CPtr 不应设置,它是纯字符指针) if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'): Gen.var_ptr_element[VarName] = True # 同时记录到全局字典,使全局变量在跨函数访问时仍能用 8 字节指针步长 Gen.global_var_ptr_element[VarName] = True parse_result = ParseListAnnotation(Node.annotation) if parse_result: elem_type_node: ast.expr = parse_result.elem_type_node ElemType, ElemTypeInfo = self.ResolveListElementType( elem_type_node, Gen, handle_str=True, void_fallback_width=32, ) if parse_result.is_pointer: # 单参数 list[type] → 指针 # 但如果有列表字面量初始化值 [a, b, c],则按数组 list[type, N] 处理 if not (Node.value and isinstance(Node.value, ast.List)): VarType: ir.Type = ir.PointerType(ElemType) var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName) Gen.variables[VarName] = var Gen._record_var_signedness(VarName, False) if self.Trans.VarScopes: self.Trans.VarScopes[-1][VarName] = ElemTypeInfo return # 有列表字面量值,继续走数组路径(count_node=None 时从列表长度推断) count_node: ast.expr | None = parse_result.count_node ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='local') 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: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '') if InitConstants: try: InitVal: ir.Constant = ir.Constant(VarType, InitConstants) Gen.builder.store(InitVal, var) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): str_val: str = Node.value.value + '\x00' str_bytes: bytearray = 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 = 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 _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if self.Trans.VarScopes: self.Trans.VarScopes[-1][VarName] = ElemTypeInfo # 记录数组元素字节序 if ElemTypeInfo and ElemTypeInfo.ByteOrder == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' return # list[T] 泛型类注解 + list 字面量值 → 构造 list[T] 对象 + append 序列 # (list[str] = ["a", "b"] 不应走 C 数组路径,而应构造 list[str] 对象) # 支持两种注解形式:list[T] 和 list[T] | t.CPtr list_sub: ast.Subscript | None = None if (isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list'): list_sub = Node.annotation elif (isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)): for side in (Node.annotation.left, Node.annotation.right): if (isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list'): list_sub = side break if (list_sub is not None and not isinstance(list_sub.slice, ast.Tuple) and Node.value is not None and isinstance(Node.value, ast.List) and hasattr(self.Trans.ClassHandler, '_generic_class_templates') and 'list' in self.Trans.ClassHandler._generic_class_templates): self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub) return if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp): found: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs) if found: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CStruct(name=found) TypeInfo.PtrCount = 1 IsPtr = True elif isinstance(Node.annotation.left, ast.Attribute): AttrTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left) if AttrTypeInfo and AttrTypeInfo.BaseType: TypeInfo = AttrTypeInfo TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1) IsPtr = True # 对于局部变量声明 s: TestStruct(不带 | t.CPtr),应为栈上结构体而非指针 # GetCTypeInfo 默认设置 PtrCount=1,但纯结构体名注解应为值类型 if (isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs and TypeInfo.IsStruct and Node.annotation.id not in Gen.class_vtable): TypeInfo.PtrCount = 0 IsPtr = False VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo) if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name: stripped: str = 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: str = 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: bool = TypeInfo.IsUInt # 修复 3: BinOp 注解(如 ast.Arguments | t.CPtr)的 var_struct_class 设置 # TypeInfo.Name 由 _HandleSubscript 设置(特化名如 list[sha1.ASTptr])或 # GetCTypeInfo 设置(普通结构体名),经 _MergeCTypeInfoInto 传播后保留。 # 此处确保 BinOp 注解的变量也能被 _get_var_class 识别,避免方法调用分派 # fallthrough 到 char pointer fallback 错误匹配其他类(如 AST.__len__)。 # 使用 not in 条件,不覆盖后续 L337-339/L396-398 对 ast.Name 注解的精确设置。 if TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs: if VarName not in Gen.var_struct_class: Gen.var_struct_class[VarName] = TypeInfo.Name Gen.global_struct_class[VarName] = TypeInfo.Name # 检测指针到指针缓冲区变量:注解为 StructName | t.CPtr,且赋值来自 t.CPtr(...) 调用。 # 这种变量(如 list[T].__getitem__ 中的 elem_ptr: T | t.CPtr = t.CPtr(...)) # 实际指向存储结构体指针的缓冲区(T=AST|t.CPtr 时特化为 AST*,缓冲区存 AST* 数组)。 # [index] 应 bitcast 为 AST** 后 GEP 指针数组再 load,而非 GEP 结构体数组。 # 泛型特化将 T|t.CPtr 降级为 StructName|t.CPtr(丢失一层指针),故通过赋值来源区分: # elem_ptr 的值是 t.CPtr(buf + idx*elem_size)(原始指针运算,缓冲区内容未知), # pts 的值是 (Point|t.CPtr)(...)(类型转换,明确指向 Point 结构体)。 _is_cptr_assign: bool = ( isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Attribute) and isinstance(Node.value.func.value, ast.Name) and Node.value.func.value.id == 't' and Node.value.func.attr == 'CPtr' ) _is_struct_ptr_union: bool = ( isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) and ((IsCPtrNode(Node.annotation.left) and isinstance(Node.annotation.right, ast.Name) and Node.annotation.right.id in Gen.structs) or (IsCPtrNode(Node.annotation.right) and isinstance(Node.annotation.left, ast.Name) and Node.annotation.left.id in Gen.structs)) ) if _is_cptr_assign and _is_struct_ptr_union: Gen.var_ptr_element[VarName] = True Gen.global_var_ptr_element[VarName] = True if VarName in Gen._reg_values: OldVal: ir.Value = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] if Node.value: InitValue: ir.Value | None = 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: ir.Value | None = None if Node.value: InitValue = self.HandleExprLlvm(Node.value, VarType=VarType) # 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型 if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): CalledName: str = Node.value.func.id if CalledName in Gen._closure_return_types: Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName] 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: ir.Type = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name: str = getattr(pointee, 'name', '') is_vtable_class: bool = 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: ir.AllocaInstr = 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: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): TargetType: ir.Type = 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 _config_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: ir.GlobalVariable = Gen.module.globals[VarName] if InitValue: Gen._store(InitValue, GVar) Gen.variables[VarName] = GVar Gen._record_var_signedness(VarName, IsUnsigned) return var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName) if InitValue and isinstance(InitValue.type, ir.PointerType): pointee: ir.Type = InitValue.type.pointee # 当 InitValue 是 i8* (t.CPtr) 且注解是 Gen.structs 中的结构体名时, # bitcast 为对应的结构体指针,以便正确存储和设置 var_struct_class # 例如: sub: dict = sub_p (sub_p 是 t.CPtr) if (isinstance(pointee, ir.IntType) and pointee.width == 8 and isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs): TargetStructType: ir.Type = Gen.structs[Node.annotation.id] if isinstance(TargetStructType, ir.PointerType): TargetStructType = TargetStructType.pointee InitValue = Gen.builder.bitcast(InitValue, ir.PointerType(TargetStructType), name=f"cast_{VarName}_to_{Node.annotation.id}") pointee = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name: str = getattr(pointee, 'name', '') is_vtable_class: bool = 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: # 若注解是泛型特化(如 ndarray[t.CDouble] | t.CPtr), # 构造正确的特化名(如 ndarray[double]),而非用 opaque 基础名 resolved_cn: str = CN if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) and '[' not in CN: for side in (Node.annotation.left, Node.annotation.right): if isinstance(side, ast.Subscript): bn: ast.expr = side.value bnm: str | None = bn.id if isinstance(bn, ast.Name) else (bn.attr if isinstance(bn, ast.Attribute) else None) if bnm and bnm == CN: sn2: ast.AST = side.slice if hasattr(ast, 'Index') and isinstance(sn2, ast.Index): sn2 = sn2.value r2: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(sn2) if r2: resolved_cn = f'{CN}[{r2[0]}]' break if resolved_cn != Gen.var_struct_class.get(VarName): Gen.var_struct_class[VarName] = resolved_cn Gen.global_struct_class[VarName] = resolved_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}") # 大端局部变量:存储时 bswap InitValue = Gen._apply_bswap_if_big(InitValue, TypeInfo.ByteOrder, f"bswap_store_{VarName}") Gen._store(InitValue, var) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") Gen.variables[VarName] = var Gen._record_var_signedness(VarName, IsUnsigned) # FakeDuck: 初始化影子结构体 a__meta__ 的字段 _meta_name_check: str = f"{VarName}__meta__" if _meta_name_check in Gen.variables and '_str' in Gen.structs: _meta_var_init: ir.Value = Gen.variables[_meta_name_check] _str_st: ir.Type = Gen.structs['_str'] # __data__ 字段 = 字符串指针 _data_off = Gen._get_member_offset('__data__', '_str') if _data_off is not None and InitValue: _data_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name=f"{VarName}_meta_data") Gen._store(InitValue, _data_ptr) # __mbuddy__ 字段 = NULL _mpool_off = Gen._get_member_offset('__mbuddy__', '_str') if _mpool_off is not None: _mpool_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name=f"{VarName}_meta_mbuddy") Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr) # FakeDuck: 从 with 上下文自动注入 requires 字段(如 __mbuddy__) self.Trans.ExprCallHandle._InjectRequiresFields(_meta_var_init, '_str', Gen) # 记录局部变量字节序 if TypeInfo.ByteOrder == 'big': if isinstance(VarType, ir.IntType) and VarType.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' elif isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): found_struct: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs) # 若 FindStructNameInAnnotation 仅返回裸模板名(如 'ndarray'),但注解中 # 含泛型特化(如 numpy.ndarray[t.CDouble]),用 LLVM 类型名构造特化名 # (如 'ndarray[double]')。main.py 的 Gen.structs 可能只有 opaque 'ndarray', # 但 numpy 模块已特化 ndarray[double],方法调用通过 sha1 前缀查找。 if found_struct and '[' not in found_struct: for side in (Node.annotation.left, Node.annotation.right): if isinstance(side, ast.Subscript): base_node: ast.expr = side.value base_nm: str | None = None if isinstance(base_node, ast.Name): base_nm = base_node.id elif isinstance(base_node, ast.Attribute): base_nm = base_node.attr if base_nm and base_nm == found_struct: slice_node: ast.AST = side.slice if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): slice_node = slice_node.value result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node) if result: found_struct = f'{base_nm}[{result[0]}]' break 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: ir.Type = 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 # 不覆盖已设置的特化名(含 '['):opaque 基础类型(如 ndarray) # 会匹配到裸模板名,但注解已提供更精确的特化名(如 ndarray[double]) existing_cn: str | None = Gen.var_struct_class.get(VarName) if not (existing_cn and '[' in existing_cn) and CN != existing_cn: 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 = 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: Any = None try: if IsListAnnotation(Node.annotation): slice_node: ast.AST = Node.annotation.slice if isinstance(slice_node, ast.Name): AttrVarType = f't.CArray[{slice_node.id}]' elif isinstance(slice_node, ast.Tuple): elts: str = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts) AttrVarType = f't.CArray[{elts}]' elif isinstance(slice_node, ast.Attribute): # 还原 t.xxx 形式(如 t.CInt、t.CArray) if isinstance(slice_node.value, ast.Name): AttrVarType = f't.CArray[{slice_node.value.id}.{slice_node.attr}]' else: AttrVarType = f't.CArray[{ast.unparse(slice_node)}]' if AttrVarType is None: AttrTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if AttrTypeInfo: AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=AttrVarType) if Value: self._HandleAttributeStoreLlvm(Node.target, Value) AttrName: str = Node.target.attr len_name: str = f'{AttrName}__len' ClassName: str | None = self._CurrentCpythonObjectClass if not ClassName: self_var: ir.Value | None = Gen.variables.get('self') if self_var: var_type: ir.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: ir.Type = 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: ir.Constant | None = 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: ir.Value | None = Gen._get_var_ptr('self') if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") offset: int = Gen._get_member_offset(len_name, ClassName) LenPtr: ir.Value = 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