This commit is contained in:
2026-06-16 16:09:42 +08:00
commit bffb0cb6b7
644 changed files with 86620 additions and 0 deletions

View File

@@ -0,0 +1,471 @@
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
from lib.includes import t
import ast
import llvmlite.ir as ir
class AnnAssignHandle(BaseHandle):
def _GetCTypeInfo(self, annotation):
return self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
def _StoreOrStrCopy(self, VarName, VarPtr, Value):
Gen = self.Trans.LlvmGen
DestPtr = Gen._load(VarPtr, name=VarName)
if isinstance(DestPtr.type, ir.PointerType) and isinstance(DestPtr.type.pointee, ir.IntType) and DestPtr.type.pointee.width == 8:
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.IntType) and Value.type.pointee.width == 8:
if 'llvm.memcpy' not in Gen.functions:
memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)])
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
if isinstance(DestPtr.type.pointee, ir.IntType) and not isinstance(DestPtr.type.pointee, ir.IntType(8)):
DestPtr = Gen.builder.bitcast(DestPtr, ir.PointerType(ir.IntType(8)), name=f"strcpy_dst_cast_{VarName}")
if isinstance(Value.type.pointee, ir.IntType) and not isinstance(Value.type.pointee, ir.IntType(8)):
Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"strcpy_src_cast_{VarName}")
size = ir.Constant(ir.IntType(64), 8)
align = ir.Constant(ir.IntType(32), 1)
isvolatile = ir.Constant(ir.IntType(1), 0)
Gen.builder.call(Gen.functions['llvm.memcpy'], [DestPtr, Value, size, align, isvolatile], name=f"strcpy_call_{VarName}")
return
try:
CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
except Exception: # 回退bitcast 失败时 alloca 新变量
NewVar = Gen._alloca_entry(Value.type, name=VarName)
Gen._store(Value, NewVar)
Gen.variables[VarName] = NewVar
def _HandleAttributeStoreLlvm(self, Target, Value):
Gen = self.Trans.LlvmGen
AttrName = Target.attr
if isinstance(Target.value, ast.Name) and Target.value.id == 'self':
ClassName = self._CurrentCpythonObjectClass
if not ClassName:
self_var = Gen.variables.get('self')
if self_var:
var_type = self_var.type
if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType):
var_type = var_type.pointee
if isinstance(var_type, ir.PointerType):
pointee = var_type.pointee
for cn, st in Gen.structs.items():
if st == pointee:
ClassName = cn
break
if ClassName and ClassName in Gen.structs:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
offset = Gen._get_member_offset(AttrName, ClassName)
MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
elif isinstance(Target.value, ast.Name):
VarName = Target.value.id
ClassName = Gen.var_struct_class.get(VarName)
if not ClassName:
for CN in Gen.structs:
if VarName == CN.lower() or VarName.startswith(CN):
ClassName = CN
break
if not ClassName and VarName in Gen.variables:
VarPtr = Gen.variables[VarName]
if isinstance(VarPtr.type, ir.PointerType):
pointee = VarPtr.type.pointee
if isinstance(pointee, ir.PointerType):
pointee = pointee.pointee
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
IsUnion = False
if ClassName and ClassName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[ClassName]
if hasattr(TypeInfo, 'IsUnion') and TypeInfo.IsUnion:
IsUnion = True
if ClassName and ClassName in Gen.structs:
ObjVal = 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 = f"{ClassName}_{AttrName}"
if NestedStructName in Gen.structs:
NestedStructType = Gen.structs[NestedStructName]
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
offset = Gen._get_member_offset(AttrName, NestedStructName)
if offset is not None and offset < len(NestedStructType.elements):
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
return
offset = Gen._get_member_offset(AttrName, ClassName)
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
elif isinstance(Target.value, ast.Attribute):
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
pointee = ObjVal.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
offset = Gen._get_member_offset(AttrName, CN)
MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
break
def _StoreWithCoerce(self, Value, Ptr):
Gen = self.Trans.LlvmGen
if isinstance(Ptr.type, ir.PointerType):
TargetType = Ptr.type.pointee
if Value.type != TargetType:
if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType):
if TargetType.width < Value.type.width:
Value = Gen.builder.trunc(Value, TargetType, name="trunc")
else:
Value = Gen.builder.zext(Value, TargetType, name="zext")
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast")
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType):
Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr")
elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType):
Value = Gen.builder.ptrtoint(Value, TargetType, name="ptr_to_int")
Gen._store(Value, Ptr)
def _HandleAnnAssignLlvm(self, Node):
Gen = self.Trans.LlvmGen
self.Trans._current_assign_node = Node
try:
self._HandleAnnAssignLlvmInner(Node)
finally:
self.Trans._current_assign_node = None
def _HandleAnnAssignLlvmInner(self, Node):
Gen = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName = Node.target.id
TypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
IsPtr = TypeInfo.IsPtr
if TypeInfo.IsDefine:
if Node.value and isinstance(Node.value, ast.Constant):
if not hasattr(Gen, '_define_constants'):
Gen._define_constants = {}
Gen._define_constants[VarName] = Node.value.value
info = CTypeInfo()
info.IsDefine = True
info.DefineValue = Node.value.value
self.Trans.SymbolTable[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
if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list':
slice_node = Node.annotation.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
elem_type_node = slice_node.elts[0]
count_node = slice_node.elts[1]
ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
ElemType = Gen.structs[elem_type_node.id]
else:
if isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str':
ElemType = ir.PointerType(ir.IntType(8))
else:
ElemType = Gen._ctype_to_llvm(ElemTypeInfo)
if isinstance(ElemType, ir.VoidType):
ElemType = ir.IntType(32)
ArrayCount = 1
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
ArrayCount = count_node.value
else:
eval_count = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable)
if eval_count is not None and isinstance(eval_count, int) and eval_count > 0:
ArrayCount = eval_count
elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
if Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
ArrayCount = len(Node.value.value) + 1
VarType = ir.ArrayType(ElemType, ArrayCount)
var = Gen._alloca_entry(VarType, name=VarName)
Gen.variables[VarName] = var
Gen._record_var_signedness(VarName, False)
if Node.value and isinstance(Node.value, ast.List):
InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen)
if InitConstants:
try:
InitVal = ir.Constant(VarType, InitConstants)
Gen.builder.store(InitVal, var)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
str_val = Node.value.value + '\x00'
str_bytes = bytearray(str_val, 'utf-8')
if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count:
str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes)))
try:
InitVal = 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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if self.Trans.VarScopes:
self.Trans.VarScopes[-1][VarName] = ElemTypeInfo
return
if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp):
def _find_struct_name_in_annot(node):
if isinstance(node, ast.Name) and node.id in Gen.structs:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs:
return node.value
if isinstance(node, ast.Attribute) and node.attr in Gen.structs:
return node.attr
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result = _find_struct_name_in_annot(node.left)
if result:
return result
return _find_struct_name_in_annot(node.right)
return None
found = _find_struct_name_in_annot(Node.annotation)
if found:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CStruct(name=found)
TypeInfo.PtrCount = 1
IsPtr = True
elif isinstance(Node.annotation.left, ast.Attribute):
AttrTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left)
if AttrTypeInfo and AttrTypeInfo.BaseType:
TypeInfo = AttrTypeInfo
TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1)
IsPtr = True
VarType = Gen._ctype_to_llvm(TypeInfo)
if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name:
stripped = TypeInfo.Name
if stripped in Gen.class_vtable and stripped in Gen.structs:
VarType = ir.PointerType(Gen.structs[stripped])
IsPtr = True
if isinstance(VarType, ir.IdentifiedStructType):
struct_name = getattr(VarType, 'name', '')
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 = TypeInfo.IsUInt
if VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
if isinstance(OldVal.type, ir.PointerType):
var = Gen._alloca_entry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if Node.value:
InitValue = self.HandleExprLlvm(Node.value, VarType=VarType)
if InitValue:
self._StoreOrStrCopy(VarName, var, InitValue)
Gen._record_var_signedness(VarName, IsUnsigned)
return
del Gen._reg_values[VarName]
InitValue = None
if Node.value:
InitValue = self.HandleExprLlvm(Node.value, VarType=VarType)
if VarName in Gen._reg_values:
del Gen._reg_values[VarName]
if VarName in Gen.variables and Gen.variables[VarName] is not None:
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee = InitValue.type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
struct_name = getattr(pointee, 'name', '')
is_vtable_class = False
for cls_name in Gen.class_vtable:
if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name:
is_vtable_class = True
break
if is_vtable_class:
var = Gen._alloca_entry(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 = Gen.variables[VarName]
if isinstance(VarPtr.type, ir.PointerType):
TargetType = 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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
Gen._record_var_signedness(VarName, IsUnsigned)
return
if VarName in Gen.global_vars:
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
if InitValue:
Gen._store(InitValue, GVar)
Gen.variables[VarName] = GVar
Gen._record_var_signedness(VarName, IsUnsigned)
return
var = Gen._alloca_entry(VarType, name=VarName)
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee = InitValue.type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
struct_name = getattr(pointee, 'name', '')
is_vtable_class = 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._alloca_entry(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._alloca_entry(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}")
Gen._store(InitValue, var)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
Gen.variables[VarName] = var
Gen._record_var_signedness(VarName, IsUnsigned)
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
def _find_struct_in_binop(node):
if isinstance(node, ast.Name) and node.id in Gen.structs:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs:
return node.value
if isinstance(node, ast.Attribute) and node.attr in Gen.structs:
return node.attr
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result = _find_struct_in_binop(node.left)
if result:
return result
return _find_struct_in_binop(node.right)
return None
found_struct = _find_struct_in_binop(Node.annotation)
if found_struct:
Gen.var_struct_class[VarName] = found_struct
Gen.global_struct_class[VarName] = found_struct
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee = InitValue.type.pointee
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()
DefaultInfo.BaseType = t.CInt
self.Trans.VarScopes[-1][VarName] = DefaultInfo
elif isinstance(Node.target, ast.Attribute):
if isinstance(Node.target.value, ast.Name) and Node.target.value.id == 'self':
if Node.value:
AttrVarType = None
try:
if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list':
slice_node = Node.annotation.slice
if isinstance(slice_node, ast.Name):
AttrVarType = f'list[{slice_node.id}]'
elif isinstance(slice_node, ast.Tuple):
elts = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts)
AttrVarType = f'list[{elts}]'
elif isinstance(slice_node, ast.Attribute):
AttrVarType = f'list[{ast.dump(slice_node)}]'
if AttrVarType is None:
AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if AttrTypeInfo:
AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo)
except Exception as e:
pass
Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
if Value:
self._HandleAttributeStoreLlvm(Node.target, Value)
AttrName = Node.target.attr
len_name = f'{AttrName}__len'
ClassName = self._CurrentCpythonObjectClass
if not ClassName:
self_var = Gen.variables.get('self')
if self_var:
var_type = self_var.type
if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType):
var_type = var_type.pointee
if isinstance(var_type, ir.PointerType):
pointee = var_type.pointee
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 = None
if isinstance(Node.value, ast.List):
list_len = ir.Constant(ir.IntType(64), len(Node.value.elts))
if list_len is not None:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
offset = Gen._get_member_offset(len_name, ClassName)
LenPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name)
Gen._store(list_len, LenPtr)
break

View File

@@ -0,0 +1,57 @@
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):
Gen = self.Trans.LlvmGen
cond_val = 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(cond_val.type, 0)
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
AssertFailBB = Gen.func.append_basic_block(name="assert.fail")
AssertOkBB = Gen.func.append_basic_block(name="assert.ok")
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
Gen.builder.position_at_start(AssertFailBB)
exc_code = 9
exc_msg = 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 = 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, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1]
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.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
Gen.builder.branch(ExceptBB)
else:
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
if exc_msg:
fmt = Gen.emit_constant("AssertionError: %s\n", 'string')
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
else:
fmt = Gen.emit_constant("AssertionError\n", 'string')
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
exit_func = 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,212 @@
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 AugAssignHandle(BaseHandle):
_AUGOP_MAP = {
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
}
_AUGOP_FALLBACK = {
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, OldVal, Value):
"""判断增量赋值操作是否应使用无符号指令"""
Gen = 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):
Gen = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName = Node.target.id
if VarName in Gen.var_const_flags:
src_info = Gen._get_node_info()
print(f"[错误] 不能对 const 变量 '{VarName}' 增量赋值{src_info}")
import sys
sys.exit(1)
ClassName = Gen.var_struct_class.get(VarName)
iop_name = self._AUGOP_MAP.get(type(Node.op))
if ClassName and iop_name:
iFuncName = f'{ClassName}.{iop_name}'
FuncName = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
if iFuncName in Gen.functions or FuncName in Gen.functions:
OldVal = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
Value = self.HandleExprLlvm(Node.value)
if OldVal and Value:
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 = 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 = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
else:
NewVar = Gen._alloca_entry(result.type, name=VarName)
Gen._store(result, NewVar)
Gen.variables[VarName] = NewVar
else:
Gen._reg_values[VarName] = result
Gen.variables[VarName] = None
return
Value = self.HandleExprLlvm(Node.value)
if not Value:
return
is_unsigned = self._is_aug_unsigned(Node, None, Value)
if isinstance(Node.target, ast.Name):
VarName = Node.target.id
Op = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
OldVal = Gen._load(GVar, name=VarName)
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, GVar)
return
if VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
saved_block = Gen.builder.block
entry_block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var = 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 = Gen._direct_values.pop(VarName)
saved_block = Gen.builder.block
entry_block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var = 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 = Gen._load(Gen.variables[VarName], name=VarName)
store_ptr = 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")
if Op == '-' or Op == '+':
if Op == '-':
NegValue = 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 = OldVal
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
orig_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")
if Op == '-':
NegValue = 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 = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(store_ptr.type, ir.PointerType):
TargetType = store_ptr.type.pointee
if NewVal.type != TargetType:
Coerced = Gen._coerce_value(NewVal, TargetType)
if Coerced is not None:
NewVal = Coerced
Gen._store(NewVal, store_ptr)
elif VarName == 'pos':
var = Gen._alloca_entry(Value.type, name=VarName)
Gen.variables[VarName] = var
OldVal = Gen._load(var, name=VarName)
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, var)
elif isinstance(Node.target, ast.Attribute):
AttrName = Node.target.attr
OldVal = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
if OldVal:
def _deref_if_ptr(val):
if isinstance(val.type, ir.PointerType):
pointee = 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 = 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 = 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 = Node.target
ElemPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
if ElemPtr:
if isinstance(ElemPtr.type, ir.PointerType):
OldVal = Gen._load(ElemPtr, name="old_subscript_val")
Op = 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")
if Op == '-':
NegValue = 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 = 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)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
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
class BodyHandle(BaseHandle):
def __init__(self, translator: "Translator"):
super().__init__(translator)
def HandleBodyLlvm(self, Body):
Gen = 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 = getattr(Node, 'lineno', 0)
source_line = Gen._get_source_line(lineno)
src_file = getattr(Gen, '_current_source_file', '')
src_path = src_file if src_file else 'unknown'
line_info = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self.Trans._error_stack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._emit_temp_frees()
def HandleExprLlvm(self, Node, VarType=None):
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)

