snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

View File

@@ -0,0 +1,704 @@
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
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}")
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
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
# 当 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:
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):
# 还原 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

View File

@@ -0,0 +1,60 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import ast
import llvmlite.ir as ir
class AssertHandle(BaseHandle):
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
if not cond_val:
return
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
zero: ir.Constant = ir.Constant(cond_val.type, 0)
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
Gen.builder.position_at_start(AssertFailBB)
exc_code: int = 9
exc_msg: ir.Value | None = None
if Node.msg:
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
exc_msg = self.HandleExprLlvm(Node.msg)
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
if Node.msg.args:
first_arg: ast.expr = Node.msg.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(Node.msg, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
else:
exc_msg = self.HandleExprLlvm(Node.msg)
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
Gen.builder.branch(ExceptBB)
else:
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
if exc_msg:
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
else:
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
Gen.builder.unreachable()
Gen.builder.position_at_start(AssertOkBB)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ast
import sys
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.VLogger import get_logger as _vlog
from lib.core.Handles.HandlesBase import BaseHandle
class AugAssignHandle(BaseHandle):
_AUGOP_MAP: dict[type, str] = {
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
}
_AUGOP_FALLBACK: dict[type, str] = {
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
}
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
"""判断增量赋值操作是否应使用无符号指令"""
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Attribute):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Subscript):
if Gen._check_node_unsigned(Node.target):
return True
if Node.value is not None and Gen._check_node_unsigned(Node.value):
return True
return False
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
if (VarName not in Gen.variables
and VarName not in Gen.global_vars
and VarName not in Gen._reg_values
and VarName not in Gen._direct_values):
src_info: str = Gen._get_node_info()
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
sys.exit(1)
if VarName in Gen.var_const_flags:
src_info: str = Gen._get_node_info()
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
sys.exit(1)
ClassName: str | None = Gen.var_struct_class.get(VarName)
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
if ClassName and iop_name:
iFuncName: str = f'{ClassName}.{iop_name}'
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
if iFuncName in Gen.functions or FuncName in Gen.functions:
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if OldVal and Value:
result: ir.Value | None
if iFuncName in Gen.functions:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
else:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
if result is not None:
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: ir.Value = Gen.variables[VarName]
if VarPtr.type.pointee == result.type:
Gen._store(result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
Gen._store(result, NewVar)
Gen.variables[VarName] = NewVar
else:
Gen._reg_values[VarName] = result
Gen.variables[VarName] = None
return
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if not Value:
return
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
OldVal: ir.Value = Gen._load(GVar, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, GVar)
return
if VarName in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[VarName]
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal: ir.Value = Gen._direct_values.pop(VarName)
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[VarName] = var
if Gen.builder.block.is_terminated:
return
if VarName in Gen.variables and Gen.variables[VarName] is not None:
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
store_ptr: ir.Value = Gen.variables[VarName]
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Value.type.width != 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
NewVal: ir.Value
if Op == '-' or Op == '+':
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
else:
ptr_val: ir.Value = OldVal
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
orig_type: ir.Type = OldVal.type
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
if NewVal.type.width > orig_type.width:
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
store_ptr = ptr_val
else:
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
Gen._store(NewVal, store_ptr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(store_ptr.type, ir.PointerType):
TargetType: ir.Type = store_ptr.type.pointee
if NewVal.type != TargetType:
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
if Coerced is not None:
NewVal = Coerced
Gen._store(NewVal, store_ptr)
elif VarName == 'pos':
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
Gen.variables[VarName] = var
OldVal: ir.Value = Gen._load(var, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, var)
elif isinstance(Node.target, ast.Attribute):
AttrName: str = Node.target.attr
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
if OldVal:
def _deref_if_ptr(val: ir.Value) -> ir.Value:
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
return Gen._load(val, name="deref_aug")
return val
OldVal = _deref_if_ptr(OldVal)
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
elif isinstance(Node.target, ast.Subscript):
SubTarget: ast.Subscript = Node.target
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
if ElemPtr:
if isinstance(ElemPtr.type, ir.PointerType):
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
Gen._store(NewVal, ElemPtr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
if NewVal.type.width > ElemPtr.type.pointee.width:
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
Gen._store(NewVal, ElemPtr)

View File

@@ -0,0 +1,832 @@
from __future__ import annotations
from typing import TYPE_CHECKING, List, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
from enum import IntFlag, auto
from llvmlite import ir as _ir
from lib.constants import config as _config
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
from lib.core.VLogger import get_logger as _vlog
EXCEPTION_CODE_MAP: dict[str, int] = {
'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3,
'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6,
'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99,
}
class FuncMeta(IntFlag):
NONE = 0
STATIC_METHOD = auto()
PROPERTY_GETTER = auto()
PROPERTY_SETTER = auto()
PROPERTY_DELETER = auto()
CLASS_METHOD = auto()
ABSTRACT = auto()
class _Delegated:
"""CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段
替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由:
描述符在类创建时绑定,访问时直接走 __get__/__set__
无 dict 查找和字符串比较的运行时开销。
"""
__slots__ = ('_target_attr', '_field_name')
def __init__(self, target_attr: str, field_name: str) -> None:
self._target_attr: str = target_attr # '_ts' or '_sm'
self._field_name: str = field_name
def __get__(self, obj: Any, objtype: type | None = None) -> Any:
if obj is None:
return self
target: Any = object.__getattribute__(obj, self._target_attr)
return getattr(target, self._field_name)
def __set__(self, obj: Any, value: Any) -> None:
target: Any = object.__getattribute__(obj, self._target_attr)
setattr(target, self._field_name, value)
class CTypeInfo:
"""
C 类型信息对象 - 统一符号表条目和类型计算
设计原则:
- BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串
- 描述符分为两种:
- VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const
- DataConst/DataVolatile: 指向数据的限定符,如 const int *
属性(类型计算):
- BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid())
- PtrCount: int - 指针层数
- VarConst: bool - 变量本身(指针)是否 const如 int * const
- VarVolatile: bool - 变量本身(指针)是否 volatile
- DataConst: bool - 指向的数据是否 const如 const int *
- DataVolatile: bool - 指向的数据是否 volatile
- ArrayDims: List[str] - 数组维度
- Storage: t.CType - 存储类 (static, extern 等)
- IsFuncPtr: bool - 是否函数指针
- FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型)
- FuncPtrReturn: CTypeInfo - 函数指针返回类型
- IsBitField: bool - 是否位域
- BitWidth: int - 位域宽度
- IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类
属性(符号表元数据):
- Name: str - 名称struct/enum/union/typedef 名)
- Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union
- OriginalType: str - typedef 的原始类型
- DeclaredType: str - 声明类型
- CreturnTypes: list - C 返回类型列表
- Lineno: int - 定义行号
- IsAnonymous: bool - 是否匿名类型
- IsCpythonObject: bool - 是否 CPython 对象
- IsEnumMember: bool - 是否枚举成员
"""
def __init__(self) -> None:
object.__setattr__(self, '_ts', TypeSpec())
sm: SymbolMeta = SymbolMeta()
sm.meta_list = FuncMeta.NONE
object.__setattr__(self, '_sm', sm)
# --- 新公共 API供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind ---
@property
def ts(self) -> TypeSpec:
"""TypeSpec — 纯类型描述(只读)"""
return self._ts
@property
def sm(self) -> SymbolMeta:
"""SymbolMeta — 符号表元数据(只读)"""
return self._sm
@property
def kind(self) -> 'SymbolKind':
"""SymbolKind — 符号类型种类枚举"""
return self._sm.kind
# 注旧字段名PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现,
# 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由
@property
def BaseType(self) -> t.CType | tuple | None:
return self._ts._base_type
@BaseType.setter
def BaseType(self, value: t.CType | type | tuple | List | None) -> None:
"""设置 BaseType接受以下类型
- None: 清空
- t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志
- type (CType 子类): 如 t.CStruct自动实例化
- tuple/list of t.CType: 多个组合类型
"""
ts: TypeSpec = self._ts
sm: SymbolMeta = self._sm
if value is None:
ts._base_type = None
sm.is_struct = False
sm.is_enum = False
sm.is_union = False
sm.is_renum = False
return
if isinstance(value, (tuple, list)):
ts._base_type = tuple(value)
for v in value:
if isinstance(v, t.CStruct):
sm.is_struct = True
elif isinstance(v, t.CEnum):
sm.is_enum = True
elif isinstance(v, t.CUnion):
sm.is_union = True
elif isinstance(v, t.REnum):
sm.is_renum = True
sm.is_enum = True
return
if isinstance(value, type) and issubclass(value, t.CType):
ts._base_type = value()
return
if isinstance(value, t.CType):
ts._base_type = value
if isinstance(value, t.CStruct):
sm.is_struct = True
sm.is_enum = False
sm.is_union = False
sm.is_renum = False
elif isinstance(value, t.REnum):
sm.is_renum = True
sm.is_enum = True
sm.is_struct = False
sm.is_union = False
elif isinstance(value, t.CEnum):
sm.is_enum = True
sm.is_struct = False
sm.is_union = False
sm.is_renum = False
elif isinstance(value, t.CUnion):
sm.is_union = True
sm.is_struct = False
sm.is_enum = False
sm.is_renum = False
return
raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}")
@property
def TypeCls(self) -> type | None:
"""获取 CType 类(从 BaseType 推断)"""
bt: t.CType | tuple | None = self._ts._base_type
if bt:
return type(bt)
sm: SymbolMeta = self._sm
if sm.is_struct:
return t.CStruct
if sm.is_enum:
return t.CEnum
if sm.is_union:
return t.CUnion
if sm.is_typedef:
return t._CTypedef
return None
@property
def IsPtr(self) -> bool:
return self._ts.ptr_count > 0
@property
def IsVoid(self) -> bool:
return isinstance(self._ts._base_type, t.CVoid)
@property
def IsStr(self) -> bool:
return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
@property
def IsInt(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid)
@property
def IsUInt(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False
@property
def IsFloat(self) -> bool:
bt: t.CType | tuple | None = self._ts._base_type
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid)
def ToString(self) -> str:
ts: TypeSpec = self._ts
sm: SymbolMeta = self._sm
bt: t.CType | tuple | None = ts._base_type
if ts.is_func_ptr:
return 'Callable'
parts: list[str] = []
if ts.storage and not isinstance(ts.storage, t.CExport):
parts.append(type(ts.storage).__name__)
if ts.data_const or ts.data_volatile:
qualifiers: list[str] = []
if ts.data_const:
qualifiers.append("const")
if ts.data_volatile:
qualifiers.append("volatile")
parts.append("_".join(qualifiers))
if sm.is_typedef and sm.name:
return sm.name
elif sm.is_renum and sm.name:
base_name: str = sm.name
elif bt:
if isinstance(bt, str):
base_name = bt
elif isinstance(bt, type) and issubclass(bt, t.CType):
base_name = bt.__name__
elif isinstance(bt, t.CType):
# 对命名的 CTypeCStruct/CEnum/CUnion/REnum优先使用其 name 属性
# 否则回退到类名(如 'CInt'、'CChar'
_named: str | None = getattr(bt, 'name', None)
base_name = _named if _named else type(bt).__name__
else:
base_name = str(bt)
else:
base_name = "void"
if ts.is_array_ptr:
ptr_str: str = ""
if ts.ptr_count > 0:
ptr_str = "*" * ts.ptr_count
if ts.array_ptr:
inner: str = ts.array_ptr.ToString()
if ptr_str:
parts.append(f"{base_name} {ptr_str}({inner})")
else:
parts.append(f"{base_name} ({inner})")
else:
if ptr_str:
parts.append(f"{base_name} {ptr_str}()")
else:
parts.append(f"{base_name} ()")
elif ts.array_ptr:
inner = ts.array_ptr.ToString()
if ts.ptr_count > 0:
parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})")
else:
parts.append(f"{base_name} ({inner})")
else:
parts.append(base_name)
if ts.ptr_count > 0:
parts.append("*" * ts.ptr_count)
if ts.var_const:
parts.append("const")
if ts.var_volatile:
parts.append("volatile")
for dim in ts.array_dims:
if dim:
parts.append(f"[{dim}]")
else:
parts.append("[]")
return " ".join(parts) if parts else "void"
@staticmethod
def CreateFromTypeName(TypeName: str) -> "CTypeInfo":
"""从类型名字符串创建 CTypeInfo兼容旧 API"""
info: CTypeInfo = CTypeInfo()
if TypeName.startswith('struct '):
info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct()
elif TypeName.startswith('enum '):
info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum()
elif TypeName.startswith('union '):
info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion()
else:
info.BaseType = t.CStruct(name=TypeName)
return info
# LLVM primitive type name → (CTypeClass, PtrCount) mapping
# Used when generic type inference produces LLVM type names like 'i64', 'double', etc.
_LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None
@classmethod
def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]:
if cls._LLVM_PRIMITIVE_MAP is not None:
return cls._LLVM_PRIMITIVE_MAP
cls._LLVM_PRIMITIVE_MAP = {
'void': (t.CVoid, 0),
'i1': (t.CInt, 0),
'i8': (t.CChar, 0),
'i16': (t.CShort, 0),
'i32': (t.CInt, 0),
'i64': (t.CLong, 0),
'i128': (t.CInt, 0),
'float': (t.CFloat, 0),
'double': (t.CDouble, 0),
'fp128': (t.CFloat128T, 0),
}
return cls._LLVM_PRIMITIVE_MAP
@staticmethod
def FromTypeName(TypeName: str) -> "CTypeInfo":
"""从简单类型名构造 CTypeInfo不经过 FromStr 字符串解析)"""
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
return TypeAnnotationResolver.from_type_name(TypeName)
# FromStr 已移除 - 类型解析不再经过中间字符串格式
# typedef 展开直接走 CTypeInfo 对象,不经过字符串解析
@staticmethod
def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any:
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable)
@classmethod
def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo":
"""从 AST 节点解析 CTypeInfo类方法
Args:
Node: AST 节点(如 ast.Name, ast.Attribute 等)
SymbolTable: 符号表字典
"""
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
return TypeAnnotationResolver.from_node(Node, SymbolTable)
def Copy(self) -> "CTypeInfo":
NewInfo: CTypeInfo = CTypeInfo()
NewInfo._ts = self._ts.copy()
NewInfo._sm = self._sm.copy()
# CTypeInfo 引用字段需要深拷贝
if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo):
NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy()
if isinstance(NewInfo._ts.original_type, CTypeInfo):
NewInfo._ts.original_type = NewInfo._ts.original_type.Copy()
if NewInfo._ts.array_ptr:
NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy()
return NewInfo
def get(self, key: str, default: Any = None) -> Any:
"""获取额外属性"""
return self._sm._extra.get(key, default)
def set(self, key: str, value: Any) -> None:
"""设置额外属性"""
self._sm._extra[key] = value
@staticmethod
def VoidTypeInfo() -> "CTypeInfo":
info: CTypeInfo = CTypeInfo()
info.BaseType = t.CVoid()
return info
def ToLLVM(self, Gen: LlvmCodeGenerator) -> _ir.Type:
if Gen is None:
return _ir.IntType(32)
return Gen._ctype_to_llvm(self)
def __str__(self) -> str:
return self.ToString()
def __repr__(self) -> str:
ts: TypeSpec = self._ts
sm: SymbolMeta = self._sm
return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})"
# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类
# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由
for _old_name, (_target, _field) in FIELD_ROUTES.items():
setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field))
del _old_name, _target, _field
class CTypeHelper:
@staticmethod
def GetTModuleCType(TypeName: str) -> type | None:
result: type | None = CTypeRegistry.GetClassByName(TypeName)
if result is not None:
return result
TypeClass: type | None = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType):
return TypeClass
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType):
return FallbackClass
return None
@staticmethod
def GetCName(type_or_name: str | type) -> str:
if isinstance(type_or_name, str):
cls: type | None = CTypeRegistry.GetClassByName(type_or_name)
if cls is None:
cls = CTypeHelper.GetTModuleCType(type_or_name)
if cls:
return cls.__name__
return type_or_name
elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType):
return type_or_name.__name__
return ''
class BuiltinTypeMap:
"""
内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射
用法BuiltinTypeMap.Get('int') -> (t.CInt, 0)
BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1)
"""
_map: dict[str, tuple[type, int]] | None = None
@classmethod
def _build_map(cls) -> dict[str, tuple[type, int]]:
if cls._map is not None:
return cls._map
CTypeRegistry._build()
cls._map = {}
# 仅使用 Python 类名 → (CType 类, ptr_level) 映射。
# C 类型名(如 'int'、'int32_t')不再通过 _cname_to_class 提供。
# C 头文件 stub 生成器使用独立的硬编码表CTypeMapper._CNAME_TO_PY
for pyname, ctype_cls in CTypeRegistry._name_to_class.items():
pos: frozenset = getattr(ctype_cls, 'position', frozenset())
if t.CType.POINTER in pos and t.CType.BASE not in pos:
cls._map[pyname] = (ctype_cls, 1)
else:
cls._map[pyname] = (ctype_cls, 0)
# 保留一些常用的字符串速记(这些不是 CName而是硬编码的便捷别名
# 包含 Python 内置类型名int/float/bool和 C 类型名速记char/short/long 等)。
_SPECIAL: dict[str, tuple[type, int]] = {
# Python 内置类型名
'str': (t.CChar, 1), 'bytes': (t.CChar, 1),
'int': (t.CInt, 0), 'float': (t.CFloat, 0), 'bool': (t.CBool, 0),
# C 类型名速记
'char': (t.CChar, 0), 'short': (t.CShort, 0),
'long': (t.CLong, 0), 'long long': (t.CLongLong, 0),
'double': (t.CDouble, 0),
'unsigned': (t.CUnsigned, 0),
'signed': (t.CInt, 0), 'signed int': (t.CInt, 0),
'signed char': (t.CSignedChar, 0),
'void': (t.CVoid, 0), 'Void': (t.CVoid, 0),
}
for k, v in _SPECIAL.items():
if k not in cls._map:
cls._map[k] = v
_FLOAT_ALIASES: dict[str, tuple[type, int]] = {
'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0),
'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0),
'FLOAT128': (t.CFloat128T, 0),
}
for k, v in _FLOAT_ALIASES.items():
if k not in cls._map:
cls._map[k] = v
return cls._map
@classmethod
def Get(cls, type_name: str) -> tuple[type, int] | None:
"""获取类型类和指针层级"""
return cls._build_map().get(type_name)
class BaseHandle:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
self._CurrentCpythonObjectClass: str | None = None
@staticmethod
def _is_char_pointer(val: _ir.Value) -> bool:
"""检查值是否为 char* (i8*) 指针"""
if not isinstance(val.type, _ir.PointerType):
return False
pointee: _ir.Type = val.type.pointee
return isinstance(pointee, _ir.IntType) and pointee.width == 8
def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None) -> _ir.Value | None:
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any:
return self.Trans.BodyHandler.HandleBodyLlvm(Body)
def _get_int_ptr(self, Node: ast.AST) -> _ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(Node, ast.Name):
if Node.id in Gen.variables:
return Gen.variables[Node.id]
elif isinstance(Node, ast.Attribute):
obj_val: Any = self.HandleExprLlvm(Node.value)
if not obj_val:
return None
if isinstance(obj_val.type, _ir.PointerType):
pointee: _ir.Type = obj_val.type.pointee
if isinstance(pointee, (_ir.IdentifiedStructType, _ir.LiteralStructType)):
StructName: str | None = None
if isinstance(pointee, _ir.IdentifiedStructType):
StructName = pointee.name
if not StructName:
for ClassName, struct_type in Gen.structs.items():
if struct_type == pointee:
StructName = ClassName
break
if StructName and StructName in Gen.structs:
offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen)
member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr")
return member_ptr
return None
def _IsTModuleType(self, TypeName: str) -> bool:
if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'):
return True
TypeClass: type | None = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type):
if issubclass(TypeClass, t.CType):
return True
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type):
if issubclass(FallbackClass, t.CType):
return True
return False
def ResolveListElementType(
self,
elem_type_node: ast.expr,
Gen: Any,
*,
check_func_ptr: bool = False,
handle_str: bool = False,
void_fallback_width: int = 32,
fallback_to_cint: bool = False,
) -> tuple[Any, CTypeInfo | None]:
"""解析 list 元素类型,返回 (LLVM类型, CTypeInfo|None)。
统一处理结构体、str、函数指针、VoidType 回退等变体。
Args:
check_func_ptr: 是否检查函数指针(全局变量路径需要)
handle_str: 是否处理 str → i8*(局部变量路径需要)
void_fallback_width: VoidType 回退宽度 (32 或 8)
fallback_to_cint: 无类型信息时回退到 CInt
"""
elem_type_info: CTypeInfo | None = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
# 结构体类型
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
if check_func_ptr:
sym_entry: CTypeInfo | None = self.Trans.SymbolTable.lookup(elem_type_node.id)
if sym_entry and isinstance(sym_entry, CTypeInfo) and sym_entry.IsFuncPtr:
return _ir.IntType(8).as_pointer(), elem_type_info
return Gen.structs[elem_type_node.id], elem_type_info
# str → i8*
if handle_str and isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str':
return _ir.PointerType(_ir.IntType(8)), elem_type_info
# 函数指针检查
if check_func_ptr and elem_type_info and elem_type_info.IsFuncPtr:
return _ir.IntType(8).as_pointer(), elem_type_info
# 回退到 CInt
if elem_type_info is None and fallback_to_cint:
elem_type_info = CTypeInfo()
elem_type_info.BaseType = t.CInt()
elem_type: Any = Gen._ctype_to_llvm(elem_type_info)
if isinstance(elem_type, _ir.VoidType):
elem_type = _ir.IntType(void_fallback_width)
return elem_type, elem_type_info
def ParseArrayCount(
self,
count_node: ast.expr | None,
Gen: Any,
value_node: ast.expr | None = None,
*,
mode: str = 'global',
) -> int:
"""解析数组计数,返回计数(默认 1
统一处理 Constant/Name/Attribute/BinOp/None 等形式。
None 或 Constant(None) 时从 value_node 推断List 长度或 str 长度+1
Args:
count_node: 计数 AST 节点
value_node: 赋值右侧值节点(用于 count_node 为 None 时推断)
mode: 'global' 使用 _eval_global_count + SymbolTable + _define_constants
'local' 使用 TryEvalConstExpr
"""
# None 或 Constant(None) → 从 value_node 推断
if count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
if value_node and isinstance(value_node, ast.List):
return len(value_node.elts)
if value_node and isinstance(value_node, ast.Constant) and isinstance(value_node.value, str):
return len(value_node.value) + 1
return 1
# Constant(int)
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
return count_node.value
if mode == 'global':
# Name → SymbolTable + _define_constants
if isinstance(count_node, ast.Name):
ArrayCount: int = 1
if self.Trans.SymbolTable.has(count_node.id):
sym_info: Any = self.Trans.SymbolTable[count_node.id]
if isinstance(sym_info.value, int):
ArrayCount = sym_info.value
if ArrayCount == 1 and count_node.id in Gen._define_constants:
def_val: Any = Gen._define_constants[count_node.id]
if isinstance(def_val, int):
ArrayCount = def_val
return ArrayCount
# Attribute / BinOp → _eval_global_count
if isinstance(count_node, (ast.Attribute, ast.BinOp)):
eval_fn: Any = getattr(self, '_eval_global_count', None)
if eval_fn is not None:
ev: int | None = eval_fn(count_node, Gen)
if ev is not None:
return ev
return 1
else:
# local mode → TryEvalConstExpr
eval_count: Any = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable)
if eval_count is not None and isinstance(eval_count, int) and eval_count > 0:
return eval_count
return 1
return 1
def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None:
"""解析注解类型BinOp(BitOr) 优先使用 MergeTypes其他使用 FromNode。
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
if merger:
info: CTypeInfo | None = merger.MergeTypes(annotation)
if info is not None and isinstance(info, CTypeInfo):
return info
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
def CollectAnnAssignMember(
self, item: ast.AST, Gen: Any
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
"""从 ast.AnnAssign 节点解析成员信息。
返回 (VarName, MemberType, TypeInfo)TypeInfo 为 None 表示解析回退到 i32。
非 AnnAssign/Name 目标时返回 None。
"""
if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name):
return None
VarName: str = item.target.id
try:
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, _ir.VoidType):
MemberType = _ir.PointerType(_ir.IntType(8))
return VarName, MemberType, TypeInfo
except Exception as e:
_vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e)
return VarName, _ir.IntType(32), None
def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None:
"""查找函数符号,先尝试 module_path.name再回退到 name。
统一处理 HandlesExprCall / HandlesAssign 中重复的二级查找模式。
返回 CTypeInfo不限定 IsFunction由调用方检查标志位。
"""
st = self.Trans.SymbolTable
if module_path:
sym: CTypeInfo | None = st.lookup(f'{module_path}.{name}')
if sym:
return sym
return st.lookup(name)
def BuildLLVMFuncTypeFromSig(
self,
sym_info: CTypeInfo,
Gen: Any,
*,
mangled_name: str | None = None,
use_infer_fallback: bool = False,
) -> tuple[Any, list[Any], bool] | None:
"""从 CTypeInfo 函数签名构建 LLVM 函数类型。
返回 (ret_type, llvm_param_types, is_variadic),非函数返回 None。
统一处理 FuncPtrReturn/FuncPtrParams → ToLLVM 转换、VoidType 回退。
Args:
mangled_name: 用于 _infer_return_type + stub 查找回退
use_infer_fallback: 为 True 时启用 _infer_return_type + stub 查找回退链
"""
if not sym_info.IsFunction:
return None
is_variadic: bool = sym_info.IsVariadic
ret_type_info = sym_info.FuncPtrReturn
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_type: Any = ret_type_info.ToLLVM(Gen)
elif use_infer_fallback and mangled_name:
inferred: Any = Gen._infer_return_type(mangled_name)
if isinstance(inferred, _ir.IntType) and inferred.width == 32:
try:
stub_ft: Any = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
if stub_ft and hasattr(stub_ft, 'return_type'):
inferred = stub_ft.return_type
except Exception:
pass
ret_type = inferred
else:
ret_type = Gen._CType2LLVM('i32', False)
param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])]
if isinstance(ret_type, _ir.VoidType):
ret_type = _ir.IntType(32)
llvm_param_types: list[Any] = []
for pt in param_type_infos:
if isinstance(pt, CTypeInfo) and pt.BaseType:
lp: Any = pt.ToLLVM(Gen)
else:
lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False)
if isinstance(lp, _ir.VoidType):
lp = _ir.IntType(8).as_pointer()
llvm_param_types.append(lp)
return ret_type, llvm_param_types, is_variadic
def GetOrCreateFuncDecl(
self,
name: str,
ret_type: Any,
param_types: list[Any],
Gen: Any,
*,
is_variadic: bool = False,
replace_name: str | None = None,
) -> Any:
"""创建或替换 LLVM 函数声明。
若 name 已存在且类型不匹配,通过 _replace_function_decl 替换。
replace_name 传递给 _replace_function_decl通常为未 mangle 的 func_name
"""
if name not in Gen.functions:
func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
func_decl = _ir.Function(Gen.module, func_type, name=name)
Gen.functions[name] = func_decl
else:
existing = Gen.functions[name]
existing_type = getattr(existing, 'ftype', None)
new_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
if existing_type and existing_type != new_type:
replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, replace_name or name, new_type)
if replaced and replaced != existing:
Gen.functions[name] = replaced
return Gen.functions[name]
def GetOrCreateStubFuncDecl(
self,
decl_name: str,
stub_func_type: Any,
Gen: Any,
*,
alias: str | None = None,
check_existing: bool = True,
) -> Any:
"""创建 stub 函数声明,可选注册别名。
check_existing=False 时跳过存在性检查(用于确定不存在的场景)。
"""
if check_existing and decl_name in Gen.functions:
func_decl = Gen.functions[decl_name]
else:
func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name)
Gen.functions[decl_name] = func_decl
if alias and alias != decl_name:
if not check_existing or alias not in Gen.functions:
Gen.functions[alias] = func_decl
return func_decl
StrictMode: bool = _config.mode == 'strict'

View File

@@ -0,0 +1,77 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class BodyHandle(BaseHandle):
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for Node in Body:
if Gen.builder and Gen.builder.block.is_terminated:
break
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Expr):
self.HandleExprLlvm(Node.value)
elif isinstance(Node, ast.Return):
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
elif isinstance(Node, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(Node)
elif isinstance(Node, ast.AugAssign):
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
elif isinstance(Node, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
elif isinstance(Node, ast.If):
self.Trans.IfHandler._HandleIfLlvm(Node)
elif isinstance(Node, ast.For):
self.Trans.ForHandler._HandleForLlvm(Node)
elif isinstance(Node, ast.While):
self.Trans.WhileHandler._HandleWhileLlvm(Node)
elif isinstance(Node, ast.Break):
if Gen.loop_break_targets:
Gen.builder.branch(Gen.loop_break_targets[-1])
elif isinstance(Node, ast.Continue):
if Gen.loop_continue_targets:
Gen.builder.branch(Gen.loop_continue_targets[-1])
elif isinstance(Node, ast.With):
self.Trans.WithHandler._HandleWithLlvm(Node)
elif isinstance(Node, ast.ClassDef):
pass
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
self.Trans.MatchHandler._HandleMatchLlvm(Node)
elif isinstance(Node, ast.Try):
self.Trans.TryHandler._HandleTryLlvm(Node)
elif isinstance(Node, ast.Raise):
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
elif isinstance(Node, ast.Assert):
self.Trans.AssertHandler._HandleAssertLlvm(Node)
elif isinstance(Node, ast.Global):
self.Trans.ForHandler._HandleGlobalLlvm(Node)
elif isinstance(Node, ast.FunctionDef):
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
elif isinstance(Node, ast.Nonlocal):
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
elif isinstance(Node, ast.Delete):
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = Gen._current_source_file or ''
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._EmitTempFrees()
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import llvmlite.ir as ir
class DeleteHandle(BaseHandle):
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for target in Node.targets:
if isinstance(target, ast.Subscript):
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
if obj_val and idx_val:
# 处理 obj_val 为 i8整数的情况联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
elif isinstance(target, ast.Name):
ClassName: str | None = Gen.var_struct_class.get(target.id)
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
# 处理 obj_val 为 i8整数的情况联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
elif isinstance(target, ast.Attribute):
# 检查 property deleter
AttrName: str = target.attr
ClassName: str | None = None
obj_val_for_prop: ir.Value | None = None
if isinstance(target.value, ast.Name) and target.value.id == 'self':
# del self.attr — 检查当前类的 property deleter
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc and SelfPtr:
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
continue
else:
# del obj.attr — 检查 obj 类的 property deleter
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
if obj_val:
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc:
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
continue
# 原有的 __del__ 处理逻辑
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
obj_val = Gen._load(obj_val, name="Load_del_ptr")
ClassName = None
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if obj_val.type.pointee == ST:
ClassName = CN
break
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if isinstance(target.value, ast.Name) and target.value.id == 'self':
AttrName = target.attr
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
if SelfClassName and SelfClassName in Gen.class_members:
for member_name, member_type in Gen.class_members[SelfClassName]:
if member_name == AttrName:
for CN in Gen.structs:
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
break
if not ClassName:
for CN, ST in Gen.structs.items():
if Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__")

View File

@@ -0,0 +1,446 @@
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 re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.constants.config import mode as _config_mode
from lib.includes.t import CTypeRegistry as _CR
class ExprHandle(BaseHandle):
# list 元素类型 → (字节大小, LLVM 元素类型) 映射表
# 用于 _HandleListLlvm 中 alloc_size / byte_offset / elem_ptr 类型统一查表,
# 消除原代码三处重复的 if-elif 链。
_ELEM_TYPE_INFO: dict[str, tuple[int, ir.Type]] = {
'i8': (1, ir.IntType(8)),
'i16': (2, ir.IntType(16)),
'i32': (4, ir.IntType(32)),
'float': (4, ir.FloatType()),
'double': (8, ir.DoubleType()),
}
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node: ast.AST, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
return self._HandleNameLlvm(Node, VarType)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node: ast.List, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
elements: list[ast.expr] = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len: int = len(elements)
elem_type: str = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
match: re.Match | None = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_str: str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size: int = array_len
elem_info: tuple[int, ir.Type] = self._ELEM_TYPE_INFO.get(elem_type, (1, ir.IntType(8)))
elem_size: int = elem_info[0]
elem_llvm_type: ir.Type = elem_info[1]
alloc_size *= elem_size
malloc_fn: Any = None
malloc_arg_type: ir.IntType = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype: Any = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
Gen.functions['malloc'] = malloc_fn
except Exception: # 回退malloc 函数创建失败时返回 null
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr: Any = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr: Any = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset: int = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
ptr_as_int: Any = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val: Any = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr: Any = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type in ('float', 'double'):
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(elem_llvm_type), name=f"list_{elem_type}_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node: ast.Constant, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Value: Any = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
resolved: Any = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls: type = resolved[0] if isinstance(resolved, tuple) else resolved
inst: Any = ctype_cls()
size: int = getattr(inst, 'Size', 32)
is_unsigned: bool = getattr(inst, 'IsSigned', True) is False
mask: int = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match: re.Match | None = re.match(r'^i(\d+)$', VarType)
if llvm_match:
width: int = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide: bool = getattr(Node, 'kind', None) == 'u'
# 引号类型推断:单引号单字符 → i8双引号/多字符/三重 → i8*,空 → 0(None)
quote_char: str | None = None
is_triple: bool = False
if not is_wide:
col_offset: int = getattr(Node, 'col_offset', 0)
node_lineno: int = getattr(Node, 'lineno', 0)
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
# 因此在 lineno 和 lineno-1 两行中查找引号
for try_lineno in (node_lineno, node_lineno - 1):
source_line: str | None = Gen._get_source_line(try_lineno)
if source_line and col_offset < len(source_line):
ch: str = source_line[col_offset]
if ch in ("'", '"'):
quote_char = ch
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
is_triple = True
break
# 空字符串 → 创建指向 \0 的全局变量 (而非 null, 避免 strcmp 解引用空指针崩溃)
# 走与非空字符串相同的路径, 由下方 else 分支处理
# 单引号单字符(非三重)→ i8
is_char_literal: bool = (not is_triple) and (quote_char == "'") and (len(Value) == 1) and not is_wide
if is_char_literal:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass # 类型不匹配:目标是 ptr 但值是 char走 string 路径
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
resolved = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = re.match(r'^i(\d+)$', VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
else:
# 无类型提示:单引号单字符默认为 i8
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value: str = Value + '\x00'
wide_chars: list[int] = [ord(c) for c in str_value]
target_count: int = len(wide_chars)
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(16), target_count)
gv_name: str = f"str_const_{Gen.string_const_counter}"
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr: Any = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes: bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
VarName: str = Node.id
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val: Any = define_constants[VarName]
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in getattr(Gen, '_define_constants', {}):
try:
sym_info: Any = self.translator.SymbolTable.lookup(VarName)
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
val = sym_info.DefineValue
if isinstance(val, int):
# Use VarType hint if available
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 优先检查 variablesalloca因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: Any = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
# 大端局部变量:读取时 bswap 还原
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
return loaded
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: Any = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
return Gen.GetVarPtr('self')
if Gen._has_function(VarName):
func: Any = Gen._get_function(VarName)
if func:
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
if VarName in Gen.class_methods:
return ir.Constant(ir.IntType(8).as_pointer(), None)
if VarName == 'True' or VarName == 'False':
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
if SymInfo:
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
MangledName: str = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g: Any = Gen.module.globals[MangledName]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
for sha1 in Gen.ModuleSha1Map.values():
prefixed: str = f"{sha1}.{VarName}"
if prefixed in Gen.module.globals:
g = Gen.module.globals[prefixed]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
t_c_imported: dict[str, tuple[str, str]] = getattr(self.Trans, '_t_c_imported_names', {})
if VarName in t_c_imported:
src_module: str
src_name: str
src_module, src_name = t_c_imported[VarName]
virtual_attr: ast.Attribute = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
return ir.Constant(ir.IntType(32), 0)

View File

@@ -0,0 +1,580 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import ast
import re
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.SymbolUtils import IsTModule
from lib.includes import t
# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数
# 添加保护避免重复补丁
_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False)
if not _InlineAsmPatched:
_OrigInlineAsmInit = ir.InlineAsm.__init__
_OrigInlineAsmDescr = ir.InlineAsm.descr
def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None):
_OrigInlineAsmInit(self, ftype, asm, constraint, side_effect)
self.asm_dialect = asm_dialect
def _patched_inline_asm_descr(self, buf):
sideeffect = 'sideeffect' if self.side_effect else ''
dialect_str = getattr(self, 'asm_dialect', None)
if dialect_str == 'intel':
dialect = 'inteldialect'
else:
dialect = ''
fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"'
buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm,
constraint=self.constraint))
ir.InlineAsm.__init__ = _patched_inline_asm_init
ir.InlineAsm.descr = _patched_inline_asm_descr
ir.InlineAsm._transpyc_patched = True
class ExprAsmHandle(BaseHandle):
@staticmethod
def _format_to_dialect(asm_format: str | None) -> str | None:
"""将用户指定的 format 参数转换为 LLVM asm_dialect 值"""
fmt: str = asm_format.lower() if asm_format else 'intel'
if fmt == 'att':
return 'att'
elif fmt == 'arm':
return None # ARM 没有专门的 dialect 标记
else:
return 'intel' # 默认 Intel
def _HandleAsmLlvm(self, Node: ast.Call) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
op_arg: Any = None
input_arg: Any = None
output_arg: Any = None
asm_format: str = 'Intel' # 汇编格式: Intel / AT&T / ARM
for kw in Node.keywords:
if kw.arg == 'op':
op_arg = kw.value
elif kw.arg in ('input', 'inp', 'inputs'):
input_arg = kw.value
elif kw.arg in ('output', 'out', 'outputs'):
output_arg = kw.value
elif kw.arg == 'format':
if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str):
asm_format = kw.value.value
if len(Node.args) >= 1:
pos_op: Any = None
if len(Node.args) >= 2 and op_arg is None:
pos_op = Node.args[1]
return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format)
if len(Node.args) < 2:
return ir.Constant(ir.IntType(32), 1)
args: list[ast.AST] = Node.args
if len(args) == 4:
output_type_arg: ast.AST = args[0]
asm_template_arg: ast.AST = args[1]
constraint_arg: ast.AST = args[2]
clobber_arg: ast.AST = args[3]
output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg)
if not output_type:
output_type = ir.IntType(32)
asm_template: str = ''
if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value))
constraint: str = ''
if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str):
constraint = constraint_arg.value
clobber: str = ''
if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str):
clobber = clobber_arg.value
full_constraint: str = constraint
func_type: ir.FunctionType = ir.FunctionType(output_type, [])
asm_dialect: str | None = self._format_to_dialect(asm_format)
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect)
result: Any = Gen.builder.call(inline_asm, [], name="asm_result")
return result
elif len(args) >= 2:
output_type_arg: ast.AST = args[0]
asm_template_arg: ast.AST = args[1]
output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg)
if not output_type:
output_type = ir.IntType(32)
asm_template: str = ''
if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value))
output_constraints: list[str] = []
output_values: list[Any] = []
if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)):
for item in args[2].elts:
if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
constraint_node: ast.AST = item.elts[0]
value_node: ast.AST = item.elts[1]
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
output_constraints.append(constraint_node.value)
value: Any = self.HandleExprLlvm(value_node)
if value:
output_values.append(value)
input_constraints: list[str] = []
input_values: list[Any] = []
if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)):
for item in args[3].elts:
if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
constraint_node: ast.AST = item.elts[0]
value_node: ast.AST = item.elts[1]
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
input_constraints.append(constraint_node.value)
value: Any = self.HandleExprLlvm(value_node)
if value:
input_values.append(value)
clobbers: list[str] = []
if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)):
for item in args[4].elts:
if isinstance(item, ast.Constant) and isinstance(item.value, str):
clobbers.append(item.value)
constraint_parts: list[str] = []
for oc in output_constraints:
constraint_parts.append(oc)
input_start_idx: int = len(output_constraints)
for ic in input_constraints:
constraint_parts.append(ic)
full_constraint: str = ",".join(constraint_parts)
if clobbers:
if full_constraint:
full_constraint += ","
for c in clobbers:
full_constraint += f"~{{{c}}}"
operands: list[Any] = output_values + input_values
param_types: list[ir.Type] = [v.type for v in operands]
func_type: ir.FunctionType = ir.FunctionType(output_type, param_types)
asm_dialect: str | None = self._format_to_dialect(asm_format)
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect)
result: Any = Gen.builder.call(inline_asm, operands, name="asm_result")
return result
return None
def _prepare_intel_asm(self, template: str) -> str:
template = re.sub(r'%(\d+)', r'$\1', template)
template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template)
return template
def _normalize_asm_template(self, template: str) -> str:
lines = template.split('\n')
if len(lines) <= 1:
return template
first_line = lines[0]
rest_lines = lines[1:]
stripped = []
for line in rest_lines:
s = line.lstrip()
if s:
stripped.append(s)
else:
stripped.append('')
return '\n'.join([first_line] + stripped)
def _process_joined_str_template(self, node: ast.AST, out_input_ops: list[Any], out_input_constraints: list[str],
out_output_ops: list[Any], out_output_constraints: list[str]) -> str:
if not isinstance(node, ast.JoinedStr):
if isinstance(node, ast.Constant) and isinstance(node.value, str):
return node.value
return ''
raw_parts: list[tuple[str, str | int]] = []
for value in node.values:
if isinstance(value, ast.Constant) and isinstance(value.value, str):
raw_parts.append(('text', value.value))
elif isinstance(value, ast.FormattedValue):
expr: ast.AST = value.value
if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute):
if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c':
if expr.func.attr == 'AsmInp':
if expr.args:
v: Any = self.HandleExprLlvm(expr.args[0])
if v:
c: str = 'r'
if len(expr.args) >= 2:
c = self._parse_asm_descr(expr.args[1])
if not c:
c = 'r'
out_input_ops.append(v)
out_input_constraints.append(c)
raw_parts.append(('input', len(out_input_ops) - 1))
elif expr.func.attr == 'AsmOut':
if expr.args:
target_ptr: Any = self._get_var_ptr_for_asm(expr.args[0])
if target_ptr:
v = target_ptr
else:
v = self.HandleExprLlvm(expr.args[0])
if v:
c: str = '=r'
if len(expr.args) >= 2:
c = self._parse_asm_descr(expr.args[1])
if not c:
c = '=r'
if not c.startswith('='):
c = '=' + c
out_output_ops.append(v)
out_output_constraints.append(c)
raw_parts.append(('output', len(out_output_ops) - 1))
else:
fallback: Any = self.HandleExprLlvm(expr)
if fallback and isinstance(fallback.type, ir.IntType):
out_input_ops.append(fallback)
out_input_constraints.append('r')
raw_parts.append(('input', len(out_input_ops) - 1))
else:
raw_parts.append(('text', ''))
num_outputs: int = len(out_output_ops)
parts: list[str] = []
for kind, data in raw_parts:
if kind == 'text':
parts.append(data)
elif kind == 'output':
parts.append(f'%{data}')
elif kind == 'input':
parts.append(f'%{num_outputs + data}')
return ''.join(parts)
_X86_REGISTERS = frozenset({
'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp',
'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp',
'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp',
'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh',
'sil', 'dil', 'bpl', 'spl',
'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d',
'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w',
'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b',
})
def _mangle_asm_calls(self, template: str) -> str:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
sha1: str = getattr(Gen, 'module_sha1', '')
if not sha1:
return template
def replace_call(m: re.Match[str]) -> str:
prefix: str = m.group(1)
func_name: str = m.group(2)
if func_name.lower() in self._X86_REGISTERS:
return m.group(0)
mangled: str = Gen._mangle_func_name(func_name)
if '.' in mangled:
return f'{prefix}\\22{mangled}\\22'
return f"{prefix}{mangled}"
return re.sub(r'(call\s+)(\w+)', replace_call, template)
def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
input_ops: list[Any] = []
input_constraints: list[str] = []
output_ops: list[Any] = []
output_constraints: list[str] = []
if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)):
for item in output_arg.elts:
if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute):
if item.func.value.id == 'c' and item.func.attr == 'AsmOut':
if len(item.args) >= 1:
target_ptr: Any = self._get_var_ptr_for_asm(item.args[0])
if target_ptr:
output_ops.append(target_ptr)
else:
value: Any = self.HandleExprLlvm(item.args[0])
if value:
output_ops.append(value)
constraint: str = '=r'
if len(item.args) >= 2:
base_constraint: str = self._parse_asm_descr(item.args[1])
if base_constraint:
if base_constraint.startswith('='):
constraint = base_constraint
else:
constraint = '=' + base_constraint
output_constraints.append(constraint)
raw_template: str
if isinstance(asm_template_arg, ast.JoinedStr):
raw_template = self._normalize_asm_template(
self._process_joined_str_template(
asm_template_arg, input_ops, input_constraints, output_ops, output_constraints
)
)
elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
raw_template = self._normalize_asm_template(asm_template_arg.value)
else:
raw_template = ''
raw_template = self._mangle_asm_calls(raw_template)
asm_dialect: str | None = self._format_to_dialect(asm_format)
asm_template: str
if asm_format == 'AT&T':
asm_template = raw_template # AT&T 不需要转换
elif asm_format == 'ARM':
asm_template = raw_template # ARM 不需要转换
else:
asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式
if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)):
for item in input_arg.elts:
if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute):
if item.func.value.id == 'c' and item.func.attr == 'AsmInp':
if len(item.args) >= 1:
value: Any = self.HandleExprLlvm(item.args[0])
if value:
input_ops.append(value)
constraint: str = 'r'
if len(item.args) >= 2:
constraint = self._parse_asm_descr(item.args[1])
if not constraint:
constraint = 'r'
input_constraints.append(constraint)
elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
value_node: ast.AST = item.elts[0]
descr_node: ast.AST = item.elts[1]
value: Any = self.HandleExprLlvm(value_node)
if value:
input_ops.append(value)
constraint: str = self._parse_asm_descr(descr_node)
if not constraint:
constraint = 'r'
input_constraints.append(constraint)
clobbers: list[str] = []
if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)):
for item in op_arg.elts:
clobber: str = self._parse_asm_descr(item)
if clobber:
clobbers.append(clobber)
constraint_parts: list[str] = []
for oc in output_constraints:
c: str = oc if oc.startswith('=') else ('=' + oc)
constraint_parts.append(c)
for ic in input_constraints:
if ic in ('d', 'edx', 'rdx'):
constraint_parts.append('{dx}')
else:
constraint_parts.append(ic)
full_constraint: str = ",".join(constraint_parts)
constraint_to_reg: dict[str, str] = {
'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx',
'S': 'rsi', 'D': 'rdi',
'A': 'rax', 'U': 'r8',
}
used_regs: set[str] = set()
for ic in input_constraints:
if ic in constraint_to_reg:
used_regs.add(constraint_to_reg[ic])
for oc in output_constraints:
base_oc: str = oc.lstrip('=').lstrip('+')
if base_oc in constraint_to_reg:
used_regs.add(constraint_to_reg[base_oc])
if clobbers:
has_memory: bool = 'memory' in clobbers
if has_memory and output_ops:
clobbers = [c for c in clobbers if c != 'memory']
clobber_final: list[str]
if asm_format == 'ARM':
# ARM 不需要 x86 的 e→r 寄存器名转换
clobber_final = [c for c in clobbers if c not in used_regs]
else:
clobber_64bit: list[str] = []
for c in clobbers:
if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']:
clobber_64bit.append(c.replace('e', 'r'))
else:
clobber_64bit.append(c)
clobber_final = [c for c in clobber_64bit if c not in used_regs]
if clobber_final:
if full_constraint:
full_constraint += ","
full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final])
if output_ops:
single_out: bool = len(output_ops) == 1
if single_out:
op: Any = output_ops[0]
ret_type: ir.Type
if isinstance(op, ir.AllocaInstr):
ret_type = op.type.pointee
elif isinstance(op, ir.GlobalVariable):
ret_type = op.type.pointee
elif isinstance(op, (ir.GEPInstr, ir.CastInstr)):
ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type
else:
ret_type = op.type
else:
def _get_ret_type(op: Any) -> ir.Type:
if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)):
return op.type.pointee
return op.type
ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops])
if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType):
ret_type = ir.IntType(64)
operands: list[Any] = input_ops
param_types: list[ir.Type] = [op.type for op in operands]
func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect)
result: Any = Gen.builder.call(inline_asm, operands, name="asm_result")
if single_out:
target: Any = output_ops[0]
if isinstance(target, ir.AllocaInstr):
if target.type.pointee != result.type:
i64t: ir.IntType = ir.IntType(64)
iv: Any = Gen.builder.ptrtoint(result, i64t)
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
Gen.builder.store(iv, ptr)
else:
Gen.builder.store(result, target)
elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)):
target_pointee: ir.Type = target.type.pointee
if target_pointee != result.type:
if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64):
ptr_val: Any = Gen.builder.inttoptr(result, target_pointee)
Gen.builder.store(ptr_val, target)
else:
i64t: ir.IntType = ir.IntType(64)
iv: Any = Gen.builder.ptrtoint(result, i64t)
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
Gen.builder.store(iv, ptr)
else:
Gen.builder.store(result, target)
else:
dst: Any = Gen._allocaEntry(result.type)
Gen.builder.store(result, dst)
else:
for i, out_op in enumerate(output_ops):
val: Any = Gen.builder.extract_value(result, i, name=f"asm_out_{i}")
target: Any = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._allocaEntry(val.type)
if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type:
i64t: ir.IntType = ir.IntType(64)
iv: Any = Gen.builder.ptrtoint(val, i64t)
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
Gen.builder.store(iv, ptr)
else:
Gen.builder.store(val, target)
else:
operands: list[Any] = input_ops
param_types: list[ir.Type] = [op.type for op in operands]
func_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), param_types)
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect)
Gen.builder.call(inline_asm, operands, name="asm_call")
return ir.Constant(ir.IntType(32), 1)
def _get_var_ptr_for_asm(self, node: ast.AST) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(node, ast.Name):
var_name: str = node.id
if var_name in Gen.variables and Gen.variables[var_name] is not None:
ptr: Any = Gen.variables[var_name]
if isinstance(ptr, ir.AllocaInstr):
return ptr
if isinstance(ptr, ir.GlobalVariable):
return ptr
elif isinstance(node, ast.Attribute):
obj_ptr: Any = self._get_var_ptr_for_asm(node.value)
if obj_ptr is not None:
obj_type: ir.Type = obj_ptr.type.pointee
if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType):
Loaded: Any = Gen.builder.load(obj_ptr, name="asm_attr_Load")
struct_type: ir.IdentifiedStructType = obj_type.pointee
class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
if class_name:
offset: int = Gen._get_member_offset(node.attr, class_name)
gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0),
ir.Constant(ir.IntType(32), offset)],
inbounds=True)
return gep
for idx, elem_type in enumerate(struct_type.elements):
gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0),
ir.Constant(ir.IntType(32), idx)],
inbounds=True)
return gep
elif isinstance(obj_type, ir.IdentifiedStructType):
class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
if class_name:
offset: int = Gen._get_member_offset(node.attr, class_name)
gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0),
ir.Constant(ir.IntType(32), offset)],
inbounds=True)
return gep
for idx, elem_type in enumerate(obj_type.elements):
gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0),
ir.Constant(ir.IntType(32), idx)],
inbounds=True)
return gep
return None
def _parse_asm_descr(self, expr: ast.AST) -> str:
if isinstance(expr, ast.BinOp):
left_val: str = self._parse_asm_descr(expr.left)
right_val: str = self._parse_asm_descr(expr.right)
return left_val + right_val
elif isinstance(expr, ast.Attribute):
if isinstance(expr.value, ast.Attribute):
if (isinstance(expr.value.value, ast.Name) and
IsTModule(expr.value.value.id, self.Trans.SymbolTable) and
expr.value.attr == 'ASM_DESCR'):
AttrName: str = expr.attr
return getattr(t.ASM_DESCR, AttrName, "")
elif isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable):
AttrName: str = expr.attr
return getattr(t.ASM_DESCR, AttrName, "")
elif isinstance(expr, ast.Constant):
return expr.value
return ""
def _infer_expr_llvm_type(self, expr: ast.AST) -> ir.Type | None:
if isinstance(expr, ast.Name):
type_name: str = expr.id
if hasattr(t, type_name):
ctype: Any = getattr(t, type_name)
if isinstance(ctype, type) and issubclass(ctype, t.CType):
size: Any = getattr(ctype, 'Size', None)
if size is not None:
return ir.IntType(size)
if type_name == 'CFloat':
return ir.FloatType()
elif type_name == 'CDouble':
return ir.DoubleType()
elif isinstance(expr, ast.Attribute):
if isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable):
return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load()))
return None

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,988 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
class ExprBuiltinHandle(BaseHandle):
_C_LIB_FUNCS: dict[str, object] = {
'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]),
'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
'abs': lambda: (ir.IntType(32), [ir.IntType(32)]),
'labs': lambda: (ir.IntType(64), [ir.IntType(64)]),
}
def _HandleBuiltinCallLlvm(self, Node: ast.Call) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not isinstance(Node.func, ast.Name):
return None
FuncName: str = Node.func.id
if FuncName == 'print':
return self._HandlePrintLlvm(Node)
elif FuncName == 'len':
if Node.args:
return self._HandleLenLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'sizeof':
if Node.args:
return self._HandleSizeofLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'abs':
if Node.args:
return self._HandleAbsLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'arg':
return self._HandleArgLlvm(Node.args)
elif FuncName == 'bool':
if Node.args:
Val = self.HandleExprLlvm(Node.args[0])
if Val:
if isinstance(Val.type, ir.IntType):
if Val.type.width == 1:
return Val
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
elif isinstance(Val.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
return Val
return ir.Constant(ir.IntType(1), 0)
elif FuncName == 'int':
if Node.args:
Val = self.HandleExprLlvm(Node.args[0])
if Val:
if isinstance(Val.type, ir.IntType):
if Val.type.width < 32:
return Gen.builder.zext(Val, ir.IntType(32), name="cast_int")
elif Val.type.width > 32:
return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int")
return Val
elif isinstance(Val.type, ir.PointerType):
if isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
result = self._HandleAtoiLlvm(Val)
if result:
return result
elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fptosi(Val, ir.IntType(32), name="float_to_int")
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'float' or FuncName == 'double':
if Node.args:
Val = self.HandleExprLlvm(Node.args[0])
if Val:
target_type = ir.DoubleType() if FuncName == 'double' else ir.FloatType()
if isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
if Val.type != target_type:
if isinstance(target_type, ir.DoubleType):
return Gen.builder.fpext(Val, target_type, name="fpext_double")
return Gen.builder.fptrunc(Val, target_type, name="fptrunc_float")
return Val
elif isinstance(Val.type, ir.IntType):
if Val.type.width == 1:
return Gen.builder.uitofp(Val, target_type, name="uitofp")
return Gen.builder.sitofp(Val, target_type, name="sitofp")
return ir.Constant(ir.DoubleType() if FuncName == 'double' else ir.FloatType(), 0.0)
elif FuncName == 'min':
if len(Node.args) >= 2:
a = self.HandleExprLlvm(Node.args[0])
b = self.HandleExprLlvm(Node.args[1])
if a and b:
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
if is_float:
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="min_int2float")
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="min_int2float")
cmp = Gen.builder.fcmp_ordered('olt', fa, fb, name="min_cmp")
return Gen.builder.select(cmp, fa, fb, name="min_val")
else:
cmp = Gen.builder.icmp_signed('<', a, b, name="min_cmp")
return Gen.builder.select(cmp, a, b, name="min_val")
elif len(Node.args) == 1:
return self.HandleExprLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'max':
if len(Node.args) >= 2:
a = self.HandleExprLlvm(Node.args[0])
b = self.HandleExprLlvm(Node.args[1])
if a and b:
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
if is_float:
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="max_int2float")
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="max_int2float")
cmp = Gen.builder.fcmp_ordered('ogt', fa, fb, name="max_cmp")
return Gen.builder.select(cmp, fa, fb, name="max_val")
else:
cmp = Gen.builder.icmp_signed('>', a, b, name="max_cmp")
return Gen.builder.select(cmp, a, b, name="max_val")
elif len(Node.args) == 1:
return self.HandleExprLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'str':
if Node.args:
arg_node = Node.args[0]
arg_val = self.HandleExprLlvm(arg_node)
if arg_val:
if isinstance(arg_val.type, ir.PointerType):
ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
if isinstance(arg_val.type, ir.PointerType) and isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8:
if ClassName in Gen.structs:
arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str")
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__")
return str_val
return arg_val
return self._EmitStringFromValue(arg_val)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif FuncName == 'bytes':
# bytes() — 类型转换为 i8* 指针 (等同于 t.CPtr / str)
# bytes(int_addr) → inttoptr; bytes(ptr) → bitcast
if Node.args:
arg_val = self.HandleExprLlvm(Node.args[0])
if arg_val:
if isinstance(arg_val.type, ir.PointerType):
if isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8:
return arg_val
return Gen.builder.bitcast(arg_val, ir.IntType(8).as_pointer(), name="bytes_cast")
if isinstance(arg_val.type, ir.IntType):
return Gen.builder.inttoptr(arg_val, ir.IntType(8).as_pointer(), name="bytes_int2ptr")
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif FuncName == 'input':
return self._HandleInputLlvm(Node)
elif FuncName == 'ord':
if Node.args:
return self._HandleOrdLlvm(Node.args[0])
return ir.Constant(ir.IntType(32), 0)
elif FuncName == 'chr':
if Node.args:
return self._HandleChrLlvm(Node.args[0])
return ir.Constant(ir.IntType(8), 0)
elif FuncName == 'malloc':
return self._HandleMallocLlvm(Node.args)
elif FuncName == 'realloc':
return self._HandleReallocLlvm(Node.args)
elif FuncName == 'free':
return self._HandleFreeLlvm(Node.args)
elif FuncName == 'memcpy':
return self._HandleMemcpyLlvm(Node.args)
elif FuncName == 'memset':
return self._HandleMemsetLlvm(Node.args)
elif FuncName == 'va_start':
return self._HandleVaStartLlvm(Node.args)
elif FuncName == 'va_end':
return self._HandleVaEndLlvm(Node.args)
elif FuncName == 'va_arg':
return self._HandleVaArgLlvm(Node.args)
elif FuncName == 'dir':
return self._HandleDirLlvm(Node)
elif FuncName == 'type':
return self._HandleTypeLlvm(Node)
return None
def _HandlePrintLlvm(self, Node: ast.Call) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
args: list[ast.expr] = Node.args
end_arg: ast.expr | None = None
sep_arg: ast.expr | None = None
if Node.keywords:
for kw in Node.keywords:
if kw.arg == 'end':
end_arg = kw.value
elif kw.arg == 'sep':
sep_arg = kw.value
sep_str: str = ' '
if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str):
sep_str = sep_arg.value
end_str: str = '\n'
if end_arg:
if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str):
end_str = end_arg.value
elif isinstance(end_arg, ast.Constant) and end_arg.value is None:
end_str = ''
if not args:
if end_str:
nl_fmt = Gen.emit_constant(end_str, 'string')
Gen.builder.call(printf_func, [nl_fmt], name="print_nl")
return ir.Constant(ir.IntType(32), 0)
has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args)
if has_fstring:
return self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str)
fmt_parts = []
fmt_args = []
for i, arg in enumerate(args):
if i > 0:
fmt_parts.append(sep_str)
val = self.HandleExprLlvm(arg)
if not val:
fmt_parts.append('(null)')
continue
if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None:
fmt_parts.append('nil')
continue
if isinstance(val.type, ir.PointerType):
pointee = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
fmt_parts.append('%s')
fmt_args.append(val)
elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr")
fmt_parts.append('%s')
fmt_args.append(elem_ptr)
elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
if not ClassName and isinstance(arg, ast.Name):
ClassName = Gen.var_struct_class.get(arg.id)
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
if isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
if ClassName in Gen.structs:
val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__")
fmt_parts.append('%s')
fmt_args.append(str_val)
else:
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
fmt_parts.append('0x%llx')
fmt_args.append(int_val)
else:
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
fmt_parts.append('%lld')
fmt_args.append(int_val)
elif isinstance(val.type, ir.IntType):
is_unsigned = self._is_val_unsigned(arg, val)
if val.type.width == 1:
fmt_parts.append('%d')
val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print")
elif val.type.width == 8:
if self._is_char_type(arg):
char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf")
Gen.builder.store(val, char_var)
fmt_parts.append('%c')
fmt_args.append(char_var)
continue
fmt_parts.append('%d')
if is_unsigned:
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print")
else:
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print")
elif val.type.width == 16:
fmt_parts.append('%u' if is_unsigned else '%d')
if is_unsigned:
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print")
else:
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print")
elif val.type.width == 32:
fmt_parts.append('%u' if is_unsigned else '%d')
elif val.type.width == 64:
fmt_parts.append('%llu' if is_unsigned else '%lld')
else:
fmt_parts.append('%d')
val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print")
fmt_args.append(val)
elif isinstance(val.type, ir.FloatType):
fmt_parts.append('%f')
fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float"))
elif isinstance(val.type, ir.DoubleType):
fmt_parts.append('%f')
fmt_args.append(val)
else:
fmt_parts.append('(unknown)')
fmt_parts.append(end_str)
fmt_str = ''.join(fmt_parts)
fmt_ptr = Gen._create_string_global(fmt_str)
call_args = [fmt_ptr] + fmt_args
return Gen.builder.call(printf_func, call_args, name="print_call")
def _HandlePrintWithFString(self, Node: ast.Call, printf_func: ir.Function, args: list[ast.expr], sep_str: str, end_str: str) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
for i, arg in enumerate(args):
if i > 0:
sep_const = Gen.emit_constant(sep_str, 'string')
Gen.builder.call(printf_func, [sep_const], name="print_sep")
if isinstance(arg, ast.JoinedStr):
str_val = self.HandleExprLlvm(arg)
if str_val:
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
else:
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
obj_val = self.HandleExprLlvm(arg)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if ClassName in Gen.structs:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__")
Gen._RegisterTempPtr(str_val)
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
else:
val = self.HandleExprLlvm(arg)
if val:
if isinstance(val.type, ir.PointerType):
pointee = val.type.pointee
if not (isinstance(pointee, ir.IntType) and pointee.width == 8):
try:
val = Gen._load(val, name="print_Load")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
is_u = Gen._check_node_unsigned(arg)
if not is_u and id(val) in Gen._unsigned_results:
is_u = True
Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None)
if end_str:
end_const = Gen.emit_constant(end_str, 'string')
Gen.builder.call(printf_func, [end_const], name="print_end")
return ir.Constant(ir.IntType(32), 0)
def _is_char_type(self, arg_node: ast.AST) -> bool:
if isinstance(arg_node, ast.Call):
if isinstance(arg_node.func, ast.Name):
return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T')
if isinstance(arg_node.func, ast.Attribute):
return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T')
return False
def _is_val_unsigned(self, arg_node: ast.AST, val: ir.Value) -> bool:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if isinstance(arg_node, ast.Name):
var_name: str = arg_node.id
signedness: object = Gen.var_signedness.get(var_name)
if signedness:
if isinstance(signedness, bool):
return signedness
return 'unsigned' in signedness
if isinstance(val.type, ir.IntType):
return False
return False
def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None:
if func_name not in self._C_LIB_FUNCS:
return None
ret_type: ir.Type
param_types: list[ir.Type]
ret_type, param_types = self._C_LIB_FUNCS[func_name]()
func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
func: ir.Function = ir.Function(Gen.module, func_type, name=func_name)
Gen.functions[func_name] = func
return func
def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self':
attr_name = arg_node.attr
len_member = f'{attr_name}__len'
current_class = self.Trans._CurrentCpythonObjectClass
if current_class and current_class in Gen.class_members:
for m_name, m_type in Gen.class_members[current_class]:
if m_name == len_member:
self_val = Gen._get_var_ptr('self')
if self_val:
self_ptr = Gen._load(self_val, name="self_for_len")
offset = Gen._get_member_offset(len_member, current_class)
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
return Gen._load(len_ptr, name=f"self_{len_member}")
val = self.HandleExprLlvm(arg_node)
if not val:
return None
if isinstance(val.type, ir.PointerType):
pointee = val.type.pointee
if isinstance(pointee, ir.PointerType):
val = Gen._load(val, name="len_deref")
pointee = val.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
if result is not None:
return result
break
if isinstance(pointee, ir.ArrayType):
return ir.Constant(ir.IntType(64), pointee.count)
if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8:
return ir.Constant(ir.IntType(64), 0)
if val.type != ir.PointerType(ir.IntType(8)):
val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast")
correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
strlen_func = None
if 'strlen' in Gen.functions:
existing = Gen.functions['strlen']
if existing.ftype == correct_strlen_type:
strlen_func = existing
if not strlen_func:
try:
strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen')
Gen.functions['strlen'] = strlen_func
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if strlen_func:
result = Gen.builder.call(strlen_func, [val], name="strlen_call")
return result
elif isinstance(val.type, ir.ArrayType):
return ir.Constant(ir.IntType(64), val.type.count)
return ir.Constant(ir.IntType(64), 0)
def _resolve_nested_opaque_structs(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, visited: set | None = None) -> None:
"""递归解析嵌套的 opaque struct从 stub 文件中加载其定义"""
if visited is None:
visited = set()
if isinstance(struct_type, ir.PointerType):
self._resolve_nested_opaque_structs(struct_type.pointee, Gen, visited)
return
if not isinstance(struct_type, ir.IdentifiedStructType):
return
if struct_type in visited:
return
visited.add(struct_type)
if struct_type.elements is None or len(struct_type.elements) == 0:
# 尝试从 stub 加载 opaque struct
try:
st_name = struct_type.name
except Exception:
st_name = None
if st_name:
# 提取短名称(去掉模块前缀)
if '.' in st_name:
short_name = st_name.split('.', 1)[1]
else:
short_name = st_name
self.Trans.ImportHandler._TryLoadStructFromStub(short_name, Gen)
return
# 递归解析嵌套的 struct 成员
for elem in struct_type.elements:
self._resolve_nested_opaque_structs(elem, Gen, visited)
def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
type_name: str | None
if isinstance(Node, ast.Name):
type_name = Node.id
elif isinstance(Node, ast.Attribute):
type_name = Node.attr
else:
return ir.Constant(ir.IntType(64), 0)
if type_name not in Gen.structs:
# str/bytes 是指针类型 (char*/void*)sizeof = 指针大小
if type_name in ('str', 'bytes'):
return ir.Constant(ir.IntType(64), 8)
ctype_cls = CTypeRegistry.GetClassByName(type_name)
if ctype_cls is not None:
try:
ctype_inst = ctype_cls()
size_bits = getattr(ctype_inst, 'Size', 0) or 0
size_bytes = size_bits // 8
return ir.Constant(ir.IntType(64), size_bytes)
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
resolved = CTypeRegistry.ResolveName(type_name)
if resolved:
ctype_cls, ptr_level = resolved
try:
ctype_inst = ctype_cls()
size_bits = getattr(ctype_inst, 'Size', 0) or 0
size_bytes = size_bits // 8
if ptr_level > 0:
size_bytes = 8
return ir.Constant(ir.IntType(64), size_bytes)
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
return ir.Constant(ir.IntType(64), 0)
struct_type = Gen.structs[type_name]
if isinstance(struct_type, ir.PointerType):
struct_type = struct_type.pointee
if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0):
self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen)
struct_type = Gen.structs.get(type_name, struct_type)
# 递归解析所有嵌套的 opaque struct确保 sizeof 计算正确
self._resolve_nested_opaque_structs(struct_type, Gen)
size = Gen._get_struct_size(struct_type)
if size > 0:
return ir.Constant(ir.IntType(64), size)
return ir.Constant(ir.IntType(64), 0)
def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
val: ir.Value | None = self.HandleExprLlvm(arg_node)
if not val:
return None
if isinstance(val.type, ir.PointerType):
pointee = val.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
if result is not None:
return result
break
if isinstance(val.type, ir.IntType):
neg_val = Gen.builder.neg(val, name="abs_neg")
is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg")
return Gen.builder.select(is_neg, neg_val, val, name="abs_result")
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
zero = ir.Constant(val.type, 0.0)
neg_val = Gen.builder.fneg(val, name="fabs_neg")
is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg")
return Gen.builder.select(is_neg, neg_val, val, name="fabs_result")
return None
def _HandleDirLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
type_str: str
if not Node.args:
type_str = "<class 'unknown' size=0 signed=false, ptr=false>"
else:
arg = Node.args[0]
enum_type_name = None
def _get_attr_path(node: ast.AST) -> str | None:
if isinstance(node, ast.Name):
return node.id
elif isinstance(node, ast.Attribute):
return f"{_get_attr_path(node.value)}.{node.attr}"
return None
if isinstance(arg, ast.Name):
arg_name = arg.id
Gen = self.Trans.LlvmGen
if arg_name in Gen.var_type_info:
type_info = Gen.var_type_info[arg_name]
if isinstance(type_info, dict) and type_info.get('type') == 'enum':
enum_type_name = type_info.get('name')
if not enum_type_name and self.Trans.SymbolTable.has(arg_name):
TypeInfo = self.Trans.SymbolTable[arg_name]
if TypeInfo.IsEnum:
enum_type_name = arg_name
elif isinstance(arg, ast.Attribute):
LastPart = None
enum_class_name = None
if isinstance(arg.value, ast.Name):
LastPart = arg.attr
if self.Trans.SymbolTable.has(LastPart):
AttrInfo = self.Trans.SymbolTable[LastPart]
if AttrInfo.IsEnumMember and AttrInfo.EnumName:
enum_type_name = AttrInfo.EnumName
elif isinstance(arg.value, ast.Attribute):
attr_path = _get_attr_path(arg)
if attr_path:
parts = attr_path.split('.')
if len(parts) >= 2:
enum_class_name = parts[-2]
LastPart = parts[-1]
qualified_name_dot = f"{enum_class_name}.{LastPart}"
qualified_name_under = f"{enum_class_name}_{LastPart}"
enum_member_found = None
for qname in (qualified_name_dot, qualified_name_under):
if self.Trans.SymbolTable.has(qname):
info = self.Trans.SymbolTable[qname]
if info.IsEnumMember and info.EnumName == enum_class_name:
enum_member_found = info
break
if not enum_member_found:
for key in self.Trans.SymbolTable:
if key == LastPart:
info = self.Trans.SymbolTable[key]
if info.IsEnumMember and info.EnumName == enum_class_name:
enum_member_found = info
break
if enum_member_found:
enum_type_name = enum_class_name
if enum_type_name:
type_str = f"<enum '{enum_type_name}' size=4 signed=true, ptr=false>"
else:
llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg)
if isinstance(llvm_type, ir.PointerType):
pointee = llvm_type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
llvm_type = pointee
type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type)
type_str = f"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
return Gen.emit_constant(type_str, 'string')
def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str):
prompt = Node.args[0].value
prompt_ptr = Gen.emit_constant(prompt, 'string')
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
Gen.builder.call(printf_func, [prompt_ptr])
scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer")
result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer])
return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result")
def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
atoi_func: ir.Function = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))]))
return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result")
def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
val: ir.Value | None = self.HandleExprLlvm(expr_node)
if val and isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
return Gen._load(val, name="ord_result")
return ir.Constant(ir.IntType(32), 0)
def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
val: ir.Value | None = self.HandleExprLlvm(expr_node)
if val:
char_ptr = Gen._alloca(ir.IntType(8), name="chr_char")
Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr)
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _EmitStringFromValue(self, val: ir.Value) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2))
null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte")
Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr)
Gen.builder.store(val, buf)
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
ir.PointerType(ir.IntType(8)),
ir.IntType(64),
ir.PointerType(ir.IntType(8))
], var_arg=True))
fmt_ptr = Gen.emit_constant("%d", 'string')
Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val])
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _HandleMallocLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
param_type: ir.Type = malloc_func.type.pointee.args[0]
size_val: ir.Value | None = None
if args:
size_val = self.HandleExprLlvm(args[0])
if size_val and isinstance(size_val.type, ir.IntType):
if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width:
if size_val.type.width < param_type.width:
size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size")
else:
size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size")
if not size_val:
size_val = ir.Constant(param_type, 1)
result: ir.Value = Gen.builder.call(malloc_func, [size_val], name="malloc_result")
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast")
def _HandleReallocLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
realloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
realloc_func: ir.Function = Gen._get_or_declare_func('realloc', realloc_type)
size_param_type: ir.Type = realloc_func.type.pointee.args[1]
ptr_val: ir.Value | None = None
size_val: ir.Value | None = None
if len(args) >= 2:
ptr_val = self.HandleExprLlvm(args[0])
size_val = self.HandleExprLlvm(args[1])
elif len(args) == 1:
size_val = self.HandleExprLlvm(args[0])
if not ptr_val:
ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None)
if isinstance(ptr_val.type, ir.PointerType) and not (isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8):
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr")
if size_val and isinstance(size_val.type, ir.IntType):
if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width:
if size_val.type.width < size_param_type.width:
size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size")
else:
size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size")
if not size_val:
size_val = ir.Constant(size_param_type, 0)
result: ir.Value = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result")
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast")
def _HandleFreeLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
free_func: ir.Function = Gen._get_or_declare_func('free', free_type)
if args:
var_name: str | None = None
if isinstance(args[0], ast.Name):
var_name = args[0].id
ptr_val: ir.Value | None = self.HandleExprLlvm(args[0])
if ptr_val is not None:
if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr:
registered_val = Gen._var_to_heap_ptr[var_name]
Gen._unregister_local_heap_ptr(registered_val)
del Gen._var_to_heap_ptr[var_name]
if isinstance(ptr_val.type, ir.PointerType):
if isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8:
pass
else:
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr")
elif isinstance(ptr_val.type, ir.IntType):
ptr_val = Gen.builder.inttoptr(ptr_val, ir.PointerType(ir.IntType(8)), name="free_inttoptr")
Gen.builder.call(free_func, [ptr_val], name="free_call")
return ir.Constant(ir.IntType(32), 0)
def _HandleMemcpyLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
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(1)])
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
if len(args) >= 3:
dst: ir.Value | None = self.HandleExprLlvm(args[0])
src: ir.Value | None = self.HandleExprLlvm(args[1])
size: ir.Value | None = self.HandleExprLlvm(args[2])
if dst and src and size:
i8ptr: ir.PointerType = ir.PointerType(ir.IntType(8))
if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr:
dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast")
elif isinstance(dst.type, ir.IntType):
if dst.type.width < 64:
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr")
dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr")
if isinstance(src.type, ir.PointerType) and src.type != i8ptr:
src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast")
elif isinstance(src.type, ir.IntType):
if src.type.width < 64:
src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr")
src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr")
if isinstance(size.type, ir.IntType) and size.type.width < 64:
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size")
isvolatile: ir.Constant = ir.Constant(ir.IntType(1), 0)
Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call")
return ir.Constant(ir.IntType(32), 0)
def _HandleMemsetLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
memset_func: ir.Function = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]))
if len(args) >= 3:
dst: ir.Value | None = self.HandleExprLlvm(args[0])
val: ir.Value | None = self.HandleExprLlvm(args[1])
size: ir.Value | None = self.HandleExprLlvm(args[2])
if dst and val is not None and size:
if isinstance(dst.type, ir.PointerType) and not (isinstance(dst.type.pointee, ir.IntType) and dst.type.pointee.width == 8):
dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast")
elif isinstance(dst.type, ir.IntType):
if dst.type.width < 64:
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_memset_dst")
elif dst.type.width > 64:
dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst")
dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr")
if isinstance(val.type, ir.IntType) and val.type.width != 32:
if val.type.width < 32:
val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
else:
val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val")
if isinstance(size.type, ir.IntType) and size.type.width < 64:
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size")
elif isinstance(size.type, ir.IntType) and size.type.width > 64:
size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size")
Gen.builder.call(memset_func, [dst, val, size], name="memset_call")
return ir.Constant(ir.IntType(32), 0)
def _HandleVaStartLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
return ir.Constant(ir.IntType(32), 0)
def _HandleVaEndLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
return ir.Constant(ir.IntType(32), 0)
def _HandleArgLlvm(self, args: list[ast.expr], CallNode: ast.Call | None = None) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
va_list_ptr: ir.Value | None = None
variadic_info: dict | None = getattr(Gen, '_va_arg_info', None)
if not variadic_info:
variadic_info = getattr(Gen, '_variadic_info', None)
if variadic_info:
va_list_ptr = variadic_info.get('va_list_ptr')
if not va_list_ptr:
vararg_name: str = variadic_info.get('vararg_name', 'args') if variadic_info else 'args'
if vararg_name in Gen._direct_values:
va_list_ptr = Gen._direct_values[vararg_name]
elif vararg_name in Gen.variables:
va_list_ptr = Gen.variables[vararg_name]
if not va_list_ptr:
return ir.Constant(ir.IntType(32), 0)
target_type: ir.Type = ir.IntType(32)
if args:
type_arg: ast.expr = args[0]
if isinstance(type_arg, ast.Name):
type_name: str = type_arg.id
if type_name in ('str', 'bytes'):
target_type = ir.PointerType(ir.IntType(8))
elif type_name == 'CPtr':
target_type = ir.PointerType(ir.IntType(8))
elif type_name in Gen.structs:
target_type = ir.PointerType(Gen.structs[type_name])
else:
ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
else:
resolved: tuple | None = CTypeRegistry.ResolveName(type_name)
if resolved is not None:
ctype_cls, ptr_level = resolved
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
base: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if base is not None:
for _ in range(ptr_level):
if isinstance(base, ir.VoidType):
base = ir.IntType(8).as_pointer()
else:
base = ir.PointerType(base)
target_type = base
elif isinstance(type_arg, ast.Attribute):
if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
attr_name: str = type_arg.attr
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
else:
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
if assign_node:
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
if ann:
ann_name: str | None = None
if isinstance(ann, ast.Name):
ann_name = ann.id
elif isinstance(ann, ast.Attribute):
ann_name = ann.attr
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
ann_name = ExtractTypeNameFromBinOp(ann)
if ann_name:
ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
elif ann_name in Gen.structs:
target_type = ir.PointerType(Gen.structs[ann_name])
if not getattr(Gen, '_va_arg_counter', None):
Gen._va_arg_counter = 0
Gen._va_arg_counter += 1
result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type)
if result is not None and getattr(result, 'name', None):
result.name = f"va_arg_result_{Gen._va_arg_counter}"
return result
def _resolve_vararg_type(self, type_arg: ast.expr, Gen: LlvmGeneratorMixin) -> ir.Type:
"""将类型表达式解析为 LLVM 类型(供 arg/va_arg 共用)。"""
target_type: ir.Type = ir.IntType(32)
if isinstance(type_arg, ast.Name):
type_name: str = type_arg.id
if type_name in ('str', 'bytes'):
target_type = ir.PointerType(ir.IntType(8))
elif type_name == 'CPtr':
target_type = ir.PointerType(ir.IntType(8))
elif type_name in Gen.structs:
target_type = ir.PointerType(Gen.structs[type_name])
else:
ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
else:
resolved_tuple: tuple | None = CTypeRegistry.ResolveName(type_name)
if resolved_tuple is not None:
ctype_cls, ptr_level = resolved_tuple
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
base: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if base is not None:
for _ in range(ptr_level):
if isinstance(base, ir.VoidType):
base = ir.IntType(8).as_pointer()
else:
base = ir.PointerType(base)
target_type = base
elif isinstance(type_arg, ast.Attribute):
if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
attr_name: str = type_arg.attr
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
return target_type
def _infer_vararg_type_from_context(self, Gen: LlvmGeneratorMixin) -> ir.Type:
"""从当前赋值上下文推断 va_arg/arg 的目标类型。"""
target_type: ir.Type = ir.IntType(32)
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
if assign_node:
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
if ann:
ann_name: str | None = None
if isinstance(ann, ast.Name):
ann_name = ann.id
elif isinstance(ann, ast.Attribute):
ann_name = ann.attr
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
ann_name = ExtractTypeNameFromBinOp(ann)
if ann_name:
ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name)
if ctype_cls is not None:
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
elif ann_name in Gen.structs:
target_type = ir.PointerType(Gen.structs[ann_name])
return target_type
def _HandleVaArgLlvm(self, args: list[ast.expr]) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not args:
return ir.Constant(ir.IntType(32), 0)
# 求值 va_list 指针args[0]
va_list_ptr: ir.Value = self.HandleExprLlvm(args[0])
if va_list_ptr is None:
return ir.Constant(ir.IntType(32), 0)
# 解析目标类型
if len(args) >= 2:
target_type: ir.Type = self._resolve_vararg_type(args[1], Gen)
else:
target_type: ir.Type = self._infer_vararg_type_from_context(Gen)
if not getattr(Gen, '_va_arg_counter', None):
Gen._va_arg_counter = 0
Gen._va_arg_counter += 1
result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type)
if result is not None and getattr(result, 'name', None):
result.name = f"va_arg_explicit_{Gen._va_arg_counter}"
return result if result is not None else ir.Constant(ir.IntType(32), 0)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,271 @@
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
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import re
import llvmlite.ir as ir
class ExprFormatHandle(BaseHandle):
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return ir.Constant(ir.IntType(8).as_pointer(), None)
format_str: str = ""
cast_args: list[Any] = []
for part in Node.values:
if isinstance(part, ast.Constant) and isinstance(part.value, str):
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
elif isinstance(part, ast.FormattedValue):
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
obj_val: Any = self.HandleExprLlvm(part.value)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if fmt_class in Gen.structs:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
Gen._RegisterTempPtr(val)
format_str += "%s"
cast_args.append(val)
else:
format_str += "%s"
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue
val = self.HandleExprLlvm(part.value)
if not val:
format_str += "%d"
cast_args.append(ir.Constant(ir.IntType(32), 0))
continue
# 检查 format_specPython f-string 格式说明符)
if part.format_spec is not None:
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
if c_fmt is not None:
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
format_str += c_fmt
cast_args.append(cast_val)
continue
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
format_str += "%s"
cast_args.append(val)
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
format_str += "%d"
cast_args.append(trunc_val)
else:
Loaded: Any = Gen._load(val, name="fstr_deref")
if isinstance(Loaded.type, ir.IntType):
if Loaded.type.width == 8:
format_str += "%c"
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(Loaded)
elif isinstance(Loaded.type, ir.PointerType):
format_str += "%s"
cast_args.append(Loaded)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(val.type, ir.IntType):
if val.type.width == 8:
format_str += "%c"
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
elif val.type.width == 1:
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
format_str += "%d"
cast_args.append(zext)
else:
is_u: bool = Gen._check_node_unsigned(part.value)
format_str += "%u" if is_u else "%d"
cast_args.append(val)
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(val)
else:
format_str += "%d"
cast_args.append(val)
if not format_str:
return Gen.emit_constant("", 'string')
format_ptr: Any = Gen._create_string_global(format_str)
# 统一使用 snprintf 生成字符串,返回 i8*
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
ir.PointerType(ir.IntType(8)),
ir.IntType(64),
ir.PointerType(ir.IntType(8))
], var_arg=True)
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
# 第一遍获取所需长度NULL 缓冲size=0
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
# 加 1 用于 null 终止符
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
if in_str_method:
# 堆分配__str__ 返回值需跨函数生命周期)
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
Gen._RegisterTempPtr(buf_ptr)
return buf_ptr
# 栈分配(局部使用,自动释放)
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
return buf_ptr
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
返回 None 表示无法解析,调用方应回退到类型推断。
"""
if isinstance(format_spec_node, ast.JoinedStr):
parts: list[str] = []
for v in format_spec_node.values:
if isinstance(v, ast.Constant) and isinstance(v.value, str):
parts.append(v.value)
else:
return None
spec_str: str = ''.join(parts)
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
spec_str = format_spec_node.value
else:
return None
if not spec_str:
return None
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
if not m:
return None
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
c_flags: str = ''
if sign == '+':
c_flags += '+'
elif sign == ' ':
c_flags += ' '
if alt:
c_flags += '#'
if fill_align:
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
if align_char in ('<', '^'):
c_flags += '-'
if zero:
c_flags += '0'
c_width: str = width or ''
c_precision: str = precision or ''
length_mod: str = ''
if isinstance(val.type, ir.IntType):
if val.type.width == 64:
length_mod = 'll'
elif val.type.width == 32:
length_mod = 'l'
elif val.type.width == 16:
length_mod = 'h'
elif val.type.width == 8:
length_mod = 'hh'
c_specifier: str = ''
if fmt_type in ('d', 'n'):
c_specifier = f'{length_mod}d'
elif fmt_type == 'x':
c_specifier = f'{length_mod}x'
elif fmt_type == 'X':
c_specifier = f'{length_mod}X'
elif fmt_type == 'o':
c_specifier = f'{length_mod}o'
elif fmt_type == 'b':
return None
elif fmt_type == 'c':
c_specifier = 'c'
elif fmt_type in ('f', 'F'):
c_specifier = 'f'
elif fmt_type in ('e', 'E', 'g', 'G'):
c_specifier = fmt_type
elif fmt_type == 's':
c_specifier = 's'
elif fmt_type == '%':
c_specifier = 'f%%'
else:
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
c_specifier = 'c'
elif val.type.width == 1:
c_specifier = 'd'
else:
c_specifier = f'{length_mod}d'
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
c_specifier = 'f'
elif isinstance(val.type, ir.PointerType):
c_specifier = 's'
else:
c_specifier = 'd'
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
"""根据 C printf 格式说明符转换值类型。"""
fmt_type_char: str = ''
for ch in reversed(c_fmt):
if ch.isalpha() and ch not in ('l', 'h'):
fmt_type_char = ch
break
elif ch == '%':
break
if fmt_type_char == 's':
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
return val
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
return val
elif fmt_type_char == 'c':
if isinstance(val.type, ir.IntType) and val.type.width < 32:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
return val
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
is_u: bool = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
elif val.type.width == 16:
is_u = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
elif val.type.width == 1:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
return val
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
return val
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
if isinstance(val.type, ir.FloatType):
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
elif isinstance(val.type, ir.IntType):
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
return val
return val

