可用的回归测试通过的标准版本

This commit is contained in:
2026-06-18 00:39:43 +08:00
parent bffb0cb6b7
commit e02c867edf
365 changed files with 22562 additions and 24532 deletions

View File

@@ -2,7 +2,7 @@ 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.Handles.HandlesBase import BaseHandle, CTypeInfo
from lib.includes import t
import ast
import llvmlite.ir as ir
@@ -33,7 +33,7 @@ class AnnAssignHandle(BaseHandle):
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)
NewVar = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, NewVar)
Gen.variables[VarName] = NewVar
@@ -90,7 +90,7 @@ class AnnAssignHandle(BaseHandle):
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}")
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}"
@@ -195,7 +195,7 @@ class AnnAssignHandle(BaseHandle):
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)
var = Gen._allocaEntry(VarType, name=VarName)
Gen.variables[VarName] = var
Gen._record_var_signedness(VarName, False)
if Node.value and isinstance(Node.value, ast.List):
@@ -267,7 +267,7 @@ class AnnAssignHandle(BaseHandle):
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)
var = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
@@ -294,7 +294,7 @@ class AnnAssignHandle(BaseHandle):
is_vtable_class = True
break
if is_vtable_class:
var = Gen._alloca_entry(InitValue.type, name=VarName)
var = Gen._allocaEntry(InitValue.type, name=VarName)
Gen._store(InitValue, var)
Gen.variables[VarName] = var
if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs:
@@ -329,7 +329,7 @@ class AnnAssignHandle(BaseHandle):
Gen.variables[VarName] = GVar
Gen._record_var_signedness(VarName, IsUnsigned)
return
var = Gen._alloca_entry(VarType, name=VarName)
var = Gen._allocaEntry(VarType, name=VarName)
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee = InitValue.type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
@@ -340,7 +340,7 @@ class AnnAssignHandle(BaseHandle):
is_vtable_class = True
break
if is_vtable_class and not isinstance(VarType, ir.PointerType):
var = Gen._alloca_entry(InitValue.type, name=VarName)
var = Gen._allocaEntry(InitValue.type, name=VarName)
VarType = InitValue.type
IsPtr = True
Gen._store(InitValue, var)
@@ -356,7 +356,7 @@ class AnnAssignHandle(BaseHandle):
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)
var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName)
VarType = ir.PointerType(pointee)
break
if InitValue:
@@ -435,8 +435,12 @@ class AnnAssignHandle(BaseHandle):
AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if AttrTypeInfo:
AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo)
except Exception as e:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
if Value:
self._HandleAttributeStoreLlvm(Node.target, Value)

View File

@@ -2,7 +2,7 @@ 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, FuncMeta
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.includes import t
import ast
import llvmlite.ir as ir
@@ -89,12 +89,12 @@ class AssignHandle:
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt")
fmt_var_name = f"__{VarName}_fmt"
if fmt_var_name not in Gen.variables:
fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
fmt_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
Gen.variables[fmt_var_name] = fmt_alloca
Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name])
kind_var_name = f"__{VarName}_kind"
if kind_var_name not in Gen.variables:
kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name)
kind_alloca = Gen._allocaEntry(ir.IntType(32), name=kind_var_name)
Gen.variables[kind_var_name] = kind_alloca
Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name])
if VarName not in Gen.variables:
@@ -116,12 +116,12 @@ class AssignHandle:
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt")
fmt_var_name = f"__{VarName}_fmt"
if fmt_var_name not in Gen.variables:
fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
fmt_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name)
Gen.variables[fmt_var_name] = fmt_alloca
Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name])
kind_var_name = f"__{VarName}_kind"
if kind_var_name not in Gen.variables:
kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name)
kind_alloca = Gen._allocaEntry(ir.IntType(32), name=kind_var_name)
Gen.variables[kind_var_name] = kind_alloca
Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name])
if VarName not in Gen.variables:
@@ -129,7 +129,7 @@ class AssignHandle:
Gen.variables[VarName] = dummy_var
return
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list':
va_list_ptr = Gen._alloca_entry(ir.IntType(8).as_pointer(), name="va_list")
va_list_ptr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list")
Gen.variables[VarName] = va_list_ptr
return
IsStructCtor = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name)
@@ -147,7 +147,7 @@ class AssignHandle:
if IsUnion:
Value = self.HandleExprLlvm(Node.value)
if Value:
var = Gen._alloca_entry(Value.type, name=VarName)
var = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, var)
Gen.variables[VarName] = var
return
@@ -160,7 +160,7 @@ class AssignHandle:
elif VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
if isinstance(OldVal.type, ir.PointerType):
var = Gen._alloca_entry(OldVal.type, name=VarName)
var = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
@@ -168,7 +168,7 @@ class AssignHandle:
elif VarName in Gen._direct_values:
OldVal = Gen._direct_values.pop(VarName)
if isinstance(OldVal.type, ir.PointerType):
var = Gen._alloca_entry(OldVal.type, name=VarName)
var = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
ExistingPtr = var
@@ -195,7 +195,7 @@ class AssignHandle:
return
if isinstance(Value.type, ir.VoidType):
return
Gen._unregister_temp_ptr(Value)
Gen._UnregisterTempPtr(Value)
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found_class = None
found = Gen.find_struct_by_pointee(Value.type.pointee)
@@ -219,7 +219,7 @@ class AssignHandle:
if VarName in Gen.variables and Gen.variables[VarName] is not None:
Gen._store(Value, Gen.variables[VarName])
else:
var = Gen._alloca_entry(Value.type, name=VarName)
var = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, var)
Gen.variables[VarName] = var
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
@@ -231,17 +231,17 @@ class AssignHandle:
dst_fmt_var = f"__{VarName}_fmt"
if src_fmt_var in Gen.variables:
if dst_fmt_var not in Gen.variables:
dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
dst_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
Gen.variables[dst_fmt_var] = dst_alloca
src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}")
src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}")
Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var])
src_kind_var = f"__{call_func_name}_kind"
dst_kind_var = f"__{VarName}_kind"
if src_kind_var in Gen.variables:
if dst_kind_var not in Gen.variables:
dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var)
dst_kind_alloca = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var)
Gen.variables[dst_kind_var] = dst_kind_alloca
src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}")
src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}")
Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var])
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
return
@@ -260,13 +260,13 @@ class AssignHandle:
return
if VarName in Gen._reg_values:
OldVal = Gen._reg_values[VarName]
var = Gen._alloca_entry(OldVal.type, name=VarName)
var = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal = Gen._direct_values.pop(VarName)
var = Gen._alloca_entry(OldVal.type, name=VarName)
var = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
if VarName in Gen.variables and Gen.variables[VarName] is not None:
@@ -277,12 +277,12 @@ class AssignHandle:
except AssertionError:
types_differ = False
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType):
LoadedValue = Gen._load(Value, name=f"load_{VarName}")
LoadedValue = Gen._load(Value, name=f"Load_{VarName}")
try:
loaded_differ = TargetType and LoadedValue.type != TargetType
Loaded_differ = TargetType and LoadedValue.type != TargetType
except AssertionError:
loaded_differ = False
if loaded_differ:
Loaded_differ = False
if Loaded_differ:
try:
Coerced = Gen._coerce_value(LoadedValue, TargetType)
if Coerced is not None:
@@ -308,12 +308,12 @@ class AssignHandle:
Gen._store(Value, GVar)
Gen.variables[VarName] = GVar
elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType):
LoadedValue = Gen._load(Value, name=f"load_{VarName}")
var = Gen._alloca_entry(LoadedValue.type, name=VarName)
LoadedValue = Gen._load(Value, name=f"Load_{VarName}")
var = Gen._allocaEntry(LoadedValue.type, name=VarName)
Gen._store(LoadedValue, var)
Gen.variables[VarName] = var
else:
var = Gen._alloca_entry(Value.type, name=VarName)
var = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, var)
Gen.variables[VarName] = var
is_u = Gen._check_node_unsigned(Node.value)
@@ -327,17 +327,17 @@ class AssignHandle:
dst_fmt_var = f"__{VarName}_fmt"
if src_fmt_var in Gen.variables:
if dst_fmt_var not in Gen.variables:
dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
dst_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var)
Gen.variables[dst_fmt_var] = dst_alloca
src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}")
src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}")
Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var])
src_kind_var = f"__{call_func_name}_kind"
dst_kind_var = f"__{VarName}_kind"
if src_kind_var in Gen.variables:
if dst_kind_var not in Gen.variables:
dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var)
dst_kind_alloca = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var)
Gen.variables[dst_kind_var] = dst_kind_alloca
src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}")
src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}")
Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var])
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
else:
@@ -403,12 +403,12 @@ class AssignHandle:
elif isinstance(Target, ast.Tuple):
if isinstance(Node.value, ast.Call):
FuncName = None
module_path = None
ModulePath = None
if isinstance(Node.value.func, ast.Name):
FuncName = Node.value.func.id
elif isinstance(Node.value.func, ast.Attribute):
FuncName = Node.value.func.attr
module_path = self.Trans.ExprCallHandle._get_module_path(Node.value.func.value)
ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value)
CReturnTypes = []
FuncDef = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None
if FuncDef:
@@ -436,8 +436,8 @@ class AssignHandle:
if not CReturnTypes:
sym_key = FuncName
if sym_key not in self.Trans.SymbolTable:
if module_path:
sym_key = f"{module_path}.{FuncName}"
if ModulePath:
sym_key = f"{ModulePath}.{FuncName}"
sym_info = self.Trans.SymbolTable.get(sym_key)
if sym_info and sym_info.IsFunction:
ret_type_info = getattr(sym_info, 'FuncPtrReturn', None)
@@ -604,7 +604,7 @@ class AssignHandle:
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)
NewVar = Gen._allocaEntry(Value.type, name=VarName)
Gen._store(Value, NewVar)
Gen.variables[VarName] = NewVar
@@ -620,7 +620,7 @@ class AssignHandle:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
SetterFunc = Gen._get_function(PropKey)
SetterFunc = Gen._get_function(PropKey + '$set')
if SetterFunc and SelfPtr:
Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}")
return
@@ -683,7 +683,7 @@ class AssignHandle:
if offset >= max_offset:
VarName = f"self.{AttrName}"
if VarName not in Gen.variables:
NewVar = Gen._alloca_entry(Value.type, name=AttrName)
NewVar = Gen._allocaEntry(Value.type, name=AttrName)
Gen.variables[VarName] = NewVar
Gen._store(Value, Gen.variables[VarName])
return
@@ -736,10 +736,10 @@ class AssignHandle:
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
SetterFunc = Gen._get_function(PropKey)
SetterFunc = Gen._get_function(PropKey + '$set')
if SetterFunc and ObjVal:
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}")
ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}")
Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}")
return
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
@@ -747,7 +747,7 @@ class AssignHandle:
if BaseHandle._is_char_pointer(ObjVal):
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}")
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}"
@@ -855,8 +855,8 @@ class AssignHandle:
self._StoreWithCoerce(Value, MemberPtr)
if not ClassName:
imported_modules = getattr(self.Trans, '_imported_modules', None)
import_aliases = getattr(self.Trans, '_import_aliases', {})
imported_modules = getattr(self.Trans, '_ImportedModules', None)
import_aliases = getattr(self.Trans, '_ImportAliases', {})
resolved_mod = import_aliases.get(VarName, VarName)
if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules):
PossibleKeys = [f"{VarName}.{AttrName}", AttrName]
@@ -874,14 +874,14 @@ class AssignHandle:
return
self._StoreWithCoerce(Value, GVar)
return
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
sha1_candidates = [VarName, resolved_mod]
for mod_name in imported_modules:
if mod_name.endswith(f".{VarName}") or mod_name == VarName:
if mod_name not in sha1_candidates:
sha1_candidates.append(mod_name)
for cand in sha1_candidates:
sha1 = module_sha1_map.get(cand)
sha1 = ModuleSha1Map.get(cand)
if sha1:
prefixed = f"{sha1}.{AttrName}"
if prefixed in Gen.module.globals:
@@ -945,7 +945,7 @@ class AssignHandle:
self._StoreWithCoerce(Value, MemberPtr)
return
elif isinstance(Target.value, ast.Call):
# Check if this is c.Deref(...) — we need the pointer, not the loaded value
# Check if this is c.Deref(...) — we need the pointer, not the Loaded value
ObjVal = None
is_cderef = (isinstance(Target.value.func, ast.Attribute) and
isinstance(Target.value.func.value, ast.Name) and
@@ -953,7 +953,7 @@ class AssignHandle:
Target.value.func.attr == 'Deref' and
Target.value.args)
if is_cderef:
# Get the pointer from c.Deref argument, don't load the value
# Get the pointer from c.Deref argument, don't Load the value
deref_arg = Target.value.args[0]
inner_val = self.HandleExprLlvm(deref_arg)
if inner_val and isinstance(inner_val.type, ir.PointerType):
@@ -1019,7 +1019,7 @@ class AssignHandle:
MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
self._StoreWithCoerce(Value, MemberPtr)
elif isinstance(pointee, ir.PointerType):
LoadedPtr = Gen._load(SubPtr, name=f"load_{AttrName}_ptr")
LoadedPtr = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr")
if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(LoadedPtr.type.pointee)
if found:
@@ -1049,8 +1049,8 @@ class AssignHandle:
if not ValueVal or not IndexVal:
return
if BaseHandle._is_char_pointer(IndexVal):
loaded_byte = Gen._load(IndexVal, name="load_char_idx_store")
IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx_store")
Loaded_byte = Gen._load(IndexVal, name="Load_char_idx_store")
IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store")
if isinstance(ValueVal.type, ir.IntType):
var_ptr = self._get_int_ptr(Target.value)
if var_ptr:
@@ -1116,7 +1116,7 @@ class AssignHandle:
ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)
return
arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp")
arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
Gen._store(ValueVal, arr_alloc)
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
self._StoreWithCoerce(Value, ElemPtr)

View File

@@ -1,212 +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)
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._allocaEntry(result.type, name=VarName)
Gen._store(result, NewVar)
Gen.variables[VarName] = NewVar
else:
Gen._reg_values[VarName] = result
Gen.variables[VarName] = None
return
Value = 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._allocaEntry(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)

View File

@@ -1,5 +1,5 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Dict, Tuple
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.constants import config as _config
@@ -950,7 +950,7 @@ class CTypeInfo:
if ModulePath:
resolved = False
if hasattr(SymbolTable, 'translator'):
import_aliases = getattr(SymbolTable.translator, '_import_aliases', {})
import_aliases = getattr(SymbolTable.translator, '_ImportAliases', {})
if ModulePath in import_aliases:
ModulePath = import_aliases[ModulePath]
resolved = True
@@ -1056,10 +1056,10 @@ class CTypeInfo:
if OriginalType and 'typedef' in OriginalType:
parts = OriginalType.split()
if len(parts) >= 2:
base_type_name = parts[1]
if not base_type_name.startswith('C'):
base_type_name = 'C' + base_type_name
CNAME = CTypeHelper.GetCName(base_type_name)
BaseType_name = parts[1]
if not BaseType_name.startswith('C'):
BaseType_name = 'C' + BaseType_name
CNAME = CTypeHelper.GetCName(BaseType_name)
if CNAME:
return cls.FromTypeName(CNAME)
Result = cls()