View File

@@ -0,0 +1,965 @@
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
from lib.core.SymbolNode import SymbolNode
from lib.includes import t
import ast
import llvmlite.ir as ir
class ClassHandle(BaseHandle):
def _is_exception_class(self, Node):
if not Node.bases:
return False
for base in Node.bases:
if hasattr(base, 'id'):
if base.id == 'Exception':
return True
if base.id in self.Trans.exception_registry:
return True
elif hasattr(base, 'attr'):
if base.attr == 'Exception':
return True
if base.attr in self.Trans.exception_registry:
return True
return False
def _get_exception_parent(self, Node):
if not Node.bases:
return None
for base in Node.bases:
if hasattr(base, 'id'):
if base.id != 'Exception' and base.id in self.Trans.exception_registry:
return base.id
elif hasattr(base, 'attr'):
if base.attr != 'Exception' and base.attr in self.Trans.exception_registry:
return base.attr
return None
def _RegisterExceptionClass(self, Node):
ClassName = Node.name
if ClassName in self.Trans.exception_registry:
return
code = self.Trans._next_exception_code
self.Trans._next_exception_code += 1
self.Trans.exception_registry[ClassName] = code
parent = self._get_exception_parent(Node)
if parent:
self.Trans.exception_parents[ClassName] = parent
ExcTypeInfo = CTypeInfo()
ExcTypeInfo.Name = ClassName
ExcTypeInfo.IsExceptionClass = True
ExcTypeInfo.value = code
self.Trans.SymbolTable[ClassName] = ExcTypeInfo
def _is_generic_class(self, Node):
if hasattr(Node, 'type_params') and Node.type_params:
return True
return False
def _mangle_generic_class_name(self, class_name, type_args):
from lib.includes.t import CTypeRegistry
mangled_args = []
for ta in type_args:
llvm_str = CTypeRegistry.NameToLLVM(ta)
if llvm_str:
if llvm_str in ('float', 'double', 'half', 'fp128'):
mangled = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size)
else:
mangled = llvm_str
else:
mangled = ta
mangled_args.append(mangled)
return class_name + '[' + ']['.join(mangled_args) + ']'
def _specialize_generic_class(self, ClassName, type_args, Gen, type_names=None):
if not hasattr(self, '_generic_class_templates') or ClassName not in self._generic_class_templates:
return None
template = self._generic_class_templates[ClassName]
Node = template['node']
type_param_names = template['type_params']
if len(type_args) != len(type_param_names):
return None
spec_key = ClassName + '<' + ','.join(type_args) + '>'
if not hasattr(self, '_generic_class_specializations'):
self._generic_class_specializations = {}
if spec_key in self._generic_class_specializations:
return self._generic_class_specializations[spec_key]
spec_name = self._mangle_generic_class_name(ClassName, type_args)
type_map = {}
for i, tp_name in enumerate(type_param_names):
if type_names and i < len(type_names):
type_map[tp_name] = type_names[i]
else:
type_map[tp_name] = type_args[i]
if type_names:
if not hasattr(self.Trans, '_t_c_imported_names'):
self.Trans._t_c_imported_names = {}
for tn in type_names:
if tn not in self.Trans._t_c_imported_names:
self.Trans._t_c_imported_names[tn] = ('t', tn)
import copy
SpecNode = copy.deepcopy(Node)
SpecNode.type_params = []
SpecNode.name = spec_name
for item in SpecNode.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
if item.annotation:
item.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(item.annotation, type_map)
elif isinstance(item, ast.FunctionDef):
for arg in item.args.args:
if arg.annotation:
arg.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(arg.annotation, type_map)
if item.returns:
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map)
self.Trans.FunctionHandler._apply_type_map_to_body(item.body, type_map)
saved_builder = Gen.builder
saved_func = Gen.func
saved_variables = dict(Gen.variables) if Gen.variables else {}
saved_direct_values = dict(Gen._direct_values) if Gen._direct_values else {}
saved_var_type_info = dict(Gen.var_type_info) if Gen.var_type_info else {}
saved_var_signedness = dict(Gen.var_signedness) if Gen.var_signedness else {}
saved_global_vars = set(Gen.global_vars) if Gen.global_vars else set()
saved_var_scopes = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else []
saved_block = None
if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated:
saved_block = Gen.builder.block
self._EmitClassLlvm(SpecNode, Gen)
Gen.builder = saved_builder
if saved_block is not None and Gen.builder is not None:
Gen.builder.position_at_end(saved_block)
Gen.func = saved_func
Gen.variables = saved_variables
Gen._direct_values = saved_direct_values
Gen.var_type_info = saved_var_type_info
Gen.var_signedness = saved_var_signedness
Gen.global_vars = saved_global_vars
self.Trans.VarScopes = saved_var_scopes
self._generic_class_specializations[spec_key] = spec_name
if not hasattr(self.Trans, '_generic_class_specializations'):
self.Trans._generic_class_specializations = {}
self.Trans._generic_class_specializations[spec_key] = spec_name
if hasattr(self.Trans, '_module_sha1') and self.Trans._module_sha1:
Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1
return spec_name
def _EmitClassLlvm(self, Node, Gen):
ClassName = Node.name
if self._is_generic_class(Node):
if not hasattr(self, '_generic_class_templates'):
self._generic_class_templates = {}
type_params = [tp.name for tp in Node.type_params]
self._generic_class_templates[ClassName] = {
'node': Node,
'type_params': type_params,
}
return
if self._is_exception_class(Node):
self._RegisterExceptionClass(Node)
return
IsCenum = False
IsCunion = False
IsRenum = False
if Node.bases:
for base in Node.bases:
if hasattr(base, 'attr'):
if base.attr == 'CEnum' or base.attr == 'Enum':
IsCenum = True
break
elif base.attr == 'CUnion':
IsCunion = True
elif base.attr == 'REnum':
IsRenum = True
elif hasattr(base, 'id'):
if base.id == 'CEnum' or base.id == 'Enum':
IsCenum = True
break
elif base.id == 'CUnion':
IsCunion = True
elif base.id == 'REnum':
IsRenum = True
if IsCenum:
self._RegisterEnumMembers(Node)
return
if IsCunion:
self._EmitUnionLlvm(Node, Gen)
return
if IsRenum:
self._EmitREnumLlvm(Node, Gen)
return
IsCpythonObject = False
IsCVTable = False
if hasattr(Node, 'decorator_list') and Node.decorator_list:
for decorator in Node.decorator_list:
if isinstance(decorator, ast.Attribute):
if hasattr(decorator.value, 'id') and decorator.value.id == 't':
if decorator.attr == 'Object':
IsCpythonObject = True
elif decorator.attr == 'CVTable':
IsCVTable = True
elif isinstance(decorator, ast.Name):
if decorator.id == 'Object':
IsCpythonObject = True
elif decorator.id == 'CVTable':
IsCVTable = True
elif isinstance(decorator, ast.Call):
# 检测 @c.Attribute(t.attr.packed)
if isinstance(decorator.func, ast.Attribute):
if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Attribute):
if isinstance(arg.value, ast.Attribute):
if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed':
Gen.class_packed.add(ClassName)
HasMethods = any(isinstance(item, ast.FunctionDef) for item in Node.body)
if HasMethods and not IsCpythonObject:
IsCpythonObject = True
HasParentClass = False
ParentClassName = None
if Node.bases:
for base in Node.bases:
base_name = None
if hasattr(base, 'id'):
base_name = base.id
elif hasattr(base, 'attr'):
base_name = base.attr
if base_name and base_name not in ('CEnum', 'Enum', 'CUnion', 'CStruct', 'Object', 'CVTable', 'Exception'):
if base_name in Gen.class_members or base_name in Gen.structs:
HasParentClass = True
ParentClassName = base_name
break
if HasParentClass and not IsCVTable:
IsCVTable = True
if IsCVTable:
Gen.class_vtable.add(ClassName)
if ParentClassName:
Gen.class_vtable.add(ParentClassName)
if ClassName not in Gen.class_methods:
Gen.class_methods[ClassName] = []
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明
Gen.class_members[ClassName] = []
Gen.class_member_defaults[ClassName] = {}
Gen.class_member_signeds[ClassName] = {}
Gen.class_member_bitfields[ClassName] = {}
Gen.class_member_byteorders[ClassName] = {}
Gen.class_member_bitoffsets[ClassName] = {}
ParentClass = None
if Node.bases:
for base in Node.bases:
if hasattr(base, 'id'):
base_name = base.id
if base_name in Gen.class_members and base_name != ClassName:
ParentClass = base_name
break
elif hasattr(base, 'attr'):
base_name = base.attr
if base_name in Gen.class_members and base_name != ClassName:
ParentClass = base_name
break
if ParentClass:
Gen.class_parent[ClassName] = ParentClass
if ParentClass:
parent_members = list(Gen.class_members[ParentClass])
parent_defaults = dict(Gen.class_member_defaults.get(ParentClass, {}))
existing_names = {m[0] for m in Gen.class_members[ClassName]}
inherited = []
for pm_name, pm_type in parent_members:
if pm_name not in existing_names:
inherited.append((pm_name, pm_type))
if pm_name in parent_defaults:
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
if ParentClass in Gen.class_methods:
parent_methods = list(Gen.class_methods[ParentClass])
for pm in parent_methods:
method_name = pm.split('.')[-1] if '.' in pm else pm
child_method = f"{ClassName}.{method_name}"
if child_method not in Gen.class_methods[ClassName]:
Gen.class_methods[ClassName].append(child_method)
Gen.register_method(ClassName, child_method)
for item in Node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
VarName = item.target.id
try:
TypeInfo = CTypeInfo.FromNode(item.annotation, self.Trans.SymbolTable)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
IsPtr = TypeInfo.IsPtr
MemberType = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, ir.VoidType):
MemberType = ir.PointerType(ir.IntType(8))
Gen.class_members[ClassName].append((VarName, MemberType))
if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
def _find_struct_in_annot(node):
if isinstance(node, ast.Name) and node.id in Gen.structs:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs:
return node.value
if isinstance(node, ast.Attribute) and node.attr in Gen.structs:
return node.attr
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result = _find_struct_in_annot(node.left)
if result:
return result
return _find_struct_in_annot(node.right)
return None
element_class = _find_struct_in_annot(item.annotation)
if element_class:
if ClassName not in Gen.class_member_element_class:
Gen.class_member_element_class[ClassName] = {}
Gen.class_member_element_class[ClassName][VarName] = element_class
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
Gen.class_member_signeds[ClassName][VarName] = TypeInfo.BaseType.IsSigned
else:
Gen.class_member_signeds[ClassName][VarName] = None
if TypeInfo and TypeInfo.IsBitField:
Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth
else:
Gen.class_member_bitfields[ClassName][VarName] = 0
if TypeInfo and TypeInfo.ByteOrder:
Gen.class_member_byteorders[ClassName][VarName] = TypeInfo.ByteOrder
else:
Gen.class_member_byteorders[ClassName][VarName] = ""
if item.value:
const = self._BuildScalarConstant(item.value, MemberType)
if const:
Gen.class_member_defaults[ClassName][VarName] = const
except Exception: # 回退:类成员类型解析失败时使用默认 i32
Gen.class_members[ClassName].append((VarName, ir.IntType(32)))
Gen.class_member_signeds[ClassName][VarName] = None
Gen.class_member_bitfields[ClassName][VarName] = 0
existing_members = {m[0] for m in Gen.class_members[ClassName]}
for item in Node.body:
if isinstance(item, ast.FunctionDef):
self._current_method_args = {}
for arg in item.args.args:
if arg.arg != 'self' and arg.annotation:
self._current_method_args[arg.arg] = arg.annotation
self._scan_method_body_for_self_members(item.body, ClassName, existing_members, Gen)
self._current_method_args = {}
for item in Node.body:
if isinstance(item, ast.FunctionDef):
MethodName = item.name
FullMethodName = f"{ClassName}.{MethodName}"
if FullMethodName not in Gen.class_methods[ClassName]:
Gen.class_methods[ClassName].append(FullMethodName)
Gen.register_method(ClassName, FullMethodName)
if IsCVTable:
Gen.class_vtable.add(ClassName)
Gen._generate_structs()
Gen._create_Vtable_globals()
if (IsCpythonObject or IsCVTable) and ClassName in Gen.structs:
self._EmitNewFunctionLlvm(ClassName, Gen, IsCVTable=IsCVTable, IsCpythonObject=IsCpythonObject)
for item in Node.body:
if isinstance(item, ast.FunctionDef):
self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(item, Gen, ClassName=ClassName)
for item in Node.body:
if isinstance(item, ast.FunctionDef):
self.Trans.FunctionHandler._EmitFunctionLlvm(item, Gen, ClassName=ClassName)
if IsCVTable and ClassName in Gen.Vtables:
self._fill_vtable_with_methods(ClassName, Gen)
# Generate wrapper functions for inherited methods that are not overridden
if ParentClass:
self._generate_inherited_method_wrappers(ClassName, Gen)
def _generate_inherited_method_wrappers(self, ClassName, Gen):
"""为子类继承但未覆写的方法生成包装函数,使跨模块调用能正确链接。
例如 Label 继承 Widget.place生成 Label.place 函数,
内部将 self 从 Label* bitcast 为 Widget*,然后调用 Widget.place。
"""
methods = Gen.class_methods.get(ClassName, [])
if not methods:
return
if ClassName not in Gen.structs:
return
for method_name in methods:
method_short = method_name.split('.')[-1] if '.' in method_name else method_name
child_full = f"{ClassName}.{method_short}"
# 如果子类已经有该方法的实现,跳过
if Gen._find_function(child_full):
continue
# 沿继承链查找父类实现
parent_func = None
parent_class = None
p = Gen.class_parent.get(ClassName)
while p:
parent_full = f"{p}.{method_short}"
parent_func = Gen._find_function(parent_full)
if parent_func:
parent_class = p
break
p = Gen.class_parent.get(p)
if not parent_func or not parent_class:
continue
# 父类和子类都需要有 struct 定义
if parent_class not in Gen.structs:
continue
# 构造子类包装函数签名:与父类函数相同,但 self 参数类型为子类指针
parent_ftype = parent_func.function_type
parent_ret_type = parent_ftype.return_type
parent_param_types = list(parent_ftype.args)
is_vararg = parent_ftype.var_arg
# 判断父类方法是否是静态方法:
# 如果第一个参数类型是父类指针,说明是实例方法;否则是静态方法
parent_struct_ptr_type = ir.PointerType(Gen.structs[parent_class]) if parent_class in Gen.structs else None
is_static = True
if parent_param_types and parent_struct_ptr_type:
first_param = parent_param_types[0]
# 检查第一个参数是否是父类指针(或可以 bitcast 为父类指针的指针类型)
if isinstance(first_param, ir.PointerType):
if isinstance(first_param.pointee, ir.IdentifiedStructType):
if first_param.pointee.name == Gen.structs[parent_class].name:
is_static = False
elif first_param == ir.IntType(8):
# i8* 可能是前向声明时的 self 类型,视为实例方法
is_static = False
if is_static:
# 静态方法:签名与父类完全一致,不需要 self 参数
child_param_types = list(parent_param_types)
child_struct_ptr = None
else:
# 实例方法替换第一个参数self的类型为子类指针
child_struct_ptr = ir.PointerType(Gen.structs[ClassName])
if parent_param_types:
child_param_types = [child_struct_ptr] + parent_param_types[1:]
else:
child_param_types = [child_struct_ptr]
child_func_type = ir.FunctionType(parent_ret_type, child_param_types, var_arg=is_vararg)
child_mangled = Gen._mangle_func_name(child_full)
child_func = Gen._get_or_declare_function(child_mangled, child_func_type)
Gen.functions[child_full] = child_func
# 生成函数体
entry_block = child_func.append_basic_block(name="entry")
saved_builder = Gen.builder
saved_func = Gen.func
Gen.builder = ir.IRBuilder(entry_block)
Gen.func = child_func
# 准备参数
call_args = []
if is_static:
# 静态方法:参数直接传递,不做 bitcast
for arg in child_func.args:
call_args.append(arg)
else:
# 实例方法bitcast self其余参数直接传递
for i, arg in enumerate(child_func.args):
if i == 0 and parent_param_types:
actual_self_type = parent_param_types[0]
casted_self = Gen.builder.bitcast(arg, actual_self_type, name="self_cast")
call_args.append(casted_self)
else:
call_args.append(arg)
result = Gen.builder.call(parent_func, call_args, name="inherited_call")
if isinstance(parent_ret_type, ir.VoidType):
Gen.builder.ret_void()
else:
Gen.builder.ret(result)
Gen.builder = saved_builder
Gen.func = saved_func
def _fill_vtable_with_methods(self, ClassName, Gen):
methods = Gen.class_methods.get(ClassName, [])
if not methods or ClassName not in Gen.Vtables:
return
Vtable = Gen.Vtables[ClassName]
VtableType = Vtable.type.pointee
null_i8ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
initializers = []
for mi, method_name in enumerate(methods):
method_short = method_name.split('.')[-1] if '.' in method_name else method_name
func = Gen._find_function(f"{ClassName}.{method_short}")
if not func:
func = Gen._find_function(f"{ClassName}.{method_short}__")
if not func:
p = Gen.class_parent.get(ClassName)
while p:
func = Gen._find_function(f"{p}.{method_short}")
if not func:
func = Gen._find_function(f"{p}.{method_short}__")
if func:
break
p = Gen.class_parent.get(p)
if func:
initializers.append(func.bitcast(ir.PointerType(ir.IntType(8))))
else:
initializers.append(null_i8ptr)
if initializers:
Vtable.initializer = ir.Constant(VtableType, initializers)
def _scan_method_body_for_self_members(self, body, ClassName, existing_members, Gen):
for stmt in body:
self._scan_node_for_self_assign(stmt, ClassName, existing_members, Gen)
def _scan_node_for_self_assign(self, node, ClassName, existing_members, Gen):
if isinstance(node, ast.AnnAssign):
if (isinstance(node.target, ast.Attribute)
and isinstance(node.target.value, ast.Name)
and node.target.value.id == 'self'):
VarName = node.target.attr
if VarName not in existing_members:
try:
TypeInfo = CTypeInfo.FromNode(node.annotation, self.Trans.SymbolTable)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, ir.VoidType):
MemberType = ir.IntType(32)
except Exception: # 回退:成员类型解析失败时使用默认 i32
MemberType = ir.IntType(32)
Gen.class_members[ClassName].append((VarName, MemberType))
Gen.class_member_signeds[ClassName][VarName] = None
Gen.class_member_bitfields[ClassName][VarName] = 0
Gen.class_member_byteorders[ClassName][VarName] = ""
Gen.class_member_bitoffsets[ClassName][VarName] = 0
existing_members.add(VarName)
len_name = f'{VarName}__len'
if isinstance(MemberType, ir.PointerType) and node.value and isinstance(node.value, ast.List):
if len_name not in existing_members:
Gen.class_members[ClassName].append((len_name, ir.IntType(64)))
Gen.class_member_signeds[ClassName][len_name] = None
Gen.class_member_bitfields[ClassName][len_name] = 0
Gen.class_member_byteorders[ClassName][len_name] = ""
Gen.class_member_bitoffsets[ClassName][len_name] = 0
Gen.class_member_defaults[ClassName][len_name] = ir.Constant(ir.IntType(64), len(node.value.elts))
existing_members.add(len_name)
elif isinstance(node, ast.Assign):
for target in node.targets:
if (isinstance(target, ast.Attribute)
and isinstance(target.value, ast.Name)
and target.value.id == 'self'):
VarName = target.attr
if VarName not in existing_members:
MemberType = ir.IntType(32)
if node.value:
try:
if isinstance(node.value, ast.Constant):
if isinstance(node.value.value, int):
MemberType = ir.IntType(32)
elif isinstance(node.value.value, float):
MemberType = ir.DoubleType()
elif isinstance(node.value.value, str):
MemberType = ir.PointerType(ir.IntType(8))
elif isinstance(node.value, ast.Name):
if hasattr(self, '_current_method_args'):
arg_info = self._current_method_args.get(node.value.id)
if arg_info:
TypeInfo = CTypeInfo.FromNode(arg_info, self.Trans.SymbolTable)
if TypeInfo:
InferredType = Gen._ctype_to_llvm(TypeInfo)
if not isinstance(InferredType, ir.VoidType):
MemberType = InferredType
elif isinstance(node.value, ast.Call):
if isinstance(node.value.func, ast.Name):
if node.value.func.id in ('float', 'double'):
MemberType = ir.DoubleType()
elif node.value.func.id in ('int', 'long', 'short', 'char'):
MemberType = ir.IntType(32)
elif isinstance(node.value.func, ast.Attribute):
if node.value.func.attr == 'len':
MemberType = ir.IntType(32)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
Gen.class_members[ClassName].append((VarName, MemberType))
Gen.class_member_signeds[ClassName][VarName] = None
Gen.class_member_bitfields[ClassName][VarName] = 0
Gen.class_member_byteorders[ClassName][VarName] = ""
Gen.class_member_bitoffsets[ClassName][VarName] = 0
existing_members.add(VarName)
for child in ast.iter_child_nodes(node):
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
continue
self._scan_node_for_self_assign(child, ClassName, existing_members, Gen)
def _EmitUnionLlvm(self, Node, Gen):
ClassName = Node.name
union_member_types = []
for item in Node.body:
if isinstance(item, ast.ClassDef):
nested_class_name = item.name
nested_member_types = []
for nested_item in item.body:
if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name):
VarName = nested_item.target.id
try:
TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, ir.VoidType):
MemberType = ir.PointerType(ir.IntType(8))
nested_member_types.append(MemberType)
except Exception: # 回退:嵌套成员类型解析失败时使用默认 i32
nested_member_types.append(ir.IntType(32))
if nested_member_types:
nested_struct_type = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
nested_struct_type.set_body(*nested_member_types)
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
union_member_types.append(nested_struct_type)
nested_class_full_name = f"{ClassName}_{nested_class_name}"
if nested_class_full_name not in Gen.class_members:
Gen.class_members[nested_class_full_name] = []
if nested_class_full_name not in Gen.class_member_signeds:
Gen.class_member_signeds[nested_class_full_name] = {}
for nested_item in item.body:
if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name):
VarName = nested_item.target.id
try:
TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, ir.VoidType):
MemberType = ir.PointerType(ir.IntType(8))
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
else:
Gen.class_member_signeds[nested_class_full_name][VarName] = None
except Exception: # 回退:嵌套类成员类型解析失败时使用默认 i32
Gen.class_members[nested_class_full_name].append((VarName, ir.IntType(32)))
Gen.class_member_signeds[nested_class_full_name][VarName] = None
if union_member_types:
max_size = 0
for member_type in union_member_types:
try:
size = member_type.get_abi_size(ir.DataLayout(Gen.module.data_layout))
except Exception: # 回退:获取类型大小失败时使用默认值 8
size = 8
max_size = max(max_size, size)
union_type = ir.IdentifiedStructType(Gen.module, ClassName)
union_type.set_body(ir.ArrayType(ir.IntType(8), max_size))
Gen.structs[ClassName] = union_type
UnionNode = SymbolNode.CreateClass(
name=ClassName,
TypeKind='union',
lineno=Node.lineno,
file='<stdin>'
)
self.Trans.SymbolTable[ClassName] = UnionNode.attributes
def _EmitREnumLlvm(self, Node, Gen):
ClassName = Node.name
variant_info = []
variant_names = []
variant_index = 0
for item in Node.body:
if isinstance(item, ast.ClassDef):
VariantName = item.name
variant_names.append(VariantName)
member_types = []
member_names = []
member_annotations = []
for nested_item in item.body:
if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name):
VarName = nested_item.target.id
try:
TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
MemberType = Gen._ctype_to_llvm(TypeInfo)
if isinstance(MemberType, ir.VoidType):
MemberType = ir.PointerType(ir.IntType(8))
member_types.append(MemberType)
member_names.append(VarName)
member_annotations.append(nested_item.annotation)
except Exception: # 回退:成员类型解析失败时使用默认 i32
member_types.append(ir.IntType(32))
member_names.append(VarName)
member_annotations.append(None)
variant_info.append((VariantName, member_types, member_names, member_annotations, item.lineno, variant_index))
variant_index += 1
elif isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
VarName = target.id
variant_names.append(VarName)
value = None
if item.value and isinstance(item.value, ast.Constant):
value = item.value.value
variant_index = value + 1
else:
value = variant_index
variant_index += 1
variant_info.append((VarName, [], [], [], item.lineno, value))
max_variant_struct = None
max_variant_size = 0
for _, member_types, _, _, _, _ in variant_info:
if member_types:
full_types = [ir.IntType(32)] + member_types
size = 4
for mt in full_types:
if isinstance(mt, ir.IntType):
size += mt.width // 8
elif isinstance(mt, ir.PointerType):
size += 8
elif isinstance(mt, ir.FloatType):
size += 4
elif isinstance(mt, ir.DoubleType):
size += 8
elif isinstance(mt, ir.ArrayType):
if isinstance(mt.element, ir.IntType):
size += mt.element.width // 8 * mt.count
else:
size += 8 * mt.count
else:
size += 8
if size > max_variant_size:
max_variant_size = size
max_variant_struct = full_types
if max_variant_struct is None:
max_variant_struct = [ir.IntType(32), ir.IntType(32)]
renum_type = ir.IdentifiedStructType(Gen.module, ClassName)
renum_type.set_body(*max_variant_struct)
Gen.structs[ClassName] = renum_type
for VariantName, member_types, member_names, member_annotations, lineno, tag_value in variant_info:
NestedStructName = f"{ClassName}_{VariantName}"
if member_types:
padded_member_types = list(max_variant_struct)
nested_struct_type = ir.IdentifiedStructType(Gen.module, NestedStructName)
nested_struct_type.set_body(*padded_member_types)
Gen.structs[NestedStructName] = nested_struct_type
if NestedStructName not in Gen.class_members:
Gen.class_members[NestedStructName] = []
if NestedStructName not in Gen.class_member_signeds:
Gen.class_member_signeds[NestedStructName] = {}
Gen.class_members[NestedStructName].append(('__tag', ir.IntType(32)))
Gen.class_member_signeds[NestedStructName]['__tag'] = None
for i, (mname, mtype) in enumerate(zip(member_names, member_types)):
Gen.class_members[NestedStructName].append((mname, mtype))
try:
ti = CTypeInfo.FromNode(member_annotations[i], self.Trans.SymbolTable)
if ti and hasattr(ti.BaseType, 'IsSigned'):
Gen.class_member_signeds[NestedStructName][mname] = ti.BaseType.IsSigned
else:
Gen.class_member_signeds[NestedStructName][mname] = None
except Exception: # 回退:签名信息解析失败时设为 None
Gen.class_member_signeds[NestedStructName][mname] = None
MemberNode = CTypeInfo()
MemberNode.Name = VariantName
MemberNode.BaseType = t.CEnum(ClassName)
MemberNode.value = tag_value
MemberNode.EnumName = ClassName
MemberNode.Lineno = lineno
MemberNode.IsEnumMember = True
self.Trans.SymbolTable[VariantName] = MemberNode
RenumTypeInfo = CTypeInfo()
RenumTypeInfo.Name = ClassName
RenumTypeInfo.BaseType = t.REnum(ClassName)
RenumTypeInfo.IsRenum = True
RenumTypeInfo.IsEnum = True
RenumTypeInfo.RenumVariants = variant_names
self.Trans.SymbolTable[ClassName] = RenumTypeInfo
def _RegisterEnumMembers(self, Node):
ClassName = Node.name
EnumTypeInfo = CTypeInfo()
EnumTypeInfo.Name = ClassName
EnumTypeInfo.BaseType = t.CEnum(ClassName)
EnumTypeInfo.IsEnum = True
self.Trans.SymbolTable[ClassName] = EnumTypeInfo
from lib.core.export_table import EnumMember as ExportEnumMember
enum_export = self.Trans.ExportTable.add_enum(
name=ClassName,
lineno=Node.lineno,
is_public=True
)
next_enum_value = 0
for item in Node.body:
if isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
VarName = target.id
value = None
if item.value:
if isinstance(item.value, ast.Constant):
value = item.value.value
next_enum_value = value + 1
elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub):
if isinstance(item.value.operand, ast.Constant):
value = -item.value.operand.value
next_enum_value = value + 1
elif isinstance(item.value, ast.Name):
value = item.value.id
if value in self.Trans.SymbolTable:
ref_info = self.Trans.SymbolTable[value]
if ref_info.value is not None and isinstance(ref_info.value, int):
next_enum_value = ref_info.value + 1
else:
value = next_enum_value
next_enum_value += 1
MemberNode = CTypeInfo()
MemberNode.Name = VarName
MemberNode.BaseType = t.CEnum(ClassName)
MemberNode.value = value
MemberNode.EnumName = ClassName
MemberNode.Lineno = item.lineno
MemberNode.IsEnumMember = True
self.Trans.SymbolTable[VarName] = MemberNode
enum_export.members.append(ExportEnumMember(
name=VarName,
value=value,
lineno=item.lineno
))
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
VarName = item.target.id
value = None
if item.value:
if isinstance(item.value, ast.Constant):
value = item.value.value
next_enum_value = value + 1
elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub):
if isinstance(item.value.operand, ast.Constant):
value = -item.value.operand.value
next_enum_value = value + 1
elif isinstance(item.value, ast.Name):
value = item.value.id
if value in self.Trans.SymbolTable:
ref_info = self.Trans.SymbolTable[value]
if ref_info.value is not None and isinstance(ref_info.value, int):
next_enum_value = ref_info.value + 1
else:
value = next_enum_value
next_enum_value += 1
MemberNode = CTypeInfo()
MemberNode.Name = VarName
MemberNode.BaseType = t.CEnum(ClassName)
MemberNode.value = value
MemberNode.EnumName = ClassName
MemberNode.Lineno = item.lineno
MemberNode.IsEnumMember = True
self.Trans.SymbolTable[VarName] = MemberNode
enum_export.members.append(ExportEnumMember(
name=VarName,
value=value,
lineno=item.lineno
))
def _EmitNewFunctionLlvm(self, ClassName, Gen, IsCVTable=False, IsCpythonObject=False):
NewFuncName = f'{ClassName}.__before_init__'
existing_func = Gen.functions.get(NewFuncName)
if existing_func and len(existing_func.blocks) > 0:
return
MangledName = Gen._mangle_name(NewFuncName)
StructType = Gen.structs[ClassName]
if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0):
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
StructType = Gen.structs.get(ClassName, StructType)
StructPtrType = ir.PointerType(StructType)
FuncType = ir.FunctionType(ir.VoidType(), [StructPtrType])
if existing_func:
func = existing_func
else:
func = Gen._get_or_declare_function(MangledName, FuncType)
Gen.functions[NewFuncName] = func
EntryBlock = func.append_basic_block(name="entry")
saved_builder = Gen.builder
saved_func = Gen.func
Gen.builder = ir.IRBuilder(EntryBlock)
Gen.func = func
StructPtr = func.args[0]
if IsCVTable:
base = 1
if ClassName in Gen.Vtables:
VtablePtr = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="vtable_slot")
VtableAddr = Gen.builder.bitcast(Gen.Vtables[ClassName], ir.PointerType(ir.IntType(8)), name="vtable_addr")
Gen.builder.store(VtableAddr, VtablePtr)
members = Gen.class_members.get(ClassName, [])
defaults = Gen.class_member_defaults.get(ClassName, {})
for i, (member_name, member_type) in enumerate(members):
ElemPtr = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}")
if member_name in defaults:
try:
val = defaults[member_name]
if not isinstance(val, ir.Constant):
val = ir.Constant(ElemPtr.type.pointee, val)
Gen.builder.store(val, ElemPtr)
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
Gen.builder.ret_void()
Gen.builder = saved_builder
Gen.func = saved_func
def _BuildScalarConstant(self, node, llvm_type):
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
try:
return ir.Constant(llvm_type, 1 if node.value else 0)
except Exception: # 回退:常量创建失败
return None
elif isinstance(node.value, int):
try:
return ir.Constant(llvm_type, node.value)
except Exception: # 回退:常量创建失败
return None
elif isinstance(node.value, float):
try:
return ir.Constant(llvm_type, node.value)
except Exception: # 回退:常量创建失败
return None
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
if isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int):
try:
return ir.Constant(llvm_type, -node.operand.value)
except Exception: # 回退:常量创建失败
return None
return None
def _BuildStructConstant(self, call_node, StructName, Gen):
struct_type = Gen.structs[StructName]
members = Gen.class_members.get(StructName, [])
defaults = Gen.class_member_defaults.get(StructName, {})
member_values = []
for member_name, member_type in members:
if member_name in defaults:
val = defaults[member_name]
if not isinstance(val, ir.Constant):
try:
val = ir.Constant(member_type, val)
except Exception: # 回退:常量转换失败时使用零值
val = ir.Constant(member_type, 0)
member_values.append(val)
else:
try:
if isinstance(member_type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.PointerType, ir.ArrayType)):
member_values.append(ir.Constant(member_type, None))
else:
member_values.append(ir.Constant(member_type, ir.Undefined))
except Exception: # 回退:常量创建失败时使用零值
member_values.append(ir.Constant(member_type, 0))
if call_node.args:
for i, arg in enumerate(call_node.args):
if i < len(members):
_, member_type = members[i]
const = self._BuildScalarConstant(arg, member_type)
if const is not None:
member_values[i] = const
try:
return ir.Constant(struct_type, member_values)
except Exception: # 回退:结构体常量创建失败
return None

