补充
This commit is contained in:
471
lib/core/Handles/HandlesAnnAssign.py
Normal file
471
lib/core/Handles/HandlesAnnAssign.py
Normal 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
|
||||
57
lib/core/Handles/HandlesAssert.py
Normal file
57
lib/core/Handles/HandlesAssert.py
Normal 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)
|
||||
1657
lib/core/Handles/HandlesAssign.py
Normal file
1657
lib/core/Handles/HandlesAssign.py
Normal file
File diff suppressed because it is too large
Load Diff
212
lib/core/Handles/HandlesAugAssign.py
Normal file
212
lib/core/Handles/HandlesAugAssign.py
Normal 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)
|
||||
1364
lib/core/Handles/HandlesBase.py
Normal file
1364
lib/core/Handles/HandlesBase.py
Normal file
File diff suppressed because it is too large
Load Diff
76
lib/core/Handles/HandlesBody.py
Normal file
76
lib/core/Handles/HandlesBody.py
Normal 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)
|
||||
965
lib/core/Handles/HandlesClassDef.py
Normal file
965
lib/core/Handles/HandlesClassDef.py
Normal 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
|
||||
96
lib/core/Handles/HandlesDelete.py
Normal file
96
lib/core/Handles/HandlesDelete.py
Normal 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__")
|
||||
429
lib/core/Handles/HandlesExpr.py
Normal file
429
lib/core/Handles/HandlesExpr.py
Normal 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}")
|
||||
# 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 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)
|
||||
578
lib/core/Handles/HandlesExprAsm.py
Normal file
578
lib/core/Handles/HandlesExprAsm.py
Normal 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
|
||||
1161
lib/core/Handles/HandlesExprAttr.py
Normal file
1161
lib/core/Handles/HandlesExprAttr.py
Normal file
File diff suppressed because it is too large
Load Diff
854
lib/core/Handles/HandlesExprBuiltin.py
Normal file
854
lib/core/Handles/HandlesExprBuiltin.py
Normal 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)
|
||||
3350
lib/core/Handles/HandlesExprCall.py
Normal file
3350
lib/core/Handles/HandlesExprCall.py
Normal file
File diff suppressed because it is too large
Load Diff
110
lib/core/Handles/HandlesExprFormat.py
Normal file
110
lib/core/Handles/HandlesExprFormat.py
Normal 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")
|
||||
232
lib/core/Handles/HandlesExprLambda.py
Normal file
232
lib/core/Handles/HandlesExprLambda.py
Normal 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
|
||||
402
lib/core/Handles/HandlesExprOps.py
Normal file
402
lib/core/Handles/HandlesExprOps.py
Normal 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
|
||||
240
lib/core/Handles/HandlesExprUtils.py
Normal file
240
lib/core/Handles/HandlesExprUtils.py
Normal 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)
|
||||
495
lib/core/Handles/HandlesFor.py
Normal file
495
lib/core/Handles/HandlesFor.py
Normal 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)
|
||||
1382
lib/core/Handles/HandlesFunctions.py
Normal file
1382
lib/core/Handles/HandlesFunctions.py
Normal file
File diff suppressed because it is too large
Load Diff
302
lib/core/Handles/HandlesIf.py
Normal file
302
lib/core/Handles/HandlesIf.py
Normal 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)
|
||||
1884
lib/core/Handles/HandlesImports.py
Normal file
1884
lib/core/Handles/HandlesImports.py
Normal file
File diff suppressed because it is too large
Load Diff
333
lib/core/Handles/HandlesMatch.py
Normal file
333
lib/core/Handles/HandlesMatch.py
Normal 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)
|
||||
135
lib/core/Handles/HandlesRaise.py
Normal file
135
lib/core/Handles/HandlesRaise.py
Normal 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()
|
||||
155
lib/core/Handles/HandlesReturn.py
Normal file
155
lib/core/Handles/HandlesReturn.py
Normal 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()
|
||||
354
lib/core/Handles/HandlesSpecialCall.py
Normal file
354
lib/core/Handles/HandlesSpecialCall.py
Normal 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
|
||||
211
lib/core/Handles/HandlesTry.py
Normal file
211
lib/core/Handles/HandlesTry.py
Normal 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)
|
||||
1052
lib/core/Handles/HandlesTypeMerge.py
Normal file
1052
lib/core/Handles/HandlesTypeMerge.py
Normal file
File diff suppressed because it is too large
Load Diff
54
lib/core/Handles/HandlesWhile.py
Normal file
54
lib/core/Handles/HandlesWhile.py
Normal 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)
|
||||
138
lib/core/Handles/HandlesWith.py
Normal file
138
lib/core/Handles/HandlesWith.py
Normal 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)
|
||||
32
lib/core/Handles/__init__.py
Normal file
32
lib/core/Handles/__init__.py
Normal 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
|
||||
Reference in New Issue
Block a user