View File

@@ -67,10 +67,10 @@ class BodyHandle(BaseHandle):
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))
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._emit_temp_frees()
Gen._EmitTempFrees()
def HandleExprLlvm(self, Node, VarType=None):
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)

View File

@@ -2,7 +2,7 @@ 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.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolNode import SymbolNode
from lib.includes import t
import ast
@@ -345,6 +345,12 @@ class ClassHandle(BaseHandle):
if isinstance(item, ast.FunctionDef):
MethodName = item.name
FullMethodName = f"{ClassName}.{MethodName}"
# property setter/deleter 使用不同的函数名后缀
item_meta = self.Trans.FunctionHandler._ExtractFuncMeta(item.decorator_list)
if FuncMeta.PROPERTY_SETTER in item_meta:
FullMethodName = FullMethodName + '$set'
elif FuncMeta.PROPERTY_DELETER in item_meta:
FullMethodName = FullMethodName + '$del'
if FullMethodName not in Gen.class_methods[ClassName]:
Gen.class_methods[ClassName].append(FullMethodName)
Gen.register_method(ClassName, FullMethodName)
@@ -781,8 +787,8 @@ class ClassHandle(BaseHandle):
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(
from lib.core.Exportable import EnumMember as ExportEnumMember
enum_export = self.Trans.Exportable.add_enum(
name=ClassName,
lineno=Node.lineno,
is_public=True

View File

@@ -44,7 +44,7 @@ class DeleteHandle(BaseHandle):
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
DeleterFunc = Gen._get_function(PropKey)
DeleterFunc = Gen._get_function(PropKey + '$del')
if DeleterFunc and SelfPtr:
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
continue
@@ -57,7 +57,7 @@ class DeleteHandle(BaseHandle):
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)
DeleterFunc = Gen._get_function(PropKey + '$del')
if DeleterFunc:
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
continue
@@ -66,7 +66,7 @@ class DeleteHandle(BaseHandle):
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")
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():

View File

@@ -1,429 +1,429 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprHandle(BaseHandle):
def __init__(self, translator: "Translator"):
super().__init__(translator)
def GetOpSymbol(self, Op):
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op):
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op):
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node, Gen):
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None):
return self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name, ClassName, Gen):
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
return self._HandleNameLlvm(Node, VarType)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
elements = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len = len(elements)
elem_type = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
import re
match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size = array_len
if elem_type == 'i32':
alloc_size *= 4
elif elem_type == 'i16':
alloc_size *= 2
elif elem_type == 'float':
alloc_size *= 4
elif elem_type == 'double':
alloc_size *= 8
malloc_fn = None
malloc_arg_type = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
Gen.functions['malloc'] = malloc_fn
except Exception: # 回退malloc 函数创建失败时返回 null
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
ptr_as_int = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type == 'float':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr")
elif elem_type == 'double':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
Value = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
is_unsigned = getattr(inst, 'IsSigned', True) is False
mask = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match = __import__('re').match(r'^i(\d+)$', VarType)
if llvm_match:
width = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide = getattr(Node, 'kind', None) == 'u'
if len(Value) == 1 and not is_wide:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = __import__('re').match(r'^i(\d+)$', VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value = Value + '\x00'
wide_chars = [ord(c) for c in str_value]
target_count = len(wide_chars)
str_type = ir.ArrayType(ir.IntType(16), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
VarName = Node.id
define_constants = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val = define_constants[VarName]
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in getattr(Gen, '_define_constants', {}):
try:
sym_info = self.translator.SymbolTable.get(VarName)
if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None:
val = sym_info.DefineValue
if isinstance(val, int):
# Use VarType hint if available
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 优先检查 variablesalloca因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
return Gen._load(VarPtr, name=VarName)
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
return Gen._get_var_ptr('self')
if Gen._has_function(VarName):
func = Gen._get_function(VarName)
if func:
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
if VarName in Gen.class_methods:
return ir.Constant(ir.IntType(8).as_pointer(), None)
if VarName == 'True' or VarName == 'False':
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
if VarName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VarName]
if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False):
MangledName = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g = Gen.module.globals[MangledName]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
for sha1 in Gen.module_sha1_map.values():
prefixed = f"{sha1}.{VarName}"
if prefixed in Gen.module.globals:
g = Gen.module.globals[prefixed]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
if VarName in t_c_imported:
src_module, src_name = t_c_imported[VarName]
virtual_attr = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
return ir.Constant(ir.IntType(32), 0)
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprHandle(BaseHandle):
def __init__(self, translator: "Translator"):
super().__init__(translator)
def GetOpSymbol(self, Op):
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op):
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op):
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node, Gen):
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overLoad(self, ClassName, op_name, obj_val, Gen, other_val=None):
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name, ClassName, Gen):
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
return self._HandleNameLlvm(Node, VarType)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
elements = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len = len(elements)
elem_type = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
import re
match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size = array_len
if elem_type == 'i32':
alloc_size *= 4
elif elem_type == 'i16':
alloc_size *= 2
elif elem_type == 'float':
alloc_size *= 4
elif elem_type == 'double':
alloc_size *= 8
malloc_fn = None
malloc_arg_type = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
Gen.functions['malloc'] = malloc_fn
except Exception: # 回退malloc 函数创建失败时返回 null
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
ptr_as_int = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type == 'float':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr")
elif elem_type == 'double':
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
Value = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
is_unsigned = getattr(inst, 'IsSigned', True) is False
mask = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match = __import__('re').match(r'^i(\d+)$', VarType)
if llvm_match:
width = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide = getattr(Node, 'kind', None) == 'u'
if len(Value) == 1 and not is_wide:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
from lib.includes.t import CTypeRegistry as _CR
resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = __import__('re').match(r'^i(\d+)$', VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value = Value + '\x00'
wide_chars = [ord(c) for c in str_value]
target_count = len(wide_chars)
str_type = ir.ArrayType(ir.IntType(16), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node, VarType=None):
Gen = self.Trans.LlvmGen
VarName = Node.id
define_constants = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val = define_constants[VarName]
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in getattr(Gen, '_define_constants', {}):
try:
sym_info = self.translator.SymbolTable.get(VarName)
if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None:
val = sym_info.DefineValue
if isinstance(val, int):
# Use VarType hint if available
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
str_value = val + '\x00'
str_bytes = str_value.encode('utf-8')
str_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 优先检查 variablesalloca因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
return Gen._load(VarPtr, name=VarName)
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
return Gen.GetVarPtr('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.ModuleSha1Map.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)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -56,9 +56,9 @@ class ExprBuiltinHandle(BaseHandle):
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")
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
elif isinstance(Val.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result")
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
return Val
return ir.Constant(ir.IntType(1), 0)
elif FuncName == 'int':
@@ -254,7 +254,7 @@ class ExprBuiltinHandle(BaseHandle):
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")
char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf")
Gen.builder.store(val, char_var)
fmt_parts.append('%c')
fmt_args.append(char_var)
@@ -316,7 +316,7 @@ class ExprBuiltinHandle(BaseHandle):
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._RegisterTempPtr(str_val)
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
else:
val = self.HandleExprLlvm(arg)
@@ -325,7 +325,7 @@ class ExprBuiltinHandle(BaseHandle):
pointee = val.type.pointee
if not (isinstance(pointee, ir.IntType) and pointee.width == 8):
try:
val = Gen._load(val, name="print_load")
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}")
@@ -394,7 +394,7 @@ class ExprBuiltinHandle(BaseHandle):
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)
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
if result is not None:
return result
break
@@ -442,8 +442,12 @@ class ExprBuiltinHandle(BaseHandle):
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
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
resolved = CTypeRegistry.ResolveName(type_name)
if resolved:
ctype_cls, ptr_level = resolved
@@ -454,8 +458,12 @@ class ExprBuiltinHandle(BaseHandle):
if ptr_level > 0:
size_bytes = 8
return ir.Constant(ir.IntType(64), size_bytes)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
return ir.Constant(ir.IntType(64), 0)
struct_type = Gen.structs[type_name]
@@ -479,7 +487,7 @@ class ExprBuiltinHandle(BaseHandle):
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)
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
if result is not None:
return result
break
@@ -525,12 +533,12 @@ class ExprBuiltinHandle(BaseHandle):
if TypeInfo.IsEnum:
enum_type_name = arg_name
elif isinstance(arg, ast.Attribute):
last_part = None
LastPart = 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]
LastPart = arg.attr
if LastPart in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[LastPart]
if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None):
enum_type_name = AttrInfo.EnumName
elif isinstance(arg.value, ast.Attribute):
@@ -539,9 +547,9 @@ class ExprBuiltinHandle(BaseHandle):
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}"
LastPart = parts[-1]
qualified_name_dot = f"{enum_class_name}.{LastPart}"
qualified_name_under = f"{enum_class_name}_{LastPart}"
enum_member_found = None
for qname in (qualified_name_dot, qualified_name_under):
if qname in self.Trans.SymbolTable:
@@ -551,7 +559,7 @@ class ExprBuiltinHandle(BaseHandle):
break
if not enum_member_found:
for key in self.Trans.SymbolTable:
if key == last_part:
if key == LastPart:
info = self.Trans.SymbolTable[key]
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name:
enum_member_found = info

View File