View File

@@ -0,0 +1,249 @@
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
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprLambdaHandle(BaseHandle):
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not getattr(Gen, '_lambda_counter', None):
Gen._lambda_counter = 0
lambda_id: int = Gen._lambda_counter
Gen._lambda_counter += 1
fn_name: str = f"lambda_fn_{lambda_id}"
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
env_types: list[ir.Type] = []
env_var_names: list[str] = []
for var_name, var_val in captured_vars:
env_types.append(var_val.type)
env_var_names.append(var_name)
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
if Node.args:
for arg in Node.args.args:
param_types.append(ir.IntType(32))
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
Gen.functions[fn_name] = fn
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
prev_builder: Any = Gen.builder
prev_func: Any = Gen.func
prev_vars: dict[str, Any] = dict(Gen.variables)
Gen.builder = ir.IRBuilder(entry_block)
Gen.func = fn
Gen.variables = {}
for i, arg in enumerate(fn.args):
arg.name = f"arg_{i}" if i > 0 else "env"
if env_types:
for idx, var_name in enumerate(env_var_names):
env_ptr: Any = fn.args[0]
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
Gen._store(Loaded, temp_alloca)
Gen.variables[var_name] = temp_alloca
if Node.args:
for i, arg in enumerate(Node.args.args):
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
body_val: Any = self.HandleExprLlvm(Node.body)
if body_val:
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
body_val = Gen._load(body_val, name="Load_lambda_ret")
if body_val.type != ret_type:
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
if body_val.type.width < ret_type.width:
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
elif body_val.type.width > ret_type.width:
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
Gen.builder.ret(body_val)
else:
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
Gen.builder = prev_builder
Gen.func = prev_func
Gen.variables = prev_vars
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
ir.PointerType(ir.IntType(8)),
ir.PointerType(fn_type)
])
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
if env_types:
for idx, (var_name, var_val) in enumerate(captured_vars):
zero = ir.Constant(ir.IntType(32), 0)
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
Gen._store(var_val, member_ptr)
zero = ir.Constant(ir.IntType(32), 0)
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
Gen._store(env_i8_ptr, env_field_ptr)
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
Gen._store(fn, fn_field_ptr)
return closure_ptr
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
captured: list[tuple[str, Any]] = []
free_vars: list[str] = self._get_lambda_free_vars(Node)
for var_name in free_vars:
if var_name in Gen.variables:
var_ptr: Any = Gen.variables[var_name]
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
captured.append((var_name, Loaded))
return captured
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
bound_vars: set[str] = set()
free_vars: set[str] = set()
# 收集 lambda body 中的 bound 和 free 变量
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
# lambda 参数也是 bound 的
if Node.args:
for arg in Node.args.args:
bound_vars.add(arg.arg)
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
result: list[str] = list(free_vars - bound_vars)
return result
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
TestVal: Any = self.HandleExprLlvm(Node.test)
if not TestVal:
return None
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
# 先在 ThenBB 中生成 BodyVal
Gen.builder.position_at_start(ThenBB)
BodyVal: Any = self.HandleExprLlvm(Node.body)
if not BodyVal:
BodyVal = ir.Constant(ir.IntType(32), 0)
ThenEndBB: ir.Block = Gen.builder.block
# 在 ElseBB 中生成 OrelseVal
Gen.builder.position_at_start(ElseBB)
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
if not OrelseVal:
OrelseVal = ir.Constant(ir.IntType(32), 0)
ElseEndBB: ir.Block = Gen.builder.block
# 确定 phi 节点的目标类型
result_type: ir.Type = BodyVal.type
if BodyVal.type != OrelseVal.type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
# 指针类型,使用 BodyVal 的类型
result_type = BodyVal.type
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
# BodyVal 是整数OrelseVal 是指针(字符串字面量)
# 如果指针指向 i8将指针转换为 i8加载字符
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
# BodyVal 是指针字符串字面量OrelseVal 是整数
# 如果指针指向 i8将指针转换为 i8加载字符
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = BodyVal.type
else:
result_type = OrelseVal.type
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
if not ThenEndBB.is_terminated:
Gen.builder.position_at_end(ThenEndBB)
if BodyVal.type != result_type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if BodyVal.type.width < result_type.width:
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
else:
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 Else 分支的类型转换
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 指针转整数
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
Gen.builder.branch(MergeBB)
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
if not ElseEndBB.is_terminated:
Gen.builder.position_at_end(ElseEndBB)
if OrelseVal.type != result_type:
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if OrelseVal.type.width < result_type.width:
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
else:
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 如果指针指向 i8加载字符值
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
else:
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
Gen.builder.branch(MergeBB)
Gen.builder.position_at_start(MergeBB)
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
result_phi.add_incoming(BodyVal, ThenEndBB)
result_phi.add_incoming(OrelseVal, ElseEndBB)
return result_phi
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
ValueVal: Any = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
TargetName: str = Node.target.id
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
VarPtr: Any = Gen.variables[TargetName]
if VarPtr.type.pointee == ValueVal.type:
Gen._store(ValueVal, VarPtr)
else:
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
else:
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
Gen._reg_values[TargetName] = ValueVal
return ValueVal