View File

@@ -0,0 +1,96 @@
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):
Gen = self.Trans.LlvmGen
for target in Node.targets:
if isinstance(target, ast.Subscript):
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value)
idx_val = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
if obj_val and idx_val:
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 = Gen.var_struct_class.get(target.id)
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
obj_val = self.Trans.ExprHandler.HandleExprLlvm(target)
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:
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 = target.attr
ClassName = None
obj_val_for_prop = None
if isinstance(target.value, ast.Name) and target.value.id == 'self':
# del self.attr — 检查当前类的 property deleter
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
DeleterFunc = Gen._get_function(PropKey)
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 = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value)
if obj_val:
DeleterFunc = Gen._get_function(PropKey)
if DeleterFunc:
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
continue
# 原有的 __del__ 处理逻辑
obj_val = 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 = 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,429 @@
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 ExprHandle(BaseHandle):
def __init__(self, translator: "Translator"):
super().__init__(translator)
def GetOpSymbol(self, Op):
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op):
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op):
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node, Gen):
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None):
return self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name, ClassName, Gen):
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node, VarType=None):
Gen = 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):
in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method)
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, VarType=None):
Gen = self.Trans.LlvmGen
elements = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len = len(elements)
elem_type = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
import re
match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_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 = array_len
if elem_type == 'i32':
alloc_size *= 4
elif elem_type == 'i16':
alloc_size *= 2
elif elem_type == 'float':
alloc_size *= 4
elif elem_type == 'double':
alloc_size *= 8
malloc_fn = None
malloc_arg_type = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype = 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.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 = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset = 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 = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr = 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 == 'float':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr")
elif elem_type == 'double':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
Value = 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):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(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)
is_unsigned = getattr(inst, 'IsSigned', True) is False
mask = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match = __import__('re').match(r'^i(\d+)$', VarType)
if llvm_match:
width = 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 = getattr(Node, 'kind', None) == 'u'
if len(Value) == 1 and not is_wide:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(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 = __import__('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]))
if is_wide:
str_value = Value + '\x00'
wide_chars = [ord(c) for c in str_value]
target_count = len(wide_chars)
str_type = ir.ArrayType(ir.IntType(16), 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, wide_chars)
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
else:
str_value = Value + '\x00'
str_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, VarType=None):
Gen = self.Trans.LlvmGen
VarName = Node.id
define_constants = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val = 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):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
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
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in getattr(Gen, '_define_constants', {}):
try:
sym_info = self.translator.SymbolTable.get(VarName)
if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) 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):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
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
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 优先检查 variablesalloca因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = 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
return Gen._load(VarPtr, name=VarName)
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 = 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._get_var_ptr('self')
if Gen._has_function(VarName):
func = 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)
if VarName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VarName]
if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False):
MangledName = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g = 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.module_sha1_map.values():
prefixed = 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 = getattr(self.Trans, '_t_c_imported_names', {})
if VarName in t_c_imported:
src_module, src_name = t_c_imported[VarName]
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.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
return ir.Constant(ir.IntType(32), 0)

