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

499 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, 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
class AnnAssignHandle(BaseHandle):
def _GetCTypeInfo(self, annotation: ast.AST) -> CTypeInfo | None:
return self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
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}")
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 _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)
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 字节 (字符)
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
Gen.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
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
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
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 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
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:
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}")
# 大端局部变量:存储时 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)
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
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 = 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):
AttrVarType = f't.CArray[{ast.dump(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