View File

@@ -0,0 +1,453 @@
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
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprOpsHandle(BaseHandle):
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Gen._set_node_info(Node, "BinOp")
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
if not LeftVal:
return None
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
if not RightVal:
return None
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if not Op:
return None
OP_OVERLOAD_MAP: dict[str, str] = {
'+': '__add__', '-': '__sub__', '*': '__mul__',
'/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
'**': '__pow__',
}
if Op in OP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_name: str = OP_OVERLOAD_MAP[Op]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
return TruncResult
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
if LeftVal.type.width < RightVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
elif LeftVal.type.width > RightVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
if RightVal.type.width < LeftVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
elif RightVal.type.width > LeftVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
vname: str = Node.left.id
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
is_unsigned = True
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
return result
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
def _to_bool(val: Any, name: str) -> Any:
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
return val
values: list[ast.expr] = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
for idx in range(len(values) - 1):
val: Any = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block: ir.Block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"andcond{idx}")
cur_bb: ir.Block = Gen.builder.block
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
Gen.builder.cbranch(val, next_bb, end_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val: Any = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 0)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "andcond_last")
last_bb: ir.Block = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
elif isinstance(Node.op, ast.Or):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="or.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"orcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
Gen.builder.cbranch(val, end_bb, next_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 1)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "orcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
return None
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
OperandVal: Any = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP: dict[str, str] = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName: str | None = None
if isinstance(OperandVal.type, ir.PointerType):
pointee: ir.Type = OperandVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
if ClassName and ClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName is None and isinstance(Node.operand, ast.Name):
ClassName = Gen.var_struct_class.get(Node.operand.id)
if ClassName and ClassName in Gen.structs:
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName:
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
if result is not None:
return result
if OpSymbol == 'not':
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
return Gen.builder.not_(OperandVal, name="not_result")
if isinstance(OperandVal.type, ir.PointerType):
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask: int = (1 << OperandVal.type.width) - 1
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
elif OpSymbol == '+':
return OperandVal
elif OpSymbol == '-':
if isinstance(OperandVal.type, ir.IntType):
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")
return None
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
LeftVal: Any = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
if len(Node.ops) == 1:
Op: ast.cmpop = Node.ops[0]
# in/not in: 调用 __contains__
if isinstance(Op, (ast.In, ast.NotIn)):
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if RightVal:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
# 处理 RightVal 为 i8整数的情况联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
# 归一化为 i1
if isinstance(result.type, ir.IntType) and result.type.width > 1:
zero: ir.Constant = ir.Constant(result.type, 0)
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
if isinstance(Op, ast.NotIn):
result = Gen.builder.not_(result, name="not_in_result")
return result
return ir.Constant(ir.IntType(1), 0)
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if not RightVal:
return None
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
lv: int = LeftVal.constant
rv: int = RightVal.constant
lw: int = LeftVal.type.width
rw: int = RightVal.type.width
if lw < rw:
lv = lv if lv >= 0 else lv + (1 << lw)
elif rw < lw:
rv = rv if rv >= 0 else rv + (1 << rw)
if is_unsigned:
mask_l: int = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map: dict[str, bool] = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result: bool = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围则必须用zext
# i8 类型默认使用 zext系统编程中 i8 几乎总是无符号字节)
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
else:
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
RightVal = ir.Constant(LeftVal.type, None)
else:
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
else:
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
LeftVal = ir.Constant(RightVal.type, None)
else:
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
# is / is not: 地址比较指针或值比较int
if ComparatorSymbol in ('is', 'is not'):
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
return addr_cmp
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
return val_cmp
# str/bytes == str/bytes: 值比较(调用 strcmpNone 比较用地址
if ComparatorSymbol in ('==', '!='):
if (isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8
and isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8):
left_is_null: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None
right_is_null: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None
if not (left_is_null or right_is_null):
strcmp_func = Gen.get_or_declare_c_func('strcmp', ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer(), ir.IntType(8).as_pointer()]))
cmp_result = Gen.builder.call(strcmp_func, [LeftVal, RightVal], name="str_eq_cmp")
zero = ir.Constant(ir.IntType(32), 0)
eq_result = Gen.builder.icmp_signed('==', cmp_result, zero, name="str_eq")
if ComparatorSymbol == '!=':
eq_result = Gen.builder.not_(eq_result, name="str_neq")
return eq_result
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif is_unsigned:
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
else:
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
return result
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
continue
RightVal = self.HandleExprLlvm(Comparator)
if not RightVal:
continue
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
if is_unsigned:
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
else:
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
if i < len(Node.ops) - 1:
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
cur_bb: ir.Block = Gen.builder.block
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
else:
cur_bb = Gen.builder.block
Gen.builder.branch(EndBB)
phi_incomings.append((cmp_result, cur_bb))
Gen.builder.position_at_start(EndBB)
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
for val, bb in phi_incomings:
final_result.add_incoming(val, bb)
return final_result