View File

@@ -0,0 +1,578 @@
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
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):
"""将用户指定的 format 参数转换为 LLVM asm_dialect 值"""
fmt = 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):
Gen = self.Trans.LlvmGen
op_arg = None
input_arg = None
output_arg = None
asm_format = '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 = 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 = Node.args
if len(args) == 4:
output_type_arg = args[0]
asm_template_arg = args[1]
constraint_arg = args[2]
clobber_arg = args[3]
output_type = self._infer_expr_llvm_type(output_type_arg)
if not output_type:
output_type = ir.IntType(32)
asm_template = ''
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 = ''
if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str):
constraint = constraint_arg.value
clobber = ''
if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str):
clobber = clobber_arg.value
full_constraint = constraint
func_type = ir.FunctionType(output_type, [])
asm_dialect = self._format_to_dialect(asm_format)
inline_asm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect)
result = Gen.builder.call(inline_asm, [], name="asm_result")
return result
elif len(args) >= 2:
output_type_arg = args[0]
asm_template_arg = args[1]
output_type = self._infer_expr_llvm_type(output_type_arg)
if not output_type:
output_type = ir.IntType(32)
asm_template = ''
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 = []
output_values = []
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 = item.elts[0]
value_node = item.elts[1]
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
output_constraints.append(constraint_node.value)
value = self.HandleExprLlvm(value_node)
if value:
output_values.append(value)
input_constraints = []
input_values = []
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 = item.elts[0]
value_node = item.elts[1]
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
input_constraints.append(constraint_node.value)
value = self.HandleExprLlvm(value_node)
if value:
input_values.append(value)
clobbers = []
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 = []
for oc in output_constraints:
constraint_parts.append(oc)
input_start_idx = len(output_constraints)
for ic in input_constraints:
constraint_parts.append(ic)
full_constraint = ",".join(constraint_parts)
if clobbers:
if full_constraint:
full_constraint += ","
for c in clobbers:
full_constraint += f"~{{{c}}}"
operands = output_values + input_values
param_types = [v.type for v in operands]
func_type = ir.FunctionType(output_type, param_types)
asm_dialect = self._format_to_dialect(asm_format)
inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect)
result = Gen.builder.call(inline_asm, operands, name="asm_result")
return result
return None
def _prepare_intel_asm(self, template: str) -> str:
import re
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, out_input_ops, out_input_constraints,
out_output_ops, out_output_constraints):
if not isinstance(node, ast.JoinedStr):
if isinstance(node, ast.Constant) and isinstance(node.value, str):
return node.value
return ''
raw_parts = []
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 = 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 = self.HandleExprLlvm(expr.args[0])
if v:
c = '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 = 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 = '=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 = 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 = len(out_output_ops)
parts = []
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:
import re
Gen = self.Trans.LlvmGen
sha1 = getattr(Gen, 'module_sha1', '')
if not sha1:
return template
def replace_call(m):
prefix = m.group(1)
func_name = m.group(2)
if func_name.lower() in self._X86_REGISTERS:
return m.group(0)
mangled = 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, op_arg, input_arg=None, output_arg=None, asm_format='Intel'):
Gen = self.Trans.LlvmGen
input_ops = []
input_constraints = []
output_ops = []
output_constraints = []
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 = self._get_var_ptr_for_asm(item.args[0])
if target_ptr:
output_ops.append(target_ptr)
else:
value = self.HandleExprLlvm(item.args[0])
if value:
output_ops.append(value)
constraint = '=r'
if len(item.args) >= 2:
base_constraint = 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)
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 = self._format_to_dialect(asm_format)
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 = self.HandleExprLlvm(item.args[0])
if value:
input_ops.append(value)
constraint = '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 = item.elts[0]
descr_node = item.elts[1]
value = self.HandleExprLlvm(value_node)
if value:
input_ops.append(value)
constraint = self._parse_asm_descr(descr_node)
if not constraint:
constraint = 'r'
input_constraints.append(constraint)
clobbers = []
if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)):
for item in op_arg.elts:
clobber = self._parse_asm_descr(item)
if clobber:
clobbers.append(clobber)
constraint_parts = []
for oc in output_constraints:
c = 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 = ",".join(constraint_parts)
constraint_to_reg = {
'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx',
'S': 'rsi', 'D': 'rdi',
'A': 'rax', 'U': 'r8',
}
used_regs = 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 = oc.lstrip('=').lstrip('+')
if base_oc in constraint_to_reg:
used_regs.add(constraint_to_reg[base_oc])
if clobbers:
has_memory = 'memory' in clobbers
if has_memory and output_ops:
clobbers = [c for c in clobbers if c != 'memory']
if asm_format == 'ARM':
# ARM 不需要 x86 的 e→r 寄存器名转换
clobber_final = [c for c in clobbers if c not in used_regs]
else:
clobber_64bit = []
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 = len(output_ops) == 1
if single_out:
op = output_ops[0]
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):
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 = input_ops
param_types = [op.type for op in operands]
func_type = ir.FunctionType(ret_type, param_types)
inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect)
result = Gen.builder.call(inline_asm, operands, name="asm_result")
if single_out:
target = output_ops[0]
if isinstance(target, ir.AllocaInstr):
if target.type.pointee != result.type:
i64t = ir.IntType(64)
iv = Gen.builder.ptrtoint(result, i64t)
ptr = 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 = 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 = Gen.builder.inttoptr(result, target_pointee)
Gen.builder.store(ptr_val, target)
else:
i64t = ir.IntType(64)
iv = Gen.builder.ptrtoint(result, i64t)
ptr = Gen.builder.bitcast(target, ir.PointerType(i64t))
Gen.builder.store(iv, ptr)
else:
Gen.builder.store(result, target)
else:
dst = Gen._alloca_entry(result.type)
Gen.builder.store(result, dst)
else:
for i, out_op in enumerate(output_ops):
val = Gen.builder.extract_value(result, i, name=f"asm_out_{i}")
target = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._alloca_entry(val.type)
if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type:
i64t = ir.IntType(64)
iv = Gen.builder.ptrtoint(val, i64t)
ptr = Gen.builder.bitcast(target, ir.PointerType(i64t))
Gen.builder.store(iv, ptr)
else:
Gen.builder.store(val, target)
else:
operands = input_ops
param_types = [op.type for op in operands]
func_type = ir.FunctionType(ir.VoidType(), param_types)
inline_asm = 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):
Gen = self.Trans.LlvmGen
if isinstance(node, ast.Name):
var_name = node.id
if var_name in Gen.variables and Gen.variables[var_name] is not None:
ptr = 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 = self._get_var_ptr_for_asm(node.value)
if obj_ptr is not None:
obj_type = obj_ptr.type.pointee
if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType):
loaded = Gen.builder.load(obj_ptr, name="asm_attr_load")
struct_type = obj_type.pointee
class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
if class_name:
offset = Gen._get_member_offset(node.attr, class_name)
gep = 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 = 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 = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
if class_name:
offset = Gen._get_member_offset(node.attr, class_name)
gep = 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 = 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):
from lib.includes import t
if isinstance(expr, ast.BinOp):
left_val = self._parse_asm_descr(expr.left)
right_val = 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
expr.value.value.id == 't' and
expr.value.attr == 'ASM_DESCR'):
AttrName = expr.attr
return getattr(t.ASM_DESCR, AttrName, "")
elif isinstance(expr.value, ast.Name) and expr.value.id == 't':
AttrName = expr.attr
return getattr(t.ASM_DESCR, AttrName, "")
elif isinstance(expr, ast.Constant):
return expr.value
return ""
def _infer_expr_llvm_type(self, expr):
import llvmlite.ir as ir
if isinstance(expr, ast.Name):
type_name = expr.id
if hasattr(t, type_name):
ctype = getattr(t, type_name)
if isinstance(ctype, type) and issubclass(ctype, t.CType):
size = 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 expr.value.id == 't':
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,854 @@
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 ExprBuiltinHandle(BaseHandle):
_C_LIB_FUNCS = {
'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):
Gen = self.Trans.LlvmGen
if not isinstance(Node.func, ast.Name):
return None
FuncName = 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._zero_const(Val.type), name="bool_result")
elif isinstance(Val.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(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 == '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):
Gen = self.Trans.LlvmGen
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
args = Node.args
end_arg = None
sep_arg = 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 = ' '
if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str):
sep_str = sep_arg.value
end_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
has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args)
if has_fstring:
self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str)
return
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._alloca_entry(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_bytes = fmt_str.encode('utf-8') + b'\x00'
fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes))
fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes))
fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}")
Gen.string_const_counter += 1
fmt_gvar.initializer = fmt_const
fmt_gvar.linkage = 'internal'
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name="print_fmt")
call_args = [fmt_ptr] + fmt_args
return Gen.builder.call(printf_func, call_args, name="print_call")
def _HandlePrintWithFString(self, Node, printf_func, args, sep_str, end_str):
Gen = 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):
self.HandleExprLlvm(arg)
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._register_temp_ptr(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 __import__('lib.constants.config', fromlist=['mode']).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):
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, val):
Gen = self.Trans.LlvmGen
if isinstance(arg_node, ast.Name):
var_name = arg_node.id
signedness = 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, Gen):
if func_name not in self._C_LIB_FUNCS:
return None
ret_type, param_types = self._C_LIB_FUNCS[func_name]()
func_type = ir.FunctionType(ret_type, param_types)
func = ir.Function(Gen.module, func_type, name=func_name)
Gen.functions[func_name] = func
return func
def _HandleLenLlvm(self, arg_node):
Gen = 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 __import__('lib.constants.config', fromlist=['mode']).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 _HandleSizeofLlvm(self, Node):
Gen = self.Trans.LlvmGen
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:
from lib.includes.t import CTypeRegistry
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:
pass
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:
pass
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)
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):
Gen = self.Trans.LlvmGen
val = 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):
Gen = self.Trans.LlvmGen
return ir.Constant(ir.IntType(8).as_pointer(), None)
def _HandleTypeLlvm(self, Node):
Gen = self.Trans.LlvmGen
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):
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 arg_name in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[arg_name]
if TypeInfo.IsEnum:
enum_type_name = arg_name
elif isinstance(arg, ast.Attribute):
last_part = None
enum_class_name = None
if isinstance(arg.value, ast.Name):
last_part = arg.attr
if last_part in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[last_part]
if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None):
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]
last_part = parts[-1]
qualified_name_dot = f"{enum_class_name}.{last_part}"
qualified_name_under = f"{enum_class_name}_{last_part}"
enum_member_found = None
for qname in (qualified_name_dot, qualified_name_under):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name:
enum_member_found = info
break
if not enum_member_found:
for key in self.Trans.SymbolTable:
if key == last_part:
info = self.Trans.SymbolTable[key]
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == 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):
Gen = 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):
Gen = self.Trans.LlvmGen
atoi_func = 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):
Gen = self.Trans.LlvmGen
val = 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):
Gen = self.Trans.LlvmGen
val = 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):
Gen = 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):
Gen = self.Trans.LlvmGen
malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_func = Gen._get_or_declare_func('malloc', malloc_type)
param_type = malloc_func.type.pointee.args[0]
size_val = 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 = 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):
Gen = self.Trans.LlvmGen
realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
realloc_func = Gen._get_or_declare_func('realloc', realloc_type)
size_param_type = realloc_func.type.pointee.args[1]
ptr_val = None
size_val = 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 = 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):
Gen = self.Trans.LlvmGen
free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
free_func = Gen._get_or_declare_func('free', free_type)
if args:
var_name = None
if isinstance(args[0], ast.Name):
var_name = args[0].id
ptr_val = 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):
Gen = self.Trans.LlvmGen
if 'llvm.memcpy' not in Gen.functions:
memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
if len(args) >= 3:
dst = self.HandleExprLlvm(args[0])
src = self.HandleExprLlvm(args[1])
size = self.HandleExprLlvm(args[2])
if dst and src and size:
i8ptr = 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.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):
Gen = self.Trans.LlvmGen
memset_func = 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 = self.HandleExprLlvm(args[0])
val = self.HandleExprLlvm(args[1])
size = 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):
Gen = self.Trans.LlvmGen
return ir.Constant(ir.IntType(32), 0)
def _HandleVaEndLlvm(self, args):
Gen = self.Trans.LlvmGen
return ir.Constant(ir.IntType(32), 0)
def _HandleArgLlvm(self, args, CallNode=None):
Gen = self.Trans.LlvmGen
va_list_ptr = None
variadic_info = 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 = variadic_info.get('vararg_name', 'args') if variadic_info else 'args'
if 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.IntType(32)
if args:
type_arg = args[0]
if isinstance(type_arg, ast.Name):
type_name = type_arg.id
from lib.includes.t import CTypeRegistry
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 = CTypeRegistry.GetClassByName(type_name)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
else:
resolved = CTypeRegistry.ResolveName(type_name)
if resolved is not None:
ctype_cls, ptr_level = resolved
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
if llvm_str:
base = 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 type_arg.value.id == 't':
attr_name = type_arg.attr
from lib.includes.t import CTypeRegistry
ctype_cls = CTypeRegistry.GetClassByName(attr_name)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved = Gen._type_str_to_llvm(llvm_str)
if resolved:
target_type = resolved
else:
assign_node = getattr(self.Trans, '_current_assign_node', None)
if assign_node:
ann = getattr(assign_node, 'annotation', None)
if ann:
ann_name = 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):
left = ann.left
if isinstance(left, ast.Name):
ann_name = left.id
elif isinstance(left, ast.Attribute):
ann_name = left.attr
if ann_name:
from lib.includes.t import CTypeRegistry
ctype_cls = CTypeRegistry.GetClassByName(ann_name)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
resolved = 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 = 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 _HandleVaArgLlvm(self, args):
Gen = self.Trans.LlvmGen
return ir.Constant(ir.IntType(32), 0)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
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 ExprFormatHandle(BaseHandle):
def _HandleJoinedStrLlvm(self, Node, return_str=False):
Gen = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return ir.Constant(ir.IntType(8).as_pointer(), None)
format_str = ""
cast_args = []
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 = self.Trans.ExprHandler._get_var_class(part.value, Gen)
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
obj_val = 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 = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
Gen._register_temp_ptr(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
if isinstance(val.type, ir.PointerType):
pointee = 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 = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
trunc_val = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
format_str += "%d"
cast_args.append(trunc_val)
else:
loaded = Gen._load(val, name="fstr_deref")
if isinstance(loaded.type, ir.IntType):
if loaded.type.width == 8:
format_str += "%c"
ext = 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 = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
format_str += "%d"
cast_args.append(zext)
else:
is_u = 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 and not cast_args:
return Gen.emit_constant("", 'string')
encoded = format_str.encode('utf-8') + b'\x00'
string_type = ir.ArrayType(ir.IntType(8), len(encoded))
string_const = ir.Constant(string_type, bytearray(encoded))
global_var = ir.GlobalVariable(Gen.module, string_type, name=f"str_const_{Gen.string_const_counter}")
Gen.string_const_counter += 1
global_var.initializer = string_const
global_var.linkage = 'internal'
format_ptr = Gen.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)))
if return_str:
buf_size = ir.Constant(ir.IntType(64), 1024)
calloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)])
calloc_func = Gen._get_or_declare_func('calloc', calloc_type)
buf_ptr = Gen.builder.call(calloc_func, [ir.Constant(ir.IntType(64), 1), buf_size], name="call_calloc_buf")
sprintf_func = Gen.get_or_declare_c_func('sprintf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))], var_arg=True))
sprintf_args = [buf_ptr, format_ptr] + cast_args
Gen.builder.call(sprintf_func, sprintf_args, name="call_sprintf")
return buf_ptr
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
call_args = [format_ptr] + cast_args
return Gen.builder.call(printf_func, call_args, name="call_fstring")

View File

@@ -0,0 +1,232 @@
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 ExprLambdaHandle(BaseHandle):
def _HandleLambdaLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not getattr(Gen, '_lambda_counter', None):
Gen._lambda_counter = 0
lambda_id = Gen._lambda_counter
Gen._lambda_counter += 1
fn_name = f"lambda_fn_{lambda_id}"
captured_vars = self._get_lambda_captured_vars(Node)
env_types = []
env_var_names = []
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(env_types) if env_types else ir.LiteralStructType([])
ret_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
param_types = [ir.PointerType(env_struct_type)]
if Node.args:
for arg in Node.args.args:
param_types.append(ir.IntType(32))
fn_type = ir.FunctionType(ret_type, param_types)
fn = ir.Function(Gen.module, fn_type, name=fn_name)
Gen.functions[fn_name] = fn
entry_block = fn.append_basic_block(name=f"{fn_name}_entry")
prev_builder = Gen.builder
prev_func = Gen.func
prev_vars = 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 = fn.args[0]
zero = ir.Constant(ir.IntType(32), 0)
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
loaded = Gen._load(member_ptr, name=f"load_env_{var_name}")
temp_alloca = 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 = 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:
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.PointerType(ir.IntType(8)),
ir.PointerType(fn_type)
])
closure_ptr = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
env_ptr = 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 = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
env_i8_ptr = 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 = 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):
Gen = self.Trans.LlvmGen
captured = []
free_vars = self._get_lambda_free_vars(Node)
for var_name in free_vars:
if var_name in Gen.variables:
var_ptr = Gen.variables[var_name]
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
loaded = Gen._load(var_ptr, name=f"capture_{var_name}")
captured.append((var_name, loaded))
return captured
def _get_lambda_free_vars(self, Node):
bound_vars = set()
free_vars = 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 = free_vars - bound_vars
return list(result)
def _HandleIfExpLlvm(self, Node):
Gen = self.Trans.LlvmGen
TestVal = 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._zero_const(TestVal.type), name="ifexp_cond")
ThenBB = Gen.func.append_basic_block(name="ifexp.then")
ElseBB = Gen.func.append_basic_block(name="ifexp.else")
MergeBB = Gen.func.append_basic_block(name="ifexp.end")
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
# 先在 ThenBB 中生成 BodyVal
Gen.builder.position_at_start(ThenBB)
BodyVal = self.HandleExprLlvm(Node.body)
if not BodyVal:
BodyVal = ir.Constant(ir.IntType(32), 0)
ThenEndBB = Gen.builder.block
# 在 ElseBB 中生成 OrelseVal
Gen.builder.position_at_start(ElseBB)
OrelseVal = self.HandleExprLlvm(Node.orelse)
if not OrelseVal:
OrelseVal = ir.Constant(ir.IntType(32), 0)
ElseEndBB = Gen.builder.block
# 确定 phi 节点的目标类型
result_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 = 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):
Gen = self.Trans.LlvmGen
ValueVal = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
TargetName = 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 = Gen.variables[TargetName]
if VarPtr.type.pointee == ValueVal.type:
Gen._store(ValueVal, VarPtr)
else:
NewVar = 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,402 @@
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 ExprOpsHandle(BaseHandle):
def _HandleBinOpLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
Gen._set_node_info(Node, "BinOp")
LeftVal = self.HandleExprLlvm(Node.left, VarType)
if not LeftVal:
return None
RightVal = self.HandleExprLlvm(Node.right, VarType)
if not RightVal:
return None
Op = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if not Op:
return None
OP_OVERLOAD_MAP = {
'+': '__add__', '-': '__sub__', '*': '__mul__',
'/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
'**': '__pow__',
}
if Op in OP_OVERLOAD_MAP:
LeftClassName = None
if isinstance(LeftVal.type, ir.PointerType):
pointee = 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(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 = OP_OVERLOAD_MAP[Op]
result = 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 = Gen._load(LeftVal, name="load_char_const")
CharAsInt = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
TruncResult = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
return TruncResult
is_unsigned = 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 = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (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
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="zext_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 = 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):
Gen = self.Trans.LlvmGen
def _to_bool(val, name):
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._zero_const(val.type), name=name)
return val
values = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="and.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"andcond{idx}")
cur_bb = Gen.builder.block
next_bb = 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 = 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 = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = 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):
Gen = self.Trans.LlvmGen
OperandVal = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName = None
if isinstance(OperandVal.type, ir.PointerType):
pointee = 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(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 = UNARY_OVERLOAD_MAP[OpSymbol]
result = 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(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask = (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):
Gen = self.Trans.LlvmGen
LeftVal = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned = 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 = Node.ops[0]
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal = 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, rv = LeftVal.constant, RightVal.constant
lw, rw = LeftVal.type.width, 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 = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result = 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 = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8
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="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
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:
RightVal = Gen.builder.inttoptr(RightVal, LeftVal.type, name="int2ptr_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:
LeftVal = Gen.builder.inttoptr(LeftVal, RightVal.type, name="int2ptr_cmp")
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 = Gen.func.append_basic_block(name="cmp.end")
result_val = None
PrevBB = Gen.builder.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
NextBB = Gen.func.append_basic_block(name="cmp.next")
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
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
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 = 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 result_val is None:
result_val = cmp_result
else:
result_val = Gen.builder.and_(result_val, cmp_result, name=f"and_cmp_{i}")
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
Gen.builder.branch(EndBB)
Gen.builder.position_at_start(EndBB)
final_result = Gen.builder.phi(ir.IntType(1), name="final_cmp")
final_result.add_incoming(ir.Constant(ir.IntType(1), 0), PrevBB)
for i in range(len(Node.ops)):
bb = Gen.func.append_basic_block(name=f"cmp.end.{i}")
final_result.add_incoming(ir.Constant(ir.IntType(1), 1), bb)
return final_result

View File

@@ -0,0 +1,240 @@
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
class ExprUtils:
def __init__(self, translator: "Translator"):
self.Trans = translator
def GetOpSymbol(self, Op):
OpMap = {
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):
OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op):
OpMap = {
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, Gen):
if isinstance(node, ast.Name):
VarName = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName = node.attr
return Gen.var_struct_class.get(AttrName)
return None
def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None):
FullMethodName = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if Gen._has_function(FullMethodName):
func = Gen._get_function(FullMethodName)
call_args = [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 = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type, var_name=""):
info = {
'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 = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size = 0
for elem in llvm_type.elements:
elem_info = 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):
Gen = 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 = 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 = node.attr
if attr_name in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[attr_name]
if getattr(AttrInfo, 'IsEnumMember', None):
return ir.IntType(32)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type = self._infer_expr_llvm_type_full(node.left)
right_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 = 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 = node.func.id
if Gen._has_function(func_name):
fn = 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 node.func.value.id == 't':
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, bound, free=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 = 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)