@@ -48,9 +48,9 @@ class ExprCallHandle(BaseHandle):
elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
eh_code_ptr = arg
if eh_msg_ptr is None:
eh_msg_ptr = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null")
eh_msg_ptr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null")
if eh_code_ptr is None:
eh_code_ptr = Gen._alloca_entry(ir.IntType(32), name="eh_code_out_null")
eh_code_ptr = Gen._allocaEntry(ir.IntType(32), name="eh_code_out_null")
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr)
Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr)
CallArgs.append(eh_msg_ptr)
@@ -83,7 +83,7 @@ class ExprCallHandle(BaseHandle):
elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
eh_code_ptr = arg
if eh_msg_ptr is not None:
eh_msg_val = Gen._load(eh_msg_ptr, name=f"load_eh_msg_{func_name}")
eh_msg_val = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}")
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
is_error = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}")
OkBB = Gen.func.append_basic_block(name=f"ok_after_{func_name}")
@@ -114,7 +114,7 @@ class ExprCallHandle(BaseHandle):
ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1]
if ExceptBB is not None:
if has_eh_code_out and eh_code_ptr is not None:
eh_code_val = Gen._load(eh_code_ptr, name=f"load_eh_code_{func_name}")
eh_code_val = Gen._load(eh_code_ptr, name=f"Load_eh_code_{func_name}")
Gen._store(eh_code_val, exception_code)
else:
Gen._store(ir.Constant(ir.IntType(32), 1), exception_code)
@@ -199,8 +199,8 @@ class ExprCallHandle(BaseHandle):
def _HandleCallLlvm(self, Node):
Gen = self.Trans.LlvmGen
func_attr = None
module_path = None
FuncAttr = None
ModulePath = None
if isinstance(Node.func, ast.Name):
FuncName = Node.func.id
if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates:
@@ -231,9 +231,9 @@ class ExprCallHandle(BaseHandle):
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")
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
elif isinstance(Val.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result")
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
return Val
return ir.Constant(ir.IntType(1), 0)
elif FuncName == 'int':
@@ -355,7 +355,7 @@ class ExprCallHandle(BaseHandle):
return self._HandleCallLlvm(virtual_node)
# 检查是否是闭包变量lambda 赋值给变量后调用)
if FuncName in Gen.variables and Gen.variables[FuncName] is not None:
closure_ptr = Gen._load(Gen.variables[FuncName], name=f"load_closure_{FuncName}")
closure_ptr = Gen._load(Gen.variables[FuncName], name=f"Load_closure_{FuncName}")
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType):
st = closure_ptr.type.pointee
if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType):
@@ -428,30 +428,30 @@ class ExprCallHandle(BaseHandle):
type_name = Node.func.value.attr
SizeofNode = ast.Name(id=type_name, ctx=ast.Load())
return self._HandleSizeofLlvm(SizeofNode)
module_path = self._get_module_path(Node.func.value)
if module_path:
aliases = getattr(self.Trans, '_import_aliases', {})
first_part = module_path.split('.')[0]
ModulePath = self._get_ModulePath(Node.func.value)
if ModulePath:
aliases = getattr(self.Trans, '_ImportAliases', {})
first_part = ModulePath.split('.')[0]
if first_part in aliases:
module_path = aliases[first_part] + module_path[len(first_part):]
is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.module_sha1_map
ModulePath = aliases[first_part] + ModulePath[len(first_part):]
is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.ModuleSha1Map
is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False)))
if is_instance_var and not is_class_name:
return self._HandleMethodCallLlvm(Node)
func_attr = Node.func.attr
if func_attr in Gen.structs:
result = self._HandleClassNewLlvm(Node, func_attr)
FuncAttr = Node.func.attr
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and func_attr in self.Trans.ClassHandler._generic_class_templates:
return self._HandleGenericClassNewLlvm(Node, func_attr)
if func_attr in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[func_attr]
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncAttr in self.Trans.ClassHandler._generic_class_templates:
return self._HandleGenericClassNewLlvm(Node, FuncAttr)
if FuncAttr in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[FuncAttr]
if SymInfo.IsStruct:
if func_attr not in Gen.structs:
self._ensure_struct_declared(func_attr)
if func_attr in Gen.structs:
result = self._HandleClassNewLlvm(Node, func_attr)
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None):
@@ -459,58 +459,58 @@ class ExprCallHandle(BaseHandle):
if EnumName in self.Trans.SymbolTable:
EnumInfo = self.Trans.SymbolTable[EnumName]
if getattr(EnumInfo, 'IsRenum', False):
result = self._HandleREnumConstructLlvm(Node, EnumName, func_attr, SymInfo.value)
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
if result is not None:
return result
FullAttrKey = f"{module_path}.{func_attr}"
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if FullAttrKey in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[FullAttrKey]
if SymInfo.IsStruct:
if func_attr not in Gen.structs:
self._ensure_struct_declared(func_attr)
if func_attr in Gen.structs:
result = self._HandleClassNewLlvm(Node, func_attr)
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if is_class_name:
ClassName = Node.func.value.id
result = self._HandleStaticMethodCallLlvm(Node, ClassName, func_attr)
result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr)
if result is not None:
return result
FullAttrKey = f"{module_path}.{func_attr}"
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if FullAttrKey in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[FullAttrKey]
if getattr(SymInfo, 'IsTypedef', False):
return ir.Constant(ir.IntType(32), 0)
if getattr(SymInfo, 'IsStruct', False):
if func_attr not in Gen.structs:
self._ensure_struct_declared(func_attr)
if func_attr in Gen.structs:
result = self._HandleClassNewLlvm(Node, func_attr)
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if func_attr in Gen.structs:
result = self._HandleClassNewLlvm(Node, func_attr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if module_path == 'c':
if func_attr == 'Asm':
if ModulePath == 'c':
if FuncAttr == 'Asm':
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
elif func_attr == 'Addr':
elif FuncAttr == 'Addr':
return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
elif func_attr == 'Set':
elif FuncAttr == 'Set':
return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
elif func_attr == 'Load':
elif FuncAttr == 'Load':
return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
elif func_attr == 'Deref':
elif FuncAttr == 'Deref':
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
elif func_attr == 'DerefAs':
elif FuncAttr == 'DerefAs':
return self._HandleCDerefAsLlvm(Node)
elif func_attr == 'PtrToInt':
elif FuncAttr == 'PtrToInt':
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
elif func_attr in ('CIf', 'CElif'):
elif FuncAttr in ('CIf', 'CElif'):
return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
elif func_attr == 'CError':
elif FuncAttr == 'CError':
msg = "compile-time error"
if Node.args:
arg = Node.args[0]
@@ -520,52 +520,119 @@ class ExprCallHandle(BaseHandle):
msg = arg.s
lineno = getattr(Node, 'lineno', 0)
raise Exception(f"#error: {msg} (line {lineno})")
elif func_attr in ('AsmInp', 'AsmOut'):
elif FuncAttr in ('AsmInp', 'AsmOut'):
return ir.Constant(ir.IntType(32), 0)
elif func_attr == 'LLVMIR':
elif FuncAttr == 'LLVMIR':
return self._HandleLLVMIRLlvm(Node)
elif func_attr in ('LInp', 'LOut'):
elif FuncAttr in ('LInp', 'LOut'):
return ir.Constant(ir.IntType(32), 0)
if module_path == 't':
method_result_t = self._HandleMethodCallLlvm(Node)
if method_result_t is not None:
return method_result_t
raise Exception(f"Undefined method: 't.{func_attr}'")
if ModulePath == 't':
MethodResult_t = self._HandleMethodCallLlvm(Node)
if MethodResult_t is not None:
return MethodResult_t
raise Exception(f"Undefined method: 't.{FuncAttr}'")
if isinstance(Node.func.value, ast.Attribute):
inner_attr = Node.func.value.attr
if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)):
static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, func_attr)
static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr)
if static_result is not None:
return static_result
method_result_attr = self._HandleMethodCallLlvm(Node)
is_zero_attr = isinstance(method_result_attr, ir.Constant) and isinstance(method_result_attr.type, ir.IntType) and method_result_attr.constant == 0
if method_result_attr is not None and not is_zero_attr:
return method_result_attr
result = self._HandleExternalCallLlvm(Node, func_attr, module_path)
MethodResult_attr = self._HandleMethodCallLlvm(Node)
is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0
if MethodResult_attr is not None and not is_zero_attr:
return MethodResult_attr
result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath)
if result is not None:
return result
method_result = self._HandleMethodCallLlvm(Node)
is_zero_result = isinstance(method_result, ir.Constant) and isinstance(method_result.type, ir.IntType) and method_result.constant == 0
if is_zero_result and func_attr is not None:
mangled_name = Gen._mangle_func_name(func_attr, module_path if module_path and module_path != 't' else None)
MethodResult = self._HandleMethodCallLlvm(Node)
IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0
if IsZeroResult and FuncAttr is not None:
mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None)
if Gen._has_function(mangled_name):
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{func_attr}")
if method_result is None or is_zero_result:
imported = getattr(self.Trans, '_imported_modules', set())
aliases = getattr(self.Trans, '_import_aliases', {})
is_known = module_path in imported or module_path in aliases
if module_path and is_known:
raise Exception(f"Undefined symbol: '{module_path}.{func_attr}'")
if module_path and module_path not in {'t', 'c'} and not is_known:
raise Exception(f"Unknown module: '{module_path}' (undefined symbol: '{module_path}.{func_attr}')")
if not module_path and func_attr:
raise Exception(f"Undefined method: '{func_attr}'")
return method_result if method_result is not None else ir.Constant(ir.IntType(32), 0)
return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}")
if MethodResult is None or IsZeroResult:
imported = getattr(self.Trans, '_ImportedModules', set())
aliases = getattr(self.Trans, '_ImportAliases', {})
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
IsKnown = (ModulePath in imported or ModulePath in aliases or
ModulePath in ModuleSha1Map)
if not IsKnown and ModulePath and '.' in ModulePath:
LastPart = ModulePath.split('.')[-1]
IsKnown = (LastPart in imported or LastPart in aliases or
LastPart in ModuleSha1Map)
# 最后尝试: 用 FuncAttr 直接查找 Gen.functions_find_function 会遍历 SHA1 前缀)
if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}:
# 优先检查 FuncAttr 是否为 struct/类构造器
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
# 检查 FullAttrKey 是否为 struct如 hashlib.md5
if ModulePath:
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if FullAttrKey in self.Trans.SymbolTable:
FullSymInfo = self.Trans.SymbolTable[FullAttrKey]
if getattr(FullSymInfo, 'IsStruct', False) or getattr(FullSymInfo, 'IsCpythonObject', False):
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
fallback_func = Gen._find_function(FuncAttr)
if fallback_func is not None:
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen)
result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}")
return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func)
# 尝试从 stub 按需加载函数声明
if ModulePath in ModuleSha1Map:
sha1 = ModuleSha1Map[ModulePath]
stub_mangled = f"{sha1}.{FuncAttr}"
try:
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(stub_mangled, Gen)
except Exception:
stub_func_type = None
if not stub_func_type:
try:
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FuncAttr, Gen)
except Exception:
stub_func_type = None
if stub_func_type:
decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr
if decl_name not in Gen.functions:
func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name)
Gen.functions[decl_name] = func_decl
if decl_name != FuncAttr and FuncAttr not in Gen.functions:
Gen.functions[FuncAttr] = func_decl
else:
func_decl = Gen.functions[decl_name]
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
self._append_eh_msg_out_arg(CallArgs, func_decl, Gen)
result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}")
return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl)
if ModulePath and IsKnown:
raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'")
if ModulePath and ModulePath not in {'t', 'c'} and not IsKnown:
raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')")
if not ModulePath and FuncAttr:
raise Exception(f"Undefined method: '{FuncAttr}'")
return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0)
if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr):
return self._HandleTypeUnionCastLlvm(Node)
raise Exception(f"Unsupported call expression")
@@ -771,7 +838,7 @@ class ExprCallHandle(BaseHandle):
ast.copy_location(new_node, Node)
return new_node
def _get_module_path(self, node):
def _get_ModulePath(self, node):
parts = []
while isinstance(node, ast.Attribute):
parts.append(node.attr)
@@ -936,9 +1003,9 @@ class ExprCallHandle(BaseHandle):
result = method(src_val, dest_type, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
load_match = re.match(r'load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template)
if load_match:
ptr_val = resolve_op(int(load_match.group(3)))
Load_match = re.match(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template)
if Load_match:
ptr_val = resolve_op(int(Load_match.group(3)))
if ptr_val:
result = Gen.builder.load(ptr_val, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
@@ -1095,8 +1162,8 @@ class ExprCallHandle(BaseHandle):
expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*'))
if not expected_type:
return val
is_ptr = expected_type_str.endswith('*')
if is_ptr:
IsPtr = expected_type_str.endswith('*')
if IsPtr:
expected_ptr_type = ir.PointerType(expected_type)
if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type:
try:
@@ -1124,31 +1191,32 @@ class ExprCallHandle(BaseHandle):
return Gen.builder.inttoptr(val, expected_type)
return val
def _HandleExternalCallLlvm(self, Node, func_name, module_path):
def _HandleExternalCallLlvm(self, Node, func_name, ModulePath):
Gen = self.Trans.LlvmGen
# 解析 import 别名: 如 window -> vpsdk.window
if module_path and module_path not in ('c', 't'):
import_aliases = getattr(self.Trans, '_import_aliases', {})
if module_path in import_aliases:
module_path = import_aliases[module_path]
if ModulePath and ModulePath not in ('c', 't'):
import_aliases = getattr(self.Trans, '_ImportAliases', {})
if ModulePath in import_aliases:
ModulePath = import_aliases[ModulePath]
is_user_module = (module_path and module_path not in ('c', 't') and
(module_path in Gen.module_sha1_map or
module_path in getattr(self.Trans, '_imported_modules', set()) or
module_path in getattr(self.Trans, '_import_aliases', {})))
if module_path and module_path not in ('c', 't') and not is_user_module:
is_user_module = (module_path in Gen.module_sha1_map or
module_path.split('.')[-1] in Gen.module_sha1_map)
if is_user_module and module_path not in Gen.module_sha1_map:
module_path = module_path.split('.')[-1]
is_user_module = (ModulePath and ModulePath not in ('c', 't') and
(ModulePath in Gen.ModuleSha1Map or
ModulePath in getattr(self.Trans, '_ImportedModules', set()) or
ModulePath in getattr(self.Trans, '_ImportAliases', {})))
if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
is_user_module = (ModulePath in Gen.ModuleSha1Map or
ModulePath.split('.')[-1] in Gen.ModuleSha1Map or
ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set()))
if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()):
ModulePath = ModulePath.split('.')[-1]
if module_path and module_path not in ('c', 't') and not is_user_module:
if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
return None
if is_user_module:
mangled_name = Gen._mangle_func_name(func_name, module_path)
sym_key = f'{module_path}.{func_name}'
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
sym_key = f'{ModulePath}.{func_name}'
sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name)
is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline))
if is_inline and getattr(sym_info, 'InlineBody', None):
@@ -1166,11 +1234,11 @@ class ExprCallHandle(BaseHandle):
kw_provided.add(exact_param_names.index(kw.arg))
for i in range(len(exact_param_names)):
if i >= provided and i not in kw_provided:
raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值")
elif module_path in Gen.module_sha1_map and len(Node.args) == 0:
raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值")
elif ModulePath in Gen.ModuleSha1Map and len(Node.args) == 0:
func = Gen.functions.get(mangled_name)
if func and len(func.function_type.args) > 0:
raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数")
raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数")
if Gen._has_function(mangled_name):
return self._HandleClosureCallLlvm(Node, mangled_name)
try:
@@ -1195,7 +1263,7 @@ class ExprCallHandle(BaseHandle):
if decl_name != func_name and func_name not in Gen.functions:
Gen.functions[func_name] = func_decl
return self._HandleClosureCallLlvm(Node, decl_name)
sym_key = f'{module_path}.{func_name}'
sym_key = f'{ModulePath}.{func_name}'
sym_info = self.Trans.SymbolTable.get(sym_key)
if not sym_info:
sym_info = self.Trans.SymbolTable.get(func_name)
@@ -1234,9 +1302,13 @@ class ExprCallHandle(BaseHandle):
if replaced and replaced != existing:
Gen.functions[mangled_name] = replaced
return self._HandleClosureCallLlvm(Node, mangled_name)
# 回退: 直接用 func_name 查找_find_function 会遍历 SHA1 前缀)
fallback_func = Gen._find_function(func_name)
if fallback_func is not None:
return self._HandleClosureCallLlvm(Node, func_name)
return None
if module_path == 'c':
if ModulePath == 'c':
if func_name == 'Asm':
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
elif func_name == 'Addr':
@@ -1276,7 +1348,7 @@ class ExprCallHandle(BaseHandle):
'GetConsoleOutputCP': (ir.IntType(32), []),
'GetConsoleCP': (ir.IntType(32), []),
}
if module_path and 'win32console' in module_path and func_name in win32_apis:
if ModulePath and 'win32console' in ModulePath and func_name in win32_apis:
ret_type, param_types = win32_apis[func_name]
if func_name not in Gen.functions:
func_type = ir.FunctionType(ret_type, param_types)
@@ -1304,7 +1376,7 @@ class ExprCallHandle(BaseHandle):
if func_name in self._C_LIB_FUNCS:
return self._HandleClosureCallLlvm(Node, func_name)
mangled_name = Gen._mangle_func_name(func_name, module_path)
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
try:
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
except Exception:
@@ -1322,7 +1394,7 @@ class ExprCallHandle(BaseHandle):
Gen.functions[func_name] = func_decl
return self._HandleClosureCallLlvm(Node, decl_name)
sym_key = f'{module_path}.{func_name}' if module_path else func_name
sym_key = f'{ModulePath}.{func_name}' if ModulePath else func_name
sym_info = self.Trans.SymbolTable.get(sym_key)
if not sym_info:
sym_info = self.Trans.SymbolTable.get(func_name)
@@ -1347,7 +1419,7 @@ class ExprCallHandle(BaseHandle):
if isinstance(lp, ir.VoidType):
lp = ir.IntType(8).as_pointer()
llvm_param_types.append(lp)
mangled_name = Gen._mangle_func_name(func_name, module_path)
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
if mangled_name not in Gen.functions:
func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic)
func_decl = ir.Function(Gen.module, func_type, name=mangled_name)
@@ -1372,18 +1444,22 @@ class ExprCallHandle(BaseHandle):
type_info = None
try:
type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
if not isinstance(type_info, CTypeInfo):
return None
target_type_str = type_info.ToString()
is_ptr = type_info.IsPtr
if is_ptr and target_type_str and '*' not in target_type_str:
IsPtr = type_info.IsPtr
if IsPtr and target_type_str and '*' not in target_type_str:
target_type_str += ' *'
if not target_type_str:
return None
if type_info.IsPtr and not is_ptr:
is_ptr = True
if type_info.IsPtr and not IsPtr:
IsPtr = True
if '*' not in target_type_str:
target_type_str += ' *'
if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern):
@@ -1408,8 +1484,8 @@ class ExprCallHandle(BaseHandle):
dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType))
src_is_int = isinstance(val.type, ir.IntType)
dst_is_int = isinstance(target_type, ir.IntType)
src_is_ptr = isinstance(val.type, ir.PointerType)
dst_is_ptr = isinstance(target_type, ir.PointerType)
src_IsPtr = isinstance(val.type, ir.PointerType)
dst_IsPtr = isinstance(target_type, ir.PointerType)
if src_is_int and dst_is_float:
is_unsigned = Gen._check_node_unsigned(expr_node)
if is_unsigned:
@@ -1442,17 +1518,17 @@ class ExprCallHandle(BaseHandle):
if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType):
return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast")
return val
if src_is_ptr and dst_is_int:
if src_IsPtr and dst_is_int:
if target_type.width < 64:
ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64")
return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast")
return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast")
if src_is_int and dst_is_ptr:
if src_is_int and dst_IsPtr:
return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast")
if src_is_ptr and dst_is_ptr:
if src_IsPtr and dst_IsPtr:
if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType):
loaded = Gen._load(val, name="load_ptr")
return loaded
Loaded = Gen._load(val, name="load_ptr")
return Loaded
return Gen.builder.bitcast(val, target_type, name="ptrcast")
try:
return Gen.builder.bitcast(val, target_type, name="cast")
@@ -1464,7 +1540,7 @@ class ExprCallHandle(BaseHandle):
if RenumName not in Gen.structs:
return None
RenumType = Gen.structs[RenumName]
result = Gen._alloca_entry(RenumType, name=f"{RenumName}_{VariantName}")
result = Gen._allocaEntry(RenumType, name=f"{RenumName}_{VariantName}")
tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr")
Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr)
NestedStructName = f"{RenumName}_{VariantName}"
@@ -1473,10 +1549,10 @@ class ExprCallHandle(BaseHandle):
NestedStructPtrType = ir.PointerType(NestedStructType)
variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}")
members = Gen.class_members.get(NestedStructName, [])
payload_members = [(n, t) for n, t in members if n != '__tag']
payLoad_members = [(n, t) for n, t in members if n != '__tag']
for i, arg in enumerate(Node.args):
if i < len(payload_members):
member_name, member_type = payload_members[i]
if i < len(payLoad_members):
member_name, member_type = payLoad_members[i]
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
Coerced = Gen._coerce_value(ArgVal, member_type)
@@ -1543,7 +1619,7 @@ class ExprCallHandle(BaseHandle):
old_var_scopes = list(self.Trans.VarScopes)
for param_name, val in saved_vars.items():
if val is not None:
alloca = Gen._alloca_entry(val.type, name=f"inline_arg_{param_name}")
alloca = Gen._allocaEntry(val.type, name=f"inline_arg_{param_name}")
Gen._store(val, alloca)
self.Trans.VarScopes.append((param_name, alloca))
self.Trans.BodyHandler.HandleBodyLlvm(inline_body)
@@ -1679,7 +1755,7 @@ class ExprCallHandle(BaseHandle):
CallArgs.append(Gen.variables[var_name])
elif var_name in Gen._reg_values:
OldVal = Gen._reg_values[var_name]
var = Gen._alloca_entry(OldVal.type, name=var_name)
var = Gen._allocaEntry(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.variables[var_name] = var
del Gen._reg_values[var_name]
@@ -1762,7 +1838,7 @@ class ExprCallHandle(BaseHandle):
if target_bits is None:
target_bits = 0
is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False
is_ptr_cast = len(Node.args) >= 2 and (
IsPtr_cast = len(Node.args) >= 2 and (
(isinstance(Node.args[1], ast.Attribute) and Node.args[1].attr == 'CPtr' and isinstance(Node.args[1].value, ast.Name) and Node.args[1].value.id == 't') or
(isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr')
)
@@ -1771,10 +1847,10 @@ class ExprCallHandle(BaseHandle):
if isinstance(ArgNode, ast.Subscript):
SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode)
if SubscriptPtr:
if MethodName == 'CPtr' or is_ptr_cast:
if MethodName == 'CPtr' or IsPtr_cast:
return SubscriptPtr
if isinstance(SubscriptPtr.type, ir.PointerType):
val = Gen._load(SubscriptPtr, name="load_subscript_val")
val = Gen._load(SubscriptPtr, name="Load_subscript_val")
else:
val = SubscriptPtr
if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float:
@@ -1784,7 +1860,7 @@ class ExprCallHandle(BaseHandle):
val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast")
return val
val = self.HandleExprLlvm(ArgNode)
if is_ptr_cast:
if IsPtr_cast:
if target_bits > 0 and not is_float:
target_ptr_type = ir.PointerType(ir.IntType(target_bits))
elif is_float and target_bits == 32:
@@ -1839,9 +1915,9 @@ class ExprCallHandle(BaseHandle):
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")
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
if isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond")
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
return ir.Constant(ir.IntType(1), 0)
elif MethodName in ('CIfdef', 'CIfndef'):
return ir.Constant(ir.IntType(1), 1)
@@ -1858,8 +1934,12 @@ class ExprCallHandle(BaseHandle):
val = self.HandleExprLlvm(arg)
if isinstance(val, str):
msg = val
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理函数调用失败: {_e}", "Exception")
lineno = getattr(Node, 'lineno', 0)
raise Exception(f"#error: {msg} (line {lineno})")
elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'):
@@ -1877,21 +1957,21 @@ class ExprCallHandle(BaseHandle):
if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
ObjVal = var_ptr
else:
tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp")
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
Gen._store(ObjVal, tmp)
ObjVal = tmp
else:
tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp")
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
Gen._store(ObjVal, tmp)
ObjVal = tmp
else:
tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp")
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
Gen._store(ObjVal, tmp)
ObjVal = tmp
if isinstance(Node.func.value, ast.Name):
ModuleName = Node.func.value.id
aliases = getattr(self.Trans, '_import_aliases', {})
imported = getattr(self.Trans, '_imported_modules', set())
aliases = getattr(self.Trans, '_ImportAliases', {})
imported = getattr(self.Trans, '_ImportedModules', set())
actual_module = aliases.get(ModuleName, ModuleName)
if ModuleName in imported or actual_module in imported:
mangled_name = Gen._mangle_func_name(MethodName, actual_module)
@@ -2001,7 +2081,7 @@ class ExprCallHandle(BaseHandle):
if not stub_func_type:
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen)
if not stub_func_type and mangled_name != MethodName:
for sha1 in getattr(Gen, 'module_sha1_map', {}).values():
for sha1 in getattr(Gen, 'ModuleSha1Map', {}).values():
alt_name = f"{sha1}.{MethodName}"
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen)
if stub_func_type:
@@ -2250,7 +2330,7 @@ class ExprCallHandle(BaseHandle):
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")
char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf")
Gen.builder.store(val, char_var)
fmt_parts.append('%c')
fmt_args.append(char_var)
@@ -2314,7 +2394,7 @@ class ExprCallHandle(BaseHandle):
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._RegisterTempPtr(str_val)
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
elif isinstance(arg, ast.Name) and arg.id in Gen.var_struct_class:
ClassName = Gen.var_struct_class[arg.id]
@@ -2325,7 +2405,7 @@ class ExprCallHandle(BaseHandle):
if isinstance(obj_val.type, ir.PointerType) and not isinstance(obj_val.type.pointee, type(Gen.structs[ClassName])):
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
str_val = Gen.builder.call(str_func, [obj_val], name=f"call_{ClassName}.__str__")
Gen._register_temp_ptr(str_val)
Gen._RegisterTempPtr(str_val)
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
else:
val = self.HandleExprLlvm(arg)
@@ -2340,7 +2420,7 @@ class ExprCallHandle(BaseHandle):
pointee = val.type.pointee
if not self._is_char_pointer(val):
try:
val = Gen._load(val, name="print_load")
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}")
@@ -2431,7 +2511,7 @@ class ExprCallHandle(BaseHandle):
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)
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
if result is not None:
return result
break
@@ -2479,8 +2559,12 @@ class ExprCallHandle(BaseHandle):
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
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
resolved = CTypeRegistry.ResolveName(type_name)
if resolved:
ctype_cls, ptr_level = resolved
@@ -2491,8 +2575,12 @@ class ExprCallHandle(BaseHandle):
if ptr_level > 0:
size_bytes = 8
return ir.Constant(ir.IntType(64), size_bytes)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型失败: {_e}", "Exception")
return ir.Constant(ir.IntType(64), 0)
struct_type = Gen.structs[type_name]
@@ -2516,7 +2604,7 @@ class ExprCallHandle(BaseHandle):
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)
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
if result is not None:
return result
break
@@ -2562,12 +2650,12 @@ class ExprCallHandle(BaseHandle):
if TypeInfo.IsEnum:
enum_type_name = arg_name
elif isinstance(arg, ast.Attribute):
last_part = None
LastPart = 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]
LastPart = arg.attr
if LastPart in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[LastPart]
if AttrInfo.IsEnumMember and AttrInfo.EnumName:
enum_type_name = AttrInfo.EnumName
elif isinstance(arg.value, ast.Attribute):
@@ -2576,9 +2664,9 @@ class ExprCallHandle(BaseHandle):
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}"
LastPart = parts[-1]
qualified_name_dot = f"{enum_class_name}.{LastPart}"
qualified_name_under = f"{enum_class_name}_{LastPart}"
enum_member_found = None
for qname in (qualified_name_dot, qualified_name_under):
if qname in self.Trans.SymbolTable:
@@ -2588,7 +2676,7 @@ class ExprCallHandle(BaseHandle):
break
if not enum_member_found:
for key in self.Trans.SymbolTable:
if key == last_part:
if key == LastPart:
info = self.Trans.SymbolTable[key]
if info.IsEnumMember and info.EnumName == enum_class_name:
enum_member_found = info
@@ -2921,7 +3009,7 @@ class ExprCallHandle(BaseHandle):
NewFunc = Gen._get_function(NewFuncName)
StructType = Gen.structs.get(ClassName)
if StructType:
result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca")
result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
else:
return ir.Constant(ir.IntType(32), 0)
Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}")
@@ -2983,7 +3071,7 @@ class ExprCallHandle(BaseHandle):
StructType = StructType.pointee
is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
if is_opaque:
result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca")
result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
Gen.builder.store(ir.Constant(StructType, None), result)
InitFunc = Gen.functions.get(InitFuncName)
if not InitFunc:
@@ -3006,7 +3094,7 @@ class ExprCallHandle(BaseHandle):
adjusted_init = Gen._adjust_args(InitArgs, InitFunc)
Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}")
return result
result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca")
result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
# Call __new__ method if it exists (may replace self with heap pointer)
if has_new_method:
NewMethodFunc = Gen._find_function(NewMethodFuncName)
@@ -3196,7 +3284,7 @@ class ExprCallHandle(BaseHandle):
return ptr
return None
if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType):
LoadedValueVal = Gen._load(ValueVal, name="load_subscript")
LoadedValueVal = Gen._load(ValueVal, name="Load_subscript")
if isinstance(LoadedValueVal.type, ir.PointerType):
ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name="subscript")
return ElemPtr
@@ -3232,7 +3320,7 @@ class ExprCallHandle(BaseHandle):
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript")
return ElemPtr
arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp")
arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
Gen._store(ValueVal, arr_alloc)
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
return ElemPtr