View File

@@ -0,0 +1,266 @@
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.SymbolUtils import IsTModule
class ExprUtils:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
ast.MatMult: '@',
}
return OpMap.get(type(Op), None)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
OpMap: dict[type, str] = {
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
ast.In: 'in', ast.NotIn: 'not in',
}
return OpMap.get(type(Op), None)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
if isinstance(node, ast.Name):
VarName: str = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName: str = node.attr
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable
# 必须先查 BaseClass避免字段名和变量名冲突导致错误分派
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST'
BaseClass: str | None = self._get_var_class(node.value, Gen)
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
if BaseClass and BaseClass in Gen.class_members:
for m_name, m_type in Gen.class_members[BaseClass]:
if m_name == AttrName:
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(m_type.pointee)
if found:
return found[0]
# 联合类型(如 GSList[Param] | t.CPtr降级为 i8* 时,
# 从 class_member_element_class 查找泛型特化类名
element_class_map = getattr(Gen, 'class_member_element_class', {})
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
if element_class:
return element_class
break
# Fallback: 直接查找 var_struct_class放在 BaseClass 查找之后,
# 避免字段名和变量名冲突导致错误分派)
cls: str | None = Gen.var_struct_class.get(AttrName)
if cls:
return cls
return None
return None
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if Gen._has_function(FullMethodName):
func: Any = Gen._get_function(FullMethodName)
call_args: list[Any] = [obj_val]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
if expected_type != actual_val.type:
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
info: dict[str, Any] = {
'name': "unknown",
'size': 0,
'signed': False,
'ptr': False
}
if isinstance(llvm_type, ir.IntType):
info['size'] = llvm_type.width // 8
info['signed'] = True
if llvm_type.width == 8:
info['name'] = "char"
elif llvm_type.width == 16:
info['name'] = "short"
elif llvm_type.width == 32:
info['name'] = "int"
elif llvm_type.width == 64:
info['name'] = "long long"
else:
info['name'] = f"int{llvm_type.width}"
elif isinstance(llvm_type, ir.DoubleType):
info['size'] = 8
info['signed'] = True
info['name'] = "double"
elif isinstance(llvm_type, ir.FloatType):
info['size'] = 4
info['signed'] = True
info['name'] = "float"
elif isinstance(llvm_type, ir.PointerType):
info['size'] = 8
info['signed'] = False
info['ptr'] = True
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size: int = 0
for elem in llvm_type.elements:
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
size += elem_info['size']
info['size'] = size
info['signed'] = False
if isinstance(llvm_type, ir.IdentifiedStructType):
info['name'] = llvm_type.name
else:
info['name'] = "struct"
elif isinstance(llvm_type, ir.ArrayType):
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
info['size'] = elem_info['size'] * llvm_type.count
info['signed'] = elem_info['signed']
info['name'] = f"{elem_info['name']}[]"
elif isinstance(llvm_type, ir.VoidType):
info['size'] = 0
info['signed'] = False
info['name'] = "void"
else:
info['size'] = 0
info['signed'] = False
info['name'] = str(llvm_type)
return info
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return ir.IntType(32)
elif isinstance(node.value, int):
return ir.IntType(32)
elif isinstance(node.value, float):
return ir.DoubleType()
elif isinstance(node.value, str):
if getattr(node, 'kind', None) == 'u':
return ir.PointerType(ir.IntType(16))
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Name):
if node.id in Gen.variables:
var_ptr: Any = Gen.variables[node.id]
if isinstance(var_ptr.type, ir.PointerType):
return var_ptr.type.pointee
return var_ptr.type
if node.id in Gen._reg_values:
return Gen._reg_values[node.id].type
return ir.IntType(32)
elif isinstance(node, ast.Attribute):
attr_name: str = node.attr
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
return ir.IntType(32)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
return ir.DoubleType()
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.UnaryOp):
return self._infer_expr_llvm_type_full(node.operand)
elif isinstance(node, ast.Subscript):
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
if isinstance(val_type, ir.PointerType):
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
return ir.IntType(8)
if isinstance(val_type.pointee, ir.ArrayType):
return ir.PointerType(val_type.pointee.element)
return val_type.pointee
if isinstance(val_type, ir.ArrayType):
return val_type.element
if isinstance(val_type, ir.IntType):
return ir.IntType(8)
return ir.IntType(32)
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name: str = node.func.id
if Gen._has_function(func_name):
fn: Any = Gen._get_function(func_name)
return fn.function_type.return_type
if func_name == 'len':
return ir.IntType(32)
if func_name == 'sizeof':
return ir.IntType(32)
if func_name == 'ord':
return ir.IntType(32)
if func_name == 'chr':
return ir.IntType(8)
if func_name == 'int':
return ir.IntType(32)
if func_name == 'float' or func_name == 'double':
return ir.DoubleType()
elif isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
if node.func.attr == 'Deref':
return ir.IntType(64)
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
if node.func.attr == 'CChar':
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Compare):
return ir.IntType(1)
elif isinstance(node, ast.BoolOp):
return ir.IntType(1)
elif isinstance(node, ast.IfExp):
return self._infer_expr_llvm_type_full(node.body)
elif isinstance(node, ast.Attribute):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
"""收集 AST 节点中的绑定变量和自由变量
Args:
node: AST 节点
bound: 集合收集绑定变量ast.Store 上下文)
free: 集合收集自由变量ast.Load 上下文),可为 None
"""
if free is None:
free = set()
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
bound.add(node.id)
elif isinstance(node.ctx, ast.Load):
free.add(node.id)
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
# 这些节点有自己的作用域,不递归进入
# 但需要收集参数名作为 bound
if hasattr(node, 'args') and node.args:
for arg in node.args.args:
bound.add(arg.arg)
elif getattr(node, '_fields', None):
for field in node._fields:
value: Any = getattr(node, field, None)
if isinstance(value, list):
for item in value:
if isinstance(item, (ast.stmt, ast.expr)):
self._collect_names(item, bound, free)
elif isinstance(value, (ast.stmt, ast.expr)):
self._collect_names(value, bound, free)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
class IfHandle(BaseHandle):
def _get_attr_full_name(self, node: ast.expr) -> str | None:
if isinstance(node, ast.Attribute):
parts: list[str] = []
cur: ast.expr = node
while isinstance(cur, ast.Attribute):
parts.append(cur.attr)
cur = cur.value
if isinstance(cur, ast.Name):
parts.append(cur.id)
parts.reverse()
return '.'.join(parts)
return None
def _is_cif_call(self, node: ast.expr) -> bool:
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
if isinstance(node.func, ast.Name):
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
return False
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
if isinstance(arg, ast.Name):
return arg.id
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
return arg.value
if isinstance(arg, ast.Attribute):
full_name: str | None = self._get_attr_full_name(arg)
if full_name:
return full_name
return None
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
if not isinstance(node, ast.Call):
return None
args: list[ast.expr] = node.args
if not args:
return 0
kind: str | None = None
if isinstance(node.func, ast.Attribute):
kind = node.func.attr
elif isinstance(node.func, ast.Name):
kind = node.func.id
else:
return None
if kind == 'CIfdef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 0
return 1 if self._is_macro_defined(name) else 0
elif kind == 'CIfndef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 1
return 0 if self._is_macro_defined(name) else 1
elif kind == 'CIf':
return self._eval_const_expr(args[0])
return None
def _is_macro_defined(self, name: str) -> bool:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
return True
if self.Trans.SymbolTable.is_define(name):
return True
platform_macros: dict[str, int] = self._get_platform_macros()
return name in platform_macros
def _get_macro_value(self, name: str) -> int | float | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
val: int | float | None = Gen._define_constants[name]
if isinstance(val, (int, float)):
return val
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
if info:
if info.IsDefine:
val: int | float | None = info.DefineValue
if isinstance(val, (int, float)):
return val
platform_macros: dict[str, int] = self._get_platform_macros()
if name in platform_macros:
return platform_macros[name]
return None
def _get_platform_macros(self) -> dict[str, int]:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
macros: dict[str, int] = {}
pi: dict[str, object] = Gen._platform_info
ptr_size: int = getattr(Gen, 'ptr_size', 8)
# 根据目标平台设置宏(从三元组推导)
if pi.get('is_windows'):
macros['_WIN32'] = 1
if not pi.get('is_32bit'):
macros['_WIN64'] = 1
macros['WIN64'] = 1
macros['WIN32'] = 1
if pi.get('is_linux'):
macros['__linux__'] = 1
if pi.get('is_macos'):
macros['__APPLE__'] = 1
macros['__MACH__'] = 1
if pi.get('is_x86_64'):
macros['__x86_64__'] = 1
macros['__x86_64'] = 1
macros['_M_X64'] = 1
elif pi.get('is_arm64'):
macros['__aarch64__'] = 1
macros['_M_ARM64'] = 1
if not pi.get('is_32bit') and pi.get('is_linux'):
macros['__LP64__'] = 1
elif pi.get('is_32bit'):
macros['_ILP32'] = 1
macros['SIZEOF_VOID_P'] = ptr_size
macros['__SIZEOF_POINTER__'] = ptr_size
macros['NDEBUG'] = 0
return macros
def _eval_const_expr(self, node: ast.expr) -> int | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
if result is None:
# 保留 CIf 嵌套调用处理HandlesIf 特有逻辑)
if isinstance(node, ast.Call) and self._is_cif_call(node):
return self._evaluate_cif_condition(node)
return None
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
if isinstance(result, bool):
return 1 if result else 0
if isinstance(result, float):
return 1 if result != 0.0 else 0
return result
def _HandleIfLlvm(self, Node: ast.If) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if self._is_cif_call(Node.test):
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
if compile_time_val is not None:
if compile_time_val:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
if is_const:
if Cond.constant:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
obj_val: ir.Value = Cond
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
else:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
Gen.builder.position_at_start(ThenBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if not MergeBB.is_terminated:
Gen.builder.position_at_start(MergeBB)
else:
Gen.builder.position_at_end(MergeBB)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,382 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class MatchHandle(BaseHandle):
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
if not SubjectVal:
return
IsRenumMatch: bool = False
RenumName: str | None = None
SubjectPtr: ir.Value | None = None
if isinstance(Node.subject, ast.Name):
VarName: str = Node.subject.id
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
if TypeInfo and TypeInfo.IsRenum:
IsRenumMatch = True
RenumName = TypeInfo.Name
SubjectPtr = Gen._Load_var(VarName)
if not IsRenumMatch:
for case in Node.cases:
if isinstance(case.pattern, ast.MatchClass):
cls_node: ast.expr = case.pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
# Extract enum name for qualified lookup to avoid collision
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
# collision with same-name functions (e.g., def Ptr(...))
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName: str = SymInfo.EnumName
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
if EnumInfo and EnumInfo.IsRenum:
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
SubjectPtr = self.HandleExprLlvm(Node.subject)
break
if IsRenumMatch and SubjectPtr:
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
return
if not isinstance(SubjectVal.type, ir.IntType):
try:
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
except Exception: # 回退ptrtoint 失败时直接返回
return
SwitchIntType: ir.IntType = SubjectVal.type
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchOr):
for j, SubPattern in enumerate(pattern.patterns):
if isinstance(SubPattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
elif isinstance(pattern, ast.MatchSingleton):
if pattern.value is None:
CaseValues.append(ir.Constant(SwitchIntType, 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases: int = len(pattern.patterns)
for j in range(NumSubCases):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load返回值而非指针。
# 情况1: SubjectPtr 不是指针类型(如 IntType→ alloca REnum 结构体 + store
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag→ bitcast
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
if NeedAlloca or NeedBitcast:
RenumStructType: Any = Gen.structs.get(RenumName)
if RenumStructType is None:
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
# (如 import llvmlite 后 LLVMType 仅在符号表Gen.structs 无条目)。
# 使用 _get_or_create_struct 按需创建(可能为 opaque
RenumStructType = Gen._get_or_create_struct(RenumName)
if NeedAlloca:
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
Gen._store(SubjectPtr, CastedPtr)
SubjectPtr = AllocaPtr
else:
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
# REnum 布局为 { i32 __tag, <payload> }tag 在偏移 0。
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
# (跨模块编译时 REnum 结构体可能未 set_bodygep 会失败)。
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
bindings: list[tuple[str, str, ir.Type, int]] = []
if isinstance(pattern, ast.MatchClass):
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
TagValue: int | None = None
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember:
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
for j, sub_pat in enumerate(pattern.patterns):
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
CaseBindings.append(bindings)
else:
CaseValues.append(ir.Constant(ir.IntType(32), 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(ir.IntType(32), 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType: ir.Type = Gen.structs[NestedStructName]
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
Gen.variables[bind_name] = elem_ptr
self.HandleBodyLlvm(case.body)
for bind_name, _, _, _ in bindings:
if bind_name in Gen.variables:
del Gen.variables[bind_name]
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchValue):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)

View File

@@ -0,0 +1,155 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
from lib.constants.config import mode as _config_mode
class RaiseHandle(BaseHandle):
def _get_exception_code(self, ExcName: str) -> int:
if ExcName in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[ExcName]
if ExcName in self.Trans.exception_registry:
return self.Trans.exception_registry[ExcName]
return 1
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
exc_msg: ir.Value | None = None
IsStopIteration: bool = False
if Node.exc:
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
elif isinstance(Node.exc, ast.Name):
ExcName: str = Node.exc.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
ExcName: str = Node.exc.func.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
if Node.exc.args:
first_arg: ast.expr = Node.exc.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
if arg_val:
if isinstance(arg_val.type, ir.PointerType):
if self._is_char_pointer(arg_val):
exc_msg = arg_val
else:
try:
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
try:
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
if val:
if isinstance(val.type, ir.IntType):
if val.type.width != 32:
try:
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
except Exception: # 回退trunc 失败时设默认值 1
val = ir.Constant(ir.IntType(32), 1)
exc_val = val
else:
try:
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
exc_val = val
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if IsStopIteration:
if Gen._stop_iter_flag_param is not None:
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
ret_type: ir.Type = Gen.func.type.pointee.return_type
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
else:
Gen.builder.ret_void()
return
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(exc_val, exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
Gen.builder.branch(ExceptBB)
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen.builder.ret_void()
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen.builder.ret_void()

View File

@@ -0,0 +1,165 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
import ast
import llvmlite.ir as ir
class ReturnHandle(BaseHandle):
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
for item in reversed(Gen.eh_finally_stack):
if item is not None and item[0] is not None:
return item
return None
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
return_values: list[ast.expr] = []
if isinstance(Node.value, ast.Tuple):
return_values = Node.value.elts
else:
return_values = [Node.value]
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
llvm_vals: list[ir.Value] = []
expected_types: list[ir.Type] = []
for i, val in enumerate(return_values):
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
IsRetPtr = True
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
expected_types.append(ExpectedType)
Val: ir.Value | None = self.HandleExprLlvm(val)
if Val is None:
if isinstance(ExpectedType, ir.PointerType):
Val = ir.Constant(ExpectedType, None)
elif isinstance(ExpectedType, ir.IntType):
Val = ir.Constant(ExpectedType, 0)
else:
Val = ir.Constant(ExpectedType, ir.Undefined)
else:
if Val.type != ExpectedType:
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < ExpectedType.width:
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
elif Val.type.width > ExpectedType.width:
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
llvm_vals.append(Val)
if llvm_vals:
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
for i, val in enumerate(llvm_vals):
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if Node.value:
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
if Val:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(zero_val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(zero_val)
return
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
struct_type: ir.Type = Gen.func.ftype.return_type
if isinstance(struct_type, ir.LiteralStructType):
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
for j in range(1, len(struct_type.elements)):
elem_type: ir.Type = struct_type.elements[j]
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
for j, elem_type in enumerate(struct_type.elements):
if j == 0:
if Val.type == elem_type:
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < elem_type.width:
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
elif Val.type.width > elem_type.width:
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(Val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(Val)
else:
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.ArrayType):
Gen.builder.ret(ir.Constant(ret_type, None))
else:
Gen.emit_return()

View File

@@ -0,0 +1,467 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ast
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
from lib.core.Handles.HandlesBase import BaseHandle, BuiltinTypeMap
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsTModule
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
class CSpecialCallHandle(BaseHandle):
def _HandleCIfLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if Node.args:
ArgVal: ir.Value | None = self.HandleExprLlvm(Node.args[0])
if ArgVal:
if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType):
return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0)
if isinstance(ArgVal.type, ir.IntType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
if isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
return ir.Constant(ir.IntType(1), 0)
def _HandleCAddrLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(8).as_pointer(), None)
Arg = Node.args[0]
if isinstance(Arg, ast.Call):
ClassName = None
if isinstance(Arg.func, ast.Name):
ClassName = Arg.func.id
elif isinstance(Arg.func, ast.Attribute):
ClassName = Arg.func.attr
if ClassName and ClassName in Gen.structs:
StructType = Gen.structs[ClassName]
if isinstance(StructType, ir.PointerType):
StructType = StructType.pointee
ObjPtr = Gen._allocaEntry(StructType, name=f"{ClassName}_obj")
zero_val = Gen._zero_value_for_type(StructType)
if zero_val is not None:
Gen.builder.store(zero_val, ObjPtr)
ConstructorName = f"{ClassName}.__init__"
if ConstructorName in Gen.functions:
func = Gen.functions[ConstructorName]
InitArgs = [ObjPtr]
for carg in Arg.args:
ArgVal = self.HandleExprLlvm(carg)
if ArgVal:
InitArgs.append(ArgVal)
for kw in Arg.keywords:
ArgVal = self.HandleExprLlvm(kw.value)
if ArgVal:
InitArgs.append(ArgVal)
if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'):
self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen)
adjusted = Gen._adjust_args(InitArgs, func)
Gen.builder.call(func, adjusted, name=f"{ClassName}_construct")
return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr")
if isinstance(Arg, ast.Subscript):
SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg)
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr")
if isinstance(Arg, ast.Attribute):
AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg)
if AttrPtr and isinstance(AttrPtr.type, ir.PointerType):
return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr")
if isinstance(Arg, ast.Name):
VarName = Arg.id
if VarName in Gen.functions:
func = Gen.functions[VarName]
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr")
if VarName in Gen.variables and Gen.variables[VarName] is not None:
var_ptr = Gen.variables[VarName]
if isinstance(var_ptr.type, ir.PointerType):
# For pointer-to-pointer allocas (var_ptr is T**):
# - If T is a named struct (@t.Object class), the variable semantically
# IS the struct, so c.Addr should return the struct pointer value.
# - If T is a primitive pointer type (e.g., i8*), the variable semantically
# holds a pointer, so c.Addr should return &var (alloca address).
if isinstance(var_ptr.type.pointee, ir.PointerType):
pointee = var_ptr.type.pointee.pointee
if isinstance(pointee, ir.IdentifiedStructType):
# @t.Object class variable — return Loaded struct pointer
ArgVal = self.HandleExprLlvm(Arg)
if ArgVal and isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
# Pointer-type variable — return alloca address (&var)
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
ArgVal = self.HandleExprLlvm(Arg)
if ArgVal:
if isinstance(ArgVal.type, ir.IntType):
alloca = Gen._alloca(ArgVal.type, name="addr_tmp")
Gen._store(ArgVal, alloca)
return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
elif isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast")
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _HandleCSetLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if len(Node.args) >= 2:
target_arg: ast.expr = Node.args[0]
value_arg: ast.expr = Node.args[1]
target_ptr: ir.Value | None = None
if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute):
if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c':
if target_arg.func.attr == 'Deref' and target_arg.args:
deref_arg = target_arg.args[0]
if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None:
target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr")
else:
inner_value = self.HandleExprLlvm(deref_arg)
if inner_value:
if isinstance(inner_value.type, ir.PointerType):
if isinstance(inner_value.type.pointee, ir.PointerType):
inner_value = Gen._load(inner_value, name="cast_deref")
target_ptr = inner_value
elif target_arg.func.attr == 'Addr' and target_arg.args:
target_ptr = self.HandleExprLlvm(target_arg)
elif isinstance(target_arg.func.value, ast.Name) and IsTModule(target_arg.func.value.id, self.Trans.SymbolTable):
type_attr = target_arg.func.attr
resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr)
if target_arg.args and resolved_cname is not None:
inner_val = self.HandleExprLlvm(target_arg.args[0])
if inner_val and isinstance(inner_val.type, ir.PointerType):
target_llvm_type = Gen._basic_type_to_llvm(resolved_cname)
if target_llvm_type:
target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr")
if not target_ptr:
if isinstance(target_arg, ast.Subscript):
target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg)
else:
target_ptr = self.HandleExprLlvm(target_arg)
Val = self.HandleExprLlvm(value_arg)
if target_ptr and Val:
if isinstance(target_ptr.type, ir.PointerType):
ValToStore = Val
pointee = target_ptr.type.pointee
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8:
if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
ValToStore = Val
elif isinstance(Val.type, ir.IntType):
ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set")
elif isinstance(pointee, ir.IntType):
if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8:
zero = ir.Constant(ir.IntType(32), 0)
value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr")
ValToStore = Gen._load(value_ptr, name="Load_value")
elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
ValToStore = Gen._load(Val, name="Load_char_value")
if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType):
if ValToStore.type.width < pointee.width:
ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set")
elif ValToStore.type.width > pointee.width:
ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set")
elif Val.type != pointee:
if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType):
ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set")
Gen._store(ValToStore, target_ptr)
return ir.Constant(ir.IntType(32), 1)
def _HandleCLoadLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if len(Node.args) < 2:
return ir.Constant(ir.IntType(32), 0)
# c.Load(a, b) 语义: *a = *ba 是目标b 是源)
# wiki 文档: c.Load(ptr, value) -> *ptr = *value;
dst_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
src_val: ir.Value | None = self.HandleExprLlvm(Node.args[1])
if not src_val or not dst_val:
return ir.Constant(ir.IntType(32), 0)
if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType):
return ir.Constant(ir.IntType(32), 0)
pointee = dst_val.type.pointee
# c.Addr 统一返回 i8* 通用指针,丢失原始类型信息。
# 若 dst 是 c.Addr(var),从 var 的 alloca 类型推断真实 pointee如 i64
# 否则 c.Load 只会按 i8 加载 1 字节IEEE 754 double→u64 位重解释 bug
if (isinstance(pointee, ir.IntType) and pointee.width == 8
and isinstance(Node.args[0], ast.Call)
and isinstance(Node.args[0].func, ast.Attribute)
and Node.args[0].func.attr == 'Addr'
and Node.args[0].args
and isinstance(Node.args[0].args[0], ast.Name)):
var_name = Node.args[0].args[0].id
if var_name in Gen.variables and Gen.variables[var_name] is not None:
var_ptr = Gen.variables[var_name]
if isinstance(var_ptr.type, ir.PointerType):
pointee = var_ptr.type.pointee
# 按 pointee 类型 bitcast src 加载bitcast dst 存储
if src_val.type.pointee != pointee:
src_cast = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_src_cast")
else:
src_cast = src_val
Loaded = Gen._load(src_cast, name="cLoad_loaded")
if Loaded is None:
return ir.Constant(ir.IntType(32), 0)
if dst_val.type.pointee != pointee:
dst_cast = Gen.builder.bitcast(dst_val, ir.PointerType(pointee), name="cLoad_dst_cast")
else:
dst_cast = dst_val
Gen._store(Loaded, dst_cast)
return ir.Constant(ir.IntType(32), 1)
def _HandleCDerefLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
# 检测嵌套 c.Deref(c.Deref(...)):设置标志让内层 Deref 加载为指针
IsNestedDeref: bool = (
isinstance(Node.args[0], ast.Call)
and isinstance(Node.args[0].func, ast.Attribute)
and Node.args[0].func.attr == 'Deref'
)
if IsNestedDeref:
Gen._nested_deref_load_ptr = True
try:
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
finally:
if IsNestedDeref:
Gen._nested_deref_load_ptr = False
if arg_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(arg_val.type, ir.PointerType):
pointee: ir.Type = arg_val.type.pointee
# 嵌套 Deref 的内层:加载为指针 (i8*),不推断目标类型
# 因为结果会被外层 Deref 再次解引用
NestedLoadPtr: bool = getattr(Gen, '_nested_deref_load_ptr', False)
if NestedLoadPtr:
PtrType: ir.Type = ir.PointerType(ir.IntType(8))
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(PtrType), name="deref_cast")
Loaded = Gen._load(casted, name="deref")
if Loaded is not None:
return Loaded
# void* (i8*) 需要根据赋值目标类型推断加载类型
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
target_type: ir.Type | None = self._infer_deref_target_type(Gen, Node)
if target_type is not None and not isinstance(target_type, ir.IntType):
# bitcast i8* -> target_type* then load
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast")
Loaded = Gen._load(casted, name="deref")
if Loaded is not None:
return Loaded
elif target_type is not None and isinstance(target_type, ir.IntType):
# 目标是整数类型 (如 i32/i64): bitcast 并加载
if target_type.width != 8:
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast")
Loaded = Gen._load(casted, name="deref")
if Loaded is not None:
return Loaded
Loaded = Gen._load(arg_val, name="deref")
if Loaded is not None:
return Loaded
return arg_val
def _infer_deref_target_type(self, Gen: LlvmGeneratorMixin, DerefNode: ast.Call | None = None) -> ir.Type | None:
"""从当前赋值上下文推断 c.Deref 的目标加载类型。
当用户写 v: int = c.Deref(ptr) 时,从赋值注解推断目标类型。
注意:仅当 c.Deref 是赋值的直接 RHS 时才推断;若 c.Deref 嵌套在
ifexp/compare/binop 中(如 `a = 1 if c.Deref(p) == 65 else 0`
不应推断,否则会把 i8* 错误 bitcast 为 i32* 加载 4 字节。"""
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
if not assign_node:
return None
# 仅当 c.Deref 是赋值的直接 RHS 时才推断类型
if DerefNode is not None and getattr(assign_node, 'value', None) is not DerefNode:
return None
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
if not ann:
return None
ann_name: str | None = None
if isinstance(ann, ast.Name):
ann_name = ann.id
elif isinstance(ann, ast.Attribute):
ann_name = ann.attr
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
# 处理 int | t.CPtr 形式的联合类型注解
for side in (ann.left, ann.right):
if isinstance(side, ast.Name):
ann_name = side.id
break
elif isinstance(side, ast.Attribute):
ann_name = side.attr
break
if not ann_name:
return None
# 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记)
entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name)
if entry is not None:
ctype_cls: type = entry[0]
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
if resolved:
return resolved
# 检查是否是已注册的结构体类型
if ann_name in Gen.structs:
return Gen.structs[ann_name]
return None
def _HandleCPtrToIntLlvm(self, Node: ast.Call) -> ir.Value:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
if arg_val is None:
return ir.Constant(ir.IntType(64), 0)
if isinstance(arg_val.type, ir.PointerType):
return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result")
if isinstance(arg_val.type, ir.IntType):
if arg_val.type.width < 64:
return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint")
elif arg_val.type.width > 64:
return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint")
return arg_val
return ir.Constant(ir.IntType(64), 0)
class TSpecialCallHandle(BaseHandle):
@staticmethod
def _ResolveTAttrToCName(attr: str) -> str | None:
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
try:
inst = ctype_cls()
cname = type(inst).__name__
if cname:
return cname
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"处理函数调用失败: {_e}", "Exception")
return None
def _HandleTSpecialCallLlvm(self, Node: ast.Call) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if not Node.args:
return None
attr: str = Node.func.attr
if attr == 'CType':
return self._HandleCTypeLlvm(Node)
target_type: str | None = self._ResolveTAttrToCName(attr)
if target_type is not None:
IsPtr_cast = False
if len(Node.args) >= 2:
second_arg = Node.args[1]
if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and IsTModule(second_arg.value.id, self.Trans.SymbolTable) and second_arg.attr == 'CPtr':
IsPtr_cast = True
elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr':
IsPtr_cast = True
if IsPtr_cast:
return self._HandleTPtrCastLlvm(Node, attr)
if target_type == 'void':
target_type = 'void *'
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type)
return None
def _HandleCTypeLlvm(self, Node: ast.Call) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
if not arg_val:
return None
target_type_str: str = 'unsigned long long'
if len(Node.args) >= 2:
type_parts: list[str] = []
ptr_count: int = 0
for i in range(1, len(Node.args)):
type_arg = Node.args[i]
if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
type_attr = type_arg.attr
_PREFIX_MAP: dict[str, str] = {
'CUnsigned': 'unsigned', 'CSigned': 'signed',
'CConst': 'const', 'CVolatile': 'volatile',
}
if type_attr in _PREFIX_MAP:
type_parts.append(_PREFIX_MAP[type_attr])
elif type_attr in ('CPtr', 'CArrayPtr'):
ptr_count += 1
else:
resolved = self._ResolveTAttrToCName(type_attr)
if resolved is not None:
type_parts.append(resolved)
if type_parts:
target_type_str = ' '.join(type_parts)
if ptr_count > 0:
target_type_str += ' ' + '*' * ptr_count
if isinstance(arg_val.type, ir.PointerType):
int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int")
return int_val
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str)
def _HandleTPtrCastLlvm(self, Node: ast.Call, attr: str) -> ir.Value | None:
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
if attr in ('CChar', 'CUnsignedChar'):
first_arg = Node.args[0]
if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and IsTModule(first_arg.func.value.id, self.Trans.SymbolTable) and first_arg.func.attr == 'CInt' and first_arg.args:
inner_val = self.HandleExprLlvm(first_arg.args[0])
if isinstance(inner_val.type, ir.PointerType):
return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint")
expr_val = self.HandleExprLlvm(Node.args[0])
if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8:
var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr")
zero = ir.Constant(ir.IntType(32), 0)
char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr")
Gen._store(expr_val, char_ptr)
null_char = ir.Constant(ir.IntType(8), 0)
null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr")
Gen._store(null_char, null_ptr)
return char_ptr
elif isinstance(expr_val.type, ir.PointerType):
if isinstance(expr_val.type.pointee, ir.PointerType):
Loaded_ptr = Gen._load(expr_val, name="load_ptr")
if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8:
return Loaded_ptr
if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8:
return expr_val
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr")
elif isinstance(expr_val.type, ir.IntType):
if expr_val.type.width == 32:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}")
return Gen.emit_constant(0, 'int')
elif attr == 'CVoid':
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *')
elif attr == 'CInt':
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
else:
ctype_cls = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
target_type = Gen._type_str_to_llvm(llvm_str)
if target_type:
# 基础类型 (int/float) → 加一层指针 → T*
if isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)):
target_ptr_type = ir.PointerType(target_type)
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
# 指针类型 (如 CPtr → i8*) → 再加一层指针 → i8**
elif isinstance(target_type, ir.PointerType):
target_ptr_type = ir.PointerType(target_type)
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return None