View File

@@ -0,0 +1,495 @@
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 ForHandle(BaseHandle):
def _HandleForLlvm(self, Node):
Gen = self.Trans.LlvmGen
Gen._set_node_info(Node, "For")
if not isinstance(Node.target, ast.Name):
return
TargetName = Node.target.id
StartVal = None
EndVal = None
StepVal = None
IsRange = False
CondOp = '<'
if isinstance(Node.iter, ast.Call):
CallFunc = Node.iter.func
if isinstance(CallFunc, ast.Name) and CallFunc.id == 'range':
IsRange = True
RangeArgs = Node.iter.args
RangeEndArg = RangeArgs[1] if len(RangeArgs) >= 2 else RangeArgs[0] if len(RangeArgs) >= 1 else None
OptimizedEnd = False
if len(RangeArgs) >= 2 and isinstance(RangeEndArg, ast.BinOp):
if isinstance(RangeEndArg.op, ast.Add):
if (isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1):
EndVal = self.HandleExprLlvm(RangeEndArg.left)
CondOp = '<='
OptimizedEnd = True
elif (isinstance(RangeEndArg.left, ast.Constant) and RangeEndArg.left.value == 1):
EndVal = self.HandleExprLlvm(RangeEndArg.right)
CondOp = '<='
OptimizedEnd = True
elif isinstance(RangeEndArg.op, ast.Sub):
if isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1:
EndVal = self.HandleExprLlvm(RangeEndArg.left)
CondOp = '<'
OptimizedEnd = True
if not OptimizedEnd:
if len(RangeArgs) == 1:
EndVal = self.HandleExprLlvm(RangeArgs[0])
else:
EndVal = self.HandleExprLlvm(RangeEndArg)
if len(RangeArgs) == 1:
StartVal = ir.Constant(ir.IntType(32), 0)
elif len(RangeArgs) >= 2:
StartVal = self.HandleExprLlvm(RangeArgs[0])
if len(RangeArgs) >= 3:
StepVal = self.HandleExprLlvm(RangeArgs[2])
# Check if step is a negative constant — need to flip condition
step_arg = RangeArgs[2]
if isinstance(step_arg, ast.UnaryOp) and isinstance(step_arg.op, ast.USub):
if isinstance(step_arg.operand, ast.Constant) and isinstance(step_arg.operand.value, (int, float)):
if step_arg.operand.value > 0:
CondOp = '>'
elif isinstance(step_arg, ast.Constant) and isinstance(step_arg.value, (int, float)):
if step_arg.value < 0:
CondOp = '>'
if not EndVal:
return
if not isinstance(EndVal.type, ir.IntType):
if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType):
EndVal = Gen._load(EndVal, name="load_end")
else:
EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end")
if StartVal and not isinstance(StartVal.type, ir.IntType):
if isinstance(StartVal.type, ir.PointerType) and isinstance(StartVal.type.pointee, ir.IntType):
StartVal = Gen._load(StartVal, name="load_start")
else:
StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start")
else:
StartVal = ir.Constant(ir.IntType(64), 0)
if not StartVal:
StartVal = ir.Constant(EndVal.type, 0)
if StepVal is None:
StepVal = ir.Constant(EndVal.type, 1)
if not IsRange:
IterClassName = self.Trans.ExprHandler._get_var_class(Node.iter, Gen)
if not IterClassName and isinstance(Node.iter, ast.Call) and isinstance(Node.iter.func, ast.Name):
IterClassName = Node.iter.func.id
if IterClassName not in Gen.structs:
IterClassName = None
if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'):
self._HandleForIterLlvm(Node, IterClassName)
return
IterVal = self.HandleExprLlvm(Node.iter)
if not IterVal:
return
if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8:
self._HandleForStrLlvm(Node, IterVal)
return
if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType):
self._HandleForListLlvm(Node, IterVal)
return
StartVal = ir.Constant(ir.IntType(32), 0)
EndVal = IterVal
if not isinstance(EndVal.type, ir.IntType):
EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end")
StartVal = ir.Constant(ir.IntType(64), 0)
StepVal = ir.Constant(EndVal.type, 1)
CondOp = '<'
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
LoopVar = Gen.variables[TargetName]
if isinstance(LoopVar.type, ir.PointerType) and isinstance(LoopVar.type.pointee, ir.IntType) and LoopVar.type.pointee == EndVal.type and isinstance(EndVal.type, ir.IntType) and StartVal.type == LoopVar.type.pointee and EndVal.type == StartVal.type:
Gen._store(StartVal, LoopVar)
else:
NewVar = Gen._alloca_entry(EndVal.type, name=TargetName)
if StartVal.type != EndVal.type:
if isinstance(EndVal.type, ir.IntType) and isinstance(StartVal.type, ir.IntType):
if StartVal.type.width < EndVal.type.width:
StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zext_loop_start")
elif StartVal.type.width > EndVal.type.width:
StartVal = Gen.builder.trunc(StartVal, EndVal.type, name="trunc_loop_start")
Gen._store(StartVal, NewVar)
Gen.variables[TargetName] = NewVar
LoopVar = NewVar
else:
LoopVar = Gen._alloca_entry(EndVal.type, name=TargetName)
Gen.variables[TargetName] = LoopVar
Gen._store(StartVal, LoopVar)
if StepVal and isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType):
if StepVal.type.width < EndVal.type.width:
StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zext_loop_step")
elif StepVal.type.width > EndVal.type.width:
StepVal = Gen.builder.trunc(StepVal, EndVal.type, name="trunc_loop_step")
Gen._record_var_signedness(TargetName, 'int')
CondBB = Gen.func.append_basic_block(name="for.cond")
BodyBB = Gen.func.append_basic_block(name="for.body")
StepBB = Gen.func.append_basic_block(name="for.step")
ElseBB = Gen.func.append_basic_block(name="for.else") if Node.orelse else None
AfterBB = Gen.func.append_basic_block(name="for.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(StepBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
LoopVal = Gen._load(LoopVar, name=TargetName)
is_unsigned = Gen._is_var_unsigned(TargetName)
if is_unsigned:
Cond = Gen.builder.icmp_unsigned(CondOp, LoopVal, EndVal, name="forcond")
else:
Cond = Gen.builder.icmp_signed(CondOp, LoopVal, EndVal, name="forcond")
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
CachedLoopVal = Gen._load(LoopVar, name=TargetName)
Gen._reg_values[TargetName] = CachedLoopVal
self.HandleBodyLlvm(Node.body)
StepLoopVal = CachedLoopVal
if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is CachedLoopVal:
del Gen._reg_values[TargetName]
else:
StepLoopVal = Gen._load(LoopVar, name=TargetName)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(StepBB)
Gen.builder.position_at_start(StepBB)
StepLoopVal2 = Gen._load(LoopVar, name=TargetName)
NextVal = Gen.builder.add(StepLoopVal2, StepVal, name="next")
Gen._store(NextVal, LoopVar)
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)
def _HandleGlobalLlvm(self, Node):
Gen = self.Trans.LlvmGen
for name in Node.names:
Gen.global_vars.add(name)
if name in Gen.module.globals:
Gen.variables[name] = Gen.module.globals[name]
if name in Gen._reg_values:
del Gen._reg_values[name]
def _HandleNonlocalLlvm(self, Node):
Gen = self.Trans.LlvmGen
for name in Node.names:
if name in Gen._reg_values and name not in Gen.variables:
OldVal = Gen._reg_values[name]
var = Gen._alloca_entry(OldVal.type, name=name)
Gen._store(OldVal, var)
Gen.variables[name] = var
del Gen._reg_values[name]
def _collect_implicit_nonlocal(self, Node, Gen):
param_names = set()
for arg in Node.args.args:
param_names.add(arg.arg)
local_names = set()
for child in ast.walk(Node):
if isinstance(child, ast.Assign):
for target in child.targets:
if isinstance(target, ast.Name):
local_names.add(target.id)
elif isinstance(target, ast.Tuple):
for elt in target.elts:
if isinstance(elt, ast.Name):
local_names.add(elt.id)
elif isinstance(child, ast.AugAssign):
if isinstance(child.target, ast.Name):
local_names.add(child.target.id)
elif isinstance(child, ast.AnnAssign):
if isinstance(child.target, ast.Name):
local_names.add(child.target.id)
elif isinstance(child, ast.For):
if isinstance(child.target, ast.Name):
local_names.add(child.target.id)
read_names = set()
for child in ast.walk(Node):
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load):
name = child.id
if name not in param_names and name not in local_names:
read_names.add(name)
implicit = []
for name in read_names:
if name in Gen.variables and Gen.variables[name] is not None:
implicit.append(name)
elif name in Gen._reg_values:
implicit.append(name)
for called_name in read_names:
if called_name in Gen.nonlocal_params:
for nv, _ in Gen.nonlocal_params[called_name]:
if nv not in param_names and nv not in local_names:
if nv not in read_names:
if nv in Gen.variables and Gen.variables[nv] is not None:
implicit.append(nv)
elif nv in Gen._reg_values:
implicit.append(nv)
return implicit
def _collect_all_nonlocal_names(self, Node):
"""Recursively collect all nonlocal variable names from a function and its nested functions."""
names = set()
for stmt in Node.body:
if isinstance(stmt, ast.Nonlocal):
for name in stmt.names:
names.add(name)
elif isinstance(stmt, ast.FunctionDef):
# Recursively collect from nested functions
sub_names = self._collect_all_nonlocal_names(stmt)
names.update(sub_names)
return names
def _HandleNestedFunctionLlvm(self, Node):
Gen = self.Trans.LlvmGen
nonlocal_var_names = []
for stmt in Node.body:
if isinstance(stmt, ast.Nonlocal):
for name in stmt.names:
nonlocal_var_names.append(name)
# Pre-scan ALL nested functions recursively for their nonlocal needs (passthrough)
for stmt in Node.body:
if isinstance(stmt, ast.FunctionDef):
sub_nonlocal_names = self._collect_all_nonlocal_names(stmt)
for name in sub_nonlocal_names:
if name not in nonlocal_var_names:
nonlocal_var_names.append(name)
implicit_names = self._collect_implicit_nonlocal(Node, Gen)
for name in implicit_names:
if name not in nonlocal_var_names:
nonlocal_var_names.append(name)
extra_params = []
for var_name in nonlocal_var_names:
if var_name in Gen.variables and Gen.variables[var_name] is not None:
var = Gen.variables[var_name]
extra_params.append((var_name, var.type))
elif var_name in Gen._reg_values:
OldVal = Gen._reg_values[var_name]
var = Gen._alloca_entry(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.variables[var_name] = var
del Gen._reg_values[var_name]
extra_params.append((var_name, var.type))
else:
# Search outer scope stack for the variable
found_var = None
for scope in reversed(Gen._variable_scope_stack):
if var_name in scope and scope[var_name] is not None:
found_var = scope[var_name]
break
if found_var is not None:
# Add to current scope so it can be passed to nested functions
Gen.variables[var_name] = found_var
extra_params.append((var_name, found_var.type))
else:
var = Gen._alloca_entry(ir.IntType(32), name=var_name)
Gen.variables[var_name] = var
extra_params.append((var_name, var.type))
if extra_params:
Gen.nonlocal_params[Node.name] = [(name, ptr_type) for name, ptr_type in extra_params]
# Push current variables to scope stack before compiling nested function
Gen._variable_scope_stack.append(Gen.variables.copy())
saved_builder = Gen.builder
saved_func = Gen.func
saved_variables = Gen.variables.copy()
saved_reg_values = Gen._reg_values.copy()
saved_global_vars = Gen.global_vars.copy()
saved_var_signedness = Gen.var_signedness.copy()
saved_var_type_info = Gen.var_type_info.copy()
saved_var_type_assignments = Gen.var_type_assignments.copy()
saved_CurrentCReturnTypes = getattr(self.Trans, 'CurrentCReturnTypes', None)
saved_CurrentCpythonObjectClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
saved_VarScopes = len(self.Trans.VarScopes)
self.Trans.FunctionHandler._EmitFunctionLlvm(Node, Gen, extra_params=extra_params if extra_params else None)
Gen.builder = saved_builder
Gen.func = saved_func
Gen.variables = saved_variables
Gen._reg_values = saved_reg_values
Gen.global_vars = saved_global_vars
Gen.var_signedness = saved_var_signedness
Gen.var_type_info = saved_var_type_info
Gen.var_type_assignments = saved_var_type_assignments
self.Trans.CurrentCReturnTypes = saved_CurrentCReturnTypes
self.Trans._CurrentCpythonObjectClass = saved_CurrentCpythonObjectClass
while len(self.Trans.VarScopes) > saved_VarScopes:
self.Trans.VarScopes.pop()
# Pop scope stack
if Gen._variable_scope_stack:
Gen._variable_scope_stack.pop()
def _HandleForListLlvm(self, Node, ArrPtr):
Gen = self.Trans.LlvmGen
if not isinstance(Node.target, ast.Name):
return
TargetName = Node.target.id
ElemType = ArrPtr.type.pointee.element
ArrayCount = ArrPtr.type.pointee.count
IdxVal = Gen._alloca_entry(ir.IntType(32), name=f"arr_idx")
Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVal)
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
LoopVar = Gen._alloca_entry(ElemType, name=TargetName)
Gen.variables[TargetName] = LoopVar
Gen._store(ir.Constant(ElemType, None), LoopVar)
CondBB = Gen.func.append_basic_block(name="arrfor.cond")
BodyBB = Gen.func.append_basic_block(name="arrfor.body")
StepBB = Gen.func.append_basic_block(name="arrfor.step")
ElseBB = Gen.func.append_basic_block(name="arrfor.else") if Node.orelse else None
AfterBB = Gen.func.append_basic_block(name="arrfor.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(StepBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
CurIdx = Gen._load(IdxVal, name="cur_idx")
IsDone = Gen.builder.icmp_signed('<', CurIdx, ir.Constant(ir.IntType(32), ArrayCount), name="arr_in_bounds")
Gen.builder.cbranch(IsDone, BodyBB, ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
ElemPtr = Gen.builder.gep(ArrPtr, [ir.Constant(ir.IntType(32), 0), CurIdx], name="arr_elem_ptr")
ElemVal = Gen._load(ElemPtr, name="arr_elem_val")
Gen._store(ElemVal, LoopVar)
Gen._record_var_signedness(TargetName, 'ptr')
Gen._reg_values[TargetName] = ElemVal
self.HandleBodyLlvm(Node.body)
if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is ElemVal:
del Gen._reg_values[TargetName]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(StepBB)
Gen.builder.position_at_start(StepBB)
CurIdx2 = Gen._load(IdxVal, name="cur_idx2")
NextIdx = Gen.builder.add(CurIdx2, ir.Constant(ir.IntType(32), 1), name="next_idx")
Gen._store(NextIdx, IdxVal)
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)
def _HandleForStrLlvm(self, Node, StrVal):
Gen = self.Trans.LlvmGen
if not isinstance(Node.target, ast.Name):
return
TargetName = Node.target.id
Gen._unregister_temp_ptr(StrVal)
PtrVal = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"str_ptr_copy")
Gen.builder.store(StrVal, PtrVal)
CharType = ir.IntType(8)
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
LoopVar = Gen._alloca_entry(CharType, name=TargetName)
Gen.variables[TargetName] = LoopVar
Gen._store(ir.Constant(CharType, 0), LoopVar)
CondBB = Gen.func.append_basic_block(name="strfor.cond")
BodyBB = Gen.func.append_basic_block(name="strfor.body")
StepBB = Gen.func.append_basic_block(name="strfor.step")
ElseBB = Gen.func.append_basic_block(name="strfor.else") if Node.orelse else None
AfterBB = Gen.func.append_basic_block(name="strfor.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(StepBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
CurrentPtr = Gen._load(PtrVal, name="current_ptr")
RawChar = Gen._load(CurrentPtr, name="raw_char")
NullCond = Gen.builder.icmp_signed('==', RawChar, ir.Constant(CharType, 0), name="is_null")
Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB)
Gen.builder.position_at_start(BodyBB)
Gen._store(RawChar, LoopVar)
Gen._record_var_signedness(TargetName, 'char')
Gen._reg_values[TargetName] = RawChar
self.HandleBodyLlvm(Node.body)
if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawChar:
del Gen._reg_values[TargetName]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(StepBB)
Gen.builder.position_at_start(StepBB)
CurrentPtr2 = Gen._load(PtrVal, name="current_ptr2")
NextPtr = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr")
Gen._store(NextPtr, PtrVal)
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)
def _HandleForIterLlvm(self, Node, ClassName):
Gen = self.Trans.LlvmGen
if not isinstance(Node.target, ast.Name):
return
TargetName = Node.target.id
IterVal = self.HandleExprLlvm(Node.iter)
if not IterVal:
return
Gen._unregister_temp_ptr(IterVal)
if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8:
IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
IterCall = Gen._get_function(f'{ClassName}.__iter__')
IterResult = Gen.builder.call(IterCall, [IterVal], name=f"call_{ClassName}.__iter__")
Gen._unregister_temp_ptr(IterResult)
if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8:
IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"cast_iter_{ClassName}")
NextCall = Gen._get_function(f'{ClassName}.__next__')
StopFlagPtr = Gen._alloca_entry(ir.IntType(1), name="stop_iter_flag")
Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr)
NextReturnType = NextCall.function_type.return_type
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
LoopVar = Gen._alloca_entry(NextReturnType, name=TargetName)
Gen.variables[TargetName] = LoopVar
CondBB = Gen.func.append_basic_block(name="iter.cond")
BodyBB = Gen.func.append_basic_block(name="iter.body")
StepBB = Gen.func.append_basic_block(name="iter.step")
ElseBB = Gen.func.append_basic_block(name="iter.else") if Node.orelse else None
AfterBB = Gen.func.append_basic_block(name="iter.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(StepBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr)
NextCallArgs = [IterResult, StopFlagPtr]
if NextCall and len(NextCall.function_type.args) > len(NextCallArgs):
last_param_type = NextCall.function_type.args[-1]
if (isinstance(last_param_type, ir.PointerType)
and isinstance(last_param_type.pointee, ir.PointerType)
and isinstance(last_param_type.pointee.pointee, ir.IntType)
and last_param_type.pointee.pointee.width == 8):
null_msg = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null")
NextCallArgs.append(null_msg)
NextVal = Gen.builder.call(NextCall, NextCallArgs, name=f"call_{ClassName}.__next__")
StopFlag = Gen.builder.load(StopFlagPtr, name="stop_flag")
Cond = Gen.builder.icmp_signed('==', StopFlag, ir.Constant(ir.IntType(1), 0), name="iter_cond")
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
Gen._store(NextVal, LoopVar)
Gen._reg_values[TargetName] = NextVal
self.HandleBodyLlvm(Node.body)
if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is NextVal:
del Gen._reg_values[TargetName]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(StepBB)
Gen.builder.position_at_start(StepBB)
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)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,302 @@
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
import ast
class IfHandle(BaseHandle):
def _get_attr_full_name(self, node):
if isinstance(node, ast.Attribute):
parts = []
cur = 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):
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):
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 = self._get_attr_full_name(arg)
if full_name:
return full_name
return None
def _evaluate_cif_condition(self, node):
if not isinstance(node, ast.Call):
return None
args = node.args
if not args:
return False
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 = self._resolve_macro_name(args[0])
if name is None:
return False
return self._is_macro_defined(name)
elif kind == 'CIfndef':
name = self._resolve_macro_name(args[0])
if name is None:
return True
return not self._is_macro_defined(name)
elif kind == 'CIf':
return self._eval_const_expr(args[0])
return None
def _is_macro_defined(self, name):
Gen = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
return True
if name in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[name]
if getattr(info, 'IsDefine', False):
return True
platform_macros = self._get_platform_macros()
return name in platform_macros
def _get_macro_value(self, name):
Gen = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
val = Gen._define_constants[name]
if isinstance(val, (int, float)):
return val
if name in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[name]
if getattr(info, 'IsDefine', False):
val = getattr(info, 'DefineValue', 0)
if isinstance(val, (int, float)):
return val
platform_macros = self._get_platform_macros()
if name in platform_macros:
return platform_macros[name]
return None
def _get_platform_macros(self):
Gen = self.Trans.LlvmGen
macros = {}
pi = getattr(Gen, '_platform_info', {})
ptr_size = 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):
if isinstance(node, ast.Constant):
val = node.value
if isinstance(val, bool):
return 1 if val else 0
if isinstance(val, int):
return val
if isinstance(val, float):
return 1 if val != 0.0 else 0
return 0
if isinstance(node, ast.Name):
name = node.id
val = self._get_macro_value(name)
if val is not None:
return val
return None
if isinstance(node, ast.Attribute):
full_key = self._get_attr_full_name(node)
if full_key:
val = self._get_macro_value(full_key)
if val is not None:
return val
short_name = full_key.split('.')[-1] if '.' in full_key else full_key
val = self._get_macro_value(short_name)
if val is not None:
return val
return None
if isinstance(node, ast.UnaryOp):
operand = self._eval_const_expr(node.operand)
if operand is None:
return None
if isinstance(node.op, ast.Not):
return 1 if not operand else 0
if isinstance(node.op, ast.USub):
return -operand
if isinstance(node.op, ast.Invert):
return ~operand
return None
if isinstance(node, ast.BinOp):
left = self._eval_const_expr(node.left)
right = self._eval_const_expr(node.right)
if left is None or right is None:
return None
try:
if isinstance(node.op, ast.Add):
return left + right
elif isinstance(node.op, ast.Sub):
return left - right
elif isinstance(node.op, ast.Mult):
return left * right
elif isinstance(node.op, ast.FloorDiv):
return left // right if right != 0 else 0
elif isinstance(node.op, ast.Mod):
return left % right if right != 0 else 0
elif isinstance(node.op, ast.LShift):
return left << right
elif isinstance(node.op, ast.RShift):
return left >> right
elif isinstance(node.op, ast.BitOr):
return left | right
elif isinstance(node.op, ast.BitAnd):
return left & right
elif isinstance(node.op, ast.BitXor):
return left ^ right
except Exception:
return None
return None
if isinstance(node, ast.BoolOp):
if isinstance(node.op, ast.And):
for val in node.values:
result = self._eval_const_expr(val)
if result is None:
return None
if not result:
return 0
return 1
elif isinstance(node.op, ast.Or):
for val in node.values:
result = self._eval_const_expr(val)
if result is None:
return None
if result:
return 1
return 0
if isinstance(node, ast.Compare):
left = self._eval_const_expr(node.left)
if left is None:
return None
for op, comparator in zip(node.ops, node.comparators):
right = self._eval_const_expr(comparator)
if right is None:
return None
if isinstance(op, ast.Eq):
result = left == right
elif isinstance(op, ast.NotEq):
result = left != right
elif isinstance(op, ast.Lt):
result = left < right
elif isinstance(op, ast.LtE):
result = left <= right
elif isinstance(op, ast.Gt):
result = left > right
elif isinstance(op, ast.GtE):
result = left >= right
else:
return None
if not result:
return 0
return 1
if isinstance(node, ast.Call):
if self._is_cif_call(node):
return self._evaluate_cif_condition(node)
return None
def _HandleIfLlvm(self, Node):
Gen = self.Trans.LlvmGen
if self._is_cif_call(Node.test):
compile_time_val = 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 = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
is_const = 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 = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
obj_val = 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._zero_const(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._zero_const(Cond.type), name="ifcond")
ThenBB = Gen.func.append_basic_block(name="then")
ElseBB = Gen.func.append_basic_block(name="else") if Node.orelse else None
MergeBB = 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,333 @@
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):
Gen = self.Trans.LlvmGen
SubjectVal = self.HandleExprLlvm(Node.subject)
if not SubjectVal:
return
IsRenumMatch = False
RenumName = None
SubjectPtr = None
if isinstance(Node.subject, ast.Name):
VarName = Node.subject.id
if VarName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[VarName]
if getattr(TypeInfo, 'IsRenum', False):
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 = case.pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName and VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None):
EnumName = SymInfo.EnumName
if EnumName in self.Trans.SymbolTable:
EnumInfo = self.Trans.SymbolTable[EnumName]
if getattr(EnumInfo, 'IsRenum', False):
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 = SubjectVal.type
DefaultBB = Gen.func.append_basic_block(name="match.default")
AfterBB = Gen.func.append_basic_block(name="match.end")
CaseBBs = []
CaseValues = []
HasDefault = False
HasNoBreak = []
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val = self.HandleExprLlvm(pattern.value)
if Val:
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 = self.HandleExprLlvm(SubPattern.value)
if Val:
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):
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 = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx = 0
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases = 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, RenumName, SubjectPtr):
Gen = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="load_match_subj")
tag_ptr = Gen.builder.gep(SubjectPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="match_tag_ptr")
TagVal = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB = Gen.func.append_basic_block(name="match.default")
AfterBB = Gen.func.append_basic_block(name="match.end")
CaseBBs = []
CaseValues = []
CaseBindings = []
HasDefault = False
HasNoBreak = []
for i, case in enumerate(Node.cases):
pattern = case.pattern
bindings = []
if isinstance(pattern, ast.MatchClass):
cls_node = pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
TagValue = None
if VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False):
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
NestedStructName = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
members = Gen.class_members.get(NestedStructName, [])
payload_members = [(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 = self.HandleExprLlvm(pattern.value)
if Val:
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):
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 = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx = 0
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node = pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType = Gen.structs[NestedStructName]
NestedStructPtrType = ir.PointerType(NestedStructType)
variant_ptr = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
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,135 @@
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 RaiseHandle(BaseHandle):
def _get_exception_code(self, ExcName):
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):
Gen = self.Trans.LlvmGen
exc_val = ir.Constant(ir.IntType(32), 1)
exc_msg = None
IsStopIteration = 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 = 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 = 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 = 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 = 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 __import__('lib.constants.config', fromlist=['mode']).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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
val = 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 __import__('lib.constants.config', fromlist=['mode']).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 = Gen.func.type.pointee.return_type
Gen.builder.ret(ir.Constant(ret_type, 0))
else:
Gen.builder.ret_void()
return
if Gen.eh_except_block_stack:
ExceptBB, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1]
Gen._store(exc_val, exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr = 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 = None
eh_code_arg = 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 = None
eh_code_arg = 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()

View File

@@ -0,0 +1,155 @@
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, CTypeHelper
import ast
import llvmlite.ir as ir
class ReturnHandle(BaseHandle):
def _find_active_finally(self, Gen):
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):
Gen = self.Trans.LlvmGen
active_finally = self._find_active_finally(Gen)
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
return_values = []
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 = []
expected_types = []
for i, val in enumerate(return_values):
ReturnTypeInfo = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
IsRetPtr = 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 = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
expected_types.append(ExpectedType)
Val = 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(expected_types)
result = 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, pending_ret_flag, pending_ret_val = active_finally
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 = self.HandleExprLlvm(Node.value)
if Val:
ret_type = 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(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, pending_ret_flag, pending_ret_val = active_finally
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 = Gen.func.ftype.return_type
if isinstance(struct_type, ir.LiteralStructType):
result = 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 = struct_type.elements[j]
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:
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, pending_ret_flag, pending_ret_val = active_finally
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, pending_ret_flag, pending_ret_val = active_finally
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, pending_ret_flag, pending_ret_val = active_finally
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
ret_type = 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.IdentifiedStructType):
if ret_type.elements:
zero_val = 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,354 @@
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 CSpecialCallHandle(BaseHandle):
def _HandleCIfLlvm(self, Node):
Gen = self.Trans.LlvmGen
if Node.args:
ArgVal = 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._zero_const(ArgVal.type), name="cif_cond")
if isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond")
return ir.Constant(ir.IntType(1), 0)
def _HandleCAddrLlvm(self, Node):
Gen = 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._alloca_entry(StructType, name=f"{ClassName}_obj")
Gen.builder.store(ir.Constant(StructType, None), 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):
Gen = self.Trans.LlvmGen
if len(Node.args) >= 2:
target_arg = Node.args[0]
value_arg = Node.args[1]
target_ptr = 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 target_arg.func.value.id == 't':
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):
Gen = self.Trans.LlvmGen
if len(Node.args) < 2:
return ir.Constant(ir.IntType(32), 0)
src_val = self.HandleExprLlvm(Node.args[0])
dst_val = 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)
loaded = Gen._load(src_val, name="cload_src")
if loaded is None:
return ir.Constant(ir.IntType(32), 0)
pointee = dst_val.type.pointee
val_to_store = loaded
if isinstance(pointee, ir.IntType) and isinstance(loaded.type, ir.IntType):
if loaded.type.width < pointee.width:
val_to_store = Gen.builder.zext(loaded, pointee, name="cload_zext")
elif loaded.type.width > pointee.width:
val_to_store = Gen.builder.trunc(loaded, pointee, name="cload_trunc")
elif isinstance(pointee, ir.PointerType) and isinstance(loaded.type, ir.PointerType):
val_to_store = Gen.builder.bitcast(loaded, pointee, name="cload_bitcast")
elif loaded.type != pointee:
target_ptr = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cload_cast")
loaded = Gen._load(target_ptr, name="cload_casted")
if loaded is None:
return ir.Constant(ir.IntType(32), 0)
val_to_store = loaded
Gen._store(val_to_store, dst_val)
return ir.Constant(ir.IntType(32), 1)
def _HandleCDerefLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
arg_val = self.HandleExprLlvm(Node.args[0])
if arg_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(arg_val.type, ir.PointerType):
loaded = Gen._load(arg_val, name="deref")
if loaded is not None:
return loaded
return arg_val
def _HandleCPtrToIntLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return ir.Constant(ir.IntType(64), 0)
arg_val = 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:
from lib.includes.t import CTypeRegistry
ctype_cls = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
try:
inst = ctype_cls()
cname = getattr(inst, 'CName', '')
if cname:
return cname
except Exception:
pass
return None
def _HandleTSpecialCallLlvm(self, Node):
Gen = self.Trans.LlvmGen
if not Node.args:
return None
attr = Node.func.attr
if attr == 'CType':
return self._HandleCTypeLlvm(Node)
target_type = self._ResolveTAttrToCName(attr)
if target_type is not None:
is_ptr_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 second_arg.value.id == 't' and second_arg.attr == 'CPtr':
is_ptr_cast = True
elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr':
is_ptr_cast = True
if is_ptr_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):
Gen = self.Trans.LlvmGen
arg_val = self.HandleExprLlvm(Node.args[0])
if not arg_val:
return None
target_type_str = 'unsigned long long'
if len(Node.args) >= 2:
type_parts = []
ptr_count = 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 type_arg.value.id == 't':
type_attr = type_arg.attr
_PREFIX_MAP = {
'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, attr):
Gen = self.Trans.LlvmGen
from lib.includes.t import CTypeRegistry
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 first_arg.func.value.id == 't' 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 and 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")
return None

View File

@@ -0,0 +1,211 @@
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):
if isinstance(type_node, ast.Name):
name = 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 = 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 = self._get_exception_type_code(elt)
if code != 1:
return code
return 1
return 1
def _get_exception_name(self, type_node):
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):
name = 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 = [self.Trans.exception_registry[name]]
self._collect_descendant_codes(name, codes)
return codes
def _collect_descendant_codes(self, parent_name, codes):
for child_name, parent in self.Trans.exception_parents.items():
if parent == parent_name:
child_code = 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):
Gen = self.Trans.LlvmGen
if not Gen.func:
return
exception_code = Gen._alloca_entry(ir.IntType(32), name="eh_code")
eh_message = Gen._alloca_entry(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(Node.finalbody)
if HasFinally:
Gen.eh_finally_stack.append((None, None, None))
else:
Gen.eh_finally_stack.append(None)
DispatchBB = Gen.func.append_basic_block(name="try.dispatch")
AfterBB = Gen.func.append_basic_block(name="try.after")
except_blocks = []
for i, handler in enumerate(Node.handlers):
ExcTypeCodes = [1]
if handler.type:
ExcTypeCodes = self._get_all_match_codes(handler.type)
ExceptBB = 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 = Gen.func.append_basic_block(name="try.body")
ElseBB = 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 = Gen._load(exception_code, name="load_eh_code")
next_check_bb = None
handler_var_map = {}
UnhandledBB = Gen.func.append_basic_block(name="try.unhandled")
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
MatchBB = 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 = None
for code in ExcTypeCodes:
is_code_match = 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 = Gen._alloca_entry(ir.IntType(8).as_pointer(), name=handler.name)
eh_msg_val = 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 = None
eh_code_out_arg = 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 = Gen._load(eh_message, name="load_eh_msg_propagate")
eh_code_val_prop = 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 = 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(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 = None
if idx in handler_var_map:
hname, var_alloca, old_var = handler_var_map[idx]
Gen.variables[hname] = var_alloca
self.HandleBodyLlvm(handler.body)
if idx in handler_var_map:
hname, _, old_var = handler_var_map[idx]
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 = Gen.func.append_basic_block(name="try.finally")
pending_ret_flag = Gen._alloca_entry(ir.IntType(32), name="pending_ret_flag")
pending_ret_val = Gen._alloca_entry(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 = Gen._load(pending_ret_flag, name="load_ret_flag")
ret_flag_is_set = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
RetBB = Gen.func.append_basic_block(name="finally.ret")
ContinueBB = 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 = 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)

File diff suppressed because it is too large Load Diff

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):
Gen = self.Trans.LlvmGen
if Gen._direct_values:
for var_name in list(Gen._direct_values.keys()):
OldVal = Gen._direct_values.pop(var_name)
if var_name not in Gen.variables or Gen.variables.get(var_name) is None:
saved_block = Gen.builder.block
entry_block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var = 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 = Gen.func.append_basic_block(name="while.cond")
BodyBB = Gen.func.append_basic_block(name="while.body")
ElseBB = Gen.func.append_basic_block(name="while.else") if Node.orelse else None
AfterBB = 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 = 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._zero_const(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,138 @@
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):
Gen = self.Trans.LlvmGen
for item in Node.items:
context_expr = item.context_expr
asname = None
target = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
if target and isinstance(target, ast.Name):
asname = target.id
ClassName = 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:
if ClassName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[ClassName]
if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False):
pass
else:
ClassName = None
else:
ClassName = None
elif isinstance(context_expr, ast.Name):
VarName = context_expr.id
if VarName in Gen.var_struct_class:
ClassName = Gen.var_struct_class[VarName]
ctx_val = self.HandleExprLlvm(context_expr)
if not ctx_val:
continue
original_ctx_val = ctx_val
if ClassName and isinstance(ctx_val.type, ir.PointerType):
pointee = ctx_val.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found = Gen.find_struct_by_pointee(pointee)
if found:
CN, ST = found
ClassName = CN
StructPtrType = 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 = Gen._alloca_entry(ctx_val.type, name="__with_ctx")
Gen._store(ctx_val, ctx_alloca)
Gen._unregister_temp_ptr(ctx_val)
if ClassName:
Gen.var_struct_class['__with_ctx'] = ClassName
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
original_asname_heap_ptr = Gen._var_to_heap_ptr.get(asname) if asname else None
ctx_is_var_ref = isinstance(context_expr, ast.Name)
enter_result = None
if ClassName:
EnterFuncName = f'{ClassName}.__enter__'
if EnterFuncName in Gen.functions:
ctx_loaded = Gen._load(ctx_alloca, name="__with_ctx")
enter_call = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_loaded], name="call_enter")
enter_result = enter_call
if isinstance(enter_call.type, ir.PointerType):
pointee = 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 = Gen.find_struct_by_pointee(enter_result.type.pointee)
if found:
CN, ST = found
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 = Gen._reg_values[asname]
var = Gen._alloca_entry(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 = 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 = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
Gen._store(CastedVal, VarPtr)
else:
NewVar = 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
self.Trans.VarScopes.append({})
if asname:
self.Trans.VarScopes[-1][asname] = True
self.HandleBodyLlvm(Node.body)
if self.Trans.VarScopes:
self.Trans.VarScopes.pop()
if ClassName:
ExitFuncName = f'{ClassName}.__exit__'
if ExitFuncName in Gen.functions:
ctx_loaded = 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 = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
enter_int = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
same_ptr = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
with_free_bb = Gen.func.append_basic_block("with_free_ctx")
with_skip_bb = 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 = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func = 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 = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func = 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