View File

@@ -1,110 +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")
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.RegisterTempPtr(val)
format_str += "%s"
cast_args.append(val)
else:
format_str += "%s"
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue
val = self.HandleExprLlvm(part.value)
if not val:
format_str += "%d"
cast_args.append(ir.Constant(ir.IntType(32), 0))
continue
if isinstance(val.type, ir.PointerType):
pointee = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
format_str += "%s"
cast_args.append(val)
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
trunc_val = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
format_str += "%d"
cast_args.append(trunc_val)
else:
Loaded = Gen._load(val, name="fstr_deref")
if isinstance(Loaded.type, ir.IntType):
if Loaded.type.width == 8:
format_str += "%c"
ext = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(Loaded)
elif isinstance(Loaded.type, ir.PointerType):
format_str += "%s"
cast_args.append(Loaded)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(val.type, ir.IntType):
if val.type.width == 8:
format_str += "%c"
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
elif val.type.width == 1:
zext = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
format_str += "%d"
cast_args.append(zext)
else:
is_u = Gen._check_node_unsigned(part.value)
format_str += "%u" if is_u else "%d"
cast_args.append(val)
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(val)
else:
format_str += "%d"
cast_args.append(val)
if not format_str and not cast_args:
return Gen.emit_constant("", 'string')
encoded = format_str.encode('utf-8') + b'\x00'
string_type = ir.ArrayType(ir.IntType(8), len(encoded))
string_const = ir.Constant(string_type, bytearray(encoded))
global_var = ir.GlobalVariable(Gen.module, string_type, name=f"str_const_{Gen.string_const_counter}")
Gen.string_const_counter += 1
global_var.initializer = string_const
global_var.linkage = 'internal'
format_ptr = Gen.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)))
if return_str:
buf_size = ir.Constant(ir.IntType(64), 1024)
calloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)])
calloc_func = Gen._get_or_declare_func('calloc', calloc_type)
buf_ptr = Gen.builder.call(calloc_func, [ir.Constant(ir.IntType(64), 1), buf_size], name="call_calloc_buf")
sprintf_func = Gen.get_or_declare_c_func('sprintf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))], var_arg=True))
sprintf_args = [buf_ptr, format_ptr] + cast_args
Gen.builder.call(sprintf_func, sprintf_args, name="call_sprintf")
return buf_ptr
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
call_args = [format_ptr] + cast_args
return Gen.builder.call(printf_func, call_args, name="call_fstring")

View File

@@ -1,232 +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
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._ZeroConst(TestVal.type), name="ifexp_cond")
ThenBB = Gen.func.append_basic_block(name="ifexp.then")
ElseBB = Gen.func.append_basic_block(name="ifexp.else")
MergeBB = Gen.func.append_basic_block(name="ifexp.end")
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
# 先在 ThenBB 中生成 BodyVal
Gen.builder.position_at_start(ThenBB)
BodyVal = self.HandleExprLlvm(Node.body)
if not BodyVal:
BodyVal = ir.Constant(ir.IntType(32), 0)
ThenEndBB = Gen.builder.block
# 在 ElseBB 中生成 OrelseVal
Gen.builder.position_at_start(ElseBB)
OrelseVal = self.HandleExprLlvm(Node.orelse)
if not OrelseVal:
OrelseVal = ir.Constant(ir.IntType(32), 0)
ElseEndBB = Gen.builder.block
# 确定 phi 节点的目标类型
result_type = BodyVal.type
if BodyVal.type != OrelseVal.type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
# 指针类型,使用 BodyVal 的类型
result_type = BodyVal.type
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
# BodyVal 是整数OrelseVal 是指针(字符串字面量)
# 如果指针指向 i8将指针转换为 i8加载字符
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
# BodyVal 是指针字符串字面量OrelseVal 是整数
# 如果指针指向 i8将指针转换为 i8加载字符
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = BodyVal.type
else:
result_type = OrelseVal.type
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
if not ThenEndBB.is_terminated:
Gen.builder.position_at_end(ThenEndBB)
if BodyVal.type != result_type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if BodyVal.type.width < result_type.width:
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
else:
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 Else 分支的类型转换
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 指针转整数
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
Gen.builder.branch(MergeBB)
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
if not ElseEndBB.is_terminated:
Gen.builder.position_at_end(ElseEndBB)
if OrelseVal.type != result_type:
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if OrelseVal.type.width < result_type.width:
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
else:
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 如果指针指向 i8加载字符值
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
else:
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
Gen.builder.branch(MergeBB)
Gen.builder.position_at_start(MergeBB)
result_phi = Gen.builder.phi(result_type, name="ifexp.result")
result_phi.add_incoming(BodyVal, ThenEndBB)
result_phi.add_incoming(OrelseVal, ElseEndBB)
return result_phi
def _HandleNamedExprLlvm(self, Node):
Gen = self.Trans.LlvmGen
ValueVal = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
TargetName = Node.target.id
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
VarPtr = Gen.variables[TargetName]
if VarPtr.type.pointee == ValueVal.type:
Gen._store(ValueVal, VarPtr)
else:
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
else:
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
Gen._reg_values[TargetName] = ValueVal
return ValueVal