View File

@@ -0,0 +1,214 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import ast
import llvmlite.ir as ir
class TryHandle(BaseHandle):
def _get_exception_type_code(self, type_node: ast.expr) -> int:
if isinstance(type_node, ast.Name):
name: str = type_node.id
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Attribute):
name: str = type_node.attr
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Tuple):
for elt in type_node.elts:
code: int = self._get_exception_type_code(elt)
if code != 1:
return code
return 1
return 1
def _get_exception_name(self, type_node: ast.expr) -> str | None:
if isinstance(type_node, ast.Name):
return type_node.id
if isinstance(type_node, ast.Attribute):
return type_node.attr
return None
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
name: str | None = self._get_exception_name(type_node)
if name is None:
return [self._get_exception_type_code(type_node)]
if name not in self.Trans.exception_registry:
return [self._get_exception_type_code(type_node)]
codes: list[int] = [self.Trans.exception_registry[name]]
self._collect_descendant_codes(name, codes)
return codes
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
for child_name, parent in self.Trans.exception_parents.items():
if parent == parent_name:
child_code: int | None = self.Trans.exception_registry.get(child_name)
if child_code is not None and child_code not in codes:
codes.append(child_code)
self._collect_descendant_codes(child_name, codes)
def _HandleTryLlvm(self, Node: ast.Try) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if not Gen.func:
return
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
HasFinally: bool = bool(Node.finalbody)
if HasFinally:
Gen.eh_finally_stack.append((None, None, None))
else:
Gen.eh_finally_stack.append(None)
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
for i, handler in enumerate(Node.handlers):
ExcTypeCodes: list[int] = [1]
if handler.type:
ExcTypeCodes = self._get_all_match_codes(handler.type)
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
ElseBB: ir.Block | None = None
if Node.orelse:
ElseBB = Gen.func.append_basic_block(name="try.else")
Gen.builder.branch(TryBB)
Gen.builder.position_at_start(TryBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
if ElseBB:
Gen.builder.branch(ElseBB)
else:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(DispatchBB)
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
next_check_bb: ir.Block | None = None
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
if i > 0 and next_check_bb is not None:
Gen.builder.position_at_start(next_check_bb)
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
if handler.type is None:
Gen.builder.branch(MatchBB)
else:
match_cond: ir.Value | None = None
for code in ExcTypeCodes:
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
if match_cond is None:
match_cond = is_code_match
else:
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
if i < len(except_blocks) - 1:
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
else:
next_check_bb = UnhandledBB
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
Gen.builder.position_at_start(MatchBB)
if handler.name:
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
Gen._store(eh_msg_val, var_alloca)
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
Gen.builder.branch(ExceptBB)
Gen.builder.position_at_start(UnhandledBB)
eh_msg_out_arg: ir.Argument | None = None
eh_code_out_arg: ir.Argument | None = None
if Gen.func and len(Gen.func.args) > 0:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_out_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_out_arg = arg
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
Gen._store(eh_msg_val, eh_msg_out_arg)
Gen._store(eh_code_val_prop, eh_code_out_arg)
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 1))
elif isinstance(ret_type, ir.VoidType):
Gen.builder.ret_void()
else:
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen.builder.branch(AfterBB)
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
Gen.builder.position_at_start(ExceptBB)
old_var: ir.Value | None = None
if idx in handler_var_map:
hname: str = handler_var_map[idx][0]
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
old_var = handler_var_map[idx][2]
Gen.variables[hname] = var_alloca
self.HandleBodyLlvm(handler.body)
if idx in handler_var_map:
hname = handler_var_map[idx][0]
old_var = handler_var_map[idx][2]
if old_var is not None:
Gen.variables[hname] = old_var
elif hname in Gen.variables:
del Gen.variables[hname]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.eh_except_block_stack.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
if HasFinally:
Gen.eh_finally_stack.pop()
if Node.finalbody:
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
Gen.builder.branch(FinallyBB)
Gen.builder.position_at_start(FinallyBB)
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
self.HandleBodyLlvm(Node.finalbody)
if Gen.eh_finally_stack:
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
Gen.eh_finally_stack.pop()
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
Gen.builder.position_at_start(RetBB)
if pending_ret_val:
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
Gen.builder.ret(ret_val)
else:
Gen.builder.ret_void()
Gen.builder.position_at_start(ContinueBB)

