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