View File

@@ -1,402 +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
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._ZeroConst(val.type), name=name)
return val
values = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="and.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"andcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"and.rhs{idx}")
Gen.builder.cbranch(val, next_bb, end_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 0)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "andcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="and.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
elif isinstance(Node.op, ast.Or):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="or.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"orcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
Gen.builder.cbranch(val, end_bb, next_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 1)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "orcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
return None
def _HandleUnaryOpLlvm(self, Node):
Gen = self.Trans.LlvmGen
OperandVal = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName = None
if isinstance(OperandVal.type, ir.PointerType):
pointee = OperandVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
if ClassName and ClassName in Gen.structs:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName is None and isinstance(Node.operand, ast.Name):
ClassName = Gen.var_struct_class.get(Node.operand.id)
if ClassName and ClassName in Gen.structs:
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName:
op_name = UNARY_OVERLOAD_MAP[OpSymbol]
result = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
if result is not None:
return result
if OpSymbol == 'not':
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
return Gen.builder.not_(OperandVal, name="not_result")
if isinstance(OperandVal.type, ir.PointerType):
null_val = ir.Constant(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask = (1 << OperandVal.type.width) - 1
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
elif OpSymbol == '+':
return OperandVal
elif OpSymbol == '-':
if isinstance(OperandVal.type, ir.IntType):
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")
return None
def _HandleCompareLlvm(self, Node):
Gen = self.Trans.LlvmGen
LeftVal = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
if len(Node.ops) == 1:
Op = Node.ops[0]
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal = self.HandleExprLlvm(Node.comparators[0])
if not RightVal:
return None
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
lv, rv = LeftVal.constant, RightVal.constant
lw, rw = LeftVal.type.width, RightVal.type.width
if lw < rw:
lv = lv if lv >= 0 else lv + (1 << lw)
elif rw < lw:
rv = rv if rv >= 0 else rv + (1 << rw)
if is_unsigned:
mask_l = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围则必须用zext
# i8 类型默认使用 zext系统编程中 i8 几乎总是无符号字节)
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
else:
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
RightVal = ir.Constant(LeftVal.type, None)
else:
RightVal = Gen.builder.inttoptr(RightVal, LeftVal.type, name="int2ptr_cmp")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
else:
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
LeftVal = ir.Constant(RightVal.type, None)
else:
LeftVal = Gen.builder.inttoptr(LeftVal, RightVal.type, name="int2ptr_cmp")
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif is_unsigned:
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
else:
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
return result
EndBB = Gen.func.append_basic_block(name="cmp.end")
result_val = None
PrevBB = Gen.builder.block
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
continue
RightVal = self.HandleExprLlvm(Comparator)
if not RightVal:
continue
NextBB = Gen.func.append_basic_block(name="cmp.next")
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
if is_unsigned:
cmp_result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
else:
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
if result_val is None:
result_val = cmp_result
else:
result_val = Gen.builder.and_(result_val, cmp_result, name=f"and_cmp_{i}")
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
Gen.builder.branch(EndBB)
Gen.builder.position_at_start(EndBB)
final_result = Gen.builder.phi(ir.IntType(1), name="final_cmp")
final_result.add_incoming(ir.Constant(ir.IntType(1), 0), PrevBB)
for i in range(len(Node.ops)):
bb = Gen.func.append_basic_block(name=f"cmp.end.{i}")
final_result.add_incoming(ir.Constant(ir.IntType(1), 1), bb)
return final_result

View File

@@ -1,240 +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)
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
class ExprUtils:
def __init__(self, translator: "Translator"):
self.Trans = translator
def GetOpSymbol(self, Op):
OpMap = {
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
ast.MatMult: '@',
}
return OpMap.get(type(Op), None)
def GetUnaryOpSymbol(self, Op):
OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op):
OpMap = {
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
ast.In: 'in', ast.NotIn: 'not in',
}
return OpMap.get(type(Op), None)
def _get_var_class(self, node, Gen):
if isinstance(node, ast.Name):
VarName = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName = node.attr
return Gen.var_struct_class.get(AttrName)
return None
def _try_operator_overLoad(self, ClassName, op_name, obj_val, Gen, other_val=None):
FullMethodName = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if Gen._has_function(FullMethodName):
func = Gen._get_function(FullMethodName)
call_args = [obj_val]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
if expected_type != actual_val.type:
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
result = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type, var_name=""):
info = {
'name': "unknown",
'size': 0,
'signed': False,
'ptr': False
}
if isinstance(llvm_type, ir.IntType):
info['size'] = llvm_type.width // 8
info['signed'] = True
if llvm_type.width == 8:
info['name'] = "char"
elif llvm_type.width == 16:
info['name'] = "short"
elif llvm_type.width == 32:
info['name'] = "int"
elif llvm_type.width == 64:
info['name'] = "long long"
else:
info['name'] = f"int{llvm_type.width}"
elif isinstance(llvm_type, ir.DoubleType):
info['size'] = 8
info['signed'] = True
info['name'] = "double"
elif isinstance(llvm_type, ir.FloatType):
info['size'] = 4
info['signed'] = True
info['name'] = "float"
elif isinstance(llvm_type, ir.PointerType):
info['size'] = 8
info['signed'] = False
info['ptr'] = True
pointee_info = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size = 0
for elem in llvm_type.elements:
elem_info = self._llvm_type_to_detailed_string(elem)
size += elem_info['size']
info['size'] = size
info['signed'] = False
if isinstance(llvm_type, ir.IdentifiedStructType):
info['name'] = llvm_type.name
else:
info['name'] = "struct"
elif isinstance(llvm_type, ir.ArrayType):
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
info['size'] = elem_info['size'] * llvm_type.count
info['signed'] = elem_info['signed']
info['name'] = f"{elem_info['name']}[]"
elif isinstance(llvm_type, ir.VoidType):
info['size'] = 0
info['signed'] = False
info['name'] = "void"
else:
info['size'] = 0
info['signed'] = False
info['name'] = str(llvm_type)
return info
def _infer_expr_llvm_type_full(self, node):
Gen = self.Trans.LlvmGen
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return ir.IntType(32)
elif isinstance(node.value, int):
return ir.IntType(32)
elif isinstance(node.value, float):
return ir.DoubleType()
elif isinstance(node.value, str):
if getattr(node, 'kind', None) == 'u':
return ir.PointerType(ir.IntType(16))
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Name):
if node.id in Gen.variables:
var_ptr = Gen.variables[node.id]
if isinstance(var_ptr.type, ir.PointerType):
return var_ptr.type.pointee
return var_ptr.type
if node.id in Gen._reg_values:
return Gen._reg_values[node.id].type
return ir.IntType(32)
elif isinstance(node, ast.Attribute):
attr_name = node.attr
if attr_name in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[attr_name]
if getattr(AttrInfo, 'IsEnumMember', None):
return ir.IntType(32)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type = self._infer_expr_llvm_type_full(node.left)
right_type = self._infer_expr_llvm_type_full(node.right)
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
return ir.DoubleType()
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.UnaryOp):
return self._infer_expr_llvm_type_full(node.operand)
elif isinstance(node, ast.Subscript):
val_type = self._infer_expr_llvm_type_full(node.value)
if isinstance(val_type, ir.PointerType):
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
return ir.IntType(8)
if isinstance(val_type.pointee, ir.ArrayType):
return ir.PointerType(val_type.pointee.element)
return val_type.pointee
if isinstance(val_type, ir.ArrayType):
return val_type.element
if isinstance(val_type, ir.IntType):
return ir.IntType(8)
return ir.IntType(32)
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name = node.func.id
if Gen._has_function(func_name):
fn = Gen._get_function(func_name)
return fn.function_type.return_type
if func_name == 'len':
return ir.IntType(32)
if func_name == 'sizeof':
return ir.IntType(32)
if func_name == 'ord':
return ir.IntType(32)
if func_name == 'chr':
return ir.IntType(8)
if func_name == 'int':
return ir.IntType(32)
if func_name == 'float' or func_name == 'double':
return ir.DoubleType()
elif isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
if node.func.attr == 'Deref':
return ir.IntType(64)
if isinstance(node.func.value, ast.Name) and node.func.value.id == 't':
if node.func.attr == 'CChar':
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Compare):
return ir.IntType(1)
elif isinstance(node, ast.BoolOp):
return ir.IntType(1)
elif isinstance(node, ast.IfExp):
return self._infer_expr_llvm_type_full(node.body)
elif isinstance(node, ast.Attribute):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
def _collect_names(self, node, bound, free=None):
"""收集 AST 节点中的绑定变量和自由变量
Args:
node: AST 节点
bound: 集合收集绑定变量ast.Store 上下文)
free: 集合收集自由变量ast.Load 上下文),可为 None
"""
if free is None:
free = set()
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
bound.add(node.id)
elif isinstance(node.ctx, ast.Load):
free.add(node.id)
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
# 这些节点有自己的作用域,不递归进入
# 但需要收集参数名作为 bound
if hasattr(node, 'args') and node.args:
for arg in node.args.args:
bound.add(arg.arg)
elif getattr(node, '_fields', None):
for field in node._fields:
value = getattr(node, field, None)
if isinstance(value, list):
for item in value:
if isinstance(item, (ast.stmt, ast.expr)):
self._collect_names(item, bound, free)
elif isinstance(value, (ast.stmt, ast.expr)):
self._collect_names(value, bound, free)

View File

@@ -65,12 +65,12 @@ class ForHandle(BaseHandle):
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")
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")
StartVal = Gen._load(StartVal, name="Load_start")
else:
StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start")
else:
@@ -111,7 +111,7 @@ class ForHandle(BaseHandle):
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)
NewVar = Gen._allocaEntry(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:
@@ -122,7 +122,7 @@ class ForHandle(BaseHandle):
Gen.variables[TargetName] = NewVar
LoopVar = NewVar
else:
LoopVar = Gen._alloca_entry(EndVal.type, name=TargetName)
LoopVar = Gen._allocaEntry(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):
@@ -186,7 +186,7 @@ class ForHandle(BaseHandle):
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)
var = Gen._allocaEntry(OldVal.type, name=name)
Gen._store(OldVal, var)
Gen.variables[name] = var
del Gen._reg_values[name]
@@ -275,7 +275,7 @@ class ForHandle(BaseHandle):
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)
var = Gen._allocaEntry(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.variables[var_name] = var
del Gen._reg_values[var_name]
@@ -292,7 +292,7 @@ class ForHandle(BaseHandle):
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)
var = Gen._allocaEntry(ir.IntType(32), name=var_name)
Gen.variables[var_name] = var
extra_params.append((var_name, var.type))
if extra_params:
@@ -334,11 +334,11 @@ class ForHandle(BaseHandle):
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")
IdxVal = Gen._allocaEntry(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)
LoopVar = Gen._allocaEntry(ElemType, name=TargetName)
Gen.variables[TargetName] = LoopVar
Gen._store(ir.Constant(ElemType, None), LoopVar)
CondBB = Gen.func.append_basic_block(name="arrfor.cond")
@@ -383,13 +383,13 @@ class ForHandle(BaseHandle):
if not isinstance(Node.target, ast.Name):
return
TargetName = Node.target.id
Gen._unregister_temp_ptr(StrVal)
Gen._UnregisterTempPtr(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)
LoopVar = Gen._allocaEntry(CharType, name=TargetName)
Gen.variables[TargetName] = LoopVar
Gen._store(ir.Constant(CharType, 0), LoopVar)
CondBB = Gen.func.append_basic_block(name="strfor.cond")
@@ -436,21 +436,21 @@ class ForHandle(BaseHandle):
IterVal = self.HandleExprLlvm(Node.iter)
if not IterVal:
return
Gen._unregister_temp_ptr(IterVal)
Gen._UnregisterTempPtr(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)
Gen._UnregisterTempPtr(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")
StopFlagPtr = Gen._allocaEntry(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)
LoopVar = Gen._allocaEntry(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")
@@ -469,7 +469,7 @@ class ForHandle(BaseHandle):
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")
null_msg = Gen._allocaEntry(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")

View File

@@ -23,13 +23,16 @@ class FunctionHandle(BaseHandle):
elif d.id == 'classmethod':
meta |= FuncMeta.CLASS_METHOD
elif isinstance(d, ast.Attribute):
if isinstance(d.value, ast.Name) and d.value.id == 'property':
if d.attr == 'setter':
meta |= FuncMeta.PROPERTY_SETTER
elif d.attr == 'getter':
meta |= FuncMeta.PROPERTY_GETTER
elif d.attr == 'deleter':
meta |= FuncMeta.PROPERTY_DELETER
if isinstance(d.value, ast.Name):
# 支持 @property.setter 和 @propname.setter 两种形式
# @propname.setter 中 propname 是之前用 @property 定义的同名属性
if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'):
if d.attr == 'setter':
meta |= FuncMeta.PROPERTY_SETTER
elif d.attr == 'getter':
meta |= FuncMeta.PROPERTY_GETTER
elif d.attr == 'deleter':
meta |= FuncMeta.PROPERTY_DELETER
return meta
def _body_contains_raise(self, body):
@@ -189,8 +192,8 @@ class FunctionHandle(BaseHandle):
if sym and isinstance(sym, dict):
ret_type_str = sym.get('return_type', '')
if ret_type_str and ret_type_str != 'int':
is_ptr = sym.get('is_ptr', False)
return (ret_type_str, is_ptr)
IsPtr = sym.get('IsPtr', False)
return (ret_type_str, IsPtr)
elif isinstance(val, ast.Constant):
if val.value is None:
return ('char', True)
@@ -204,8 +207,8 @@ class FunctionHandle(BaseHandle):
if var_info and isinstance(var_info, dict):
var_type = var_info.get('type', '')
if var_type and var_type != 'int':
is_ptr = var_info.get('is_ptr', False)
return (var_type, is_ptr)
IsPtr = var_info.get('IsPtr', False)
return (var_type, IsPtr)
elif isinstance(val, ast.Subscript):
if (isinstance(val.value, ast.Attribute)
and isinstance(val.value.value, ast.Name)
@@ -264,8 +267,8 @@ class FunctionHandle(BaseHandle):
parts = inner.split(',')
elem_type_str = parts[0].strip()
if elem_type_str and elem_type_str != 'int':
is_ptr = var_info.get('is_ptr', False)
return (elem_type_str, is_ptr)
IsPtr = var_info.get('IsPtr', False)
return (elem_type_str, IsPtr)
return None
def _GetFunctionSignatureLlvm(self, Node, Gen, ClassName=None, extra_params=None):
@@ -368,7 +371,7 @@ class FunctionHandle(BaseHandle):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CChar()
ReturnTypeInfo.PtrCount = 1
if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState:
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CInt()
except Exception: # 回退:设置默认返回类型为 CInt
@@ -762,8 +765,12 @@ class FunctionHandle(BaseHandle):
for attr_name in self._pending_llvm_attrs[FuncName]:
try:
func.attributes.add(attr_name)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
Gen.functions[MangledName] = func
Gen.functions[FuncName] = func
except Exception as _e:
@@ -820,6 +827,12 @@ class FunctionHandle(BaseHandle):
FuncName = f"{ClassName}.{RawFuncName}"
else:
FuncName = RawFuncName
# property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突
func_meta = self._ExtractFuncMeta(Node.decorator_list)
if FuncMeta.PROPERTY_SETTER in func_meta:
FuncName = FuncName + '$set'
elif FuncMeta.PROPERTY_DELETER in func_meta:
FuncName = FuncName + '$del'
CReturnTypes = []
IsPtr = False
fn_attrs = {}
@@ -971,7 +984,7 @@ class FunctionHandle(BaseHandle):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CChar()
ReturnTypeInfo.PtrCount = 1
if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState:
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CInt()
except Exception: # 回退:设置默认返回类型为 CInt
@@ -992,7 +1005,7 @@ class FunctionHandle(BaseHandle):
IsMethod = False
IsClassMethod = False
ResolvedClassName = ClassName
func_meta = self._ExtractFuncMeta(Node.decorator_list)
# func_meta 已在函数开头提取(用于 setter/deleter 函数名后缀)
if not ResolvedClassName:
for potential_class in Gen.class_methods:
if FuncName.startswith(f"{potential_class}."):
@@ -1196,21 +1209,33 @@ class FunctionHandle(BaseHandle):
if fn_attrs.get(attr_name):
try:
func.attributes.add(llvm_name)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
for key in fn_attrs:
if key.startswith('llvm.'):
llvm_attr_name = key[5:]
try:
func.attributes.add(llvm_attr_name)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs:
for attr_name in self._pending_llvm_attrs.pop(FuncName):
try:
func.attributes.add(attr_name)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"添加函数属性失败: {_e}", "Exception")
# 记录自定义行为装饰器信息,供 DecoratorPass 使用
if behavior_decorators:
if not hasattr(Gen, '_decorated_funcs'):
@@ -1272,7 +1297,7 @@ class FunctionHandle(BaseHandle):
break
else:
# 所有参数都存入 alloca确保循环体中对参数的修改能正确反映
var = Gen._alloca_entry(param.type, name=param_name)
var = Gen._allocaEntry(param.type, name=param_name)
Gen._store(param, var)
Gen.variables[param_name] = var
if ResolvedClassName and (IsMethod or RawFuncName == '__init__'):
@@ -1298,7 +1323,7 @@ class FunctionHandle(BaseHandle):
va_list_size = 8 if is_windows else 24
va_list_align = 8 if is_windows else 16
va_list_type = ir.ArrayType(ir.IntType(8), va_list_size)
va_list_alloc = Gen._alloca_entry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align)
va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align)
va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr")
Gen._variadic_info = {
'vararg_name': vararg_name,
@@ -1307,7 +1332,7 @@ class FunctionHandle(BaseHandle):
'va_start_called': False,
}
if last_param_ptr:
last_param_alloc = Gen._alloca_entry(last_param_ptr.type, name="last_param_copy")
last_param_alloc = Gen._allocaEntry(last_param_ptr.type, name="last_param_copy")
Gen.builder.store(last_param_ptr, last_param_alloc)
Gen.emit_va_start(va_list_ptr)
Gen._variadic_info['va_start_called'] = True
@@ -1379,4 +1404,17 @@ class FunctionHandle(BaseHandle):
existing.IsInline = True
existing.InlineBody = Node.body
existing.InlineParams = [arg.arg for arg in Node.args.args]
# property setter/deleter: 在原始 PropKey不带后缀下注册 MetaList
if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
BasePropKey = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName
if BasePropKey in self.Trans.SymbolTable:
base_existing = self.Trans.SymbolTable[BasePropKey]
if func_meta != FuncMeta.NONE:
base_existing.MetaList = base_existing.MetaList | func_meta
else:
PropInfo = CTypeInfo()
PropInfo.Name = BasePropKey
PropInfo.IsFunction = True
PropInfo.MetaList = func_meta
self.Trans.SymbolTable[BasePropKey] = PropInfo
return func

View File

@@ -1,302 +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)
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._ZeroConst(Cond.type), name="bool_result")
else:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
ThenBB = 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)