View File

@@ -0,0 +1,975 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from typing import List
from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.includes import t
import lib._bootstrap # noqa: F401 设置 sys.path项目根 + lib/includes
import ast
class HandlesTypeMerge(BaseHandle):
"""处理类型合并逻辑 - 所有类型分析的核心模块"""
def _MakeVoidCTypeInfo(self) -> CTypeInfo:
Info = CTypeInfo()
Info.BaseType = t.CVoid
return Info
@staticmethod
def _MakeCTypeInfoFromName(TypeName: str) -> CTypeInfo:
"""直接从类型名构造 CTypeInfo不经过 FromStr/字符串解析"""
return CTypeInfo.FromTypeName(TypeName)
def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo:
"""获取 CTypeInfo 对象"""
Result = self._GetCTypeInfoInternal(Node)
if isinstance(Result, CTypeInfo):
return Result
elif isinstance(Result, str):
return self._MakeCTypeInfoFromName(Result)
else:
return self._MakeVoidCTypeInfo()
def _GetCTypeInfoInternal(self, Node: ast.AST) -> CTypeInfo | str | None:
"""鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo"""
LineNum = getattr(Node, 'lineno', None)
self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...")
if isinstance(Node, ast.Constant):
TypeName = Node.value
return self._MakeCTypeInfoFromName(TypeName)
if isinstance(Node, ast.Name):
TypeName = Node.id
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
if TypeName in t_c_imported:
src_module, src_name = t_c_imported[TypeName]
virtual_attr = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.GetCTypeInfo(virtual_attr)
Entry = self.Trans.SymbolTable.lookup(TypeName)
if Entry and Entry.IsTypedef:
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0:
Result = Entry.Copy()
Result.IsTypedef = True
Result.Name = TypeName
return Result
if Entry.OriginalType:
if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr:
Result = CTypeInfo()
Result.IsFuncPtr = True
Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else []
Result.IsTypedef = True
Result.Name = TypeName
return Result
elif isinstance(Entry.OriginalType, CTypeInfo):
Resolved = Entry.OriginalType.Copy()
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
elif isinstance(Entry.OriginalType, str):
# 字符串 OriginalType如 'void *')需解析为 CTypeInfo
# 否则返回的 Entry BaseType=None 会被下游误判为 i32
Resolved = CTypeInfo.FromTypeName(Entry.OriginalType)
if Resolved and Resolved.BaseType:
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
return Entry
# REnum 优先于 IsEnum 处理REnum 同时有 IsEnum=True 和 IsStruct=True
# 必须设置 Name 和 PtrCount=1否则 BinOp `LLVMType | t.CPtr` 合并后丢失 REnum 语义
if isinstance(Entry, CTypeInfo) and Entry.IsRenum:
Result = Entry.Copy()
Result.Name = TypeName
Result.PtrCount = 1 # REnum 变量默认为指针(和 struct 一致)
return Result
# 类名与枚举成员名冲突时(如 Constant 既是 ASTKind.Constant 枚举成员又是结构体类名),
# 优先检查 Gen.structs类型注解应解析为结构体而非枚举值
_Gen = getattr(self.Trans, 'LlvmGen', None)
if _Gen and TypeName in _Gen.structs:
Result = CTypeInfo()
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
Result.Name = TypeName
Result.PtrCount = 1
return Result
if isinstance(Entry, CTypeInfo) and Entry.IsEnum:
return Entry.Copy()
if isinstance(Entry, dict) and Entry.get('IsEnum'):
Result = CTypeInfo()
Result.BaseType = t.CEnum(TypeName)
Result.IsEnum = True
return Result
# 检测结构体类型 (CTypeInfo with IsStruct=True, 来自 _InsertClassSymbol)
if isinstance(Entry, CTypeInfo) and Entry.IsStruct:
Result = Entry.Copy()
if Result.BaseType is None:
Result.BaseType = t.CStruct(name=TypeName)
Result.Name = TypeName
Result.PtrCount = 1 # struct 变量默认为指针
return Result
return self._MakeCTypeInfoFromName(TypeName)
elif isinstance(Node, ast.Attribute):
ModuleParts = []
Current = Node
while isinstance(Current, ast.Attribute):
ModuleParts.insert(0, Current.attr)
Current = Current.value
if isinstance(Current, ast.Name):
ModuleParts.insert(0, Current.id)
if len(ModuleParts) >= 2:
TypeName = ModuleParts[-1]
ModulePath = '.'.join(ModuleParts[:-1])
elif len(ModuleParts) == 1:
TypeName = ModuleParts[0]
ModulePath = None
else:
return self._MakeVoidCTypeInfo()
# 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types
if ModulePath:
import_aliases = self.Trans.SymbolTable.import_aliases
if ModulePath in import_aliases:
ModulePath = import_aliases[ModulePath]
else:
# 也尝试在符号表中查找模块别名
entry = self.Trans.SymbolTable.lookup(ModulePath)
if isinstance(entry, CTypeInfo) and entry.IsModuleAlias:
resolved = entry.ResolvedModule
if resolved:
ModulePath = resolved
self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}")
if ModulePath == 't' and TypeName == 'State':
Info = CTypeInfo()
Info.BaseType = t.CVoid
Info.IsState = True
return Info
if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')):
if self._IsTModuleType(TypeName):
TypeClass = CTypeHelper.GetTModuleCType(TypeName) or getattr(t, TypeName, None)
if TypeClass == t.CArrayPtr:
Info = CTypeInfo()
Info.IsArrayPtr = True
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CPtr:
Info = CTypeInfo()
Info.PtrCount = 1
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CConst:
Info = CTypeInfo()
Info.DataConst = True
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CVolatile:
Info = CTypeInfo()
Info.DataVolatile = True
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CInline:
Info = CTypeInfo()
Info.Storage = t.CInline()
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CStatic:
Info = CTypeInfo()
Info.Storage = t.CStatic()
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CExtern:
Info = CTypeInfo()
Info.Storage = t.CExtern()
Info.BaseType = t.CVoid
return Info
elif TypeClass == t.CExport:
Info = CTypeInfo()
Info.Storage = t.CExport()
Info.BaseType = t.CVoid
return Info
elif TypeClass in (t.BigEndian, t.LittleEndian):
Info = CTypeInfo()
Info.BaseType = t.CInt()
Info.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little'
return Info
elif TypeClass:
Info = CTypeInfo()
Info.BaseType = TypeClass
return Info
elif CTypeHelper.GetCName(TypeName):
return self._MakeCTypeInfoFromName(CTypeHelper.GetCName(TypeName))
FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName
# 优先检查 Gen.structs类名与枚举成员名冲突时如 Import 既是 ASTKind.Import
# 枚举成员又是 ast.Import 结构体类名),类型注解应解析为结构体而非枚举值
# (与 ast.Name 路径 line 100-107 的逻辑一致)
_Gen = getattr(self.Trans, 'LlvmGen', None)
if _Gen and TypeName in _Gen.structs:
Result = CTypeInfo()
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
Result.Name = TypeName
Result.PtrCount = 1
return Result
Entry = self.Trans.SymbolTable.lookup(TypeName)
if Entry and Entry.IsTypedef:
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0:
Result = Entry.Copy()
Result.IsTypedef = True
Result.Name = TypeName
return Result
if Entry.OriginalType:
if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr:
Result = CTypeInfo()
Result.IsFuncPtr = True
Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else []
Result.IsTypedef = True
Result.Name = TypeName
return Result
elif isinstance(Entry.OriginalType, CTypeInfo):
Resolved = Entry.OriginalType.Copy()
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
elif isinstance(Entry.OriginalType, str):
# 字符串 OriginalType如 'void *')需解析为 CTypeInfo
# 否则返回的 Result BaseType=_CTypedef 会被下游误判为 i32
Resolved = CTypeInfo.FromTypeName(Entry.OriginalType)
if Resolved and Resolved.BaseType:
Resolved.IsTypedef = True
Resolved.Name = TypeName
return Resolved
Result = CTypeInfo()
Result.BaseType = t._CTypedef(TypeName)
Result.IsTypedef = True
Result.Name = TypeName
return Result
if Entry:
# If BaseType is None but this is a class/struct, set BaseType to CStruct
Result = Entry.Copy()
if Result.BaseType is None:
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
# struct 变量默认为指针(与 ast.Name 路径一致,见 line 121
# 同时确保 Name 字段被设置,供 ToString() 使用
if Result.IsStruct:
if Result.PtrCount == 0:
Result.PtrCount = 1
if not Result.Name:
Result.Name = TypeName
return Result
return CTypeInfo()
elif isinstance(Node, ast.Call):
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
ReturnTypeInfo = self._GetCTypeInfoInternal(Node.args[0]) if Node.args else None
if isinstance(ReturnTypeInfo, CTypeInfo):
ReturnType = ReturnTypeInfo
else:
ReturnType = CTypeInfo()
ReturnType.BaseType = t.CVoid()
ParamTypes = []
ParamNames = []
for kw in Node.keywords:
ParamTypeInfo = self._GetCTypeInfoInternal(kw.value)
if not isinstance(ParamTypeInfo, CTypeInfo):
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
ParamTypes.append(ParamTypeInfo)
ParamNames.append(kw.arg)
for arg in Node.args[1:]:
if isinstance(arg, ast.Tuple):
for elt in arg.elts:
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
if not isinstance(ParamTypeInfo, CTypeInfo):
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
ParamTypes.append(ParamTypeInfo)
ParamNames.append('')
else:
ParamTypeInfo = self._GetCTypeInfoInternal(arg)
if not isinstance(ParamTypeInfo, CTypeInfo):
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
ParamTypes.append(ParamTypeInfo)
ParamNames.append('')
if not ParamTypes:
ParamTypes.append(self._MakeCTypeInfoFromName('void'))
ParamNames.append('')
Info = CTypeInfo()
Info.IsFuncPtr = True
Info.FuncPtrReturn = ReturnType
Info.FuncPtrParams = list(zip(ParamNames, ParamTypes))
return Info
if isinstance(Node.func, ast.Attribute) and isinstance(Node.func.value, ast.Name):
ModuleName = Node.func.value.id
TypeName = Node.func.attr
if ModuleName == 't' and CTypeHelper.GetTModuleCType(TypeName) == t._CTypedef and Node.args:
TypeArg = Node.args[0]
if isinstance(TypeArg, ast.Name):
return TypeArg.id
elif isinstance(TypeArg, ast.Attribute):
AttrModule = TypeArg.value.id if isinstance(TypeArg.value, ast.Name) else None
AttrName = TypeArg.attr
if AttrModule == 't' and getattr(t, AttrName, None):
TypeObj = getattr(t, AttrName)
if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType):
return TypeObj.__name__
return AttrName
elif isinstance(TypeArg, ast.Constant):
return str(TypeArg.value)
if ModuleName in self.Trans._UserTypeModules:
module = self.Trans._UserTypeModules[ModuleName]
if getattr(module, TypeName, None):
TypeObj = getattr(module, TypeName)
if isinstance(TypeObj, type):
if issubclass(TypeObj, t.CType):
return TypeObj.__name__
if ModuleName == 't':
TypeObj = CTypeHelper.GetTModuleCType(TypeName)
if TypeObj is None:
TypeObj = getattr(t, TypeName, None)
if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType):
Result = CTypeInfo()
Result.BaseType = TypeObj
return Result
if ModuleName == 't' and TypeName == 'State':
Result = CTypeInfo()
Result.IsState = True
return Result
if ModuleName == 't' and TypeName == 'Bit':
if Node.args and isinstance(Node.args[0], ast.Constant):
BitWidth = Node.args[0].value
Result = CTypeInfo()
Result.IsBitField = True
Result.BitWidth = BitWidth
Result.BaseType = t.CInt
return Result
Result = CTypeInfo()
Result.BaseType = t.CVoid
return Result
elif isinstance(Node, ast.Subscript):
if (isinstance(Node.value, ast.Attribute)
and isinstance(Node.value.value, ast.Name)
and IsTModule(Node.value.value.id, self.Trans.SymbolTable)
and Node.value.attr == 'Bit'):
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
Result = CTypeInfo()
Result.IsBitField = True
Result.BitWidth = Node.slice.value
Result.BaseType = t.CInt
return Result
return self._HandleSubscript(Node)
elif isinstance(Node, ast.BinOp):
return self.MergeTypes(Node)
elif isinstance(Node, ast.List):
if Node.elts:
BaseTypes = []
for elt in Node.elts:
EltType = self._GetCTypeInfoInternal(elt)
if isinstance(EltType, CTypeInfo) and EltType.BaseType:
BaseTypes.append(EltType.BaseType)
if BaseTypes:
Result = CTypeInfo()
Result.BaseType = tuple(BaseTypes)
return Result
return self._MakeVoidCTypeInfo()
return self._MakeVoidCTypeInfo()
def _HandleSubscript(self, Node: ast.Subscript) -> CTypeInfo:
"""澶勭悊 Subscript 鑺傜偣锛屼娇鐢?CTypeInfo 鏍戝舰缁撴瀯鍒嗘瀽 AST
例如?
t.CVoid[5] -> void *[5]
t.CPtr[t.CPtr[t.CPtr]][5][6] -> void ***[5][6]
t.CArrayPtr[t.CArrayPtr] -> void *(*)[]
t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[]
"""
def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo:
"""鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo"""
if isinstance(node, ast.Subscript):
value_node = node.value
slice_node = node.slice
if isinstance(value_node, ast.Attribute):
VtInfo = self.GetCTypeInfo(value_node)
if isinstance(value_node, ast.Attribute) and value_node.attr == 'Callable' and isinstance(value_node.value, ast.Name) and IsTModule(value_node.value.id, self.Trans.SymbolTable):
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
params_list = slice_node.elts[0]
return_node = slice_node.elts[1]
ParamTypes = []
ParamNames = []
if isinstance(params_list, ast.List):
for elt in params_list.elts:
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
if isinstance(ParamTypeInfo, CTypeInfo):
ParamTypes.append(ParamTypeInfo)
ParamNames.append('')
else:
ParamTypes.append(self._MakeCTypeInfoFromName('int'))
ParamNames.append('')
if not ParamTypes:
ParamTypes.append(self._MakeCTypeInfoFromName('void'))
ParamNames.append('')
ReturnTypeInfo = self._GetCTypeInfoInternal(return_node)
if isinstance(ReturnTypeInfo, CTypeInfo):
ReturnType = ReturnTypeInfo
else:
ReturnType = CTypeInfo()
ReturnType.BaseType = t.CVoid()
Info = CTypeInfo()
Info.IsFuncPtr = True
Info.FuncPtrReturn = ReturnType
Info.FuncPtrParams = list(zip(ParamNames, ParamTypes))
return Info
if VtInfo and VtInfo.IsArrayPtr:
ResultInfo = CTypeInfo()
ResultInfo.PtrCount = VtInfo.PtrCount
ResultInfo.IsArrayPtr = True
if isinstance(slice_node, ast.Attribute):
SliceVtInfo = self.GetCTypeInfo(slice_node)
if SliceVtInfo and SliceVtInfo.IsArrayPtr:
ResultInfo.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr.IsArrayPtr = True
ResultInfo.ArrayPtr.PtrCount = SliceVtInfo.PtrCount
if SliceVtInfo.ArrayPtr:
ResultInfo.ArrayPtr.ArrayPtr = SliceVtInfo.ArrayPtr
elif SliceVtInfo and SliceVtInfo.PtrCount > 0:
ResultInfo.ArrayPtr = SliceVtInfo
else:
ResultInfo.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr.IsArrayPtr = True
elif isinstance(slice_node, ast.Subscript):
ResultInfo.ArrayPtr = CollectAll(slice_node)
elif isinstance(slice_node, ast.Name):
ResultInfo.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType
elif isinstance(slice_node, ast.BinOp):
ResultInfo.ArrayPtr = CTypeInfo()
try:
ResultInfo.ArrayPtr.ArrayDims.append(ast.unparse(slice_node))
except Exception: # 回退unparse 失败时用 'N'
ResultInfo.ArrayPtr.ArrayDims.append('N')
elif isinstance(slice_node, ast.Constant):
ResultInfo.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr.ArrayDims.append(str(slice_node.value))
else:
ResultInfo.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr.IsArrayPtr = True
elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr:
ResultInfo = CTypeInfo()
ResultInfo.BaseType = t.CVoid
ResultInfo.PtrCount = 1
if isinstance(slice_node, ast.Subscript):
inner_info = CollectAll(slice_node)
if inner_info and inner_info.PtrCount > 0:
ResultInfo.PtrCount += inner_info.PtrCount
if inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid):
ResultInfo.BaseType = inner_info.BaseType
elif inner_info and inner_info.ArrayPtr:
ResultInfo.ArrayPtr = inner_info
elif inner_info and inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid):
ResultInfo.BaseType = inner_info.BaseType
elif isinstance(slice_node, ast.Attribute):
SliceVtInfo = self.GetCTypeInfo(slice_node)
if SliceVtInfo and SliceVtInfo.PtrCount == 1 and not SliceVtInfo.ArrayPtr:
ResultInfo.PtrCount = 2
if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
ResultInfo.BaseType = SliceVtInfo.BaseType
elif SliceVtInfo and SliceVtInfo.IsArrayPtr:
inner = CTypeInfo()
inner.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr = inner
elif SliceVtInfo and SliceVtInfo.ArrayPtr:
ResultInfo.ArrayPtr = SliceVtInfo
elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
ResultInfo.BaseType = SliceVtInfo.BaseType
elif isinstance(slice_node, ast.Name):
SliceType = getattr(t, slice_node.id, None)
if SliceType == t.CPtr:
ResultInfo.PtrCount += 1
elif SliceType == t.CArrayPtr:
inner = CTypeInfo()
inner.ArrayPtr = CTypeInfo()
ResultInfo.ArrayPtr = inner
else:
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType
elif isinstance(slice_node, ast.BinOp):
merged = self.MergeTypes(slice_node)
if merged:
ResultInfo.PtrCount += merged.PtrCount
if merged.BaseType and not isinstance(merged.BaseType, t.CVoid):
ResultInfo.BaseType = merged.BaseType
if merged.ArrayPtr:
ResultInfo.ArrayPtr = merged.ArrayPtr
elif isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif VtInfo:
ResultInfo = CTypeInfo()
ResultInfo.BaseType = VtInfo.BaseType
if isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif isinstance(slice_node, ast.Name):
ResultInfo.ArrayDims.append(slice_node.id)
elif isinstance(slice_node, ast.BinOp):
try:
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
except Exception: # 回退unparse 失败时用 'N'
ResultInfo.ArrayDims.append('N')
elif isinstance(slice_node, ast.Subscript):
ResultInfo.ArrayPtr = CollectAll(slice_node)
else:
ResultInfo = CTypeInfo()
if isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif isinstance(slice_node, ast.Name):
SliceType = getattr(t, slice_node.id, None)
if SliceType == t.CPtr:
ResultInfo.PtrCount += 1
elif SliceType == t.CArrayPtr:
ResultInfo.ArrayPtr = CTypeInfo()
else:
ResultInfo.ArrayDims.append(slice_node.id)
elif isinstance(value_node, ast.Subscript):
ResultInfo = CollectAll(value_node)
if isinstance(slice_node, ast.Attribute):
SliceVtInfo = self.GetCTypeInfo(slice_node)
if SliceVtInfo and SliceVtInfo.PtrCount >= 1 and not SliceVtInfo.ArrayPtr:
ResultInfo.PtrCount += SliceVtInfo.PtrCount
if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
ResultInfo.BaseType = SliceVtInfo.BaseType
elif SliceVtInfo and SliceVtInfo.IsArrayPtr:
NewInfo = CTypeInfo()
NewInfo.ArrayPtr = ResultInfo
ResultInfo = NewInfo
elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
ResultInfo.BaseType = SliceVtInfo.BaseType
elif isinstance(slice_node, ast.Subscript):
InnerNode = CollectAll(slice_node)
if ResultInfo.ArrayPtr is None:
ResultInfo.ArrayPtr = InnerNode
else:
current = ResultInfo
while current.ArrayPtr is not None:
current = current.ArrayPtr
current.ArrayPtr = InnerNode
elif isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif isinstance(slice_node, ast.Name):
SliceType = getattr(t, slice_node.id, None)
if SliceType == t.CPtr:
ResultInfo.PtrCount += 1
elif SliceType == t.CArrayPtr:
ResultInfo.ArrayPtr = CTypeInfo()
else:
ResultInfo.ArrayDims.append(slice_node.id)
elif isinstance(slice_node, ast.BinOp):
try:
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
except Exception: # 回退unparse 失败时用 'N'
ResultInfo.ArrayDims.append('N')
elif isinstance(value_node, ast.Name):
ResultInfo = CTypeInfo()
if IsListAnnotation(node):
if not isinstance(slice_node, ast.Tuple):
ElementType = self._GetCTypeInfoInternal(slice_node)
if ElementType and isinstance(ElementType, CTypeInfo):
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid()
ResultInfo.PtrCount = ElementType.PtrCount + 1
ResultInfo.IsFuncPtr = ElementType.IsFuncPtr
ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn
ResultInfo.FuncPtrParams = ElementType.FuncPtrParams
else:
ResultInfo.BaseType = t.CVoid()
ResultInfo.PtrCount = 1
elif isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
ElementType = self._GetCTypeInfoInternal(slice_node.elts[0])
if ElementType and isinstance(ElementType, CTypeInfo):
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid()
ResultInfo.PtrCount = ElementType.PtrCount
ResultInfo.IsFuncPtr = ElementType.IsFuncPtr
ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn
ResultInfo.FuncPtrParams = ElementType.FuncPtrParams
for elt in slice_node.elts[1:]:
if isinstance(elt, ast.Constant):
ResultInfo.ArrayDims.append(str(elt.value))
elif isinstance(elt, ast.Name):
ResultInfo.ArrayDims.append(elt.id)
else:
try:
ResultInfo.ArrayDims.append(ast.unparse(elt))
except Exception: # 回退unparse 失败时用 'N'
ResultInfo.ArrayDims.append('N')
else:
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType
else:
# 检查是否为泛型类特化(如 list[str]
_is_generic_template: bool = (
hasattr(self.Trans, 'ClassHandler')
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
and value_node.id in self.Trans.ClassHandler._generic_class_templates
)
if _is_generic_template:
# 走和 _ResolveGenericSlice 同样的规范化路径_resolve_generic_slice_type
# 确保字段类型名与特化名完全一致:
# - ast.Name: 用原始名(如 'Param' → 'Param',不加 SHA1 前缀),
# 与 _resolve_generic_slice_type 的 ast.Name 分支一致
# - BinOp/Attribute: 走 _resolve_type_arg_str加 SHA1 前缀 / 'ptr' 标记)
# 避免字段类型用 'GSList[sha1.Param]' 而特化名用 'GSList[Param]' 导致
# find_struct_by_pointee 匹配到 opaque 副本,方法分派失败
type_arg_str: str
if isinstance(slice_node, ast.Tuple):
arg_parts: list[str] = []
for elt in slice_node.elts:
slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(elt)
arg_parts.append(slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(elt))
# 必须用 '][' 分隔以匹配 _mangle_generic_class_name 的格式
# class_name + '[' + ']['.join(mangled_args) + ']'
type_arg_str = ']['.join(arg_parts)
else:
slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node)
type_arg_str = slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(slice_node)
full_spec_name: str = f'{value_node.id}[{type_arg_str}]'
ResultInfo.BaseType = t.CStruct(name=full_spec_name)
ResultInfo.Name = full_spec_name
ResultInfo.IsStruct = True
ResultInfo.PtrCount = 1
# 触发泛型特化发射:确保特化的方法被发射 + struct sha1 注册
# 与局部变量 AnnAssign 路径一致;否则函数参数注解路径
# 只构建 mangled 名,方法调用分派时 class_sha1=None 导致
# "Undefined method" 错误(如 lst.__len__() 在 list[T] | t.CPtr 参数上)
# _specialize_generic_class 内部有 spec_key 去重,重复调用安全
if hasattr(self.Trans, 'ExprCallHandle') and self.Trans.ExprCallHandle is not None:
self.Trans.ExprCallHandle._ResolveGenericSlice(node)
else:
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType
if isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif isinstance(slice_node, ast.Name):
SliceType = getattr(t, slice_node.id, None)
if SliceType == t.CPtr:
ResultInfo.PtrCount += 1
elif SliceType == t.CArrayPtr:
ResultInfo.ArrayPtr = CTypeInfo()
else:
ResultInfo.ArrayDims.append(slice_node.id)
elif isinstance(slice_node, ast.BinOp):
try:
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
except Exception: # 回退unparse 失败时用 'N'
ResultInfo.ArrayDims.append('N')
elif isinstance(slice_node, ast.Subscript):
InnerNode = CollectAll(slice_node)
ResultInfo.ArrayDims.extend(InnerNode.ArrayDims)
else:
ResultInfo = CTypeInfo()
return ResultInfo
elif isinstance(node, ast.Attribute):
VtInfo = self.GetCTypeInfo(node)
result = CTypeInfo()
if VtInfo and VtInfo.IsArrayPtr:
result.ArrayPtr = CTypeInfo()
return result
elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr:
result.BaseType = t.CVoid
result.PtrCount = 1
return result
elif VtInfo and VtInfo.BaseType:
result.BaseType = VtInfo.BaseType
return result
else:
return CTypeInfo()
elif isinstance(node, ast.Name):
result = CTypeInfo()
result.BaseType = CTypeInfo.CreateFromTypeName(node.id).BaseType
return result
else:
return CTypeInfo()
return CollectAll(Node)
def _CollectAllOperandTypes(self, Node: ast.AST) -> List:
"""递归收集所有操作数的类型(用于一次性合并)"""
Types = []
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
Types.extend(self._CollectAllOperandTypes(Node.left))
Types.extend(self._CollectAllOperandTypes(Node.right))
else:
Types.append(Node)
return Types
def _GetTypeFromNode(self, Node: ast.AST) -> CTypeInfo:
"""浠?AST 鑺傜偣鑾峰彇绫诲瀷"""
if isinstance(Node, ast.Call):
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
return self.GetCTypeInfo(Node)
elif isinstance(Node.func, ast.Attribute) and CTypeHelper.GetTModuleCType(Node.func.attr) == t._CTypedef:
return self.GetCTypeInfo(Node)
elif isinstance(Node.func, ast.Attribute) and Node.func.attr == 'Bit':
if Node.args and isinstance(Node.args[0], ast.Constant):
Result = CTypeInfo()
Result.BaseType = t.CInt
Result.IsBitField = True
Result.BitWidth = Node.args[0].value
return Result
return self._MakeVoidCTypeInfo()
elif isinstance(Node, ast.Subscript):
if (isinstance(Node.value, ast.Attribute)
and isinstance(Node.value.value, ast.Name)
and IsTModule(Node.value.value.id, self.Trans.SymbolTable)
and Node.value.attr == 'Bit'):
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
Result = CTypeInfo()
Result.BaseType = t.CInt
Result.IsBitField = True
Result.BitWidth = Node.slice.value
return Result
return self.GetCTypeInfo(Node)
else:
return self.GetCTypeInfo(Node)
def MergeTypes(self, Node: ast.BinOp):
"""处理类型组合,如 t.CInt | t.CPtr ?t.CStatic | t.CInt
这是 | 运算符的类型合并处理函数
收集所有操作数,一次性合?
"""
if not isinstance(Node, ast.BinOp) or not isinstance(Node.op, ast.BitOr):
return None
AllOperands = self._CollectAllOperandTypes(Node)
AllTypes = []
for Operand in AllOperands:
TypeItem = self._GetTypeFromNode(Operand)
AllTypes.append(TypeItem)
if isinstance(Node.left, ast.Attribute):
LeftParts = []
current = Node.left
while isinstance(current, ast.Attribute):
attr_type = getattr(t, current.attr, None)
if attr_type and isinstance(attr_type, type) and issubclass(attr_type, t.CType):
LeftParts.insert(0, attr_type)
current = current.value
if isinstance(current, ast.Name):
name_type = getattr(t, current.id, None)
if name_type and isinstance(name_type, type) and issubclass(name_type, t.CType):
LeftParts.insert(0, name_type)
if LeftParts and LeftParts[-1] == t._CTypedef:
for type_item in AllTypes:
if isinstance(type_item, CTypeInfo) and type_item.IsFuncPtr:
type_item.IsTypedef = True
type_item.OriginalType = CTypeInfo()
type_item.OriginalType.IsFuncPtr = True
type_item.OriginalType.FuncPtrReturn = type_item.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
type_item.OriginalType.FuncPtrParams = list(type_item.FuncPtrParams) if type_item.FuncPtrParams else []
return type_item
Result = CTypeInfo()
if isinstance(AllTypes[-1], CTypeInfo):
Result.BaseType = AllTypes[-1].BaseType
else:
Result.BaseType = t.CInt
Result.IsTypedef = True
return Result
return self._MergeAllComponentTypes(*AllTypes)
def _MergeAllComponentTypes(self, *Types: CTypeInfo) -> CTypeInfo:
"""合并多个类型 - 直接使用 CTypeInfo 类"""
if not Types:
return CTypeInfo()
Result = CTypeInfo()
# 统计 t.CPtrCVoid + PtrCount=1的个数用于正确累加指针层数
# 因为 (AST | t.CPtr) | t.CPtr 展开后会包含多个 t.CPtr每个都需要累加
cptr_count: int = 0
for TypeItem in Types:
if TypeItem is None:
continue
if TypeItem.IsState:
Result.IsState = True
if not Result.Storage:
Result.Storage = t.CExport()
continue
if TypeItem.IsBitField:
Result.BaseType = t.CInt
Result.IsBitField = True
Result.BitWidth = TypeItem.BitWidth
return Result
if TypeItem.IsFuncPtr:
Result.BaseType = t.CVoid
Result.IsFuncPtr = True
Result.FuncPtrParams = TypeItem.FuncPtrParams
Result.FuncPtrReturn = TypeItem.FuncPtrReturn
return Result
if TypeItem.IsTypedef:
if TypeItem.BaseType and (not isinstance(TypeItem.BaseType, (t._CTypedef,)) or TypeItem.PtrCount > 0):
if Result.BaseType is None or isinstance(Result.BaseType, (t.CVoid, t._CTypedef)):
Result.BaseType = TypeItem.BaseType
Result.Name = TypeItem.Name
Result.IsTypedef = True
Result.PtrCount = max(Result.PtrCount, TypeItem.PtrCount)
if TypeItem.OriginalType:
Result.OriginalType = TypeItem.OriginalType
else:
Result.IsTypedef = True
Result.Name = TypeItem.Name
if TypeItem.OriginalType:
Result.OriginalType = TypeItem.OriginalType
continue
# 统计 t.CPtrCVoid + PtrCount=1
if TypeItem.PtrCount > 0 and TypeItem.BaseType and (TypeItem.BaseType is t.CVoid or isinstance(TypeItem.BaseType, t.CVoid)):
cptr_count += 1
# BaseType 保持不变,只计数,后续统一累加
if TypeItem.IsRenum and TypeItem.Name:
Result.IsRenum = True
Result.IsEnum = True
Result.IsStruct = True
if not Result.Name:
Result.Name = TypeItem.Name
continue
self._MergeCTypeInfoInto(Result, TypeItem)
# 对所有 t.CPtr 统一累加指针层数
# 仅对 struct 类型吸收第一个 CPtrstruct 变量默认是指针AST | t.CPtr = AST*)。
# 对于本身已是指针的类型(如 bytes=CChar*bytes | t.CPtr = i8**(不吸收)。
base_ptr_count: int = Result.PtrCount
Result.PtrCount += cptr_count
if Result.IsStruct and base_ptr_count > 0 and cptr_count > 0:
Result.PtrCount -= 1
if Result.BaseType is None:
Result.BaseType = t.CVoid
return Result
def _MergeCTypeInfoInto(self, Target: CTypeInfo, Source: CTypeInfo):
if Source.PtrCount > 0 and Source.BaseType and (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)):
# t.CPtr 的处理已提升到 _MergeAllComponentTypes 中统一计数累加,
# 此处保留仅作为兜底(从其他路径直接调用 _MergeCTypeInfoInto 时)
if Target.PtrCount < Source.PtrCount:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > 0 and Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, t.CVoid):
if Target.BaseType is None or Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid):
Target.BaseType = Source.BaseType
# 当 Target 已有 PtrCount来自之前的 t.CPtr累加而非替换
Target.PtrCount = Source.PtrCount + Target.PtrCount
elif Target.PtrCount == 0:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
if Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, (t.CVoid, t._CTypedef)):
if Target.BaseType is None:
Target.BaseType = Source.BaseType
elif (Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid)) and Target.PtrCount == 0:
Target.BaseType = Source.BaseType
elif (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)) and Target.BaseType is None:
Target.BaseType = Source.BaseType
# Struct 名称保留BinOp `list[AST | t.CPtr] | t.CPtr` 合并时,
# _HandleSubscript 已在 Source.Name 设置了特化名(如 'list[5dab8cb390496d22.ASTptr]'
# 合并后 Target.Name 必须保留此名称,否则 class_member_element_class
# 无法获取正确的特化类名 → 方法分派 fallback 到错误的类
if Source.IsStruct and Source.Name and not Target.Name:
Target.Name = Source.Name
# REnum 标志和名称保留BinOp `LLVMType | t.CPtr` 合并时不能丢失 REnum 语义)
# 同时传播 IsStruct=True让 CPtr 吸收逻辑生效REnum 在内存布局上是 struct
if Source.IsRenum and Source.Name:
Target.IsRenum = True
Target.IsEnum = True
Target.IsStruct = True
if not Target.Name:
Target.Name = Source.Name
if Source.IsTypedef and Source.Name:
if Source.BaseType and (not isinstance(Source.BaseType, (t._CTypedef,)) or Source.PtrCount > 0):
if Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)):
Target.BaseType = Source.BaseType
Target.IsTypedef = True
Target.Name = Source.Name
if Source.OriginalType:
Target.OriginalType = Source.OriginalType
elif Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)):
if Source.OriginalType:
if isinstance(Source.OriginalType, CTypeInfo) and Source.OriginalType.BaseType:
Target.BaseType = Source.OriginalType.BaseType
Target.PtrCount = max(Target.PtrCount, Source.OriginalType.PtrCount)
Target.IsTypedef = True
Target.Name = Source.Name
Target.OriginalType = Source.OriginalType
elif isinstance(Source.OriginalType, CTypeInfo):
Target.IsTypedef = True
Target.Name = Source.Name
Target.OriginalType = Source.OriginalType
else:
Target.BaseType = t.CStruct(name=Source.Name)
Target.IsStruct = True
else:
Target.BaseType = t.CStruct(name=Source.Name)
Target.IsStruct = True
if Source.ArrayPtr:
if Target.ArrayPtr is None:
Target.ArrayPtr = Source.ArrayPtr
else:
if Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
Target.ArrayPtr = Source.ArrayPtr
if Source.PtrCount > 0:
Target.ArrayDims = []
elif Source.ArrayDims:
Target.ArrayDims.extend(Source.ArrayDims)
if Source.VarConst:
Target.VarConst = True
if Source.VarVolatile:
Target.VarVolatile = True
if Source.DataConst:
Target.DataConst = True
if Source.DataVolatile:
Target.DataVolatile = True
if Source.IsFuncPtr:
Target.IsFuncPtr = True
Target.FuncPtrParams = Source.FuncPtrParams
Target.FuncPtrReturn = Source.FuncPtrReturn
if Source.Storage and not Target.Storage:
Target.Storage = Source.Storage
if Source.ByteOrder and not Target.ByteOrder:
Target.ByteOrder = Source.ByteOrder

