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

785 lines
51 KiB
Python
Raw Permalink 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, 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