View File

@@ -2,7 +2,7 @@ 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, FuncMeta
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.includes import t
import ast
import os
@@ -13,13 +13,13 @@ import llvmlite.ir as ir
class ImportHandle(BaseHandle):
_stub_cache = {}
_stub_cache_dir = None
_struct_load_cache = {}
_struct_Load_cache = {}
_pyi_cache = {}
_pyi_cache_dir = None
_project_root_cache = None
def _reset_file_cache(self):
self._struct_load_cache.clear()
self._struct_Load_cache.clear()
def _find_project_root(self):
if self._project_root_cache is not None:
@@ -43,17 +43,17 @@ class ImportHandle(BaseHandle):
return os.getcwd()
def _EmitImportDeclarationsLlvm(self, Node, Gen):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
if not getattr(self.Trans, '_import_aliases', None):
self.Trans._import_aliases = {}
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
if not getattr(self.Trans, '_ImportAliases', None):
self.Trans._ImportAliases = {}
for alias in Node.names:
name = alias.name
if name in ('c', 't'):
continue
self.Trans._imported_modules.add(name)
self.Trans._ImportedModules.add(name)
if alias.asname:
self.Trans._import_aliases[alias.asname] = name
self.Trans._ImportAliases[alias.asname] = name
# 同时在符号表中注册模块别名,以便 CTypeInfo.FromNode 能解析
AliasInfo = CTypeInfo()
AliasInfo.IsModuleAlias = True
@@ -63,7 +63,7 @@ class ImportHandle(BaseHandle):
self._EmitModuleDeclarationsLlvm(name, Gen, register_module_name=current_module)
def _RegisterFromImportAliases(self, Node, Gen, module):
"""Register 'from module import y as z' aliases after module declarations are loaded"""
"""Register 'from module import y as z' aliases after module declarations are Loaded"""
if not Node.names:
return
for alias in Node.names:
@@ -125,11 +125,11 @@ class ImportHandle(BaseHandle):
def _EmitImportFromDeclarationsLlvm(self, Node, Gen):
module = Node.module if Node.module else ''
if module in ('c', 't'):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
if not getattr(self.Trans, '_import_aliases', None):
self.Trans._import_aliases = {}
self.Trans._imported_modules.add(module)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
if not getattr(self.Trans, '_ImportAliases', None):
self.Trans._ImportAliases = {}
self.Trans._ImportedModules.add(module)
if not hasattr(self.Trans, '_t_c_imported_names'):
self.Trans._t_c_imported_names = {}
for alias in Node.names:
@@ -137,10 +137,10 @@ class ImportHandle(BaseHandle):
asname = alias.asname or name
self.Trans._t_c_imported_names[asname] = (module, name)
return
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
if not getattr(self.Trans, '_import_aliases', None):
self.Trans._import_aliases = {}
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
if not getattr(self.Trans, '_ImportAliases', None):
self.Trans._ImportAliases = {}
current_module = self._get_current_module_name()
if Node.level and Node.level > 0:
current_file = getattr(self.Trans, 'CurrentFile', '') or ''
@@ -154,20 +154,20 @@ class ImportHandle(BaseHandle):
for ext in SearchExtensions:
candidate = sub_path_base + ext
if os.path.isfile(candidate):
self.Trans._imported_modules.add(module)
self.Trans._ImportedModules.add(module)
self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module, register_module_name=current_module)
self._RegisterFromImportAliases(Node, Gen, module)
return
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
# 尝试完整模块名和短模块名
full_mod_name = f"{current_module}.{module}" if current_module else module
target_sha1 = module_sha1_map.get(full_mod_name) or module_sha1_map.get(module)
target_sha1 = ModuleSha1Map.get(full_mod_name) or ModuleSha1Map.get(module)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
self.Trans._imported_modules.add(module)
self.Trans._ImportedModules.add(module)
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module, register_module_name=current_module)
self._RegisterFromImportAliases(Node, Gen, module)
return
@@ -177,39 +177,39 @@ class ImportHandle(BaseHandle):
SearchExtensions = ['.pyi', '.py']
pkg_name = ''
if not module:
# When 'from . import name' is used, load the package's __init__
# When 'from . import name' is used, Load the package's __init__
# to make package-level names (functions, classes, constants) available
pkg_name = self._LoadPackageInitForRelativeImport(mod_dir, Gen, current_module)
# Also try to load each alias as a submodule
# Also try to Load each alias as a submodule
for alias in Node.names:
found_sub = False
for ext in SearchExtensions:
sub_path = os.path.join(mod_dir, alias.name + ext)
if os.path.isfile(sub_path):
self.Trans._imported_modules.add(alias.name)
self.Trans._ImportedModules.add(alias.name)
self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=current_module)
if alias.asname:
self.Trans._import_aliases[alias.asname] = alias.name
self.Trans._ImportAliases[alias.asname] = alias.name
found_sub = True
break
if not found_sub:
# SHA1 map fallback for submodule
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
sub_module_path = f"{pkg_name}.{alias.name}" if pkg_name else alias.name
target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name)
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
sub_ModulePath = f"{pkg_name}.{alias.name}" if pkg_name else alias.name
target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
self.Trans._imported_modules.add(sub_module_path)
self.Trans._ImportedModules.add(sub_ModulePath)
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=current_module)
if alias.asname:
self.Trans._import_aliases[alias.asname] = alias.name
self.Trans._ImportAliases[alias.asname] = alias.name
self._RegisterFromImportAliases(Node, Gen, module or pkg_name)
return
self.Trans._imported_modules.add(module)
self.Trans._ImportedModules.add(module)
self._EmitModuleDeclarationsLlvm(module, Gen, register_module_name=current_module)
self._RegisterFromImportAliases(Node, Gen, module)
@@ -229,15 +229,15 @@ class ImportHandle(BaseHandle):
reexport_names = []
if module_name and module_name != file_module_name and module_name != effective_register:
reexport_names.append(module_name)
# When loading a submodule for 'from .xxx import yyy' inside a package's __init__.py,
# When Loading a submodule for 'from .xxx import yyy' inside a package's __init__.py,
# re-export functions under the package name so 'pkg.func()' resolves correctly
if reexport_package and reexport_package != file_module_name and reexport_package not in reexport_names:
reexport_names.append(reexport_package)
self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=file_module_name, register_module_name=effective_register, reexport_module_names=reexport_names if reexport_names else None)
elif isinstance(node, ast.AnnAssign):
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path)
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path)
elif isinstance(node, ast.Assign):
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path)
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path)
elif isinstance(node, ast.ClassDef):
if hasattr(node, 'type_params') and node.type_params:
if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'):
@@ -263,9 +263,9 @@ class ImportHandle(BaseHandle):
if os.path.isfile(candidate):
actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module
self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen)
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(actual_module)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(actual_module)
for alias in node.names:
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
@@ -276,16 +276,16 @@ class ImportHandle(BaseHandle):
# SHA1 map 回退
if not found_sub:
actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module)
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(actual_module)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(actual_module)
for alias in node.names:
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
@@ -301,10 +301,10 @@ class ImportHandle(BaseHandle):
for ext in SearchExtensions:
sub_path = os.path.join(mod_dir, alias.name + ext)
if os.path.isfile(sub_path):
sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(sub_module_path)
sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(sub_ModulePath)
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
else:
@@ -313,17 +313,17 @@ class ImportHandle(BaseHandle):
break
# SHA1 map 回退
if not found_alias:
sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name)
sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(sub_module_path)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(sub_ModulePath)
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
else:
@@ -339,52 +339,56 @@ class ImportHandle(BaseHandle):
return None
def _RegisterSubModuleSha1(self, candidate_path, actual_module, short_module, Gen):
"""Register a submodule's SHA1 in module_sha1_map so cross-module class references work"""
"""Register a submodule's SHA1 in ModuleSha1Map so cross-module class references work"""
try:
with open(candidate_path, 'r', encoding='utf-8') as f:
sub_content = f.read()
sub_sha1 = hashlib.sha1(sub_content.encode('utf-8')).hexdigest()[:16]
if hasattr(Gen, 'module_sha1_map'):
Gen.module_sha1_map[actual_module] = sub_sha1
if short_module and short_module not in Gen.module_sha1_map:
Gen.module_sha1_map[short_module] = sub_sha1
except Exception:
pass
if hasattr(Gen, 'ModuleSha1Map'):
Gen.ModuleSha1Map[actual_module] = sub_sha1
if short_module and short_module not in Gen.ModuleSha1Map:
Gen.ModuleSha1Map[short_module] = sub_sha1
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name):
"""Load __init__.py from the package directory for 'from . import name' resolution.
This makes package-level names (functions, classes, constants) available.
Returns the package name."""
pkg_name = os.path.basename(mod_dir)
init_Loaded = False
# 跳过当前正在编译的文件,避免重复加载导致 class_members 重复
current_sha1 = getattr(Gen, 'module_sha1', None)
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
pkg_sha1 = ModuleSha1Map.get(pkg_name)
if pkg_sha1 and pkg_sha1 == current_sha1:
return pkg_name
# Try SHA1 map first (correct mangled names from stub)
if pkg_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi")
if os.path.isfile(sha1_pyi):
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name)
init_Loaded = True
# Fallback: try Loading __init__.py directly from the package directory
if not init_Loaded:
for ext in ['.pyi', '.py']:
init_path = os.path.join(mod_dir, '__init__' + ext)
if os.path.isfile(init_path):
self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name)
init_Loaded = True
break
return pkg_name
def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name):
"""Load __init__.py from the package directory for 'from . import name' resolution.
This makes package-level names (functions, classes, constants) available.
Returns the package name."""
pkg_name = os.path.basename(mod_dir)
init_loaded = False
# 跳过当前正在编译的文件,避免重复加载导致 class_members 重复
current_sha1 = getattr(Gen, 'module_sha1', None)
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
pkg_sha1 = module_sha1_map.get(pkg_name)
if pkg_sha1 and pkg_sha1 == current_sha1:
return pkg_name
# Try SHA1 map first (correct mangled names from stub)
if pkg_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi")
if os.path.isfile(sha1_pyi):
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name)
init_loaded = True
# Fallback: try loading __init__.py directly from the package directory
if not init_loaded:
for ext in ['.pyi', '.py']:
init_path = os.path.join(mod_dir, '__init__' + ext)
if os.path.isfile(init_path):
self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name)
init_loaded = True
break
return pkg_name
def _EmitModuleDeclarationsLlvm(self, module_name, Gen, register_module_name=None):
if module_name in ('pyzlib',):
source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
@@ -489,10 +493,10 @@ class ImportHandle(BaseHandle):
self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=module_name, register_module_name=effective_register)
has_functions_or_classes = True
elif isinstance(node, ast.AnnAssign):
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath)
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath)
has_functions_or_classes = True
elif isinstance(node, ast.Assign):
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath)
self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath)
has_functions_or_classes = True
elif isinstance(node, ast.ClassDef):
if hasattr(node, 'type_params') and node.type_params:
@@ -520,9 +524,9 @@ class ImportHandle(BaseHandle):
if os.path.isfile(candidate):
actual_module = f"{module_name}.{node.module}" if module_name else node.module
self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen)
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(actual_module)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(actual_module)
for alias in node.names:
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
@@ -534,17 +538,17 @@ class ImportHandle(BaseHandle):
# SHA1 map 回退:当文件查找失败时,从 SHA1 映射中查找子模块 stub
if not found_sub:
actual_module = f"{module_name}.{node.module}" if module_name else node.module
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
# 尝试完整模块名和短模块名
target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module)
target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(actual_module)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(actual_module)
for alias in node.names:
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
@@ -561,10 +565,10 @@ class ImportHandle(BaseHandle):
for ext in SearchExtensions:
sub_path = os.path.join(mod_dir, alias.name + ext)
if os.path.isfile(sub_path):
sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(sub_module_path)
sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(sub_ModulePath)
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
else:
@@ -574,17 +578,17 @@ class ImportHandle(BaseHandle):
break
# SHA1 map 回退
if not found_alias:
sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name)
sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
if target_sha1:
temp_dir = getattr(Gen, '_temp_dir', None)
if temp_dir:
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
if os.path.isfile(sha1_pyi):
if not getattr(self.Trans, '_imported_modules', None):
self.Trans._imported_modules = set()
self.Trans._imported_modules.add(sub_module_path)
if not getattr(self.Trans, '_ImportedModules', None):
self.Trans._ImportedModules = set()
self.Trans._ImportedModules.add(sub_ModulePath)
if alias.name == '*':
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
else:
@@ -603,13 +607,13 @@ class ImportHandle(BaseHandle):
if module_name:
self._LoadDeclarationsFromStubLlvm(module_name, Gen)
def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, module_path=None):
def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, ModulePath=None):
"""Emit external global variable declaration from imported module"""
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name):
VarName = Node.target.id
# 不再跳过 _ 开头的全局变量,跨模块引用需要声明它们
var_type = ir.IntType(32)
is_ptr = False
IsPtr = False
is_string_val = False
if VarName in Gen.module.globals:
existing = Gen.module.globals[VarName]
@@ -637,12 +641,12 @@ class ImportHandle(BaseHandle):
var_type = ir.ArrayType(elem_type, 0)
else:
var_type = Gen._ctype_to_llvm(ElemTypeInfo)
is_ptr = False
IsPtr = False
else:
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if TypeInfo:
var_type = Gen._ctype_to_llvm(TypeInfo)
is_ptr = TypeInfo.IsPtr
IsPtr = TypeInfo.IsPtr
elif isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
list_node = None
for side in (Node.annotation.left, Node.annotation.right):
@@ -665,20 +669,20 @@ class ImportHandle(BaseHandle):
var_type = ir.ArrayType(elem_type, 0)
else:
var_type = Gen._ctype_to_llvm(ElemTypeInfo)
is_ptr = False
IsPtr = False
else:
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if TypeInfo:
var_type = Gen._ctype_to_llvm(TypeInfo)
is_ptr = TypeInfo.IsPtr
IsPtr = TypeInfo.IsPtr
else:
TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
if TypeInfo:
var_type = Gen._ctype_to_llvm(TypeInfo)
is_ptr = TypeInfo.IsPtr
IsPtr = TypeInfo.IsPtr
if isinstance(var_type, ir.IdentifiedStructType) and (var_type.elements is None or len(var_type.elements) == 0):
var_type = ir.IntType(32)
if Node.value and module_path and is_ptr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
if Node.value and ModulePath and IsPtr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
str_val = Node.value.value + '\x00'
str_bytes = str_val.encode('utf-8')
arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
@@ -743,13 +747,21 @@ class ImportHandle(BaseHandle):
if Node.value:
DefineValue = self._ExtractConstValue(Node.value)
# 注册不带前缀的键名(例如 Z_NO_COMPRESSION
self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, module_path or 'unknown')
self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, ModulePath or 'unknown')
# 如果提供了模块名,也注册带模块前缀的键名
if module_name:
FullName = f"{module_name}.{VarName}"
self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, module_path or 'unknown')
self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, ModulePath or 'unknown')
return # 不再继续生成 LLVM 全局变量
# t.State 标记的全局变量只声明不定义external linkage避免 DSO/non-DSO 重定义
if TypeInfo and TypeInfo.IsState:
if VarName not in Gen.module.globals:
gv = ir.GlobalVariable(Gen.module, var_type, name=VarName)
gv.linkage = 'external'
Gen._export_funcs.add(VarName)
return
gv = ir.GlobalVariable(Gen.module, var_type, name=VarName)
if Node.value:
@@ -768,7 +780,7 @@ class ImportHandle(BaseHandle):
if VarName in Gen.module.globals:
return
gv = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName)
if Node.value and module_path:
if Node.value and ModulePath:
InitVal = self._ExtractValue(Node.value, ir.IntType(32), VarName)
if InitVal is not None:
gv.initializer = InitVal
@@ -893,40 +905,40 @@ class ImportHandle(BaseHandle):
return self._ExtractConstValue(value_node.args[0])
return None
def _ExtractTypedefOriginalType(self, value_node):
import ast
from lib.includes.t import CTypeRegistry
if isinstance(value_node, ast.Attribute):
if getattr(value_node.value, 'id', None) == 't':
llvm_str = CTypeRegistry.NameToLLVM(value_node.attr)
if llvm_str:
return llvm_str
elif isinstance(value_node, ast.Name):
llvm_str = CTypeRegistry.NameToLLVM(value_node.id)
if llvm_str:
return llvm_str
elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr):
left = self._ExtractTypedefOriginalType(value_node.left)
right = self._ExtractTypedefOriginalType(value_node.right)
parts = []
if left:
parts.append(left)
if right:
parts.append(right)
if parts:
return '|'.join(parts)
elif isinstance(value_node, ast.Call):
if isinstance(value_node.func, ast.Attribute):
if getattr(value_node.func.value, 'id', None) == 't':
llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr)
if llvm_str:
return llvm_str
elif isinstance(value_node.func, ast.Name):
llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id)
if llvm_str:
return llvm_str
return None
def _ExtractTypedefOriginalType(self, value_node):
import ast
from lib.includes.t import CTypeRegistry
if isinstance(value_node, ast.Attribute):
if getattr(value_node.value, 'id', None) == 't':
llvm_str = CTypeRegistry.NameToLLVM(value_node.attr)
if llvm_str:
return llvm_str
elif isinstance(value_node, ast.Name):
llvm_str = CTypeRegistry.NameToLLVM(value_node.id)
if llvm_str:
return llvm_str
elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr):
left = self._ExtractTypedefOriginalType(value_node.left)
right = self._ExtractTypedefOriginalType(value_node.right)
parts = []
if left:
parts.append(left)
if right:
parts.append(right)
if parts:
return '|'.join(parts)
elif isinstance(value_node, ast.Call):
if isinstance(value_node.func, ast.Attribute):
if getattr(value_node.func.value, 'id', None) == 't':
llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr)
if llvm_str:
return llvm_str
elif isinstance(value_node.func, ast.Name):
llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id)
if llvm_str:
return llvm_str
return None
def _RegisterCDefineSymbol(self, FullName, DefineValue, lineno, FilePath):
"""Register CDefine constant to SymbolTable"""
from lib.core.Handles.HandlesBase import CTypeInfo
@@ -938,19 +950,19 @@ class ImportHandle(BaseHandle):
# 直接添加到 SymbolTable 字典
self.Trans.SymbolTable[FullName] = info
def _check_annotation_for_state(self, annotation) -> bool:
import ast
if isinstance(annotation, ast.Attribute):
if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'):
return True
if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State':
return True
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right)
elif isinstance(annotation, ast.Name):
return annotation.id in ('CExport', 'CExtern', 'State')
return False
def _check_annotation_for_state(self, annotation) -> bool:
import ast
if isinstance(annotation, ast.Attribute):
if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'):
return True
if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State':
return True
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right)
elif isinstance(annotation, ast.Name):
return annotation.id in ('CExport', 'CExtern', 'State')
return False
def _EmitExternalFuncDeclLlvm(self, Node, Gen, is_class_method=False, source_module_name=None, register_module_name=None, reexport_module_names=None):
FuncName = Node.name
if Node.returns and self._check_annotation_for_state(Node.returns):
@@ -1086,13 +1098,15 @@ class ImportHandle(BaseHandle):
elif d.id == 'classmethod':
func_meta |= FuncMeta.CLASS_METHOD
elif isinstance(d, ast.Attribute):
if isinstance(d.value, ast.Name) and d.value.id == 'property':
if d.attr == 'setter':
func_meta |= FuncMeta.PROPERTY_SETTER
elif d.attr == 'getter':
func_meta |= FuncMeta.PROPERTY_GETTER
elif d.attr == 'deleter':
func_meta |= FuncMeta.PROPERTY_DELETER
if isinstance(d.value, ast.Name):
# 支持 @property.setter 和 @propname.setter 两种形式
if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'):
if d.attr == 'setter':
func_meta |= FuncMeta.PROPERTY_SETTER
elif d.attr == 'getter':
func_meta |= FuncMeta.PROPERTY_GETTER
elif d.attr == 'deleter':
func_meta |= FuncMeta.PROPERTY_DELETER
if FuncName not in self.Trans.SymbolTable:
FuncInfo = CTypeInfo()
FuncInfo.Name = FuncName
@@ -1103,6 +1117,28 @@ class ImportHandle(BaseHandle):
existing = self.Trans.SymbolTable[FuncName]
if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
existing.MetaList = func_meta
# 同时注册带模块前缀的符号,以便 module.func_name 查找能命中
if source_module_name and source_module_name not in ('c', 't'):
FullSymKey = f"{source_module_name}.{FuncName}"
if FullSymKey not in self.Trans.SymbolTable:
FullFuncInfo = CTypeInfo()
FullFuncInfo.Name = FullSymKey
FullFuncInfo.IsFunction = True
FullFuncInfo.MetaList = func_meta
self.Trans.SymbolTable[FullSymKey] = FullFuncInfo
# property setter/deleter: 在原始 PropKey不带后缀下注册 MetaList
if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
BasePropKey = FuncName.replace('$set', '').replace('$del', '')
if BasePropKey in self.Trans.SymbolTable:
base_existing = self.Trans.SymbolTable[BasePropKey]
if func_meta != FuncMeta.NONE:
base_existing.MetaList = base_existing.MetaList | func_meta
else:
PropInfo = CTypeInfo()
PropInfo.Name = BasePropKey
PropInfo.IsFunction = True
PropInfo.MetaList = func_meta
self.Trans.SymbolTable[BasePropKey] = PropInfo
if register_module_name and register_module_name != source_module_name:
ReexportName = Gen._mangle_func_name(FuncName, module_name=register_module_name)
Gen.functions[ReexportName] = func
@@ -1207,10 +1243,10 @@ class ImportHandle(BaseHandle):
return
self._TryLoadStructFromStub(ClassName, Gen)
source_sha1 = None
if actual_module_name and hasattr(Gen, 'module_sha1_map') and actual_module_name in Gen.module_sha1_map:
source_sha1 = Gen.module_sha1_map[actual_module_name]
elif module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map:
source_sha1 = Gen.module_sha1_map[module_name]
if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map:
source_sha1 = Gen.ModuleSha1Map[actual_module_name]
elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
source_sha1 = Gen.ModuleSha1Map[module_name]
# Track which module defines this class (for cross-module name mangling)
if source_sha1:
if not hasattr(Gen, 'class_sha1_map'):
@@ -1268,9 +1304,15 @@ class ImportHandle(BaseHandle):
is_item_prop_setter = any(isinstance(d, ast.Attribute) and d.attr == 'setter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
is_item_prop_getter = any(isinstance(d, ast.Attribute) and d.attr == 'getter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
is_item_prop_deleter = any(isinstance(d, ast.Attribute) and d.attr == 'deleter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
if FuncFullName not in Gen.functions:
# setter/deleter 使用不同的函数名后缀
DeclFuncName = FuncFullName
if is_item_prop_setter:
DeclFuncName = FuncFullName + '$set'
elif is_item_prop_deleter:
DeclFuncName = FuncFullName + '$del'
if DeclFuncName not in Gen.functions:
FuncDeclNode = ast.FunctionDef(
name=FuncFullName,
name=DeclFuncName,
args=item.args,
body=item.body,
decorator_list=item.decorator_list,
@@ -1290,10 +1332,11 @@ class ImportHandle(BaseHandle):
func_meta |= FuncMeta.PROPERTY_GETTER
if is_item_prop_deleter:
func_meta |= FuncMeta.PROPERTY_DELETER
SymKey = FuncFullName
# setter/deleter 的 SymKey 使用带后缀的函数名
SymKey = DeclFuncName
if SymKey not in self.Trans.SymbolTable:
FuncInfo = CTypeInfo()
FuncInfo.Name = FuncFullName
FuncInfo.Name = SymKey
FuncInfo.IsFunction = True
FuncInfo.MetaList = func_meta
self.Trans.SymbolTable[SymKey] = FuncInfo
@@ -1301,6 +1344,18 @@ class ImportHandle(BaseHandle):
existing = self.Trans.SymbolTable[SymKey]
if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
existing.MetaList = func_meta
# setter/deleter: 同时在原始 PropKey不带后缀下注册 MetaList
if is_item_prop_setter or is_item_prop_deleter:
if FuncFullName in self.Trans.SymbolTable:
base_existing = self.Trans.SymbolTable[FuncFullName]
if func_meta != FuncMeta.NONE:
base_existing.MetaList = base_existing.MetaList | func_meta
else:
PropInfo = CTypeInfo()
PropInfo.Name = FuncFullName
PropInfo.IsFunction = True
PropInfo.MetaList = func_meta
self.Trans.SymbolTable[FuncFullName] = PropInfo
if has_methods:
if IsCVTable:
Gen._cross_module_vtable_classes.add(ClassName)
@@ -1308,8 +1363,8 @@ class ImportHandle(BaseHandle):
NewFuncName = f'{ClassName}.__before_init__'
if not Gen._has_function(NewFuncName) and (IsCpythonObject or IsCVTable):
source_sha1 = None
if module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map:
source_sha1 = Gen.module_sha1_map[module_name]
if module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
source_sha1 = Gen.ModuleSha1Map[module_name]
MangledName = Gen._mangle_name(NewFuncName) if not source_sha1 else f"{source_sha1}.{NewFuncName}"
StructType = Gen.structs.get(ClassName)
if StructType:
@@ -1327,9 +1382,9 @@ class ImportHandle(BaseHandle):
def _TryLoadStructFromStub(self, class_name: str, Gen):
cache_key = class_name
if cache_key in self._struct_load_cache:
if cache_key in self._struct_Load_cache:
return
self._struct_load_cache[cache_key] = True
self._struct_Load_cache[cache_key] = True
import os, re
ProjectRoot = self._find_project_root()
@@ -1358,9 +1413,13 @@ class ImportHandle(BaseHandle):
self._stub_cache.setdefault(short_name, []).append((full_name, struct_body, source_sha1))
if '.' in full_name:
self._stub_cache.setdefault(full_name, []).append((full_name, struct_body, source_sha1))
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
if class_name not in self._stub_cache:
return
@@ -1380,12 +1439,16 @@ class ImportHandle(BaseHandle):
elem_types.append(et if et else ir.IntType(32))
try:
st = Gen._get_or_create_struct(class_name, source_sha1=source_sha1, packed=is_packed)
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
if isinstance(st, ir.IdentifiedStructType) and st.is_opaque:
st.set_body(*elem_types)
if is_packed:
Gen.class_packed.add(class_name)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
stub_filename = source_sha1 + '.stub.ll'
self._TryLoadClassMembersFromPyi(class_name, stub_filename, Gen)
return
@@ -1419,13 +1482,13 @@ class ImportHandle(BaseHandle):
return
source_sha1 = stub_filename.replace('.stub.ll', '')
module_name = None
if hasattr(Gen, 'module_sha1_map'):
for mod_name, mod_sha1 in Gen.module_sha1_map.items():
if hasattr(Gen, 'ModuleSha1Map'):
for mod_name, mod_sha1 in Gen.ModuleSha1Map.items():
if mod_sha1 == source_sha1 and '.' not in mod_name:
module_name = mod_name
break
if module_name is None:
for mod_name, mod_sha1 in Gen.module_sha1_map.items():
for mod_name, mod_sha1 in Gen.ModuleSha1Map.items():
if mod_sha1 == source_sha1:
module_name = mod_name
break
@@ -1513,9 +1576,13 @@ class ImportHandle(BaseHandle):
stub_ret = match.group(1).strip()
stub_params = match.group(3).strip()
self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
if func_name not in self._stub_func_cache:
return None
@@ -1622,8 +1689,8 @@ class ImportHandle(BaseHandle):
target_sha1 = os.path.basename(val).replace('.pyi', '')
break
if not target_sha1:
module_sha1_map = getattr(Gen, 'module_sha1_map', {})
target_sha1 = module_sha1_map.get(module_name)
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
target_sha1 = ModuleSha1Map.get(module_name)
if target_sha1:
target_stub = f"{target_sha1}.stub.ll"
@@ -1648,21 +1715,25 @@ class ImportHandle(BaseHandle):
elif stripped.startswith('declare '):
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
needed_sha1s.add(m.group(1))
except Exception:
pass
preload_files = []
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
preLoad_files = []
for sha1 in needed_sha1s:
dep_stub = f"{sha1}.stub.ll"
if dep_stub in all_stub_files and dep_stub not in stub_files:
preload_files.append(dep_stub)
preLoad_files.append(dep_stub)
load_order = preload_files + stub_files
Load_order = preLoad_files + stub_files
for filename in load_order:
for filename in Load_order:
stub_path = os.path.join(temp_dir, filename)
source_sha1 = filename.replace('.stub.ll', '')
is_preload = filename in preload_files
is_preLoad = filename in preLoad_files
try:
with open(stub_path, 'r', encoding='utf-8') as f:
content = f.read()
@@ -1699,14 +1770,18 @@ class ImportHandle(BaseHandle):
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
try:
st.set_body(*elem_types)
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
continue
if not stripped.startswith('declare '):
continue
if is_preload:
if is_preLoad:
continue
func_name_match = stripped.split('@', 1)
@@ -1736,10 +1811,18 @@ class ImportHandle(BaseHandle):
if '.' in func_name:
short_name = func_name.split('.', 1)[1]
Gen.functions[short_name] = func
except Exception:
pass
except Exception:
pass
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理导入失败: {_e}", "Exception")
def _parse_llvm_declare(self, declare_line: str, Gen):
"""解析 LLVM declare 语句"""

View File

@@ -1,333 +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)
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._loadVar(VarName)
if not IsRenumMatch:
for case in Node.cases:
if isinstance(case.pattern, ast.MatchClass):
cls_node = case.pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName and VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None):
EnumName = SymInfo.EnumName
if EnumName in self.Trans.SymbolTable:
EnumInfo = self.Trans.SymbolTable[EnumName]
if getattr(EnumInfo, 'IsRenum', False):
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
SubjectPtr = self.HandleExprLlvm(Node.subject)
break
if IsRenumMatch and SubjectPtr:
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
return
if not isinstance(SubjectVal.type, ir.IntType):
try:
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
except Exception: # 回退ptrtoint 失败时直接返回
return
SwitchIntType = SubjectVal.type
DefaultBB = Gen.func.append_basic_block(name="match.default")
AfterBB = Gen.func.append_basic_block(name="match.end")
CaseBBs = []
CaseValues = []
HasDefault = False
HasNoBreak = []
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val = self.HandleExprLlvm(pattern.value)
if Val:
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchOr):
for j, SubPattern in enumerate(pattern.patterns):
if isinstance(SubPattern, ast.MatchValue):
Val = self.HandleExprLlvm(SubPattern.value)
if Val:
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
elif isinstance(pattern, ast.MatchSingleton):
if pattern.value is None:
CaseValues.append(ir.Constant(SwitchIntType, 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
def _HasNoBreak(stmts):
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx = 0
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases = len(pattern.patterns)
for j in range(NumSubCases):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
def _HandleRenumMatchLlvm(self, Node, RenumName, SubjectPtr):
Gen = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
tag_ptr = Gen.builder.gep(SubjectPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="match_tag_ptr")
TagVal = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB = Gen.func.append_basic_block(name="match.default")
AfterBB = Gen.func.append_basic_block(name="match.end")
CaseBBs = []
CaseValues = []
CaseBindings = []
HasDefault = False
HasNoBreak = []
for i, case in enumerate(Node.cases):
pattern = case.pattern
bindings = []
if isinstance(pattern, ast.MatchClass):
cls_node = pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
TagValue = None
if VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False):
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
NestedStructName = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
members = Gen.class_members.get(NestedStructName, [])
payLoad_members = [(n, t) for n, t in members if n != '__tag']
for j, sub_pat in enumerate(pattern.patterns):
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
CaseBindings.append(bindings)
else:
CaseValues.append(ir.Constant(ir.IntType(32), 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchValue):
Val = self.HandleExprLlvm(pattern.value)
if Val:
if isinstance(Val.type, ir.IntType):
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
except Exception: # 回退ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(ir.IntType(32), 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
def _HasNoBreak(stmts):
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx = 0
for i, case in enumerate(Node.cases):
pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node = pattern.cls
VariantName = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType = Gen.structs[NestedStructName]
NestedStructPtrType = ir.PointerType(NestedStructType)
variant_ptr = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
Gen.variables[bind_name] = elem_ptr
self.HandleBodyLlvm(case.body)
for bind_name, _, _, _ in bindings:
if bind_name in Gen.variables:
del Gen.variables[bind_name]
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchValue):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)

View File

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

View File

@@ -1,354 +1,358 @@
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
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._ZeroConst(ArgVal.type), name="cif_cond")
if isinstance(ArgVal.type, ir.PointerType):
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
return ir.Constant(ir.IntType(1), 0)
def _HandleCAddrLlvm(self, Node):
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._allocaEntry(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 as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"处理函数调用失败: {_e}", "Exception")
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:
IsPtr_cast = False
if len(Node.args) >= 2:
second_arg = Node.args[1]
if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and second_arg.value.id == 't' and second_arg.attr == 'CPtr':
IsPtr_cast = True
elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr':
IsPtr_cast = True
if IsPtr_cast:
return self._HandleTPtrCastLlvm(Node, attr)
if target_type == 'void':
target_type = 'void *'
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type)
return None
def _HandleCTypeLlvm(self, Node):
Gen = self.Trans.LlvmGen
arg_val = self.HandleExprLlvm(Node.args[0])
if not arg_val:
return None
target_type_str = 'unsigned long long'
if len(Node.args) >= 2:
type_parts = []
ptr_count = 0
for i in range(1, len(Node.args)):
type_arg = Node.args[i]
if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't':
type_attr = type_arg.attr
_PREFIX_MAP = {
'CUnsigned': 'unsigned', 'CSigned': 'signed',
'CConst': 'const', 'CVolatile': 'volatile',
}
if type_attr in _PREFIX_MAP:
type_parts.append(_PREFIX_MAP[type_attr])
elif type_attr in ('CPtr', 'CArrayPtr'):
ptr_count += 1
else:
resolved = self._ResolveTAttrToCName(type_attr)
if resolved is not None:
type_parts.append(resolved)
if type_parts:
target_type_str = ' '.join(type_parts)
if ptr_count > 0:
target_type_str += ' ' + '*' * ptr_count
if isinstance(arg_val.type, ir.PointerType):
int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int")
return int_val
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str)
def _HandleTPtrCastLlvm(self, Node, attr):
Gen = self.Trans.LlvmGen
from lib.includes.t import CTypeRegistry
if attr in ('CChar', 'CUnsignedChar'):
first_arg = Node.args[0]
if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and first_arg.func.value.id == 't' and first_arg.func.attr == 'CInt' and first_arg.args:
inner_val = self.HandleExprLlvm(first_arg.args[0])
if isinstance(inner_val.type, ir.PointerType):
return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint")
expr_val = self.HandleExprLlvm(Node.args[0])
if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8:
var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr")
zero = ir.Constant(ir.IntType(32), 0)
char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr")
Gen._store(expr_val, char_ptr)
null_char = ir.Constant(ir.IntType(8), 0)
null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr")
Gen._store(null_char, null_ptr)
return char_ptr
elif isinstance(expr_val.type, ir.PointerType):
if isinstance(expr_val.type.pointee, ir.PointerType):
Loaded_ptr = Gen._load(expr_val, name="load_ptr")
if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8:
return Loaded_ptr
if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8:
return expr_val
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr")
elif isinstance(expr_val.type, ir.IntType):
if expr_val.type.width == 32:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}")
return Gen.emit_constant(0, 'int')
elif attr == 'CVoid':
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *')
elif attr == 'CInt':
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
else:
ctype_cls = CTypeRegistry.GetClassByName(attr)
if ctype_cls is not None:
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
target_type = Gen._type_str_to_llvm(llvm_str)
if target_type and isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)):
target_ptr_type = ir.PointerType(target_type)
expr_val = self.HandleExprLlvm(Node.args[0])
if expr_val:
if isinstance(expr_val.type, ir.IntType):
if expr_val.type.width < 64:
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
return None