View File

@@ -0,0 +1,54 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import llvmlite.ir as ir
class WhileHandle(BaseHandle):
def _HandleWhileLlvm(self, Node: ast.While) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if Gen._direct_values:
for var_name in list(Gen._direct_values.keys()):
OldVal: ir.Value = Gen._direct_values.pop(var_name)
if var_name not in Gen.variables or Gen.variables.get(var_name) is None:
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[var_name] = var
CondBB: ir.Block = Gen.func.append_basic_block(name="while.cond")
BodyBB: ir.Block = Gen.func.append_basic_block(name="while.body")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="while.else") if Node.orelse else None
AfterBB: ir.Block = Gen.func.append_basic_block(name="while.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(CondBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Cond: ir.Value | None = self.HandleExprLlvm(Node.test)
if Cond:
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="whilecond")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)

View File

@@ -0,0 +1,172 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class WithHandle(BaseHandle):
def _HandleWithLlvm(self, Node: ast.With) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for item in Node.items:
context_expr: ast.expr = item.context_expr
asname: str | None = None
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
if target and isinstance(target, ast.Name):
asname = target.id
ClassName: str | None = None
if isinstance(context_expr, ast.Call):
if isinstance(context_expr.func, ast.Name):
ClassName = context_expr.func.id
elif isinstance(context_expr.func, ast.Attribute):
ClassName = context_expr.func.attr
if ClassName and ClassName not in Gen.structs:
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
if SymInfo:
if SymInfo.IsStruct or SymInfo.IsRenum:
pass
else:
ClassName = None
else:
ClassName = None
elif isinstance(context_expr, ast.Name):
VarName: str = context_expr.id
if VarName in Gen.var_struct_class:
ClassName = Gen.var_struct_class[VarName]
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
if not ctx_val:
continue
original_ctx_val: ir.Value = ctx_val
if ClassName and isinstance(ctx_val.type, ir.PointerType):
pointee: ir.Type = ctx_val.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
ClassName = CN
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
Gen._store(ctx_val, ctx_alloca)
Gen._UnregisterTempPtr(ctx_val)
if ClassName:
Gen.var_struct_class['__with_ctx'] = ClassName
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
enter_result: ir.Value | None = None
if ClassName:
EnterFuncName: str = f'{ClassName}.__enter__'
if EnterFuncName in Gen.functions:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
enter_call: ir.CallInstr = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_Loaded], name="call_enter")
enter_result = enter_call
if isinstance(enter_call.type, ir.PointerType):
pointee: ir.Type = enter_call.type.pointee
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
enter_result = Gen._load(enter_call, name="enter_deref")
elif self._is_char_pointer(enter_call) and StructPtrType:
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
if asname and enter_result:
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
Gen.var_struct_class[asname] = CN
Gen._var_to_heap_ptr[asname] = enter_result
Gen._register_local_heap_ptr(enter_result, VarName=asname)
if asname in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[asname]
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
Gen._store(OldVal, var)
Gen.variables[asname] = var
del Gen._reg_values[asname]
if asname in Gen.variables and Gen.variables[asname] is not None:
VarPtr: ir.Value = Gen.variables[asname]
if VarPtr.type.pointee == enter_result.type:
Gen._store(enter_result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
Gen._store(enter_result, NewVar)
Gen.variables[asname] = NewVar
else:
Gen._reg_values[asname] = enter_result
Gen.variables[asname] = None
# 如果类有 __provides__自动生成 push 代码
if ClassName and ClassName in Gen.class_provides:
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
new_fields: int = len(Gen.class_provides[ClassName])
if current_depth + new_fields > 32:
raise SyntaxError(
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
f"current depth {current_depth} + new {new_fields} fields > max 32. "
f"Class '{ClassName}' provides too many fields or with nesting too deep."
)
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
ctx_i8: ir.Value = ctx_Loaded
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
for field_name in Gen.class_provides[ClassName]:
field_str: ir.Value = Gen._create_string_global(field_name)
push_func = Gen.functions.get('_push_provider')
if push_func:
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
self.Trans.VarScopes.append({})
if asname:
self.Trans.VarScopes[-1][asname] = True
self.HandleBodyLlvm(Node.body)
if self.Trans.VarScopes:
self.Trans.VarScopes.pop()
# 如果类有 __provides__自动生成 pop 代码
if ClassName and ClassName in Gen.class_provides:
for _ in Gen.class_provides[ClassName]:
pop_func = Gen.functions.get('_pop_provider')
if pop_func:
Gen.builder.call(pop_func, [], name="call_pop_provider")
# 编译期弹栈
if Gen._with_provides_stack:
Gen._with_provides_stack.pop()
if ClassName:
ExitFuncName: str = f'{ClassName}.__exit__'
if ExitFuncName in Gen.functions:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
Gen.builder.call(Gen.functions[ExitFuncName], [ctx_Loaded], name="call_exit")
Gen._unregister_local_heap_ptr(original_ctx_val)
if ctx_val is not original_ctx_val:
Gen._unregister_local_heap_ptr(ctx_val)
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
if '__with_ctx' in Gen._var_to_heap_ptr:
del Gen._var_to_heap_ptr['__with_ctx']
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
Gen.builder.position_at_start(with_free_bb)
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen.builder.branch(with_skip_bb)
Gen.builder.position_at_start(with_skip_bb)
Gen._unregister_local_heap_ptr(enter_result)
Gen._unregister_local_heap_ptr(original_ctx_val)
elif isinstance(ctx_val.type, ir.PointerType):
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen._unregister_local_heap_ptr(original_ctx_val)

View File

@@ -0,0 +1,32 @@
"""
Handles 包 - 使用 Mixin 模式组织 Handle 函数
"""
from .HandlesIf import IfHandle
from .HandlesFor import ForHandle
from .HandlesWhile import WhileHandle
from .HandlesAnnAssign import AnnAssignHandle
from .HandlesTypeMerge import HandlesTypeMerge
from .HandlesExpr import ExprHandle
from .HandlesExprUtils import ExprUtils
from .HandlesExprOps import ExprOpsHandle
from .HandlesExprAttr import ExprAttrHandle
from .HandlesExprBuiltin import ExprBuiltinHandle
from .HandlesExprAsm import ExprAsmHandle
from .HandlesExprFormat import ExprFormatHandle
from .HandlesExprLambda import ExprLambdaHandle
from .HandlesExprCall import ExprCallHandle
from .HandlesSpecialCall import CSpecialCallHandle, TSpecialCallHandle
from .HandlesBody import BodyHandle
from .HandlesReturn import ReturnHandle
from .HandlesAssign import AssignHandle
from .HandlesAugAssign import AugAssignHandle
from .HandlesDelete import DeleteHandle
from .HandlesWith import WithHandle
from .HandlesTry import TryHandle
from .HandlesAssert import AssertHandle
from .HandlesRaise import RaiseHandle
from .HandlesMatch import MatchHandle
from .HandlesClassDef import ClassHandle
from .HandlesFunctions import FunctionHandle
from .HandlesImports import ImportHandle