修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -1,91 +1,108 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
from lib.includes import t
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):
def _GetCTypeInfo(self, annotation: ast.AST) -> CTypeInfo | None:
return self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
def _StoreOrStrCopy(self, VarName, VarPtr, Value):
Gen = self.Trans.LlvmGen
DestPtr = Gen._load(VarPtr, name=VarName)
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.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)])
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.IntType(64), 8)
align = ir.Constant(ir.IntType(32), 1)
isvolatile = ir.Constant(ir.IntType(1), 0)
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 = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}")
CastedVal: ir.Value = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
except Exception: # 回退bitcast 失败时 alloca 新变量
NewVar = Gen._allocaEntry(Value.type, name=VarName)
NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, NewVar)
Gen.variables[VarName] = NewVar
def _HandleAttributeStoreLlvm(self, Target, Value):
Gen = self.Trans.LlvmGen
AttrName = Target.attr
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 = self._CurrentCpythonObjectClass
ClassName: str | None = self._CurrentCpythonObjectClass
if not ClassName:
self_var = Gen.variables.get('self')
self_var: ir.Value | None = Gen.variables.get('self')
if self_var:
var_type = self_var.type
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 = var_type.pointee
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 = Gen._get_var_ptr('self')
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
offset = Gen._get_member_offset(AttrName, ClassName)
MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
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 = Target.value.id
ClassName = Gen.var_struct_class.get(VarName)
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 = Gen.variables[VarName]
VarPtr: ir.Value = Gen.variables[VarName]
if isinstance(VarPtr.type, ir.PointerType):
pointee = VarPtr.type.pointee
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 = False
if ClassName and self.Trans.SymbolTable.has(ClassName):
TypeInfo = self.Trans.SymbolTable[ClassName]
if TypeInfo.IsUnion:
IsUnion = True
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 = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
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}")
@@ -93,34 +110,34 @@ class AnnAssignHandle(BaseHandle):
ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}")
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]:
if IsUnion:
NestedStructName = f"{ClassName}_{AttrName}"
NestedStructName: str = f"{ClassName}_{AttrName}"
if NestedStructName in Gen.structs:
NestedStructType = Gen.structs[NestedStructName]
NestedStructType: ir.Type = Gen.structs[NestedStructName]
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
offset = Gen._get_member_offset(AttrName, NestedStructName)
offset: int = Gen._get_member_offset(AttrName, NestedStructName)
if offset is not None and offset < len(NestedStructType.elements):
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
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 = Gen._get_member_offset(AttrName, ClassName)
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
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 = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
pointee = ObjVal.type.pointee
pointee: ir.Type = ObjVal.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
offset = Gen._get_member_offset(AttrName, CN)
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
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, Ptr):
Gen = self.Trans.LlvmGen
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(Ptr.type, ir.PointerType):
TargetType = Ptr.type.pointee
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:
@@ -135,30 +152,30 @@ class AnnAssignHandle(BaseHandle):
Value = Gen.builder.ptrtoint(Value, TargetType, name="ptr_to_int")
Gen._store(Value, Ptr)
def _HandleAnnAssignLlvm(self, Node):
Gen = self.Trans.LlvmGen
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):
Gen = self.Trans.LlvmGen
def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName = Node.target.id
TypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
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 = TypeInfo.IsPtr
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()
info: CTypeInfo = CTypeInfo()
info.IsDefine = True
info.DefineValue = Node.value.value
self.Trans.SymbolTable.insert(VarName, info)
@@ -169,92 +186,89 @@ class AnnAssignHandle(BaseHandle):
TypeInfo.BaseType = t.CChar()
TypeInfo.PtrCount = 1
IsPtr = True
if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list':
slice_node = Node.annotation.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
elem_type_node = slice_node.elts[0]
count_node = slice_node.elts[1]
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
ElemType = Gen.structs[elem_type_node.id]
else:
if isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str':
ElemType = ir.PointerType(ir.IntType(8))
else:
ElemType = Gen._ctype_to_llvm(ElemTypeInfo)
if isinstance(ElemType, ir.VoidType):
ElemType = ir.IntType(32)
ArrayCount = 1
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
ArrayCount = count_node.value
else:
eval_count = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable)
if eval_count is not None and isinstance(eval_count, int) and eval_count > 0:
ArrayCount = eval_count
elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
if Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
ArrayCount = len(Node.value.value) + 1
VarType = ir.ArrayType(ElemType, ArrayCount)
var = Gen._allocaEntry(VarType, name=VarName)
Gen.variables[VarName] = var
Gen._record_var_signedness(VarName, False)
if Node.value and isinstance(Node.value, ast.List):
InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen)
if InitConstants:
try:
InitVal = ir.Constant(VarType, InitConstants)
Gen.builder.store(InitVal, var)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
str_val = Node.value.value + '\x00'
str_bytes = bytearray(str_val, 'utf-8')
if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count:
str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes)))
# 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(VarType, str_bytes[:VarType.count] if isinstance(VarType, ir.ArrayType) else str_bytes)
InitVal: ir.Constant = ir.Constant(VarType, InitConstants)
Gen.builder.store(InitVal, var)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if self.Trans.VarScopes:
self.Trans.VarScopes[-1][VarName] = ElemTypeInfo
return
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):
def _find_struct_name_in_annot(node):
if isinstance(node, ast.Name) and node.id in Gen.structs:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs:
return node.value
if isinstance(node, ast.Attribute) and node.attr in Gen.structs:
return node.attr
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result = _find_struct_name_in_annot(node.left)
if result:
return result
return _find_struct_name_in_annot(node.right)
return None
found = _find_struct_name_in_annot(Node.annotation)
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 = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left)
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 = Gen._ctype_to_llvm(TypeInfo)
VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name:
stripped = 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 = getattr(VarType, 'name', '')
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:
@@ -263,38 +277,38 @@ class AnnAssignHandle(BaseHandle):
break
if isinstance(VarType, ir.VoidType):
VarType = ir.IntType(32)
IsUnsigned = TypeInfo.IsUInt
IsUnsigned: bool = TypeInfo.IsUInt
if VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
OldVal: ir.Value = Gen._reg_values[VarName]
if isinstance(OldVal.type, ir.PointerType):
var = Gen._allocaEntry(OldVal.type, name=VarName)
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 = self.HandleExprLlvm(Node.value, VarType=VarType)
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 = None
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 = InitValue.type.pointee
pointee: ir.Type = InitValue.type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
struct_name = getattr(pointee, 'name', '')
is_vtable_class = False
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 = Gen._allocaEntry(InitValue.type, name=VarName)
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:
@@ -304,9 +318,9 @@ class AnnAssignHandle(BaseHandle):
return
if InitValue:
try:
VarPtr = Gen.variables[VarName]
VarPtr: ir.Value = Gen.variables[VarName]
if isinstance(VarPtr.type, ir.PointerType):
TargetType = VarPtr.type.pointee
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:
@@ -317,24 +331,24 @@ class AnnAssignHandle(BaseHandle):
InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}")
Gen._store(InitValue, VarPtr)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
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 = Gen.module.globals[VarName]
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 = Gen._allocaEntry(VarType, name=VarName)
var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName)
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee = InitValue.type.pointee
pointee: ir.Type = InitValue.type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
struct_name = getattr(pointee, 'name', '')
is_vtable_class = False
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
@@ -373,34 +387,46 @@ class AnnAssignHandle(BaseHandle):
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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
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):
def _find_struct_in_binop(node):
if isinstance(node, ast.Name) and node.id in Gen.structs:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs:
return node.value
if isinstance(node, ast.Attribute) and node.attr in Gen.structs:
return node.attr
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result = _find_struct_in_binop(node.left)
if result:
return result
return _find_struct_in_binop(node.right)
return None
found_struct = _find_struct_in_binop(Node.annotation)
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 = InitValue.type.pointee
pointee: ir.Type = InitValue.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
@@ -414,47 +440,45 @@ class AnnAssignHandle(BaseHandle):
if TypeInfo:
self.Trans.VarScopes[-1][VarName] = TypeInfo
else:
DefaultInfo = CTypeInfo()
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 = None
AttrVarType: Any = None
try:
if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list':
slice_node = Node.annotation.slice
if IsListAnnotation(Node.annotation):
slice_node: ast.AST = Node.annotation.slice
if isinstance(slice_node, ast.Name):
AttrVarType = f'list[{slice_node.id}]'
AttrVarType = f't.CArray[{slice_node.id}]'
elif isinstance(slice_node, ast.Tuple):
elts = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts)
AttrVarType = f'list[{elts}]'
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'list[{ast.dump(slice_node)}]'
AttrVarType = f't.CArray[{ast.dump(slice_node)}]'
if AttrVarType is None:
AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
AttrTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if AttrTypeInfo:
AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo)
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
if Value:
self._HandleAttributeStoreLlvm(Node.target, Value)
AttrName = Node.target.attr
len_name = f'{AttrName}__len'
ClassName = self._CurrentCpythonObjectClass
AttrName: str = Node.target.attr
len_name: str = f'{AttrName}__len'
ClassName: str | None = self._CurrentCpythonObjectClass
if not ClassName:
self_var = Gen.variables.get('self')
self_var: ir.Value | None = Gen.variables.get('self')
if self_var:
var_type = self_var.type
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 = var_type.pointee
pointee: ir.Type = var_type.pointee
for cn, st in Gen.structs.items():
if st == pointee:
ClassName = cn
@@ -462,14 +486,14 @@ class AnnAssignHandle(BaseHandle):
if ClassName and ClassName in Gen.class_members:
for m_name, m_type in Gen.class_members[ClassName]:
if m_name == len_name:
list_len = None
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 = Gen._get_var_ptr('self')
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
offset = Gen._get_member_offset(len_name, ClassName)
LenPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name)
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