View File

@@ -1,211 +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()
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._allocaEntry(ir.IntType(32), name="eh_code")
eh_message = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
HasFinally = bool(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._allocaEntry(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._allocaEntry(ir.IntType(32), name="pending_ret_flag")
pending_ret_val = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
Gen.builder.branch(FinallyBB)
Gen.builder.position_at_start(FinallyBB)
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
self.HandleBodyLlvm(Node.finalbody)
if Gen.eh_finally_stack:
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
Gen.eh_finally_stack.pop()
ret_flag_val = 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)

View File

@@ -113,7 +113,7 @@ class HandlesTypeMerge(BaseHandle):
# 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types
if ModulePath:
import_aliases = getattr(self.Trans, '_import_aliases', {})
import_aliases = getattr(self.Trans, '_ImportAliases', {})
if ModulePath in import_aliases:
ModulePath = import_aliases[ModulePath]
else:

View File

@@ -1,54 +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)
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._ZeroConst(Cond.type), name="whilecond")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)

View File

@@ -1,138 +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])
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._allocaEntry(ctx_val.type, name="__with_ctx")
Gen._store(ctx_val, ctx_alloca)
Gen._UnregisterTempPtr(ctx_val)
if ClassName:
Gen.var_struct_class['__with_ctx'] = ClassName
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
original_asname_heap_ptr = 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._allocaEntry(OldVal.type, name=asname)
Gen._store(OldVal, var)
Gen.variables[asname] = var
del Gen._reg_values[asname]
if asname in Gen.variables and Gen.variables[asname] is not None:
VarPtr = Gen.variables[asname]
if VarPtr.type.pointee == enter_result.type:
Gen._store(enter_result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
CastedVal = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
Gen._store(CastedVal, VarPtr)
else:
NewVar = Gen._alloca(enter_result.type, name=asname)
Gen._store(enter_result, NewVar)
Gen.variables[asname] = NewVar
else:
Gen._reg_values[asname] = enter_result
Gen.variables[asname] = None
self.Trans.VarScopes.append({})
if asname:
self.Trans.VarScopes[-1][asname] = True
self.HandleBodyLlvm(Node.body)
if self.Trans.VarScopes:
self.Trans.VarScopes.pop()
if ClassName:
ExitFuncName = f'{ClassName}.__exit__'
if ExitFuncName in Gen.functions:
ctx_Loaded = Gen._load(ctx_alloca, name="__with_ctx")
Gen.builder.call(Gen.functions[ExitFuncName], [ctx_Loaded], name="call_exit")
Gen._unregister_local_heap_ptr(original_ctx_val)
if ctx_val is not original_ctx_val:
Gen._unregister_local_heap_ptr(ctx_val)
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
if '__with_ctx' in Gen._var_to_heap_ptr:
del Gen._var_to_heap_ptr['__with_ctx']
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
ctx_int = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
enter_int = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
same_ptr = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
with_free_bb = Gen.func.append_basic_block("with_free_ctx")
with_skip_bb = Gen.func.append_basic_block("with_skip_free")
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
Gen.builder.position_at_start(with_free_bb)
raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen.builder.branch(with_skip_bb)
Gen.builder.position_at_start(with_skip_bb)
Gen._unregister_local_heap_ptr(enter_result)
Gen._unregister_local_heap_ptr(original_ctx_val)
elif isinstance(ctx_val.type, ir.PointerType):
raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen._unregister_local_heap_ptr(original_ctx_val)

View File

@@ -27,6 +27,6 @@ from .HandlesTry import TryHandle
from .HandlesAssert import AssertHandle
from .HandlesRaise import RaiseHandle
from .HandlesMatch import MatchHandle
from .HandlesClassDef import ClassHandle
from .HandlesClassDef import ClassHandle
from .HandlesFunctions import FunctionHandle
from .HandlesImports import ImportHandle
from .HandlesImports import ImportHandle