snapshot before regression test
This commit is contained in:
704
lib/core/Handles/HandlesAnnAssign.py
Normal file
704
lib/core/Handles/HandlesAnnAssign.py
Normal file
@@ -0,0 +1,704 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotation, AnnotationContainsName
|
||||
|
||||
|
||||
class AnnAssignHandle(BaseHandle):
|
||||
def _StoreOrStrCopy(self, VarName: str, VarPtr: ir.Value, Value: ir.Value) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
DestPtr: ir.Value = Gen._load(VarPtr, name=VarName)
|
||||
if isinstance(DestPtr.type, ir.PointerType) and isinstance(DestPtr.type.pointee, ir.IntType) and DestPtr.type.pointee.width == 8:
|
||||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.IntType) and Value.type.pointee.width == 8:
|
||||
if 'llvm.memcpy' not in Gen.functions:
|
||||
memcpy_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)])
|
||||
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
|
||||
if isinstance(DestPtr.type.pointee, ir.IntType) and not isinstance(DestPtr.type.pointee, ir.IntType(8)):
|
||||
DestPtr = Gen.builder.bitcast(DestPtr, ir.PointerType(ir.IntType(8)), name=f"strcpy_dst_cast_{VarName}")
|
||||
if isinstance(Value.type.pointee, ir.IntType) and not isinstance(Value.type.pointee, ir.IntType(8)):
|
||||
Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"strcpy_src_cast_{VarName}")
|
||||
size: ir.Constant = ir.Constant(ir.IntType(64), 8)
|
||||
align: ir.Constant = ir.Constant(ir.IntType(32), 1)
|
||||
isvolatile: ir.Constant = ir.Constant(ir.IntType(1), 0)
|
||||
Gen.builder.call(Gen.functions['llvm.memcpy'], [DestPtr, Value, size, align, isvolatile], name=f"strcpy_call_{VarName}")
|
||||
return
|
||||
try:
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
except Exception: # 回退:bitcast 失败时 alloca 新变量
|
||||
NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||||
Gen._store(Value, NewVar)
|
||||
Gen.variables[VarName] = NewVar
|
||||
|
||||
def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
AttrName: str = Target.attr
|
||||
if isinstance(Target.value, ast.Name) and Target.value.id == 'self':
|
||||
ClassName: str | None = self._CurrentCpythonObjectClass
|
||||
if not ClassName:
|
||||
self_var: ir.Value | None = Gen.variables.get('self')
|
||||
if self_var:
|
||||
var_type: ir.Type = self_var.type
|
||||
if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType):
|
||||
var_type = var_type.pointee
|
||||
if isinstance(var_type, ir.PointerType):
|
||||
pointee: ir.Type = var_type.pointee
|
||||
for cn, st in Gen.structs.items():
|
||||
if st == pointee:
|
||||
ClassName = cn
|
||||
break
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||||
if SelfVar:
|
||||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||||
offset: int = Gen._get_member_offset(AttrName, ClassName)
|
||||
MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
elif isinstance(Target.value, ast.Name):
|
||||
VarName: str = Target.value.id
|
||||
|
||||
# FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储)
|
||||
# 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖)
|
||||
_fd_meta_name: str = f"{VarName}__meta__"
|
||||
if _fd_meta_name in Gen.variables and '_str' in Gen.structs:
|
||||
_fd_offset = Gen._get_member_offset(AttrName, '_str')
|
||||
if _fd_offset is not None:
|
||||
_fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name]
|
||||
_fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr")
|
||||
self._StoreWithCoerce(Value, _fd_field_ptr)
|
||||
return
|
||||
|
||||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||||
if not ClassName:
|
||||
for CN in Gen.structs:
|
||||
if VarName == CN.lower() or VarName.startswith(CN):
|
||||
ClassName = CN
|
||||
break
|
||||
if not ClassName and VarName in Gen.variables:
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(VarPtr.type, ir.PointerType):
|
||||
pointee: ir.Type = VarPtr.type.pointee
|
||||
if isinstance(pointee, ir.PointerType):
|
||||
pointee = pointee.pointee
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
IsUnion: bool = False
|
||||
if ClassName:
|
||||
ClassTypeInfo: Any = self.Trans.SymbolTable.lookup(ClassName)
|
||||
if ClassTypeInfo:
|
||||
if ClassTypeInfo.IsUnion:
|
||||
IsUnion = True
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||||
if ObjVal:
|
||||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IntType) and ObjVal.type.pointee.width == 8:
|
||||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||||
ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}")
|
||||
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]:
|
||||
if IsUnion:
|
||||
NestedStructName: str = f"{ClassName}_{AttrName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
NestedStructType: ir.Type = Gen.structs[NestedStructName]
|
||||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}")
|
||||
offset: int = Gen._get_member_offset(AttrName, NestedStructName)
|
||||
if offset is not None and offset < len(NestedStructType.elements):
|
||||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
return
|
||||
offset: int = Gen._get_member_offset(AttrName, ClassName)
|
||||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
elif isinstance(Target.value, ast.Attribute):
|
||||
ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||||
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
|
||||
pointee: ir.Type = ObjVal.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
offset: int = Gen._get_member_offset(AttrName, CN)
|
||||
MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
break
|
||||
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(Ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = Ptr.type.pointee
|
||||
if Value.type != TargetType:
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if TargetType.width < Value.type.width:
|
||||
Value = Gen.builder.trunc(Value, TargetType, name="trunc")
|
||||
else:
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||||
Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr")
|
||||
elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType):
|
||||
Value = Gen.builder.ptrtoint(Value, TargetType, name="ptr_to_int")
|
||||
Gen._store(Value, Ptr)
|
||||
|
||||
def _HandleGenericListLiteralAssign(self, VarName: str, Node: ast.AnnAssign, Gen: LlvmCodeGenerator, list_sub: ast.Subscript) -> None:
|
||||
"""处理 list[T] = [...] → 构造 list[T] 对象 + append 序列。
|
||||
|
||||
将 list 字面量翻译为:
|
||||
1. 特化 list[T] 类
|
||||
2. alloca + __before_init__ + __new__(pool) + __before_init__ + __init__(pool)
|
||||
3. 对每个元素调用 append(elem)
|
||||
4. 将堆指针存入变量
|
||||
list_sub 是从注解中提取的 list[...] Subscript 节点(支持 list[T] 和 list[T] | t.CPtr)
|
||||
"""
|
||||
# 1. 解析元素类型
|
||||
slice_node: ast.expr = list_sub.slice
|
||||
result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node)
|
||||
if result is None:
|
||||
return
|
||||
type_arg: str = result[0]
|
||||
type_name: str = result[1]
|
||||
|
||||
# 2. 特化 list[T] 类
|
||||
spec_name: str | None = self.Trans.ClassHandler._specialize_generic_class(
|
||||
'list', [type_arg], Gen, type_names=[type_name])
|
||||
if spec_name is None:
|
||||
return
|
||||
|
||||
# 3. 获取结构体类型
|
||||
StructType: ir.Type | None = Gen.structs.get(spec_name)
|
||||
if StructType is None:
|
||||
return
|
||||
if isinstance(StructType, ir.PointerType):
|
||||
StructType = StructType.pointee
|
||||
|
||||
# 4. 查找 pool 变量(pool / _mbuddy / mbuddy / mb)
|
||||
pool_val: ir.Value | None = None
|
||||
for pool_name in ('pool', '_mbuddy', 'mbuddy', 'mb'):
|
||||
if pool_name in Gen.variables:
|
||||
pool_var: ir.Value = Gen.variables[pool_name]
|
||||
if isinstance(pool_var.type, ir.PointerType):
|
||||
pointee: ir.Type = pool_var.type.pointee
|
||||
if isinstance(pointee, ir.PointerType):
|
||||
# alloca of pointer → load
|
||||
pool_val = Gen._load(pool_var, name=f"pool_load_{VarName}")
|
||||
else:
|
||||
pool_val = pool_var
|
||||
else:
|
||||
pool_val = pool_var
|
||||
break
|
||||
if pool_val is None:
|
||||
return
|
||||
|
||||
# 5. alloca 临时结构体
|
||||
alloca_ptr: ir.AllocaInstr = Gen._allocaEntry(StructType, name=f"{VarName}_alloca")
|
||||
|
||||
# 6. 调用 __before_init__(alloca_ptr)
|
||||
before_init_name: str = f'{spec_name}.__before_init__'
|
||||
before_init_func: ir.Function | None = None
|
||||
if Gen._has_function(before_init_name):
|
||||
before_init_func = Gen._get_function(before_init_name)
|
||||
Gen.builder.call(before_init_func, [alloca_ptr], name=f"before_init_{VarName}")
|
||||
|
||||
# 7. 调用 __new__(alloca_ptr, pool_val) → heap_ptr
|
||||
new_method_name: str = f'{spec_name}.__new__'
|
||||
heap_ptr: ir.Value = alloca_ptr
|
||||
has_new: bool = Gen._find_function(new_method_name) is not None
|
||||
if has_new:
|
||||
new_func: ir.Function | None = Gen._find_function(new_method_name)
|
||||
if new_func:
|
||||
new_args: list[ir.Value] = [alloca_ptr, pool_val]
|
||||
self.Trans.ExprCallHandle._fill_default_args(new_args, new_func, new_method_name)
|
||||
new_args = Gen._apply_auto_addr(new_method_name, new_args)
|
||||
adjusted_new: list[ir.Value] = Gen._adjust_args(new_args, new_func)
|
||||
heap_ptr = Gen.builder.call(new_func, adjusted_new, name=f"new_{VarName}")
|
||||
# 转换返回指针类型
|
||||
target_ptr_type: ir.PointerType = ir.PointerType(StructType)
|
||||
if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != target_ptr_type:
|
||||
heap_ptr = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{VarName}_cast")
|
||||
elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type:
|
||||
if heap_ptr.type.width < 64:
|
||||
i64_val: ir.Value = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{VarName}_i64")
|
||||
heap_ptr = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{VarName}_ptr")
|
||||
else:
|
||||
heap_ptr = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{VarName}_ptr")
|
||||
# 对堆指针重新调用 __before_init__
|
||||
if before_init_func:
|
||||
Gen.builder.call(before_init_func, [heap_ptr], name=f"before_init_{VarName}_heap")
|
||||
|
||||
# 8. 调用 __init__(heap_ptr, pool_val, elem_size=0)
|
||||
init_name: str = f'{spec_name}.__init__'
|
||||
if Gen._has_function(init_name):
|
||||
init_func: ir.Function | None = Gen._get_function(init_name)
|
||||
if init_func:
|
||||
elem_size_val: ir.Constant = ir.Constant(ir.IntType(64), 0)
|
||||
init_args: list[ir.Value] = [heap_ptr, pool_val, elem_size_val]
|
||||
self.Trans.ExprCallHandle._fill_default_args(init_args, init_func, init_name)
|
||||
init_args = Gen._apply_auto_addr(init_name, init_args)
|
||||
adjusted_init: list[ir.Value] = Gen._adjust_args(init_args, init_func)
|
||||
Gen.builder.call(init_func, adjusted_init, name=f"init_{VarName}")
|
||||
|
||||
# 9. 对每个元素调用 append(heap_ptr, elem_val)
|
||||
append_name: str = f'{spec_name}.append'
|
||||
append_func: ir.Function | None = Gen._find_function(append_name)
|
||||
if append_func and Node.value and isinstance(Node.value, ast.List):
|
||||
elts: list[ast.expr] = Node.value.elts
|
||||
for i, elem_node in enumerate(elts):
|
||||
elem_val: ir.Value | None = self.HandleExprLlvm(elem_node)
|
||||
if elem_val:
|
||||
append_args: list[ir.Value] = [heap_ptr, elem_val]
|
||||
self.Trans.ExprCallHandle._fill_default_args(append_args, append_func, append_name)
|
||||
append_args = Gen._apply_auto_addr(append_name, append_args)
|
||||
adjusted_append: list[ir.Value] = Gen._adjust_args(append_args, append_func)
|
||||
Gen.builder.call(append_func, adjusted_append, name=f"append_{VarName}_{i}")
|
||||
|
||||
# 10. 创建变量并存储堆指针
|
||||
# 判断变量类型:list[T] | t.CPtr → i8*;list[T] → Ptr(StructType)
|
||||
is_cptr_union: bool = isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)
|
||||
if is_cptr_union:
|
||||
# list[T] | t.CPtr → 变量类型为 i8*
|
||||
i8_ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8))
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(i8_ptr_type, name=VarName)
|
||||
# bitcast heap_ptr (Ptr(StructType)) → i8*
|
||||
if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != i8_ptr_type:
|
||||
stored_val: ir.Value = Gen.builder.bitcast(heap_ptr, i8_ptr_type, name=f"store_cast_{VarName}")
|
||||
else:
|
||||
stored_val = heap_ptr
|
||||
Gen._store(stored_val, var)
|
||||
else:
|
||||
# list[T] → 变量类型为 Ptr(StructType)
|
||||
var = Gen._allocaEntry(ir.PointerType(StructType), name=VarName)
|
||||
Gen._store(heap_ptr, var)
|
||||
Gen.variables[VarName] = var
|
||||
Gen.var_struct_class[VarName] = spec_name
|
||||
Gen.global_struct_class[VarName] = spec_name
|
||||
Gen._record_var_signedness(VarName, False)
|
||||
|
||||
def _HandleAnnAssignLlvm(self, Node: ast.AnnAssign) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
self.Trans._current_assign_node = Node
|
||||
try:
|
||||
self._HandleAnnAssignLlvmInner(Node)
|
||||
finally:
|
||||
self.Trans._current_assign_node = None
|
||||
|
||||
def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
IsPtr: bool = TypeInfo.IsPtr
|
||||
|
||||
if TypeInfo.IsDefine:
|
||||
if Node.value and isinstance(Node.value, ast.Constant):
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants = {}
|
||||
Gen._define_constants[VarName] = Node.value.value
|
||||
info: CTypeInfo = CTypeInfo()
|
||||
info.IsDefine = True
|
||||
info.DefineValue = Node.value.value
|
||||
self.Trans.SymbolTable.insert(VarName, info)
|
||||
Gen._record_var_signedness(VarName, TypeInfo.IsUInt)
|
||||
elif Node.value:
|
||||
# 非 Constant 表达式:尝试编译期求值(如 t.CSizeT().Size // 8)
|
||||
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
|
||||
ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
|
||||
eval_val = ConstEvaluator.eval_full(Node.value, ctx)
|
||||
if eval_val is not None and isinstance(eval_val, (int, float)):
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants = {}
|
||||
Gen._define_constants[VarName] = eval_val
|
||||
info: CTypeInfo = CTypeInfo()
|
||||
info.IsDefine = True
|
||||
info.DefineValue = eval_val
|
||||
self.Trans.SymbolTable.insert(VarName, info)
|
||||
Gen._record_var_signedness(VarName, TypeInfo.IsUInt)
|
||||
return
|
||||
if TypeInfo.IsStr or (isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str'):
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CChar()
|
||||
TypeInfo.PtrCount = 1
|
||||
IsPtr = True
|
||||
# FakeDuck: 为 str 变量创建影子结构体 a__meta__ (栈上, per-instance)
|
||||
# a 保持为 char* 用于 printf; a__meta__ 存储 __data__ 和 __mbuddy__ 字段
|
||||
# 仅对 str 类型创建,bytes 和 t.CChar|t.CPtr 不创建
|
||||
if '_str' in Gen.structs and isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str':
|
||||
_meta_name: str = f"{VarName}__meta__"
|
||||
_meta_var: ir.AllocaInstr = Gen._allocaEntry(Gen.structs['_str'], name=_meta_name)
|
||||
Gen.variables[_meta_name] = _meta_var
|
||||
# 标记指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr)
|
||||
# elem_ptr[0] 应加载/存储 8 字节 (指针), 而非 1 字节 (字符)
|
||||
# 仅当注解包含 str 或 bytes 时设置(t.CChar | t.CPtr 不应设置,它是纯字符指针)
|
||||
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||||
if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'):
|
||||
Gen.var_ptr_element[VarName] = True
|
||||
# 同时记录到全局字典,使全局变量在跨函数访问时仍能用 8 字节指针步长
|
||||
Gen.global_var_ptr_element[VarName] = True
|
||||
parse_result = ParseListAnnotation(Node.annotation)
|
||||
if parse_result:
|
||||
elem_type_node: ast.expr = parse_result.elem_type_node
|
||||
ElemType, ElemTypeInfo = self.ResolveListElementType(
|
||||
elem_type_node, Gen,
|
||||
handle_str=True, void_fallback_width=32,
|
||||
)
|
||||
if parse_result.is_pointer:
|
||||
# 单参数 list[type] → 指针
|
||||
# 但如果有列表字面量初始化值 [a, b, c],则按数组 list[type, N] 处理
|
||||
if not (Node.value and isinstance(Node.value, ast.List)):
|
||||
VarType: ir.Type = ir.PointerType(ElemType)
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName)
|
||||
Gen.variables[VarName] = var
|
||||
Gen._record_var_signedness(VarName, False)
|
||||
if self.Trans.VarScopes:
|
||||
self.Trans.VarScopes[-1][VarName] = ElemTypeInfo
|
||||
return
|
||||
# 有列表字面量值,继续走数组路径(count_node=None 时从列表长度推断)
|
||||
count_node: ast.expr | None = parse_result.count_node
|
||||
ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='local')
|
||||
VarType = ir.ArrayType(ElemType, ArrayCount)
|
||||
var = Gen._allocaEntry(VarType, name=VarName)
|
||||
Gen.variables[VarName] = var
|
||||
Gen._record_var_signedness(VarName, False)
|
||||
if Node.value and isinstance(Node.value, ast.List):
|
||||
InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '')
|
||||
if InitConstants:
|
||||
try:
|
||||
InitVal: ir.Constant = ir.Constant(VarType, InitConstants)
|
||||
Gen.builder.store(InitVal, var)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
|
||||
str_val: str = Node.value.value + '\x00'
|
||||
str_bytes: bytearray = bytearray(str_val, 'utf-8')
|
||||
if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count:
|
||||
str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes)))
|
||||
try:
|
||||
InitVal: ir.Constant = ir.Constant(VarType, str_bytes[:VarType.count] if isinstance(VarType, ir.ArrayType) else str_bytes)
|
||||
Gen.builder.store(InitVal, var)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if self.Trans.VarScopes:
|
||||
self.Trans.VarScopes[-1][VarName] = ElemTypeInfo
|
||||
# 记录数组元素字节序
|
||||
if ElemTypeInfo and ElemTypeInfo.ByteOrder == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64):
|
||||
Gen.local_var_byteorders[VarName] = 'big'
|
||||
return
|
||||
# list[T] 泛型类注解 + list 字面量值 → 构造 list[T] 对象 + append 序列
|
||||
# (list[str] = ["a", "b"] 不应走 C 数组路径,而应构造 list[str] 对象)
|
||||
# 支持两种注解形式:list[T] 和 list[T] | t.CPtr
|
||||
list_sub: ast.Subscript | None = None
|
||||
if (isinstance(Node.annotation, ast.Subscript)
|
||||
and isinstance(Node.annotation.value, ast.Name)
|
||||
and Node.annotation.value.id == 'list'):
|
||||
list_sub = Node.annotation
|
||||
elif (isinstance(Node.annotation, ast.BinOp)
|
||||
and isinstance(Node.annotation.op, ast.BitOr)):
|
||||
for side in (Node.annotation.left, Node.annotation.right):
|
||||
if (isinstance(side, ast.Subscript)
|
||||
and isinstance(side.value, ast.Name)
|
||||
and side.value.id == 'list'):
|
||||
list_sub = side
|
||||
break
|
||||
if (list_sub is not None
|
||||
and not isinstance(list_sub.slice, ast.Tuple)
|
||||
and Node.value is not None
|
||||
and isinstance(Node.value, ast.List)
|
||||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||||
and 'list' in self.Trans.ClassHandler._generic_class_templates):
|
||||
self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub)
|
||||
return
|
||||
if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp):
|
||||
found: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
if found:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CStruct(name=found)
|
||||
TypeInfo.PtrCount = 1
|
||||
IsPtr = True
|
||||
elif isinstance(Node.annotation.left, ast.Attribute):
|
||||
AttrTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left)
|
||||
if AttrTypeInfo and AttrTypeInfo.BaseType:
|
||||
TypeInfo = AttrTypeInfo
|
||||
TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1)
|
||||
IsPtr = True
|
||||
# 对于局部变量声明 s: TestStruct(不带 | t.CPtr),应为栈上结构体而非指针
|
||||
# GetCTypeInfo 默认设置 PtrCount=1,但纯结构体名注解应为值类型
|
||||
if (isinstance(Node.annotation, ast.Name)
|
||||
and Node.annotation.id in Gen.structs
|
||||
and TypeInfo.IsStruct
|
||||
and Node.annotation.id not in Gen.class_vtable):
|
||||
TypeInfo.PtrCount = 0
|
||||
IsPtr = False
|
||||
VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name:
|
||||
stripped: str = TypeInfo.Name
|
||||
if stripped in Gen.class_vtable and stripped in Gen.structs:
|
||||
VarType = ir.PointerType(Gen.structs[stripped])
|
||||
IsPtr = True
|
||||
if isinstance(VarType, ir.IdentifiedStructType):
|
||||
struct_name: str = getattr(VarType, 'name', '')
|
||||
if struct_name and Gen.class_vtable:
|
||||
for cls_name in Gen.class_vtable:
|
||||
if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name:
|
||||
VarType = ir.PointerType(VarType)
|
||||
IsPtr = True
|
||||
break
|
||||
if isinstance(VarType, ir.VoidType):
|
||||
VarType = ir.IntType(32)
|
||||
IsUnsigned: bool = TypeInfo.IsUInt
|
||||
# 修复 3: BinOp 注解(如 ast.Arguments | t.CPtr)的 var_struct_class 设置
|
||||
# TypeInfo.Name 由 _HandleSubscript 设置(特化名如 list[sha1.ASTptr])或
|
||||
# GetCTypeInfo 设置(普通结构体名),经 _MergeCTypeInfoInto 传播后保留。
|
||||
# 此处确保 BinOp 注解的变量也能被 _get_var_class 识别,避免方法调用分派
|
||||
# fallthrough 到 char pointer fallback 错误匹配其他类(如 AST.__len__)。
|
||||
# 使用 not in 条件,不覆盖后续 L337-339/L396-398 对 ast.Name 注解的精确设置。
|
||||
if TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
|
||||
if VarName not in Gen.var_struct_class:
|
||||
Gen.var_struct_class[VarName] = TypeInfo.Name
|
||||
Gen.global_struct_class[VarName] = TypeInfo.Name
|
||||
if VarName in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||||
if isinstance(OldVal.type, ir.PointerType):
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[VarName] = var
|
||||
del Gen._reg_values[VarName]
|
||||
if Node.value:
|
||||
InitValue: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=VarType)
|
||||
if InitValue:
|
||||
self._StoreOrStrCopy(VarName, var, InitValue)
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
del Gen._reg_values[VarName]
|
||||
InitValue: ir.Value | None = None
|
||||
if Node.value:
|
||||
InitValue = self.HandleExprLlvm(Node.value, VarType=VarType)
|
||||
if VarName in Gen._reg_values:
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
if InitValue and isinstance(InitValue.type, ir.PointerType):
|
||||
pointee: ir.Type = InitValue.type.pointee
|
||||
if isinstance(pointee, ir.IdentifiedStructType):
|
||||
struct_name: str = getattr(pointee, 'name', '')
|
||||
is_vtable_class: bool = False
|
||||
for cls_name in Gen.class_vtable:
|
||||
if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name:
|
||||
is_vtable_class = True
|
||||
break
|
||||
if is_vtable_class:
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(InitValue.type, name=VarName)
|
||||
Gen._store(InitValue, var)
|
||||
Gen.variables[VarName] = var
|
||||
if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs:
|
||||
Gen.var_struct_class[VarName] = Node.annotation.id
|
||||
Gen.global_struct_class[VarName] = Node.annotation.id
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
if InitValue:
|
||||
try:
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(VarPtr.type, ir.PointerType):
|
||||
TargetType: ir.Type = VarPtr.type.pointee
|
||||
if InitValue.type != TargetType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType):
|
||||
if TargetType.width > InitValue.type.width:
|
||||
InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}")
|
||||
elif TargetType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType):
|
||||
InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}")
|
||||
Gen._store(InitValue, VarPtr)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
if VarName in Gen.global_vars:
|
||||
if VarName in Gen.module.globals:
|
||||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||||
if InitValue:
|
||||
Gen._store(InitValue, GVar)
|
||||
Gen.variables[VarName] = GVar
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName)
|
||||
if InitValue and isinstance(InitValue.type, ir.PointerType):
|
||||
pointee: ir.Type = InitValue.type.pointee
|
||||
# 当 InitValue 是 i8* (t.CPtr) 且注解是 Gen.structs 中的结构体名时,
|
||||
# bitcast 为对应的结构体指针,以便正确存储和设置 var_struct_class
|
||||
# 例如: sub: dict = sub_p (sub_p 是 t.CPtr)
|
||||
if (isinstance(pointee, ir.IntType) and pointee.width == 8
|
||||
and isinstance(Node.annotation, ast.Name)
|
||||
and Node.annotation.id in Gen.structs):
|
||||
TargetStructType: ir.Type = Gen.structs[Node.annotation.id]
|
||||
if isinstance(TargetStructType, ir.PointerType):
|
||||
TargetStructType = TargetStructType.pointee
|
||||
InitValue = Gen.builder.bitcast(InitValue, ir.PointerType(TargetStructType), name=f"cast_{VarName}_to_{Node.annotation.id}")
|
||||
pointee = InitValue.type.pointee
|
||||
if isinstance(pointee, ir.IdentifiedStructType):
|
||||
struct_name: str = getattr(pointee, 'name', '')
|
||||
is_vtable_class: bool = False
|
||||
for cls_name in Gen.class_vtable:
|
||||
if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name:
|
||||
is_vtable_class = True
|
||||
break
|
||||
if is_vtable_class and not isinstance(VarType, ir.PointerType):
|
||||
var = Gen._allocaEntry(InitValue.type, name=VarName)
|
||||
VarType = InitValue.type
|
||||
IsPtr = True
|
||||
Gen._store(InitValue, var)
|
||||
Gen.variables[VarName] = var
|
||||
if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs:
|
||||
Gen.var_struct_class[VarName] = Node.annotation.id
|
||||
Gen.global_struct_class[VarName] = Node.annotation.id
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee is ST or pointee == ST:
|
||||
if CN != Gen.var_struct_class.get(VarName):
|
||||
Gen.var_struct_class[VarName] = CN
|
||||
Gen.global_struct_class[VarName] = CN
|
||||
if isinstance(VarType, ir.PointerType) and VarType.pointee is not ST and VarType.pointee != ST:
|
||||
var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName)
|
||||
VarType = ir.PointerType(pointee)
|
||||
break
|
||||
if InitValue:
|
||||
try:
|
||||
if InitValue.type != VarType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType):
|
||||
if VarType.width > InitValue.type.width:
|
||||
InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}")
|
||||
elif VarType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType):
|
||||
InitValue = Gen.builder.bitcast(InitValue, VarType, name=f"cast_{VarName}")
|
||||
elif isinstance(VarType, ir.PointerType) and isinstance(InitValue.type, ir.IntType):
|
||||
InitValue = Gen.builder.inttoptr(InitValue, VarType, name=f"int2ptr_{VarName}")
|
||||
elif isinstance(VarType, ir.IntType) and isinstance(InitValue.type, ir.PointerType):
|
||||
InitValue = Gen.builder.ptrtoint(InitValue, VarType, name=f"ptr2int_{VarName}")
|
||||
# 大端局部变量:存储时 bswap
|
||||
InitValue = Gen._apply_bswap_if_big(InitValue, TypeInfo.ByteOrder, f"bswap_store_{VarName}")
|
||||
Gen._store(InitValue, var)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
Gen.variables[VarName] = var
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
# FakeDuck: 初始化影子结构体 a__meta__ 的字段
|
||||
_meta_name_check: str = f"{VarName}__meta__"
|
||||
if _meta_name_check in Gen.variables and '_str' in Gen.structs:
|
||||
_meta_var_init: ir.Value = Gen.variables[_meta_name_check]
|
||||
_str_st: ir.Type = Gen.structs['_str']
|
||||
# __data__ 字段 = 字符串指针
|
||||
_data_off = Gen._get_member_offset('__data__', '_str')
|
||||
if _data_off is not None and InitValue:
|
||||
_data_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name=f"{VarName}_meta_data")
|
||||
Gen._store(InitValue, _data_ptr)
|
||||
# __mbuddy__ 字段 = NULL
|
||||
_mpool_off = Gen._get_member_offset('__mbuddy__', '_str')
|
||||
if _mpool_off is not None:
|
||||
_mpool_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name=f"{VarName}_meta_mbuddy")
|
||||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr)
|
||||
# FakeDuck: 从 with 上下文自动注入 requires 字段(如 __mbuddy__)
|
||||
self.Trans.ExprCallHandle._InjectRequiresFields(_meta_var_init, '_str', Gen)
|
||||
# 记录局部变量字节序
|
||||
if TypeInfo.ByteOrder == 'big':
|
||||
if isinstance(VarType, ir.IntType) and VarType.width in (16, 32, 64):
|
||||
Gen.local_var_byteorders[VarName] = 'big'
|
||||
elif isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width in (16, 32, 64):
|
||||
Gen.local_var_byteorders[VarName] = 'big'
|
||||
|
||||
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||||
found_struct: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
if found_struct:
|
||||
Gen.var_struct_class[VarName] = found_struct
|
||||
Gen.global_struct_class[VarName] = found_struct
|
||||
|
||||
if InitValue and isinstance(InitValue.type, ir.PointerType):
|
||||
pointee: ir.Type = InitValue.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
Gen._var_to_heap_ptr[VarName] = InitValue
|
||||
if CN != Gen.var_struct_class.get(VarName):
|
||||
Gen.var_struct_class[VarName] = CN
|
||||
Gen.global_struct_class[VarName] = CN
|
||||
break
|
||||
|
||||
if self.Trans.VarScopes:
|
||||
if TypeInfo:
|
||||
self.Trans.VarScopes[-1][VarName] = TypeInfo
|
||||
else:
|
||||
DefaultInfo: CTypeInfo = CTypeInfo()
|
||||
DefaultInfo.BaseType = t.CInt
|
||||
self.Trans.VarScopes[-1][VarName] = DefaultInfo
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
if isinstance(Node.target.value, ast.Name) and Node.target.value.id == 'self':
|
||||
if Node.value:
|
||||
AttrVarType: Any = None
|
||||
try:
|
||||
if IsListAnnotation(Node.annotation):
|
||||
slice_node: ast.AST = Node.annotation.slice
|
||||
if isinstance(slice_node, ast.Name):
|
||||
AttrVarType = f't.CArray[{slice_node.id}]'
|
||||
elif isinstance(slice_node, ast.Tuple):
|
||||
elts: str = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts)
|
||||
AttrVarType = f't.CArray[{elts}]'
|
||||
elif isinstance(slice_node, ast.Attribute):
|
||||
# 还原 t.xxx 形式(如 t.CInt、t.CArray)
|
||||
if isinstance(slice_node.value, ast.Name):
|
||||
AttrVarType = f't.CArray[{slice_node.value.id}.{slice_node.attr}]'
|
||||
else:
|
||||
AttrVarType = f't.CArray[{ast.unparse(slice_node)}]'
|
||||
if AttrVarType is None:
|
||||
AttrTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
|
||||
if AttrTypeInfo:
|
||||
AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
|
||||
if Value:
|
||||
self._HandleAttributeStoreLlvm(Node.target, Value)
|
||||
AttrName: str = Node.target.attr
|
||||
len_name: str = f'{AttrName}__len'
|
||||
ClassName: str | None = self._CurrentCpythonObjectClass
|
||||
if not ClassName:
|
||||
self_var: ir.Value | None = Gen.variables.get('self')
|
||||
if self_var:
|
||||
var_type: ir.Type = self_var.type
|
||||
if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType):
|
||||
var_type = var_type.pointee
|
||||
if isinstance(var_type, ir.PointerType):
|
||||
pointee: ir.Type = var_type.pointee
|
||||
for cn, st in Gen.structs.items():
|
||||
if st == pointee:
|
||||
ClassName = cn
|
||||
break
|
||||
if ClassName and ClassName in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[ClassName]:
|
||||
if m_name == len_name:
|
||||
list_len: ir.Constant | None = None
|
||||
if isinstance(Node.value, ast.List):
|
||||
list_len = ir.Constant(ir.IntType(64), len(Node.value.elts))
|
||||
if list_len is not None:
|
||||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||||
if SelfVar:
|
||||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||||
offset: int = Gen._get_member_offset(len_name, ClassName)
|
||||
LenPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name)
|
||||
Gen._store(list_len, LenPtr)
|
||||
break
|
||||
60
lib/core/Handles/HandlesAssert.py
Normal file
60
lib/core/Handles/HandlesAssert.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
class AssertHandle(BaseHandle):
|
||||
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
|
||||
if not cond_val:
|
||||
return
|
||||
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
|
||||
zero: ir.Constant = ir.Constant(cond_val.type, 0)
|
||||
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
|
||||
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
|
||||
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
|
||||
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
|
||||
Gen.builder.position_at_start(AssertFailBB)
|
||||
exc_code: int = 9
|
||||
exc_msg: ir.Value | None = None
|
||||
if Node.msg:
|
||||
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
|
||||
if Node.msg.args:
|
||||
first_arg: ast.expr = Node.msg.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(Node.msg, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
|
||||
else:
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
if exc_msg:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
|
||||
else:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
|
||||
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
|
||||
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_start(AssertOkBB)
|
||||
1673
lib/core/Handles/HandlesAssign.py
Normal file
1673
lib/core/Handles/HandlesAssign.py
Normal file
File diff suppressed because it is too large
Load Diff
224
lib/core/Handles/HandlesAugAssign.py
Normal file
224
lib/core/Handles/HandlesAugAssign.py
Normal file
@@ -0,0 +1,224 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import ast
|
||||
import sys
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
|
||||
|
||||
class AugAssignHandle(BaseHandle):
|
||||
_AUGOP_MAP: dict[type, str] = {
|
||||
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
|
||||
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
|
||||
}
|
||||
_AUGOP_FALLBACK: dict[type, str] = {
|
||||
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
|
||||
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
|
||||
}
|
||||
|
||||
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
|
||||
"""判断增量赋值操作是否应使用无符号指令"""
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
if Node.value is not None and Gen._check_node_unsigned(Node.value):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
if (VarName not in Gen.variables
|
||||
and VarName not in Gen.global_vars
|
||||
and VarName not in Gen._reg_values
|
||||
and VarName not in Gen._direct_values):
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
|
||||
sys.exit(1)
|
||||
if VarName in Gen.var_const_flags:
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
|
||||
sys.exit(1)
|
||||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||||
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
|
||||
if ClassName and iop_name:
|
||||
iFuncName: str = f'{ClassName}.{iop_name}'
|
||||
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
|
||||
if iFuncName in Gen.functions or FuncName in Gen.functions:
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if OldVal and Value:
|
||||
result: ir.Value | None
|
||||
if iFuncName in Gen.functions:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
|
||||
else:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
|
||||
if result is not None:
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if VarPtr.type.pointee == result.type:
|
||||
Gen._store(result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
|
||||
Gen._store(result, NewVar)
|
||||
Gen.variables[VarName] = NewVar
|
||||
else:
|
||||
Gen._reg_values[VarName] = result
|
||||
Gen.variables[VarName] = None
|
||||
return
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if not Value:
|
||||
return
|
||||
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if VarName in Gen.global_vars and VarName in Gen.module.globals:
|
||||
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
|
||||
Gen.variables[VarName] = GVar
|
||||
OldVal: ir.Value = Gen._load(GVar, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, GVar)
|
||||
return
|
||||
if VarName in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
entry_block: ir.Block = Gen.func.entry_basic_block
|
||||
Gen.builder.position_at_start(entry_block)
|
||||
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
Gen.variables[VarName] = var
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen._direct_values:
|
||||
OldVal: ir.Value = Gen._direct_values.pop(VarName)
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
entry_block: ir.Block = Gen.func.entry_basic_block
|
||||
Gen.builder.position_at_start(entry_block)
|
||||
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
Gen.variables[VarName] = var
|
||||
if Gen.builder.block.is_terminated:
|
||||
return
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
|
||||
store_ptr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Value.type.width != 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
|
||||
NewVal: ir.Value
|
||||
if Op == '-' or Op == '+':
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
|
||||
else:
|
||||
ptr_val: ir.Value = OldVal
|
||||
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
|
||||
orig_type: ir.Type = OldVal.type
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
|
||||
if NewVal.type.width > orig_type.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
|
||||
store_ptr = ptr_val
|
||||
else:
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
|
||||
Gen._store(NewVal, store_ptr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(store_ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = store_ptr.type.pointee
|
||||
if NewVal.type != TargetType:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
|
||||
if Coerced is not None:
|
||||
NewVal = Coerced
|
||||
Gen._store(NewVal, store_ptr)
|
||||
elif VarName == 'pos':
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||||
Gen.variables[VarName] = var
|
||||
OldVal: ir.Value = Gen._load(var, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, var)
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
AttrName: str = Node.target.attr
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
|
||||
if OldVal:
|
||||
def _deref_if_ptr(val: ir.Value) -> ir.Value:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
|
||||
return Gen._load(val, name="deref_aug")
|
||||
return val
|
||||
OldVal = _deref_if_ptr(OldVal)
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
SubTarget: ast.Subscript = Node.target
|
||||
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
|
||||
if ElemPtr:
|
||||
if isinstance(ElemPtr.type, ir.PointerType):
|
||||
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
|
||||
Gen._store(NewVal, ElemPtr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
|
||||
if NewVal.type.width > ElemPtr.type.pointee.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
|
||||
Gen._store(NewVal, ElemPtr)
|
||||
832
lib/core/Handles/HandlesBase.py
Normal file
832
lib/core/Handles/HandlesBase.py
Normal file
@@ -0,0 +1,832 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, List, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
|
||||
import ast
|
||||
from enum import IntFlag, auto
|
||||
|
||||
from llvmlite import ir as _ir
|
||||
|
||||
from lib.constants import config as _config
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
EXCEPTION_CODE_MAP: dict[str, int] = {
|
||||
'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3,
|
||||
'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6,
|
||||
'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99,
|
||||
}
|
||||
|
||||
|
||||
class FuncMeta(IntFlag):
|
||||
NONE = 0
|
||||
STATIC_METHOD = auto()
|
||||
PROPERTY_GETTER = auto()
|
||||
PROPERTY_SETTER = auto()
|
||||
PROPERTY_DELETER = auto()
|
||||
CLASS_METHOD = auto()
|
||||
ABSTRACT = auto()
|
||||
|
||||
|
||||
class _Delegated:
|
||||
"""CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段
|
||||
|
||||
替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由:
|
||||
描述符在类创建时绑定,访问时直接走 __get__/__set__,
|
||||
无 dict 查找和字符串比较的运行时开销。
|
||||
"""
|
||||
__slots__ = ('_target_attr', '_field_name')
|
||||
|
||||
def __init__(self, target_attr: str, field_name: str) -> None:
|
||||
self._target_attr: str = target_attr # '_ts' or '_sm'
|
||||
self._field_name: str = field_name
|
||||
|
||||
def __get__(self, obj: Any, objtype: type | None = None) -> Any:
|
||||
if obj is None:
|
||||
return self
|
||||
target: Any = object.__getattribute__(obj, self._target_attr)
|
||||
return getattr(target, self._field_name)
|
||||
|
||||
def __set__(self, obj: Any, value: Any) -> None:
|
||||
target: Any = object.__getattribute__(obj, self._target_attr)
|
||||
setattr(target, self._field_name, value)
|
||||
|
||||
|
||||
class CTypeInfo:
|
||||
"""
|
||||
C 类型信息对象 - 统一符号表条目和类型计算
|
||||
|
||||
设计原则:
|
||||
- BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串
|
||||
- 描述符分为两种:
|
||||
- VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const
|
||||
- DataConst/DataVolatile: 指向数据的限定符,如 const int *
|
||||
|
||||
属性(类型计算):
|
||||
- BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid())
|
||||
- PtrCount: int - 指针层数
|
||||
- VarConst: bool - 变量本身(指针)是否 const,如 int * const
|
||||
- VarVolatile: bool - 变量本身(指针)是否 volatile
|
||||
- DataConst: bool - 指向的数据是否 const,如 const int *
|
||||
- DataVolatile: bool - 指向的数据是否 volatile
|
||||
- ArrayDims: List[str] - 数组维度
|
||||
- Storage: t.CType - 存储类 (static, extern 等)
|
||||
- IsFuncPtr: bool - 是否函数指针
|
||||
- FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型)
|
||||
- FuncPtrReturn: CTypeInfo - 函数指针返回类型
|
||||
- IsBitField: bool - 是否位域
|
||||
- BitWidth: int - 位域宽度
|
||||
- IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类
|
||||
|
||||
属性(符号表元数据):
|
||||
- Name: str - 名称(struct/enum/union/typedef 名)
|
||||
- Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union)
|
||||
- OriginalType: str - typedef 的原始类型
|
||||
- DeclaredType: str - 声明类型
|
||||
- CreturnTypes: list - C 返回类型列表
|
||||
- Lineno: int - 定义行号
|
||||
- IsAnonymous: bool - 是否匿名类型
|
||||
- IsCpythonObject: bool - 是否 CPython 对象
|
||||
- IsEnumMember: bool - 是否枚举成员
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
object.__setattr__(self, '_ts', TypeSpec())
|
||||
sm: SymbolMeta = SymbolMeta()
|
||||
sm.meta_list = FuncMeta.NONE
|
||||
object.__setattr__(self, '_sm', sm)
|
||||
|
||||
# --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind ---
|
||||
@property
|
||||
def ts(self) -> TypeSpec:
|
||||
"""TypeSpec — 纯类型描述(只读)"""
|
||||
return self._ts
|
||||
|
||||
@property
|
||||
def sm(self) -> SymbolMeta:
|
||||
"""SymbolMeta — 符号表元数据(只读)"""
|
||||
return self._sm
|
||||
|
||||
@property
|
||||
def kind(self) -> 'SymbolKind':
|
||||
"""SymbolKind — 符号类型种类枚举"""
|
||||
return self._sm.kind
|
||||
|
||||
# 注:旧字段名(PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现,
|
||||
# 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def BaseType(self) -> t.CType | tuple | None:
|
||||
return self._ts._base_type
|
||||
|
||||
@BaseType.setter
|
||||
def BaseType(self, value: t.CType | type | tuple | List | None) -> None:
|
||||
"""设置 BaseType,接受以下类型:
|
||||
|
||||
- None: 清空
|
||||
- t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志
|
||||
- type (CType 子类): 如 t.CStruct,自动实例化
|
||||
- tuple/list of t.CType: 多个组合类型
|
||||
"""
|
||||
ts: TypeSpec = self._ts
|
||||
sm: SymbolMeta = self._sm
|
||||
|
||||
if value is None:
|
||||
ts._base_type = None
|
||||
sm.is_struct = False
|
||||
sm.is_enum = False
|
||||
sm.is_union = False
|
||||
sm.is_renum = False
|
||||
return
|
||||
|
||||
if isinstance(value, (tuple, list)):
|
||||
ts._base_type = tuple(value)
|
||||
for v in value:
|
||||
if isinstance(v, t.CStruct):
|
||||
sm.is_struct = True
|
||||
elif isinstance(v, t.CEnum):
|
||||
sm.is_enum = True
|
||||
elif isinstance(v, t.CUnion):
|
||||
sm.is_union = True
|
||||
elif isinstance(v, t.REnum):
|
||||
sm.is_renum = True
|
||||
sm.is_enum = True
|
||||
return
|
||||
|
||||
if isinstance(value, type) and issubclass(value, t.CType):
|
||||
ts._base_type = value()
|
||||
return
|
||||
|
||||
if isinstance(value, t.CType):
|
||||
ts._base_type = value
|
||||
if isinstance(value, t.CStruct):
|
||||
sm.is_struct = True
|
||||
sm.is_enum = False
|
||||
sm.is_union = False
|
||||
sm.is_renum = False
|
||||
elif isinstance(value, t.REnum):
|
||||
sm.is_renum = True
|
||||
sm.is_enum = True
|
||||
sm.is_struct = False
|
||||
sm.is_union = False
|
||||
elif isinstance(value, t.CEnum):
|
||||
sm.is_enum = True
|
||||
sm.is_struct = False
|
||||
sm.is_union = False
|
||||
sm.is_renum = False
|
||||
elif isinstance(value, t.CUnion):
|
||||
sm.is_union = True
|
||||
sm.is_struct = False
|
||||
sm.is_enum = False
|
||||
sm.is_renum = False
|
||||
return
|
||||
|
||||
raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}")
|
||||
|
||||
@property
|
||||
def TypeCls(self) -> type | None:
|
||||
"""获取 CType 类(从 BaseType 推断)"""
|
||||
bt: t.CType | tuple | None = self._ts._base_type
|
||||
if bt:
|
||||
return type(bt)
|
||||
sm: SymbolMeta = self._sm
|
||||
if sm.is_struct:
|
||||
return t.CStruct
|
||||
if sm.is_enum:
|
||||
return t.CEnum
|
||||
if sm.is_union:
|
||||
return t.CUnion
|
||||
if sm.is_typedef:
|
||||
return t._CTypedef
|
||||
return None
|
||||
|
||||
@property
|
||||
def IsPtr(self) -> bool:
|
||||
return self._ts.ptr_count > 0
|
||||
|
||||
@property
|
||||
def IsVoid(self) -> bool:
|
||||
return isinstance(self._ts._base_type, t.CVoid)
|
||||
|
||||
@property
|
||||
def IsStr(self) -> bool:
|
||||
return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0
|
||||
|
||||
@property
|
||||
def IsInt(self) -> bool:
|
||||
bt: t.CType | tuple | None = self._ts._base_type
|
||||
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid)
|
||||
|
||||
@property
|
||||
def IsUInt(self) -> bool:
|
||||
bt: t.CType | tuple | None = self._ts._base_type
|
||||
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False
|
||||
|
||||
@property
|
||||
def IsFloat(self) -> bool:
|
||||
bt: t.CType | tuple | None = self._ts._base_type
|
||||
return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid)
|
||||
|
||||
def ToString(self) -> str:
|
||||
ts: TypeSpec = self._ts
|
||||
sm: SymbolMeta = self._sm
|
||||
bt: t.CType | tuple | None = ts._base_type
|
||||
|
||||
if ts.is_func_ptr:
|
||||
return 'Callable'
|
||||
parts: list[str] = []
|
||||
|
||||
if ts.storage and not isinstance(ts.storage, t.CExport):
|
||||
parts.append(type(ts.storage).__name__)
|
||||
|
||||
if ts.data_const or ts.data_volatile:
|
||||
qualifiers: list[str] = []
|
||||
if ts.data_const:
|
||||
qualifiers.append("const")
|
||||
if ts.data_volatile:
|
||||
qualifiers.append("volatile")
|
||||
parts.append("_".join(qualifiers))
|
||||
|
||||
if sm.is_typedef and sm.name:
|
||||
return sm.name
|
||||
elif sm.is_renum and sm.name:
|
||||
base_name: str = sm.name
|
||||
elif bt:
|
||||
if isinstance(bt, str):
|
||||
base_name = bt
|
||||
elif isinstance(bt, type) and issubclass(bt, t.CType):
|
||||
base_name = bt.__name__
|
||||
elif isinstance(bt, t.CType):
|
||||
# 对命名的 CType(CStruct/CEnum/CUnion/REnum),优先使用其 name 属性
|
||||
# 否则回退到类名(如 'CInt'、'CChar')
|
||||
_named: str | None = getattr(bt, 'name', None)
|
||||
base_name = _named if _named else type(bt).__name__
|
||||
else:
|
||||
base_name = str(bt)
|
||||
else:
|
||||
base_name = "void"
|
||||
|
||||
if ts.is_array_ptr:
|
||||
ptr_str: str = ""
|
||||
if ts.ptr_count > 0:
|
||||
ptr_str = "*" * ts.ptr_count
|
||||
if ts.array_ptr:
|
||||
inner: str = ts.array_ptr.ToString()
|
||||
if ptr_str:
|
||||
parts.append(f"{base_name} {ptr_str}({inner})")
|
||||
else:
|
||||
parts.append(f"{base_name} ({inner})")
|
||||
else:
|
||||
if ptr_str:
|
||||
parts.append(f"{base_name} {ptr_str}()")
|
||||
else:
|
||||
parts.append(f"{base_name} ()")
|
||||
elif ts.array_ptr:
|
||||
inner = ts.array_ptr.ToString()
|
||||
if ts.ptr_count > 0:
|
||||
parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})")
|
||||
else:
|
||||
parts.append(f"{base_name} ({inner})")
|
||||
else:
|
||||
parts.append(base_name)
|
||||
if ts.ptr_count > 0:
|
||||
parts.append("*" * ts.ptr_count)
|
||||
if ts.var_const:
|
||||
parts.append("const")
|
||||
if ts.var_volatile:
|
||||
parts.append("volatile")
|
||||
|
||||
for dim in ts.array_dims:
|
||||
if dim:
|
||||
parts.append(f"[{dim}]")
|
||||
else:
|
||||
parts.append("[]")
|
||||
|
||||
return " ".join(parts) if parts else "void"
|
||||
|
||||
@staticmethod
|
||||
def CreateFromTypeName(TypeName: str) -> "CTypeInfo":
|
||||
"""从类型名字符串创建 CTypeInfo(兼容旧 API)"""
|
||||
info: CTypeInfo = CTypeInfo()
|
||||
if TypeName.startswith('struct '):
|
||||
info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct()
|
||||
elif TypeName.startswith('enum '):
|
||||
info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum()
|
||||
elif TypeName.startswith('union '):
|
||||
info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion()
|
||||
else:
|
||||
info.BaseType = t.CStruct(name=TypeName)
|
||||
return info
|
||||
|
||||
# LLVM primitive type name → (CTypeClass, PtrCount) mapping
|
||||
# Used when generic type inference produces LLVM type names like 'i64', 'double', etc.
|
||||
_LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None
|
||||
|
||||
@classmethod
|
||||
def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]:
|
||||
if cls._LLVM_PRIMITIVE_MAP is not None:
|
||||
return cls._LLVM_PRIMITIVE_MAP
|
||||
cls._LLVM_PRIMITIVE_MAP = {
|
||||
'void': (t.CVoid, 0),
|
||||
'i1': (t.CInt, 0),
|
||||
'i8': (t.CChar, 0),
|
||||
'i16': (t.CShort, 0),
|
||||
'i32': (t.CInt, 0),
|
||||
'i64': (t.CLong, 0),
|
||||
'i128': (t.CInt, 0),
|
||||
'float': (t.CFloat, 0),
|
||||
'double': (t.CDouble, 0),
|
||||
'fp128': (t.CFloat128T, 0),
|
||||
}
|
||||
return cls._LLVM_PRIMITIVE_MAP
|
||||
|
||||
@staticmethod
|
||||
def FromTypeName(TypeName: str) -> "CTypeInfo":
|
||||
"""从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)"""
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||||
return TypeAnnotationResolver.from_type_name(TypeName)
|
||||
|
||||
# FromStr 已移除 - 类型解析不再经过中间字符串格式
|
||||
# typedef 展开直接走 CTypeInfo 对象,不经过字符串解析
|
||||
|
||||
@staticmethod
|
||||
def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any:
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||||
return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable)
|
||||
|
||||
@classmethod
|
||||
def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo":
|
||||
"""从 AST 节点解析 CTypeInfo(类方法)
|
||||
|
||||
Args:
|
||||
Node: AST 节点(如 ast.Name, ast.Attribute 等)
|
||||
SymbolTable: 符号表字典
|
||||
"""
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver
|
||||
return TypeAnnotationResolver.from_node(Node, SymbolTable)
|
||||
|
||||
|
||||
def Copy(self) -> "CTypeInfo":
|
||||
NewInfo: CTypeInfo = CTypeInfo()
|
||||
NewInfo._ts = self._ts.copy()
|
||||
NewInfo._sm = self._sm.copy()
|
||||
# CTypeInfo 引用字段需要深拷贝
|
||||
if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo):
|
||||
NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy()
|
||||
if isinstance(NewInfo._ts.original_type, CTypeInfo):
|
||||
NewInfo._ts.original_type = NewInfo._ts.original_type.Copy()
|
||||
if NewInfo._ts.array_ptr:
|
||||
NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy()
|
||||
return NewInfo
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
"""获取额外属性"""
|
||||
return self._sm._extra.get(key, default)
|
||||
|
||||
def set(self, key: str, value: Any) -> None:
|
||||
"""设置额外属性"""
|
||||
self._sm._extra[key] = value
|
||||
|
||||
@staticmethod
|
||||
def VoidTypeInfo() -> "CTypeInfo":
|
||||
info: CTypeInfo = CTypeInfo()
|
||||
info.BaseType = t.CVoid()
|
||||
return info
|
||||
|
||||
def ToLLVM(self, Gen: LlvmCodeGenerator) -> _ir.Type:
|
||||
if Gen is None:
|
||||
return _ir.IntType(32)
|
||||
return Gen._ctype_to_llvm(self)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.ToString()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
ts: TypeSpec = self._ts
|
||||
sm: SymbolMeta = self._sm
|
||||
return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})"
|
||||
|
||||
|
||||
# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类
|
||||
# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由
|
||||
for _old_name, (_target, _field) in FIELD_ROUTES.items():
|
||||
setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field))
|
||||
del _old_name, _target, _field
|
||||
|
||||
|
||||
class CTypeHelper:
|
||||
|
||||
@staticmethod
|
||||
def GetTModuleCType(TypeName: str) -> type | None:
|
||||
result: type | None = CTypeRegistry.GetClassByName(TypeName)
|
||||
if result is not None:
|
||||
return result
|
||||
TypeClass: type | None = getattr(t, TypeName, None)
|
||||
if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType):
|
||||
return TypeClass
|
||||
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
|
||||
if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType):
|
||||
return FallbackClass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def GetCName(type_or_name: str | type) -> str:
|
||||
if isinstance(type_or_name, str):
|
||||
cls: type | None = CTypeRegistry.GetClassByName(type_or_name)
|
||||
if cls is None:
|
||||
cls = CTypeHelper.GetTModuleCType(type_or_name)
|
||||
if cls:
|
||||
return cls.__name__
|
||||
return type_or_name
|
||||
elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType):
|
||||
return type_or_name.__name__
|
||||
return ''
|
||||
|
||||
|
||||
class BuiltinTypeMap:
|
||||
"""
|
||||
内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射
|
||||
|
||||
用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0)
|
||||
BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1)
|
||||
"""
|
||||
|
||||
_map: dict[str, tuple[type, int]] | None = None
|
||||
|
||||
@classmethod
|
||||
def _build_map(cls) -> dict[str, tuple[type, int]]:
|
||||
if cls._map is not None:
|
||||
return cls._map
|
||||
CTypeRegistry._build()
|
||||
cls._map = {}
|
||||
# 仅使用 Python 类名 → (CType 类, ptr_level) 映射。
|
||||
# C 类型名(如 'int'、'int32_t')不再通过 _cname_to_class 提供。
|
||||
# C 头文件 stub 生成器使用独立的硬编码表(CTypeMapper._CNAME_TO_PY)。
|
||||
for pyname, ctype_cls in CTypeRegistry._name_to_class.items():
|
||||
pos: frozenset = getattr(ctype_cls, 'position', frozenset())
|
||||
if t.CType.POINTER in pos and t.CType.BASE not in pos:
|
||||
cls._map[pyname] = (ctype_cls, 1)
|
||||
else:
|
||||
cls._map[pyname] = (ctype_cls, 0)
|
||||
# 保留一些常用的字符串速记(这些不是 CName,而是硬编码的便捷别名)。
|
||||
# 包含 Python 内置类型名(int/float/bool)和 C 类型名速记(char/short/long 等)。
|
||||
_SPECIAL: dict[str, tuple[type, int]] = {
|
||||
# Python 内置类型名
|
||||
'str': (t.CChar, 1), 'bytes': (t.CChar, 1),
|
||||
'int': (t.CInt, 0), 'float': (t.CFloat, 0), 'bool': (t.CBool, 0),
|
||||
# C 类型名速记
|
||||
'char': (t.CChar, 0), 'short': (t.CShort, 0),
|
||||
'long': (t.CLong, 0), 'long long': (t.CLongLong, 0),
|
||||
'double': (t.CDouble, 0),
|
||||
'unsigned': (t.CUnsigned, 0),
|
||||
'signed': (t.CInt, 0), 'signed int': (t.CInt, 0),
|
||||
'signed char': (t.CSignedChar, 0),
|
||||
'void': (t.CVoid, 0), 'Void': (t.CVoid, 0),
|
||||
}
|
||||
for k, v in _SPECIAL.items():
|
||||
if k not in cls._map:
|
||||
cls._map[k] = v
|
||||
_FLOAT_ALIASES: dict[str, tuple[type, int]] = {
|
||||
'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0),
|
||||
'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0),
|
||||
'FLOAT128': (t.CFloat128T, 0),
|
||||
}
|
||||
for k, v in _FLOAT_ALIASES.items():
|
||||
if k not in cls._map:
|
||||
cls._map[k] = v
|
||||
return cls._map
|
||||
|
||||
@classmethod
|
||||
def Get(cls, type_name: str) -> tuple[type, int] | None:
|
||||
"""获取类型类和指针层级"""
|
||||
return cls._build_map().get(type_name)
|
||||
|
||||
|
||||
class BaseHandle:
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
self.Trans: Translator = translator
|
||||
self._CurrentCpythonObjectClass: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def _is_char_pointer(val: _ir.Value) -> bool:
|
||||
"""检查值是否为 char* (i8*) 指针"""
|
||||
if not isinstance(val.type, _ir.PointerType):
|
||||
return False
|
||||
pointee: _ir.Type = val.type.pointee
|
||||
return isinstance(pointee, _ir.IntType) and pointee.width == 8
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None) -> _ir.Value | None:
|
||||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
|
||||
|
||||
def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any:
|
||||
return self.Trans.BodyHandler.HandleBodyLlvm(Body)
|
||||
|
||||
def _get_int_ptr(self, Node: ast.AST) -> _ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(Node, ast.Name):
|
||||
if Node.id in Gen.variables:
|
||||
return Gen.variables[Node.id]
|
||||
elif isinstance(Node, ast.Attribute):
|
||||
obj_val: Any = self.HandleExprLlvm(Node.value)
|
||||
if not obj_val:
|
||||
return None
|
||||
if isinstance(obj_val.type, _ir.PointerType):
|
||||
pointee: _ir.Type = obj_val.type.pointee
|
||||
if isinstance(pointee, (_ir.IdentifiedStructType, _ir.LiteralStructType)):
|
||||
StructName: str | None = None
|
||||
if isinstance(pointee, _ir.IdentifiedStructType):
|
||||
StructName = pointee.name
|
||||
if not StructName:
|
||||
for ClassName, struct_type in Gen.structs.items():
|
||||
if struct_type == pointee:
|
||||
StructName = ClassName
|
||||
break
|
||||
if StructName and StructName in Gen.structs:
|
||||
offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen)
|
||||
member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr")
|
||||
return member_ptr
|
||||
return None
|
||||
|
||||
def _IsTModuleType(self, TypeName: str) -> bool:
|
||||
if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'):
|
||||
return True
|
||||
TypeClass: type | None = getattr(t, TypeName, None)
|
||||
if TypeClass and isinstance(TypeClass, type):
|
||||
if issubclass(TypeClass, t.CType):
|
||||
return True
|
||||
FallbackClass: type | None = getattr(t, f'_{TypeName}', None)
|
||||
if FallbackClass and isinstance(FallbackClass, type):
|
||||
if issubclass(FallbackClass, t.CType):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ResolveListElementType(
|
||||
self,
|
||||
elem_type_node: ast.expr,
|
||||
Gen: Any,
|
||||
*,
|
||||
check_func_ptr: bool = False,
|
||||
handle_str: bool = False,
|
||||
void_fallback_width: int = 32,
|
||||
fallback_to_cint: bool = False,
|
||||
) -> tuple[Any, CTypeInfo | None]:
|
||||
"""解析 list 元素类型,返回 (LLVM类型, CTypeInfo|None)。
|
||||
|
||||
统一处理结构体、str、函数指针、VoidType 回退等变体。
|
||||
|
||||
Args:
|
||||
check_func_ptr: 是否检查函数指针(全局变量路径需要)
|
||||
handle_str: 是否处理 str → i8*(局部变量路径需要)
|
||||
void_fallback_width: VoidType 回退宽度 (32 或 8)
|
||||
fallback_to_cint: 无类型信息时回退到 CInt
|
||||
"""
|
||||
elem_type_info: CTypeInfo | None = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
|
||||
|
||||
# 结构体类型
|
||||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||||
if check_func_ptr:
|
||||
sym_entry: CTypeInfo | None = self.Trans.SymbolTable.lookup(elem_type_node.id)
|
||||
if sym_entry and isinstance(sym_entry, CTypeInfo) and sym_entry.IsFuncPtr:
|
||||
return _ir.IntType(8).as_pointer(), elem_type_info
|
||||
return Gen.structs[elem_type_node.id], elem_type_info
|
||||
|
||||
# str → i8*
|
||||
if handle_str and isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str':
|
||||
return _ir.PointerType(_ir.IntType(8)), elem_type_info
|
||||
|
||||
# 函数指针检查
|
||||
if check_func_ptr and elem_type_info and elem_type_info.IsFuncPtr:
|
||||
return _ir.IntType(8).as_pointer(), elem_type_info
|
||||
|
||||
# 回退到 CInt
|
||||
if elem_type_info is None and fallback_to_cint:
|
||||
elem_type_info = CTypeInfo()
|
||||
elem_type_info.BaseType = t.CInt()
|
||||
|
||||
elem_type: Any = Gen._ctype_to_llvm(elem_type_info)
|
||||
if isinstance(elem_type, _ir.VoidType):
|
||||
elem_type = _ir.IntType(void_fallback_width)
|
||||
|
||||
return elem_type, elem_type_info
|
||||
|
||||
def ParseArrayCount(
|
||||
self,
|
||||
count_node: ast.expr | None,
|
||||
Gen: Any,
|
||||
value_node: ast.expr | None = None,
|
||||
*,
|
||||
mode: str = 'global',
|
||||
) -> int:
|
||||
"""解析数组计数,返回计数(默认 1)。
|
||||
|
||||
统一处理 Constant/Name/Attribute/BinOp/None 等形式。
|
||||
None 或 Constant(None) 时从 value_node 推断(List 长度或 str 长度+1)。
|
||||
|
||||
Args:
|
||||
count_node: 计数 AST 节点
|
||||
value_node: 赋值右侧值节点(用于 count_node 为 None 时推断)
|
||||
mode: 'global' 使用 _eval_global_count + SymbolTable + _define_constants;
|
||||
'local' 使用 TryEvalConstExpr
|
||||
"""
|
||||
# None 或 Constant(None) → 从 value_node 推断
|
||||
if count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None):
|
||||
if value_node and isinstance(value_node, ast.List):
|
||||
return len(value_node.elts)
|
||||
if value_node and isinstance(value_node, ast.Constant) and isinstance(value_node.value, str):
|
||||
return len(value_node.value) + 1
|
||||
return 1
|
||||
|
||||
# Constant(int)
|
||||
if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
|
||||
return count_node.value
|
||||
|
||||
if mode == 'global':
|
||||
# Name → SymbolTable + _define_constants
|
||||
if isinstance(count_node, ast.Name):
|
||||
ArrayCount: int = 1
|
||||
if self.Trans.SymbolTable.has(count_node.id):
|
||||
sym_info: Any = self.Trans.SymbolTable[count_node.id]
|
||||
if isinstance(sym_info.value, int):
|
||||
ArrayCount = sym_info.value
|
||||
if ArrayCount == 1 and count_node.id in Gen._define_constants:
|
||||
def_val: Any = Gen._define_constants[count_node.id]
|
||||
if isinstance(def_val, int):
|
||||
ArrayCount = def_val
|
||||
return ArrayCount
|
||||
# Attribute / BinOp → _eval_global_count
|
||||
if isinstance(count_node, (ast.Attribute, ast.BinOp)):
|
||||
eval_fn: Any = getattr(self, '_eval_global_count', None)
|
||||
if eval_fn is not None:
|
||||
ev: int | None = eval_fn(count_node, Gen)
|
||||
if ev is not None:
|
||||
return ev
|
||||
return 1
|
||||
else:
|
||||
# local mode → TryEvalConstExpr
|
||||
eval_count: Any = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable)
|
||||
if eval_count is not None and isinstance(eval_count, int) and eval_count > 0:
|
||||
return eval_count
|
||||
return 1
|
||||
|
||||
return 1
|
||||
|
||||
def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None:
|
||||
"""解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。
|
||||
|
||||
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
|
||||
"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||||
if merger:
|
||||
info: CTypeInfo | None = merger.MergeTypes(annotation)
|
||||
if info is not None and isinstance(info, CTypeInfo):
|
||||
return info
|
||||
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
|
||||
def CollectAnnAssignMember(
|
||||
self, item: ast.AST, Gen: Any
|
||||
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
|
||||
"""从 ast.AnnAssign 节点解析成员信息。
|
||||
|
||||
返回 (VarName, MemberType, TypeInfo);TypeInfo 为 None 表示解析回退到 i32。
|
||||
非 AnnAssign/Name 目标时返回 None。
|
||||
"""
|
||||
if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name):
|
||||
return None
|
||||
VarName: str = item.target.id
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(MemberType, _ir.VoidType):
|
||||
MemberType = _ir.PointerType(_ir.IntType(8))
|
||||
return VarName, MemberType, TypeInfo
|
||||
except Exception as e:
|
||||
_vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e)
|
||||
return VarName, _ir.IntType(32), None
|
||||
|
||||
def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None:
|
||||
"""查找函数符号,先尝试 module_path.name,再回退到 name。
|
||||
|
||||
统一处理 HandlesExprCall / HandlesAssign 中重复的二级查找模式。
|
||||
返回 CTypeInfo(不限定 IsFunction),由调用方检查标志位。
|
||||
"""
|
||||
st = self.Trans.SymbolTable
|
||||
if module_path:
|
||||
sym: CTypeInfo | None = st.lookup(f'{module_path}.{name}')
|
||||
if sym:
|
||||
return sym
|
||||
return st.lookup(name)
|
||||
|
||||
def BuildLLVMFuncTypeFromSig(
|
||||
self,
|
||||
sym_info: CTypeInfo,
|
||||
Gen: Any,
|
||||
*,
|
||||
mangled_name: str | None = None,
|
||||
use_infer_fallback: bool = False,
|
||||
) -> tuple[Any, list[Any], bool] | None:
|
||||
"""从 CTypeInfo 函数签名构建 LLVM 函数类型。
|
||||
|
||||
返回 (ret_type, llvm_param_types, is_variadic),非函数返回 None。
|
||||
统一处理 FuncPtrReturn/FuncPtrParams → ToLLVM 转换、VoidType 回退。
|
||||
|
||||
Args:
|
||||
mangled_name: 用于 _infer_return_type + stub 查找回退
|
||||
use_infer_fallback: 为 True 时启用 _infer_return_type + stub 查找回退链
|
||||
"""
|
||||
if not sym_info.IsFunction:
|
||||
return None
|
||||
is_variadic: bool = sym_info.IsVariadic
|
||||
ret_type_info = sym_info.FuncPtrReturn
|
||||
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
|
||||
ret_type: Any = ret_type_info.ToLLVM(Gen)
|
||||
elif use_infer_fallback and mangled_name:
|
||||
inferred: Any = Gen._infer_return_type(mangled_name)
|
||||
if isinstance(inferred, _ir.IntType) and inferred.width == 32:
|
||||
try:
|
||||
stub_ft: Any = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
|
||||
if stub_ft and hasattr(stub_ft, 'return_type'):
|
||||
inferred = stub_ft.return_type
|
||||
except Exception:
|
||||
pass
|
||||
ret_type = inferred
|
||||
else:
|
||||
ret_type = Gen._CType2LLVM('i32', False)
|
||||
param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])]
|
||||
if isinstance(ret_type, _ir.VoidType):
|
||||
ret_type = _ir.IntType(32)
|
||||
llvm_param_types: list[Any] = []
|
||||
for pt in param_type_infos:
|
||||
if isinstance(pt, CTypeInfo) and pt.BaseType:
|
||||
lp: Any = pt.ToLLVM(Gen)
|
||||
else:
|
||||
lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False)
|
||||
if isinstance(lp, _ir.VoidType):
|
||||
lp = _ir.IntType(8).as_pointer()
|
||||
llvm_param_types.append(lp)
|
||||
return ret_type, llvm_param_types, is_variadic
|
||||
|
||||
def GetOrCreateFuncDecl(
|
||||
self,
|
||||
name: str,
|
||||
ret_type: Any,
|
||||
param_types: list[Any],
|
||||
Gen: Any,
|
||||
*,
|
||||
is_variadic: bool = False,
|
||||
replace_name: str | None = None,
|
||||
) -> Any:
|
||||
"""创建或替换 LLVM 函数声明。
|
||||
|
||||
若 name 已存在且类型不匹配,通过 _replace_function_decl 替换。
|
||||
replace_name 传递给 _replace_function_decl(通常为未 mangle 的 func_name)。
|
||||
"""
|
||||
if name not in Gen.functions:
|
||||
func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||||
func_decl = _ir.Function(Gen.module, func_type, name=name)
|
||||
Gen.functions[name] = func_decl
|
||||
else:
|
||||
existing = Gen.functions[name]
|
||||
existing_type = getattr(existing, 'ftype', None)
|
||||
new_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic)
|
||||
if existing_type and existing_type != new_type:
|
||||
replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, replace_name or name, new_type)
|
||||
if replaced and replaced != existing:
|
||||
Gen.functions[name] = replaced
|
||||
return Gen.functions[name]
|
||||
|
||||
def GetOrCreateStubFuncDecl(
|
||||
self,
|
||||
decl_name: str,
|
||||
stub_func_type: Any,
|
||||
Gen: Any,
|
||||
*,
|
||||
alias: str | None = None,
|
||||
check_existing: bool = True,
|
||||
) -> Any:
|
||||
"""创建 stub 函数声明,可选注册别名。
|
||||
|
||||
check_existing=False 时跳过存在性检查(用于确定不存在的场景)。
|
||||
"""
|
||||
if check_existing and decl_name in Gen.functions:
|
||||
func_decl = Gen.functions[decl_name]
|
||||
else:
|
||||
func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name)
|
||||
Gen.functions[decl_name] = func_decl
|
||||
if alias and alias != decl_name:
|
||||
if not check_existing or alias not in Gen.functions:
|
||||
Gen.functions[alias] = func_decl
|
||||
return func_decl
|
||||
|
||||
|
||||
StrictMode: bool = _config.mode == 'strict'
|
||||
77
lib/core/Handles/HandlesBody.py
Normal file
77
lib/core/Handles/HandlesBody.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class BodyHandle(BaseHandle):
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
super().__init__(translator)
|
||||
|
||||
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for Node in Body:
|
||||
if Gen.builder and Gen.builder.block.is_terminated:
|
||||
break
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Expr):
|
||||
self.HandleExprLlvm(Node.value)
|
||||
elif isinstance(Node, ast.Return):
|
||||
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
self.Trans.AssignHandler._HandleAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AugAssign):
|
||||
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.If):
|
||||
self.Trans.IfHandler._HandleIfLlvm(Node)
|
||||
elif isinstance(Node, ast.For):
|
||||
self.Trans.ForHandler._HandleForLlvm(Node)
|
||||
elif isinstance(Node, ast.While):
|
||||
self.Trans.WhileHandler._HandleWhileLlvm(Node)
|
||||
elif isinstance(Node, ast.Break):
|
||||
if Gen.loop_break_targets:
|
||||
Gen.builder.branch(Gen.loop_break_targets[-1])
|
||||
elif isinstance(Node, ast.Continue):
|
||||
if Gen.loop_continue_targets:
|
||||
Gen.builder.branch(Gen.loop_continue_targets[-1])
|
||||
elif isinstance(Node, ast.With):
|
||||
self.Trans.WithHandler._HandleWithLlvm(Node)
|
||||
elif isinstance(Node, ast.ClassDef):
|
||||
pass
|
||||
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
|
||||
self.Trans.MatchHandler._HandleMatchLlvm(Node)
|
||||
elif isinstance(Node, ast.Try):
|
||||
self.Trans.TryHandler._HandleTryLlvm(Node)
|
||||
elif isinstance(Node, ast.Raise):
|
||||
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
|
||||
elif isinstance(Node, ast.Assert):
|
||||
self.Trans.AssertHandler._HandleAssertLlvm(Node)
|
||||
elif isinstance(Node, ast.Global):
|
||||
self.Trans.ForHandler._HandleGlobalLlvm(Node)
|
||||
elif isinstance(Node, ast.FunctionDef):
|
||||
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
|
||||
elif isinstance(Node, ast.Nonlocal):
|
||||
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
|
||||
elif isinstance(Node, ast.Delete):
|
||||
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
|
||||
except Exception as e:
|
||||
lineno: int = getattr(Node, 'lineno', 0)
|
||||
source_line: str | None = Gen._get_source_line(lineno)
|
||||
src_file: str = Gen._current_source_file or ''
|
||||
src_path: str = src_file if src_file else 'unknown'
|
||||
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
|
||||
if source_line:
|
||||
line_info += ":\n %d | %s" % (lineno, source_line)
|
||||
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
raise
|
||||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||||
Gen._EmitTempFrees()
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
|
||||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
|
||||
1259
lib/core/Handles/HandlesClassDef.py
Normal file
1259
lib/core/Handles/HandlesClassDef.py
Normal file
File diff suppressed because it is too large
Load Diff
102
lib/core/Handles/HandlesDelete.py
Normal file
102
lib/core/Handles/HandlesDelete.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class DeleteHandle(BaseHandle):
|
||||
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for target in Node.targets:
|
||||
if isinstance(target, ast.Subscript):
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
|
||||
if obj_val and idx_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
|
||||
elif isinstance(target, ast.Name):
|
||||
ClassName: str | None = Gen.var_struct_class.get(target.id)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
|
||||
elif isinstance(target, ast.Attribute):
|
||||
# 检查 property deleter
|
||||
AttrName: str = target.attr
|
||||
ClassName: str | None = None
|
||||
obj_val_for_prop: ir.Value | None = None
|
||||
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
# del self.attr — 检查当前类的 property deleter
|
||||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||||
if SelfVar:
|
||||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc and SelfPtr:
|
||||
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
else:
|
||||
# del obj.attr — 检查 obj 类的 property deleter
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
if obj_val:
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc:
|
||||
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
|
||||
# 原有的 __del__ 处理逻辑
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
|
||||
obj_val = Gen._load(obj_val, name="Load_del_ptr")
|
||||
ClassName = None
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if obj_val.type.pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
AttrName = target.attr
|
||||
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||||
if SelfClassName and SelfClassName in Gen.class_members:
|
||||
for member_name, member_type in Gen.class_members[SelfClassName]:
|
||||
if member_name == AttrName:
|
||||
for CN in Gen.structs:
|
||||
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
break
|
||||
if not ClassName:
|
||||
for CN, ST in Gen.structs.items():
|
||||
if Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__")
|
||||
446
lib/core/Handles/HandlesExpr.py
Normal file
446
lib/core/Handles/HandlesExpr.py
Normal file
@@ -0,0 +1,446 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes.t import CTypeRegistry as _CR
|
||||
|
||||
|
||||
class ExprHandle(BaseHandle):
|
||||
|
||||
# list 元素类型 → (字节大小, LLVM 元素类型) 映射表
|
||||
# 用于 _HandleListLlvm 中 alloc_size / byte_offset / elem_ptr 类型统一查表,
|
||||
# 消除原代码三处重复的 if-elif 链。
|
||||
_ELEM_TYPE_INFO: dict[str, tuple[int, ir.Type]] = {
|
||||
'i8': (1, ir.IntType(8)),
|
||||
'i16': (2, ir.IntType(16)),
|
||||
'i32': (4, ir.IntType(32)),
|
||||
'float': (4, ir.FloatType()),
|
||||
'double': (8, ir.DoubleType()),
|
||||
}
|
||||
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
super().__init__(translator)
|
||||
|
||||
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
|
||||
return self.Trans.ExprUtils.GetOpSymbol(Op)
|
||||
|
||||
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
|
||||
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
|
||||
|
||||
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
|
||||
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
|
||||
|
||||
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
return self.Trans.ExprUtils._get_var_class(node, Gen)
|
||||
|
||||
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
|
||||
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
|
||||
|
||||
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
|
||||
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.AST, VarType: ir.Type | str | None = None) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not Gen or not Gen.builder:
|
||||
return None
|
||||
if isinstance(Node, ast.Constant):
|
||||
return self._HandleConstantLlvm(Node, VarType)
|
||||
elif isinstance(Node, ast.Name):
|
||||
return self._HandleNameLlvm(Node, VarType)
|
||||
elif isinstance(Node, ast.BinOp):
|
||||
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
|
||||
elif isinstance(Node, ast.BoolOp):
|
||||
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
|
||||
elif isinstance(Node, ast.UnaryOp):
|
||||
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
|
||||
elif isinstance(Node, ast.Call):
|
||||
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
|
||||
elif isinstance(Node, ast.Compare):
|
||||
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
|
||||
elif isinstance(Node, ast.Attribute):
|
||||
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
|
||||
elif isinstance(Node, ast.Subscript):
|
||||
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
|
||||
elif isinstance(Node, ast.IfExp):
|
||||
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
|
||||
elif isinstance(Node, ast.NamedExpr):
|
||||
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
|
||||
elif isinstance(Node, ast.JoinedStr):
|
||||
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node)
|
||||
elif isinstance(Node, ast.Lambda):
|
||||
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
|
||||
elif isinstance(Node, ast.List):
|
||||
return self._HandleListLlvm(Node, VarType)
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleListLlvm(self, Node: ast.List, VarType: ir.Type | str | None = None) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
elements: list[ast.expr] = Node.elts
|
||||
if not elements:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
array_len: int = len(elements)
|
||||
elem_type: str = 'i8'
|
||||
|
||||
if VarType and isinstance(VarType, str) and 'list[' in VarType:
|
||||
match: re.Match | None = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
|
||||
if match:
|
||||
type_str: str = match.group(1).strip()
|
||||
if match.group(2):
|
||||
array_len = int(match.group(2))
|
||||
if 'CChar' in type_str or 'char' in type_str.lower():
|
||||
elem_type = 'i8'
|
||||
elif 'CFloat' in type_str or type_str.lower() == 'float':
|
||||
elem_type = 'float'
|
||||
elif 'CDouble' in type_str or type_str.lower() == 'double':
|
||||
elem_type = 'double'
|
||||
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
|
||||
elem_type = 'i32'
|
||||
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
|
||||
elem_type = 'i32'
|
||||
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
|
||||
elem_type = 'i8'
|
||||
elif 'CShort' in type_str or 'short' in type_str.lower():
|
||||
elem_type = 'i16'
|
||||
elif 'CUnsignedShort' in type_str:
|
||||
elem_type = 'i16'
|
||||
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
|
||||
elem_type = 'float'
|
||||
|
||||
alloc_size: int = array_len
|
||||
elem_info: tuple[int, ir.Type] = self._ELEM_TYPE_INFO.get(elem_type, (1, ir.IntType(8)))
|
||||
elem_size: int = elem_info[0]
|
||||
elem_llvm_type: ir.Type = elem_info[1]
|
||||
alloc_size *= elem_size
|
||||
|
||||
malloc_fn: Any = None
|
||||
malloc_arg_type: ir.IntType = ir.IntType(64)
|
||||
for fn in Gen.module.global_values:
|
||||
if fn.name == 'malloc':
|
||||
malloc_fn = fn
|
||||
func_ftype: Any = getattr(fn, 'ftype', None)
|
||||
if func_ftype and getattr(func_ftype, 'args', None):
|
||||
if func_ftype.args:
|
||||
malloc_arg_type = fn.ftype.args[0]
|
||||
break
|
||||
|
||||
if not malloc_fn:
|
||||
try:
|
||||
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
|
||||
Gen.functions['malloc'] = malloc_fn
|
||||
except Exception: # 回退:malloc 函数创建失败时返回 null
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
alloc_ptr: Any = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
|
||||
cast_ptr: Any = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
|
||||
|
||||
for i, elem in enumerate(elements):
|
||||
if i >= array_len:
|
||||
break
|
||||
|
||||
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
|
||||
if elem_val is None:
|
||||
continue
|
||||
|
||||
byte_offset: int = i
|
||||
if elem_type == 'i32':
|
||||
byte_offset = i * 4
|
||||
elif elem_type == 'i16':
|
||||
byte_offset = i * 2
|
||||
elif elem_type == 'float':
|
||||
byte_offset = i * 4
|
||||
elif elem_type == 'double':
|
||||
byte_offset = i * 8
|
||||
|
||||
ptr_as_int: Any = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
|
||||
new_ptr_val: Any = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
|
||||
if elem_type == 'i32':
|
||||
elem_ptr: Any = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
|
||||
elif elem_type == 'i16':
|
||||
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
|
||||
elif elem_type == 'float':
|
||||
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
|
||||
elif elem_type == 'double':
|
||||
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
|
||||
else:
|
||||
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
|
||||
|
||||
if elem_type == 'i8':
|
||||
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.PointerType):
|
||||
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
|
||||
elif elem_type == 'i32':
|
||||
if isinstance(elem_val.type, ir.IntType):
|
||||
if elem_val.type.width < 32:
|
||||
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
|
||||
elif elem_val.type.width > 32:
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.PointerType):
|
||||
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
|
||||
elif elem_type == 'i16':
|
||||
if isinstance(elem_val.type, ir.IntType):
|
||||
if elem_val.type.width < 16:
|
||||
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
|
||||
elif elem_val.type.width > 16:
|
||||
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
|
||||
elif elem_type == 'float':
|
||||
if isinstance(elem_val.type, ir.DoubleType):
|
||||
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.IntType):
|
||||
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
|
||||
elif elem_type == 'double':
|
||||
if isinstance(elem_val.type, ir.FloatType):
|
||||
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
|
||||
elif isinstance(elem_val.type, ir.IntType):
|
||||
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
|
||||
|
||||
Gen.builder.store(elem_val, elem_ptr)
|
||||
|
||||
if elem_type in ('float', 'double'):
|
||||
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(elem_llvm_type), name=f"list_{elem_type}_ptr")
|
||||
return cast_ptr
|
||||
|
||||
def _HandleConstantLlvm(self, Node: ast.Constant, VarType: ir.Type | str | None = None) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
Value: Any = Node.value
|
||||
if Value is None:
|
||||
if VarType is not None and isinstance(VarType, ir.PointerType):
|
||||
return ir.Constant(VarType, None)
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
elif isinstance(Value, bool):
|
||||
return ir.Constant(ir.IntType(32), 1 if Value else 0)
|
||||
elif isinstance(Value, int):
|
||||
if VarType is not None:
|
||||
if isinstance(VarType, ir.IntType):
|
||||
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
|
||||
if isinstance(VarType, ir.PointerType):
|
||||
return ir.Constant(ir.IntType(64), Value)
|
||||
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
|
||||
return ir.Constant(VarType, float(Value))
|
||||
if isinstance(VarType, str) and '*' in VarType:
|
||||
return ir.Constant(ir.IntType(64), Value)
|
||||
if isinstance(VarType, str):
|
||||
resolved: Any = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
|
||||
if resolved:
|
||||
ctype_cls: type = resolved[0] if isinstance(resolved, tuple) else resolved
|
||||
inst: Any = ctype_cls()
|
||||
size: int = getattr(inst, 'Size', 32)
|
||||
is_unsigned: bool = getattr(inst, 'IsSigned', True) is False
|
||||
mask: int = (1 << size) - 1
|
||||
return ir.Constant(ir.IntType(size), Value & mask)
|
||||
llvm_match: re.Match | None = re.match(r'^i(\d+)$', VarType)
|
||||
if llvm_match:
|
||||
width: int = int(llvm_match.group(1))
|
||||
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
|
||||
if Value < 0 or Value > 0xFFFFFFFF:
|
||||
return ir.Constant(ir.IntType(64), Value)
|
||||
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
|
||||
elif isinstance(Value, float):
|
||||
if VarType and isinstance(VarType, ir.FloatType):
|
||||
return ir.Constant(VarType, Value)
|
||||
elif VarType and isinstance(VarType, ir.DoubleType):
|
||||
return ir.Constant(VarType, Value)
|
||||
return ir.Constant(ir.DoubleType(), Value)
|
||||
elif isinstance(Value, str):
|
||||
is_wide: bool = getattr(Node, 'kind', None) == 'u'
|
||||
# 引号类型推断:单引号单字符 → i8,双引号/多字符/三重 → i8*,空 → 0(None)
|
||||
quote_char: str | None = None
|
||||
is_triple: bool = False
|
||||
if not is_wide:
|
||||
col_offset: int = getattr(Node, 'col_offset', 0)
|
||||
node_lineno: int = getattr(Node, 'lineno', 0)
|
||||
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
|
||||
# 因此在 lineno 和 lineno-1 两行中查找引号
|
||||
for try_lineno in (node_lineno, node_lineno - 1):
|
||||
source_line: str | None = Gen._get_source_line(try_lineno)
|
||||
if source_line and col_offset < len(source_line):
|
||||
ch: str = source_line[col_offset]
|
||||
if ch in ("'", '"'):
|
||||
quote_char = ch
|
||||
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
|
||||
is_triple = True
|
||||
break
|
||||
# 空字符串 → 创建指向 \0 的全局变量 (而非 null, 避免 strcmp 解引用空指针崩溃)
|
||||
# 走与非空字符串相同的路径, 由下方 else 分支处理
|
||||
# 单引号单字符(非三重)→ i8
|
||||
is_char_literal: bool = (not is_triple) and (quote_char == "'") and (len(Value) == 1) and not is_wide
|
||||
if is_char_literal:
|
||||
if VarType is not None and isinstance(VarType, ir.PointerType):
|
||||
pass # 类型不匹配:目标是 ptr 但值是 char,走 string 路径
|
||||
elif isinstance(VarType, ir.IntType):
|
||||
return ir.Constant(VarType, ord(Value[0]))
|
||||
elif isinstance(VarType, str):
|
||||
resolved = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
|
||||
if resolved:
|
||||
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
|
||||
inst = ctype_cls()
|
||||
size = getattr(inst, 'Size', 32)
|
||||
return ir.Constant(ir.IntType(size), ord(Value[0]))
|
||||
llvm_match = re.match(r'^i(\d+)$', VarType)
|
||||
if llvm_match:
|
||||
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
|
||||
elif VarType is not None:
|
||||
return ir.Constant(ir.IntType(8), ord(Value[0]))
|
||||
else:
|
||||
# 无类型提示:单引号单字符默认为 i8
|
||||
return ir.Constant(ir.IntType(8), ord(Value[0]))
|
||||
if is_wide:
|
||||
str_value: str = Value + '\x00'
|
||||
wide_chars: list[int] = [ord(c) for c in str_value]
|
||||
target_count: int = len(wide_chars)
|
||||
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(16), target_count)
|
||||
gv_name: str = f"str_const_{Gen.string_const_counter}"
|
||||
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
|
||||
gv.initializer = ir.Constant(str_type, wide_chars)
|
||||
gv.linkage = 'internal'
|
||||
Gen.string_const_counter += 1
|
||||
ptr: Any = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
|
||||
return ptr
|
||||
else:
|
||||
str_value = Value + '\x00'
|
||||
str_bytes: bytes = str_value.encode('utf-8')
|
||||
target_count = len(str_bytes)
|
||||
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
|
||||
target_count = VarType.count
|
||||
if len(str_bytes) < target_count:
|
||||
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
|
||||
else:
|
||||
str_bytes = str_bytes[:target_count]
|
||||
str_type = ir.ArrayType(ir.IntType(8), target_count)
|
||||
gv_name = f"str_const_{Gen.string_const_counter}"
|
||||
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
|
||||
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
|
||||
gv.linkage = 'internal'
|
||||
Gen.string_const_counter += 1
|
||||
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
|
||||
return ptr
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
VarName: str = Node.id
|
||||
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
|
||||
if VarName in define_constants:
|
||||
val: Any = define_constants[VarName]
|
||||
if isinstance(val, int):
|
||||
# Use VarType hint if available to avoid unnecessary type mismatch
|
||||
if VarType is not None and isinstance(VarType, ir.IntType):
|
||||
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
|
||||
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
|
||||
if val < -(1 << 31) or val > 0xFFFFFFFF:
|
||||
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
|
||||
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
|
||||
if val < -(1 << 31) or val > 0xFFFFFFFF:
|
||||
return ir.Constant(ir.IntType(64), val)
|
||||
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
|
||||
elif isinstance(val, float):
|
||||
return ir.Constant(ir.DoubleType(), val)
|
||||
elif isinstance(val, str):
|
||||
return Gen._create_string_global(val)
|
||||
# 如果 _define_constants 中没有,尝试从符号表查找
|
||||
if VarName not in getattr(Gen, '_define_constants', {}):
|
||||
try:
|
||||
sym_info: Any = self.translator.SymbolTable.lookup(VarName)
|
||||
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
|
||||
val = sym_info.DefineValue
|
||||
if isinstance(val, int):
|
||||
# Use VarType hint if available
|
||||
if VarType is not None and isinstance(VarType, ir.IntType):
|
||||
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
|
||||
if val < -(1 << 31) or val > 0xFFFFFFFF:
|
||||
return ir.Constant(ir.IntType(64), val)
|
||||
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
|
||||
elif isinstance(val, float):
|
||||
return ir.Constant(ir.DoubleType(), val)
|
||||
elif isinstance(val, str):
|
||||
return Gen._create_string_global(val)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
# 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
VarPtr: Any = Gen.variables[VarName]
|
||||
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
if VarName in Gen.global_struct_class:
|
||||
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
|
||||
return VarPtr
|
||||
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
if VarName in Gen.global_struct_class:
|
||||
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
|
||||
return VarPtr
|
||||
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
|
||||
# 大端局部变量:读取时 bswap 还原
|
||||
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
|
||||
return loaded
|
||||
if VarName in Gen._reg_values:
|
||||
return Gen._reg_values[VarName]
|
||||
if VarName in Gen._direct_values:
|
||||
return Gen._direct_values[VarName]
|
||||
if VarName in Gen.global_vars and VarName in Gen.module.globals:
|
||||
GVar: Any = Gen.module.globals[VarName]
|
||||
Gen.variables[VarName] = GVar
|
||||
if isinstance(GVar, ir.Function):
|
||||
return GVar
|
||||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return GVar
|
||||
return Gen._load(GVar, name=VarName)
|
||||
if VarName in Gen.module.globals:
|
||||
GVar = Gen.module.globals[VarName]
|
||||
Gen.variables[VarName] = GVar
|
||||
if isinstance(GVar, ir.Function):
|
||||
return GVar
|
||||
if VarName in Gen.global_struct_class:
|
||||
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
|
||||
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
|
||||
return GVar
|
||||
return Gen._load(GVar, name=VarName)
|
||||
if VarName == 'self':
|
||||
return Gen.GetVarPtr('self')
|
||||
if Gen._has_function(VarName):
|
||||
func: Any = Gen._get_function(VarName)
|
||||
if func:
|
||||
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
|
||||
if VarName in Gen.class_methods:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
if VarName == 'True' or VarName == 'False':
|
||||
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
|
||||
SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
|
||||
if SymInfo:
|
||||
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
|
||||
return ir.Constant(ir.IntType(32), SymInfo.value)
|
||||
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
|
||||
MangledName: str = Gen._mangle_func_name(VarName)
|
||||
if MangledName in Gen.module.globals:
|
||||
g: Any = Gen.module.globals[MangledName]
|
||||
if isinstance(g, ir.Function):
|
||||
Gen.functions[VarName] = g
|
||||
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
|
||||
for sha1 in Gen.ModuleSha1Map.values():
|
||||
prefixed: str = f"{sha1}.{VarName}"
|
||||
if prefixed in Gen.module.globals:
|
||||
g = Gen.module.globals[prefixed]
|
||||
if isinstance(g, ir.Function):
|
||||
Gen.functions[VarName] = g
|
||||
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
|
||||
t_c_imported: dict[str, tuple[str, str]] = getattr(self.Trans, '_t_c_imported_names', {})
|
||||
if VarName in t_c_imported:
|
||||
src_module: str
|
||||
src_name: str
|
||||
src_module, src_name = t_c_imported[VarName]
|
||||
virtual_attr: ast.Attribute = ast.Attribute(
|
||||
value=ast.Name(id=src_module, ctx=ast.Load()),
|
||||
attr=src_name,
|
||||
ctx=ast.Load()
|
||||
)
|
||||
ast.copy_location(virtual_attr, Node)
|
||||
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
580
lib/core/Handles/HandlesExprAsm.py
Normal file
580
lib/core/Handles/HandlesExprAsm.py
Normal file
@@ -0,0 +1,580 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
import ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
from lib.includes import t
|
||||
|
||||
# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数
|
||||
# 添加保护避免重复补丁
|
||||
_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False)
|
||||
|
||||
if not _InlineAsmPatched:
|
||||
_OrigInlineAsmInit = ir.InlineAsm.__init__
|
||||
_OrigInlineAsmDescr = ir.InlineAsm.descr
|
||||
|
||||
def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None):
|
||||
_OrigInlineAsmInit(self, ftype, asm, constraint, side_effect)
|
||||
self.asm_dialect = asm_dialect
|
||||
|
||||
def _patched_inline_asm_descr(self, buf):
|
||||
sideeffect = 'sideeffect' if self.side_effect else ''
|
||||
dialect_str = getattr(self, 'asm_dialect', None)
|
||||
if dialect_str == 'intel':
|
||||
dialect = 'inteldialect'
|
||||
else:
|
||||
dialect = ''
|
||||
fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"'
|
||||
buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm,
|
||||
constraint=self.constraint))
|
||||
|
||||
ir.InlineAsm.__init__ = _patched_inline_asm_init
|
||||
ir.InlineAsm.descr = _patched_inline_asm_descr
|
||||
ir.InlineAsm._transpyc_patched = True
|
||||
|
||||
|
||||
class ExprAsmHandle(BaseHandle):
|
||||
@staticmethod
|
||||
def _format_to_dialect(asm_format: str | None) -> str | None:
|
||||
"""将用户指定的 format 参数转换为 LLVM asm_dialect 值"""
|
||||
fmt: str = asm_format.lower() if asm_format else 'intel'
|
||||
if fmt == 'att':
|
||||
return 'att'
|
||||
elif fmt == 'arm':
|
||||
return None # ARM 没有专门的 dialect 标记
|
||||
else:
|
||||
return 'intel' # 默认 Intel
|
||||
|
||||
def _HandleAsmLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
op_arg: Any = None
|
||||
input_arg: Any = None
|
||||
output_arg: Any = None
|
||||
asm_format: str = 'Intel' # 汇编格式: Intel / AT&T / ARM
|
||||
for kw in Node.keywords:
|
||||
if kw.arg == 'op':
|
||||
op_arg = kw.value
|
||||
elif kw.arg in ('input', 'inp', 'inputs'):
|
||||
input_arg = kw.value
|
||||
elif kw.arg in ('output', 'out', 'outputs'):
|
||||
output_arg = kw.value
|
||||
elif kw.arg == 'format':
|
||||
if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str):
|
||||
asm_format = kw.value.value
|
||||
|
||||
if len(Node.args) >= 1:
|
||||
pos_op: Any = None
|
||||
if len(Node.args) >= 2 and op_arg is None:
|
||||
pos_op = Node.args[1]
|
||||
return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format)
|
||||
|
||||
if len(Node.args) < 2:
|
||||
return ir.Constant(ir.IntType(32), 1)
|
||||
|
||||
args: list[ast.AST] = Node.args
|
||||
|
||||
if len(args) == 4:
|
||||
output_type_arg: ast.AST = args[0]
|
||||
asm_template_arg: ast.AST = args[1]
|
||||
constraint_arg: ast.AST = args[2]
|
||||
clobber_arg: ast.AST = args[3]
|
||||
|
||||
output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg)
|
||||
if not output_type:
|
||||
output_type = ir.IntType(32)
|
||||
|
||||
asm_template: str = ''
|
||||
if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
|
||||
asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value))
|
||||
|
||||
constraint: str = ''
|
||||
if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str):
|
||||
constraint = constraint_arg.value
|
||||
|
||||
clobber: str = ''
|
||||
if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str):
|
||||
clobber = clobber_arg.value
|
||||
|
||||
full_constraint: str = constraint
|
||||
func_type: ir.FunctionType = ir.FunctionType(output_type, [])
|
||||
asm_dialect: str | None = self._format_to_dialect(asm_format)
|
||||
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect)
|
||||
result: Any = Gen.builder.call(inline_asm, [], name="asm_result")
|
||||
return result
|
||||
|
||||
elif len(args) >= 2:
|
||||
output_type_arg: ast.AST = args[0]
|
||||
asm_template_arg: ast.AST = args[1]
|
||||
|
||||
output_type: ir.Type | None = self._infer_expr_llvm_type(output_type_arg)
|
||||
if not output_type:
|
||||
output_type = ir.IntType(32)
|
||||
|
||||
asm_template: str = ''
|
||||
if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
|
||||
asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value))
|
||||
|
||||
output_constraints: list[str] = []
|
||||
output_values: list[Any] = []
|
||||
if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)):
|
||||
for item in args[2].elts:
|
||||
if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
|
||||
constraint_node: ast.AST = item.elts[0]
|
||||
value_node: ast.AST = item.elts[1]
|
||||
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
|
||||
output_constraints.append(constraint_node.value)
|
||||
value: Any = self.HandleExprLlvm(value_node)
|
||||
if value:
|
||||
output_values.append(value)
|
||||
|
||||
input_constraints: list[str] = []
|
||||
input_values: list[Any] = []
|
||||
if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)):
|
||||
for item in args[3].elts:
|
||||
if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
|
||||
constraint_node: ast.AST = item.elts[0]
|
||||
value_node: ast.AST = item.elts[1]
|
||||
if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str):
|
||||
input_constraints.append(constraint_node.value)
|
||||
value: Any = self.HandleExprLlvm(value_node)
|
||||
if value:
|
||||
input_values.append(value)
|
||||
|
||||
clobbers: list[str] = []
|
||||
if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)):
|
||||
for item in args[4].elts:
|
||||
if isinstance(item, ast.Constant) and isinstance(item.value, str):
|
||||
clobbers.append(item.value)
|
||||
|
||||
constraint_parts: list[str] = []
|
||||
for oc in output_constraints:
|
||||
constraint_parts.append(oc)
|
||||
|
||||
input_start_idx: int = len(output_constraints)
|
||||
for ic in input_constraints:
|
||||
constraint_parts.append(ic)
|
||||
|
||||
full_constraint: str = ",".join(constraint_parts)
|
||||
|
||||
if clobbers:
|
||||
if full_constraint:
|
||||
full_constraint += ","
|
||||
for c in clobbers:
|
||||
full_constraint += f"~{{{c}}}"
|
||||
|
||||
operands: list[Any] = output_values + input_values
|
||||
param_types: list[ir.Type] = [v.type for v in operands]
|
||||
func_type: ir.FunctionType = ir.FunctionType(output_type, param_types)
|
||||
asm_dialect: str | None = self._format_to_dialect(asm_format)
|
||||
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect)
|
||||
result: Any = Gen.builder.call(inline_asm, operands, name="asm_result")
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
def _prepare_intel_asm(self, template: str) -> str:
|
||||
template = re.sub(r'%(\d+)', r'$\1', template)
|
||||
template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template)
|
||||
return template
|
||||
|
||||
def _normalize_asm_template(self, template: str) -> str:
|
||||
lines = template.split('\n')
|
||||
if len(lines) <= 1:
|
||||
return template
|
||||
first_line = lines[0]
|
||||
rest_lines = lines[1:]
|
||||
stripped = []
|
||||
for line in rest_lines:
|
||||
s = line.lstrip()
|
||||
if s:
|
||||
stripped.append(s)
|
||||
else:
|
||||
stripped.append('')
|
||||
return '\n'.join([first_line] + stripped)
|
||||
|
||||
def _process_joined_str_template(self, node: ast.AST, out_input_ops: list[Any], out_input_constraints: list[str],
|
||||
out_output_ops: list[Any], out_output_constraints: list[str]) -> str:
|
||||
if not isinstance(node, ast.JoinedStr):
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
return node.value
|
||||
return ''
|
||||
|
||||
raw_parts: list[tuple[str, str | int]] = []
|
||||
for value in node.values:
|
||||
if isinstance(value, ast.Constant) and isinstance(value.value, str):
|
||||
raw_parts.append(('text', value.value))
|
||||
elif isinstance(value, ast.FormattedValue):
|
||||
expr: ast.AST = value.value
|
||||
if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute):
|
||||
if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c':
|
||||
if expr.func.attr == 'AsmInp':
|
||||
if expr.args:
|
||||
v: Any = self.HandleExprLlvm(expr.args[0])
|
||||
if v:
|
||||
c: str = 'r'
|
||||
if len(expr.args) >= 2:
|
||||
c = self._parse_asm_descr(expr.args[1])
|
||||
if not c:
|
||||
c = 'r'
|
||||
out_input_ops.append(v)
|
||||
out_input_constraints.append(c)
|
||||
raw_parts.append(('input', len(out_input_ops) - 1))
|
||||
elif expr.func.attr == 'AsmOut':
|
||||
if expr.args:
|
||||
target_ptr: Any = self._get_var_ptr_for_asm(expr.args[0])
|
||||
if target_ptr:
|
||||
v = target_ptr
|
||||
else:
|
||||
v = self.HandleExprLlvm(expr.args[0])
|
||||
if v:
|
||||
c: str = '=r'
|
||||
if len(expr.args) >= 2:
|
||||
c = self._parse_asm_descr(expr.args[1])
|
||||
if not c:
|
||||
c = '=r'
|
||||
if not c.startswith('='):
|
||||
c = '=' + c
|
||||
out_output_ops.append(v)
|
||||
out_output_constraints.append(c)
|
||||
raw_parts.append(('output', len(out_output_ops) - 1))
|
||||
else:
|
||||
fallback: Any = self.HandleExprLlvm(expr)
|
||||
if fallback and isinstance(fallback.type, ir.IntType):
|
||||
out_input_ops.append(fallback)
|
||||
out_input_constraints.append('r')
|
||||
raw_parts.append(('input', len(out_input_ops) - 1))
|
||||
else:
|
||||
raw_parts.append(('text', ''))
|
||||
|
||||
num_outputs: int = len(out_output_ops)
|
||||
parts: list[str] = []
|
||||
for kind, data in raw_parts:
|
||||
if kind == 'text':
|
||||
parts.append(data)
|
||||
elif kind == 'output':
|
||||
parts.append(f'%{data}')
|
||||
elif kind == 'input':
|
||||
parts.append(f'%{num_outputs + data}')
|
||||
return ''.join(parts)
|
||||
|
||||
_X86_REGISTERS = frozenset({
|
||||
'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp',
|
||||
'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
|
||||
'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp',
|
||||
'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp',
|
||||
'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh',
|
||||
'sil', 'dil', 'bpl', 'spl',
|
||||
'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d',
|
||||
'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w',
|
||||
'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b',
|
||||
})
|
||||
|
||||
def _mangle_asm_calls(self, template: str) -> str:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
sha1: str = getattr(Gen, 'module_sha1', '')
|
||||
if not sha1:
|
||||
return template
|
||||
|
||||
def replace_call(m: re.Match[str]) -> str:
|
||||
prefix: str = m.group(1)
|
||||
func_name: str = m.group(2)
|
||||
if func_name.lower() in self._X86_REGISTERS:
|
||||
return m.group(0)
|
||||
mangled: str = Gen._mangle_func_name(func_name)
|
||||
if '.' in mangled:
|
||||
return f'{prefix}\\22{mangled}\\22'
|
||||
return f"{prefix}{mangled}"
|
||||
|
||||
return re.sub(r'(call\s+)(\w+)', replace_call, template)
|
||||
|
||||
def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
input_ops: list[Any] = []
|
||||
input_constraints: list[str] = []
|
||||
output_ops: list[Any] = []
|
||||
output_constraints: list[str] = []
|
||||
|
||||
if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)):
|
||||
for item in output_arg.elts:
|
||||
if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute):
|
||||
if item.func.value.id == 'c' and item.func.attr == 'AsmOut':
|
||||
if len(item.args) >= 1:
|
||||
target_ptr: Any = self._get_var_ptr_for_asm(item.args[0])
|
||||
if target_ptr:
|
||||
output_ops.append(target_ptr)
|
||||
else:
|
||||
value: Any = self.HandleExprLlvm(item.args[0])
|
||||
if value:
|
||||
output_ops.append(value)
|
||||
constraint: str = '=r'
|
||||
if len(item.args) >= 2:
|
||||
base_constraint: str = self._parse_asm_descr(item.args[1])
|
||||
if base_constraint:
|
||||
if base_constraint.startswith('='):
|
||||
constraint = base_constraint
|
||||
else:
|
||||
constraint = '=' + base_constraint
|
||||
output_constraints.append(constraint)
|
||||
|
||||
raw_template: str
|
||||
if isinstance(asm_template_arg, ast.JoinedStr):
|
||||
raw_template = self._normalize_asm_template(
|
||||
self._process_joined_str_template(
|
||||
asm_template_arg, input_ops, input_constraints, output_ops, output_constraints
|
||||
)
|
||||
)
|
||||
elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str):
|
||||
raw_template = self._normalize_asm_template(asm_template_arg.value)
|
||||
else:
|
||||
raw_template = ''
|
||||
|
||||
raw_template = self._mangle_asm_calls(raw_template)
|
||||
asm_dialect: str | None = self._format_to_dialect(asm_format)
|
||||
asm_template: str
|
||||
if asm_format == 'AT&T':
|
||||
asm_template = raw_template # AT&T 不需要转换
|
||||
elif asm_format == 'ARM':
|
||||
asm_template = raw_template # ARM 不需要转换
|
||||
else:
|
||||
asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式
|
||||
|
||||
if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)):
|
||||
for item in input_arg.elts:
|
||||
if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute):
|
||||
if item.func.value.id == 'c' and item.func.attr == 'AsmInp':
|
||||
if len(item.args) >= 1:
|
||||
value: Any = self.HandleExprLlvm(item.args[0])
|
||||
if value:
|
||||
input_ops.append(value)
|
||||
constraint: str = 'r'
|
||||
if len(item.args) >= 2:
|
||||
constraint = self._parse_asm_descr(item.args[1])
|
||||
if not constraint:
|
||||
constraint = 'r'
|
||||
input_constraints.append(constraint)
|
||||
elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2:
|
||||
value_node: ast.AST = item.elts[0]
|
||||
descr_node: ast.AST = item.elts[1]
|
||||
value: Any = self.HandleExprLlvm(value_node)
|
||||
if value:
|
||||
input_ops.append(value)
|
||||
constraint: str = self._parse_asm_descr(descr_node)
|
||||
if not constraint:
|
||||
constraint = 'r'
|
||||
input_constraints.append(constraint)
|
||||
|
||||
clobbers: list[str] = []
|
||||
if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)):
|
||||
for item in op_arg.elts:
|
||||
clobber: str = self._parse_asm_descr(item)
|
||||
if clobber:
|
||||
clobbers.append(clobber)
|
||||
|
||||
constraint_parts: list[str] = []
|
||||
for oc in output_constraints:
|
||||
c: str = oc if oc.startswith('=') else ('=' + oc)
|
||||
constraint_parts.append(c)
|
||||
for ic in input_constraints:
|
||||
if ic in ('d', 'edx', 'rdx'):
|
||||
constraint_parts.append('{dx}')
|
||||
else:
|
||||
constraint_parts.append(ic)
|
||||
|
||||
full_constraint: str = ",".join(constraint_parts)
|
||||
|
||||
constraint_to_reg: dict[str, str] = {
|
||||
'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx',
|
||||
'S': 'rsi', 'D': 'rdi',
|
||||
'A': 'rax', 'U': 'r8',
|
||||
}
|
||||
used_regs: set[str] = set()
|
||||
for ic in input_constraints:
|
||||
if ic in constraint_to_reg:
|
||||
used_regs.add(constraint_to_reg[ic])
|
||||
for oc in output_constraints:
|
||||
base_oc: str = oc.lstrip('=').lstrip('+')
|
||||
if base_oc in constraint_to_reg:
|
||||
used_regs.add(constraint_to_reg[base_oc])
|
||||
|
||||
if clobbers:
|
||||
has_memory: bool = 'memory' in clobbers
|
||||
if has_memory and output_ops:
|
||||
clobbers = [c for c in clobbers if c != 'memory']
|
||||
clobber_final: list[str]
|
||||
if asm_format == 'ARM':
|
||||
# ARM 不需要 x86 的 e→r 寄存器名转换
|
||||
clobber_final = [c for c in clobbers if c not in used_regs]
|
||||
else:
|
||||
clobber_64bit: list[str] = []
|
||||
for c in clobbers:
|
||||
if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']:
|
||||
clobber_64bit.append(c.replace('e', 'r'))
|
||||
else:
|
||||
clobber_64bit.append(c)
|
||||
clobber_final = [c for c in clobber_64bit if c not in used_regs]
|
||||
if clobber_final:
|
||||
if full_constraint:
|
||||
full_constraint += ","
|
||||
full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final])
|
||||
|
||||
if output_ops:
|
||||
single_out: bool = len(output_ops) == 1
|
||||
if single_out:
|
||||
op: Any = output_ops[0]
|
||||
ret_type: ir.Type
|
||||
if isinstance(op, ir.AllocaInstr):
|
||||
ret_type = op.type.pointee
|
||||
elif isinstance(op, ir.GlobalVariable):
|
||||
ret_type = op.type.pointee
|
||||
elif isinstance(op, (ir.GEPInstr, ir.CastInstr)):
|
||||
ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type
|
||||
else:
|
||||
ret_type = op.type
|
||||
else:
|
||||
def _get_ret_type(op: Any) -> ir.Type:
|
||||
if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)):
|
||||
return op.type.pointee
|
||||
return op.type
|
||||
ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops])
|
||||
if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType):
|
||||
ret_type = ir.IntType(64)
|
||||
operands: list[Any] = input_ops
|
||||
param_types: list[ir.Type] = [op.type for op in operands]
|
||||
func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect)
|
||||
result: Any = Gen.builder.call(inline_asm, operands, name="asm_result")
|
||||
if single_out:
|
||||
target: Any = output_ops[0]
|
||||
if isinstance(target, ir.AllocaInstr):
|
||||
if target.type.pointee != result.type:
|
||||
i64t: ir.IntType = ir.IntType(64)
|
||||
iv: Any = Gen.builder.ptrtoint(result, i64t)
|
||||
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
|
||||
Gen.builder.store(iv, ptr)
|
||||
else:
|
||||
Gen.builder.store(result, target)
|
||||
elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)):
|
||||
target_pointee: ir.Type = target.type.pointee
|
||||
if target_pointee != result.type:
|
||||
if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64):
|
||||
ptr_val: Any = Gen.builder.inttoptr(result, target_pointee)
|
||||
Gen.builder.store(ptr_val, target)
|
||||
else:
|
||||
i64t: ir.IntType = ir.IntType(64)
|
||||
iv: Any = Gen.builder.ptrtoint(result, i64t)
|
||||
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
|
||||
Gen.builder.store(iv, ptr)
|
||||
else:
|
||||
Gen.builder.store(result, target)
|
||||
else:
|
||||
dst: Any = Gen._allocaEntry(result.type)
|
||||
Gen.builder.store(result, dst)
|
||||
else:
|
||||
for i, out_op in enumerate(output_ops):
|
||||
val: Any = Gen.builder.extract_value(result, i, name=f"asm_out_{i}")
|
||||
target: Any = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._allocaEntry(val.type)
|
||||
if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type:
|
||||
i64t: ir.IntType = ir.IntType(64)
|
||||
iv: Any = Gen.builder.ptrtoint(val, i64t)
|
||||
ptr: Any = Gen.builder.bitcast(target, ir.PointerType(i64t))
|
||||
Gen.builder.store(iv, ptr)
|
||||
else:
|
||||
Gen.builder.store(val, target)
|
||||
else:
|
||||
operands: list[Any] = input_ops
|
||||
param_types: list[ir.Type] = [op.type for op in operands]
|
||||
func_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), param_types)
|
||||
inline_asm: ir.InlineAsm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect)
|
||||
Gen.builder.call(inline_asm, operands, name="asm_call")
|
||||
return ir.Constant(ir.IntType(32), 1)
|
||||
|
||||
def _get_var_ptr_for_asm(self, node: ast.AST) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(node, ast.Name):
|
||||
var_name: str = node.id
|
||||
if var_name in Gen.variables and Gen.variables[var_name] is not None:
|
||||
ptr: Any = Gen.variables[var_name]
|
||||
if isinstance(ptr, ir.AllocaInstr):
|
||||
return ptr
|
||||
if isinstance(ptr, ir.GlobalVariable):
|
||||
return ptr
|
||||
elif isinstance(node, ast.Attribute):
|
||||
obj_ptr: Any = self._get_var_ptr_for_asm(node.value)
|
||||
if obj_ptr is not None:
|
||||
obj_type: ir.Type = obj_ptr.type.pointee
|
||||
if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType):
|
||||
Loaded: Any = Gen.builder.load(obj_ptr, name="asm_attr_Load")
|
||||
struct_type: ir.IdentifiedStructType = obj_type.pointee
|
||||
class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
|
||||
if class_name:
|
||||
offset: int = Gen._get_member_offset(node.attr, class_name)
|
||||
gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0),
|
||||
ir.Constant(ir.IntType(32), offset)],
|
||||
inbounds=True)
|
||||
return gep
|
||||
for idx, elem_type in enumerate(struct_type.elements):
|
||||
gep: Any = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0),
|
||||
ir.Constant(ir.IntType(32), idx)],
|
||||
inbounds=True)
|
||||
return gep
|
||||
elif isinstance(obj_type, ir.IdentifiedStructType):
|
||||
class_name: str | None = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None
|
||||
if class_name:
|
||||
offset: int = Gen._get_member_offset(node.attr, class_name)
|
||||
gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0),
|
||||
ir.Constant(ir.IntType(32), offset)],
|
||||
inbounds=True)
|
||||
return gep
|
||||
for idx, elem_type in enumerate(obj_type.elements):
|
||||
gep: Any = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0),
|
||||
ir.Constant(ir.IntType(32), idx)],
|
||||
inbounds=True)
|
||||
return gep
|
||||
return None
|
||||
|
||||
def _parse_asm_descr(self, expr: ast.AST) -> str:
|
||||
if isinstance(expr, ast.BinOp):
|
||||
left_val: str = self._parse_asm_descr(expr.left)
|
||||
right_val: str = self._parse_asm_descr(expr.right)
|
||||
return left_val + right_val
|
||||
|
||||
elif isinstance(expr, ast.Attribute):
|
||||
if isinstance(expr.value, ast.Attribute):
|
||||
if (isinstance(expr.value.value, ast.Name) and
|
||||
IsTModule(expr.value.value.id, self.Trans.SymbolTable) and
|
||||
expr.value.attr == 'ASM_DESCR'):
|
||||
AttrName: str = expr.attr
|
||||
return getattr(t.ASM_DESCR, AttrName, "")
|
||||
elif isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable):
|
||||
AttrName: str = expr.attr
|
||||
return getattr(t.ASM_DESCR, AttrName, "")
|
||||
|
||||
elif isinstance(expr, ast.Constant):
|
||||
return expr.value
|
||||
|
||||
return ""
|
||||
|
||||
def _infer_expr_llvm_type(self, expr: ast.AST) -> ir.Type | None:
|
||||
if isinstance(expr, ast.Name):
|
||||
type_name: str = expr.id
|
||||
if hasattr(t, type_name):
|
||||
ctype: Any = getattr(t, type_name)
|
||||
if isinstance(ctype, type) and issubclass(ctype, t.CType):
|
||||
size: Any = getattr(ctype, 'Size', None)
|
||||
if size is not None:
|
||||
return ir.IntType(size)
|
||||
if type_name == 'CFloat':
|
||||
return ir.FloatType()
|
||||
elif type_name == 'CDouble':
|
||||
return ir.DoubleType()
|
||||
elif isinstance(expr, ast.Attribute):
|
||||
if isinstance(expr.value, ast.Name) and IsTModule(expr.value.id, self.Trans.SymbolTable):
|
||||
return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load()))
|
||||
return None
|
||||
1379
lib/core/Handles/HandlesExprAttr.py
Normal file
1379
lib/core/Handles/HandlesExprAttr.py
Normal file
File diff suppressed because it is too large
Load Diff
988
lib/core/Handles/HandlesExprBuiltin.py
Normal file
988
lib/core/Handles/HandlesExprBuiltin.py
Normal file
@@ -0,0 +1,988 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
|
||||
|
||||
|
||||
class ExprBuiltinHandle(BaseHandle):
|
||||
_C_LIB_FUNCS: dict[str, object] = {
|
||||
'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||||
'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||||
'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]),
|
||||
'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||||
'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||||
'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||||
'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||||
'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||||
'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||||
'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||||
'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||||
'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
||||
'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
||||
'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||||
'abs': lambda: (ir.IntType(32), [ir.IntType(32)]),
|
||||
'labs': lambda: (ir.IntType(64), [ir.IntType(64)]),
|
||||
}
|
||||
|
||||
def _HandleBuiltinCallLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not isinstance(Node.func, ast.Name):
|
||||
return None
|
||||
FuncName: str = Node.func.id
|
||||
|
||||
if FuncName == 'print':
|
||||
return self._HandlePrintLlvm(Node)
|
||||
elif FuncName == 'len':
|
||||
if Node.args:
|
||||
return self._HandleLenLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'sizeof':
|
||||
if Node.args:
|
||||
return self._HandleSizeofLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'abs':
|
||||
if Node.args:
|
||||
return self._HandleAbsLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'arg':
|
||||
return self._HandleArgLlvm(Node.args)
|
||||
elif FuncName == 'bool':
|
||||
if Node.args:
|
||||
Val = self.HandleExprLlvm(Node.args[0])
|
||||
if Val:
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width == 1:
|
||||
return Val
|
||||
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
|
||||
elif isinstance(Val.type, ir.PointerType):
|
||||
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
|
||||
return Val
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
elif FuncName == 'int':
|
||||
if Node.args:
|
||||
Val = self.HandleExprLlvm(Node.args[0])
|
||||
if Val:
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < 32:
|
||||
return Gen.builder.zext(Val, ir.IntType(32), name="cast_int")
|
||||
elif Val.type.width > 32:
|
||||
return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int")
|
||||
return Val
|
||||
elif isinstance(Val.type, ir.PointerType):
|
||||
if isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
|
||||
result = self._HandleAtoiLlvm(Val)
|
||||
if result:
|
||||
return result
|
||||
elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fptosi(Val, ir.IntType(32), name="float_to_int")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'float' or FuncName == 'double':
|
||||
if Node.args:
|
||||
Val = self.HandleExprLlvm(Node.args[0])
|
||||
if Val:
|
||||
target_type = ir.DoubleType() if FuncName == 'double' else ir.FloatType()
|
||||
if isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
|
||||
if Val.type != target_type:
|
||||
if isinstance(target_type, ir.DoubleType):
|
||||
return Gen.builder.fpext(Val, target_type, name="fpext_double")
|
||||
return Gen.builder.fptrunc(Val, target_type, name="fptrunc_float")
|
||||
return Val
|
||||
elif isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width == 1:
|
||||
return Gen.builder.uitofp(Val, target_type, name="uitofp")
|
||||
return Gen.builder.sitofp(Val, target_type, name="sitofp")
|
||||
return ir.Constant(ir.DoubleType() if FuncName == 'double' else ir.FloatType(), 0.0)
|
||||
elif FuncName == 'min':
|
||||
if len(Node.args) >= 2:
|
||||
a = self.HandleExprLlvm(Node.args[0])
|
||||
b = self.HandleExprLlvm(Node.args[1])
|
||||
if a and b:
|
||||
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
|
||||
if is_float:
|
||||
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="min_int2float")
|
||||
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="min_int2float")
|
||||
cmp = Gen.builder.fcmp_ordered('olt', fa, fb, name="min_cmp")
|
||||
return Gen.builder.select(cmp, fa, fb, name="min_val")
|
||||
else:
|
||||
cmp = Gen.builder.icmp_signed('<', a, b, name="min_cmp")
|
||||
return Gen.builder.select(cmp, a, b, name="min_val")
|
||||
elif len(Node.args) == 1:
|
||||
return self.HandleExprLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'max':
|
||||
if len(Node.args) >= 2:
|
||||
a = self.HandleExprLlvm(Node.args[0])
|
||||
b = self.HandleExprLlvm(Node.args[1])
|
||||
if a and b:
|
||||
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
|
||||
if is_float:
|
||||
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="max_int2float")
|
||||
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="max_int2float")
|
||||
cmp = Gen.builder.fcmp_ordered('ogt', fa, fb, name="max_cmp")
|
||||
return Gen.builder.select(cmp, fa, fb, name="max_val")
|
||||
else:
|
||||
cmp = Gen.builder.icmp_signed('>', a, b, name="max_cmp")
|
||||
return Gen.builder.select(cmp, a, b, name="max_val")
|
||||
elif len(Node.args) == 1:
|
||||
return self.HandleExprLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'str':
|
||||
if Node.args:
|
||||
arg_node = Node.args[0]
|
||||
arg_val = self.HandleExprLlvm(arg_node)
|
||||
if arg_val:
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
||||
if isinstance(arg_val.type, ir.PointerType) and isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8:
|
||||
if ClassName in Gen.structs:
|
||||
arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str")
|
||||
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__")
|
||||
return str_val
|
||||
return arg_val
|
||||
return self._EmitStringFromValue(arg_val)
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
elif FuncName == 'bytes':
|
||||
# bytes() — 类型转换为 i8* 指针 (等同于 t.CPtr / str)
|
||||
# bytes(int_addr) → inttoptr; bytes(ptr) → bitcast
|
||||
if Node.args:
|
||||
arg_val = self.HandleExprLlvm(Node.args[0])
|
||||
if arg_val:
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
if isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8:
|
||||
return arg_val
|
||||
return Gen.builder.bitcast(arg_val, ir.IntType(8).as_pointer(), name="bytes_cast")
|
||||
if isinstance(arg_val.type, ir.IntType):
|
||||
return Gen.builder.inttoptr(arg_val, ir.IntType(8).as_pointer(), name="bytes_int2ptr")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
elif FuncName == 'input':
|
||||
return self._HandleInputLlvm(Node)
|
||||
elif FuncName == 'ord':
|
||||
if Node.args:
|
||||
return self._HandleOrdLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncName == 'chr':
|
||||
if Node.args:
|
||||
return self._HandleChrLlvm(Node.args[0])
|
||||
return ir.Constant(ir.IntType(8), 0)
|
||||
elif FuncName == 'malloc':
|
||||
return self._HandleMallocLlvm(Node.args)
|
||||
elif FuncName == 'realloc':
|
||||
return self._HandleReallocLlvm(Node.args)
|
||||
elif FuncName == 'free':
|
||||
return self._HandleFreeLlvm(Node.args)
|
||||
elif FuncName == 'memcpy':
|
||||
return self._HandleMemcpyLlvm(Node.args)
|
||||
elif FuncName == 'memset':
|
||||
return self._HandleMemsetLlvm(Node.args)
|
||||
elif FuncName == 'va_start':
|
||||
return self._HandleVaStartLlvm(Node.args)
|
||||
elif FuncName == 'va_end':
|
||||
return self._HandleVaEndLlvm(Node.args)
|
||||
elif FuncName == 'va_arg':
|
||||
return self._HandleVaArgLlvm(Node.args)
|
||||
elif FuncName == 'dir':
|
||||
return self._HandleDirLlvm(Node)
|
||||
elif FuncName == 'type':
|
||||
return self._HandleTypeLlvm(Node)
|
||||
return None
|
||||
|
||||
def _HandlePrintLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
args: list[ast.expr] = Node.args
|
||||
end_arg: ast.expr | None = None
|
||||
sep_arg: ast.expr | None = None
|
||||
if Node.keywords:
|
||||
for kw in Node.keywords:
|
||||
if kw.arg == 'end':
|
||||
end_arg = kw.value
|
||||
elif kw.arg == 'sep':
|
||||
sep_arg = kw.value
|
||||
sep_str: str = ' '
|
||||
if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str):
|
||||
sep_str = sep_arg.value
|
||||
end_str: str = '\n'
|
||||
if end_arg:
|
||||
if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str):
|
||||
end_str = end_arg.value
|
||||
elif isinstance(end_arg, ast.Constant) and end_arg.value is None:
|
||||
end_str = ''
|
||||
if not args:
|
||||
if end_str:
|
||||
nl_fmt = Gen.emit_constant(end_str, 'string')
|
||||
Gen.builder.call(printf_func, [nl_fmt], name="print_nl")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args)
|
||||
if has_fstring:
|
||||
return self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str)
|
||||
fmt_parts = []
|
||||
fmt_args = []
|
||||
for i, arg in enumerate(args):
|
||||
if i > 0:
|
||||
fmt_parts.append(sep_str)
|
||||
val = self.HandleExprLlvm(arg)
|
||||
if not val:
|
||||
fmt_parts.append('(null)')
|
||||
continue
|
||||
if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None:
|
||||
fmt_parts.append('nil')
|
||||
continue
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
fmt_parts.append('%s')
|
||||
fmt_args.append(val)
|
||||
elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
|
||||
elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr")
|
||||
fmt_parts.append('%s')
|
||||
fmt_args.append(elem_ptr)
|
||||
elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
|
||||
if not ClassName and isinstance(arg, ast.Name):
|
||||
ClassName = Gen.var_struct_class.get(arg.id)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
||||
if isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
|
||||
if ClassName in Gen.structs:
|
||||
val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__")
|
||||
fmt_parts.append('%s')
|
||||
fmt_args.append(str_val)
|
||||
else:
|
||||
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
|
||||
fmt_parts.append('0x%llx')
|
||||
fmt_args.append(int_val)
|
||||
else:
|
||||
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
|
||||
fmt_parts.append('%lld')
|
||||
fmt_args.append(int_val)
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
is_unsigned = self._is_val_unsigned(arg, val)
|
||||
if val.type.width == 1:
|
||||
fmt_parts.append('%d')
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print")
|
||||
elif val.type.width == 8:
|
||||
if self._is_char_type(arg):
|
||||
char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf")
|
||||
Gen.builder.store(val, char_var)
|
||||
fmt_parts.append('%c')
|
||||
fmt_args.append(char_var)
|
||||
continue
|
||||
fmt_parts.append('%d')
|
||||
if is_unsigned:
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print")
|
||||
else:
|
||||
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print")
|
||||
elif val.type.width == 16:
|
||||
fmt_parts.append('%u' if is_unsigned else '%d')
|
||||
if is_unsigned:
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print")
|
||||
else:
|
||||
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print")
|
||||
elif val.type.width == 32:
|
||||
fmt_parts.append('%u' if is_unsigned else '%d')
|
||||
elif val.type.width == 64:
|
||||
fmt_parts.append('%llu' if is_unsigned else '%lld')
|
||||
else:
|
||||
fmt_parts.append('%d')
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print")
|
||||
fmt_args.append(val)
|
||||
elif isinstance(val.type, ir.FloatType):
|
||||
fmt_parts.append('%f')
|
||||
fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float"))
|
||||
elif isinstance(val.type, ir.DoubleType):
|
||||
fmt_parts.append('%f')
|
||||
fmt_args.append(val)
|
||||
else:
|
||||
fmt_parts.append('(unknown)')
|
||||
fmt_parts.append(end_str)
|
||||
fmt_str = ''.join(fmt_parts)
|
||||
fmt_ptr = Gen._create_string_global(fmt_str)
|
||||
call_args = [fmt_ptr] + fmt_args
|
||||
return Gen.builder.call(printf_func, call_args, name="print_call")
|
||||
|
||||
def _HandlePrintWithFString(self, Node: ast.Call, printf_func: ir.Function, args: list[ast.expr], sep_str: str, end_str: str) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
for i, arg in enumerate(args):
|
||||
if i > 0:
|
||||
sep_const = Gen.emit_constant(sep_str, 'string')
|
||||
Gen.builder.call(printf_func, [sep_const], name="print_sep")
|
||||
if isinstance(arg, ast.JoinedStr):
|
||||
str_val = self.HandleExprLlvm(arg)
|
||||
if str_val:
|
||||
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
|
||||
else:
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
||||
obj_val = self.HandleExprLlvm(arg)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if ClassName in Gen.structs:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__")
|
||||
Gen._RegisterTempPtr(str_val)
|
||||
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
|
||||
else:
|
||||
val = self.HandleExprLlvm(arg)
|
||||
if val:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee = val.type.pointee
|
||||
if not (isinstance(pointee, ir.IntType) and pointee.width == 8):
|
||||
try:
|
||||
val = Gen._load(val, name="print_Load")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
is_u = Gen._check_node_unsigned(arg)
|
||||
if not is_u and id(val) in Gen._unsigned_results:
|
||||
is_u = True
|
||||
Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None)
|
||||
if end_str:
|
||||
end_const = Gen.emit_constant(end_str, 'string')
|
||||
Gen.builder.call(printf_func, [end_const], name="print_end")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _is_char_type(self, arg_node: ast.AST) -> bool:
|
||||
if isinstance(arg_node, ast.Call):
|
||||
if isinstance(arg_node.func, ast.Name):
|
||||
return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T')
|
||||
if isinstance(arg_node.func, ast.Attribute):
|
||||
return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T')
|
||||
return False
|
||||
|
||||
def _is_val_unsigned(self, arg_node: ast.AST, val: ir.Value) -> bool:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if isinstance(arg_node, ast.Name):
|
||||
var_name: str = arg_node.id
|
||||
signedness: object = Gen.var_signedness.get(var_name)
|
||||
if signedness:
|
||||
if isinstance(signedness, bool):
|
||||
return signedness
|
||||
return 'unsigned' in signedness
|
||||
if isinstance(val.type, ir.IntType):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None:
|
||||
if func_name not in self._C_LIB_FUNCS:
|
||||
return None
|
||||
ret_type: ir.Type
|
||||
param_types: list[ir.Type]
|
||||
ret_type, param_types = self._C_LIB_FUNCS[func_name]()
|
||||
func_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
func: ir.Function = ir.Function(Gen.module, func_type, name=func_name)
|
||||
Gen.functions[func_name] = func
|
||||
return func
|
||||
|
||||
def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self':
|
||||
attr_name = arg_node.attr
|
||||
len_member = f'{attr_name}__len'
|
||||
current_class = self.Trans._CurrentCpythonObjectClass
|
||||
if current_class and current_class in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[current_class]:
|
||||
if m_name == len_member:
|
||||
self_val = Gen._get_var_ptr('self')
|
||||
if self_val:
|
||||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||||
offset = Gen._get_member_offset(len_member, current_class)
|
||||
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
|
||||
return Gen._load(len_ptr, name=f"self_{len_member}")
|
||||
val = self.HandleExprLlvm(arg_node)
|
||||
if not val:
|
||||
return None
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee = val.type.pointee
|
||||
if isinstance(pointee, ir.PointerType):
|
||||
val = Gen._load(val, name="len_deref")
|
||||
pointee = val.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
break
|
||||
if isinstance(pointee, ir.ArrayType):
|
||||
return ir.Constant(ir.IntType(64), pointee.count)
|
||||
if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8:
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
if val.type != ir.PointerType(ir.IntType(8)):
|
||||
val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast")
|
||||
correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
|
||||
strlen_func = None
|
||||
if 'strlen' in Gen.functions:
|
||||
existing = Gen.functions['strlen']
|
||||
if existing.ftype == correct_strlen_type:
|
||||
strlen_func = existing
|
||||
if not strlen_func:
|
||||
try:
|
||||
strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen')
|
||||
Gen.functions['strlen'] = strlen_func
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if strlen_func:
|
||||
result = Gen.builder.call(strlen_func, [val], name="strlen_call")
|
||||
return result
|
||||
elif isinstance(val.type, ir.ArrayType):
|
||||
return ir.Constant(ir.IntType(64), val.type.count)
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
def _resolve_nested_opaque_structs(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, visited: set | None = None) -> None:
|
||||
"""递归解析嵌套的 opaque struct,从 stub 文件中加载其定义"""
|
||||
if visited is None:
|
||||
visited = set()
|
||||
if isinstance(struct_type, ir.PointerType):
|
||||
self._resolve_nested_opaque_structs(struct_type.pointee, Gen, visited)
|
||||
return
|
||||
if not isinstance(struct_type, ir.IdentifiedStructType):
|
||||
return
|
||||
if struct_type in visited:
|
||||
return
|
||||
visited.add(struct_type)
|
||||
if struct_type.elements is None or len(struct_type.elements) == 0:
|
||||
# 尝试从 stub 加载 opaque struct
|
||||
try:
|
||||
st_name = struct_type.name
|
||||
except Exception:
|
||||
st_name = None
|
||||
if st_name:
|
||||
# 提取短名称(去掉模块前缀)
|
||||
if '.' in st_name:
|
||||
short_name = st_name.split('.', 1)[1]
|
||||
else:
|
||||
short_name = st_name
|
||||
self.Trans.ImportHandler._TryLoadStructFromStub(short_name, Gen)
|
||||
return
|
||||
# 递归解析嵌套的 struct 成员
|
||||
for elem in struct_type.elements:
|
||||
self._resolve_nested_opaque_structs(elem, Gen, visited)
|
||||
|
||||
def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
type_name: str | None
|
||||
if isinstance(Node, ast.Name):
|
||||
type_name = Node.id
|
||||
elif isinstance(Node, ast.Attribute):
|
||||
type_name = Node.attr
|
||||
else:
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
if type_name not in Gen.structs:
|
||||
# str/bytes 是指针类型 (char*/void*),sizeof = 指针大小
|
||||
if type_name in ('str', 'bytes'):
|
||||
return ir.Constant(ir.IntType(64), 8)
|
||||
ctype_cls = CTypeRegistry.GetClassByName(type_name)
|
||||
if ctype_cls is not None:
|
||||
try:
|
||||
ctype_inst = ctype_cls()
|
||||
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
||||
size_bytes = size_bits // 8
|
||||
return ir.Constant(ir.IntType(64), size_bytes)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||||
resolved = CTypeRegistry.ResolveName(type_name)
|
||||
if resolved:
|
||||
ctype_cls, ptr_level = resolved
|
||||
try:
|
||||
ctype_inst = ctype_cls()
|
||||
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
||||
size_bytes = size_bits // 8
|
||||
if ptr_level > 0:
|
||||
size_bytes = 8
|
||||
return ir.Constant(ir.IntType(64), size_bytes)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
struct_type = Gen.structs[type_name]
|
||||
if isinstance(struct_type, ir.PointerType):
|
||||
struct_type = struct_type.pointee
|
||||
if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0):
|
||||
self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen)
|
||||
struct_type = Gen.structs.get(type_name, struct_type)
|
||||
# 递归解析所有嵌套的 opaque struct,确保 sizeof 计算正确
|
||||
self._resolve_nested_opaque_structs(struct_type, Gen)
|
||||
size = Gen._get_struct_size(struct_type)
|
||||
if size > 0:
|
||||
return ir.Constant(ir.IntType(64), size)
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
val: ir.Value | None = self.HandleExprLlvm(arg_node)
|
||||
if not val:
|
||||
return None
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee = val.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
break
|
||||
if isinstance(val.type, ir.IntType):
|
||||
neg_val = Gen.builder.neg(val, name="abs_neg")
|
||||
is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg")
|
||||
return Gen.builder.select(is_neg, neg_val, val, name="abs_result")
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
zero = ir.Constant(val.type, 0.0)
|
||||
neg_val = Gen.builder.fneg(val, name="fabs_neg")
|
||||
is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg")
|
||||
return Gen.builder.select(is_neg, neg_val, val, name="fabs_result")
|
||||
return None
|
||||
|
||||
def _HandleDirLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
type_str: str
|
||||
if not Node.args:
|
||||
type_str = "<class 'unknown' size=0 signed=false, ptr=false>"
|
||||
else:
|
||||
arg = Node.args[0]
|
||||
enum_type_name = None
|
||||
|
||||
def _get_attr_path(node: ast.AST) -> str | None:
|
||||
if isinstance(node, ast.Name):
|
||||
return node.id
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return f"{_get_attr_path(node.value)}.{node.attr}"
|
||||
return None
|
||||
|
||||
if isinstance(arg, ast.Name):
|
||||
arg_name = arg.id
|
||||
Gen = self.Trans.LlvmGen
|
||||
if arg_name in Gen.var_type_info:
|
||||
type_info = Gen.var_type_info[arg_name]
|
||||
if isinstance(type_info, dict) and type_info.get('type') == 'enum':
|
||||
enum_type_name = type_info.get('name')
|
||||
if not enum_type_name and self.Trans.SymbolTable.has(arg_name):
|
||||
TypeInfo = self.Trans.SymbolTable[arg_name]
|
||||
if TypeInfo.IsEnum:
|
||||
enum_type_name = arg_name
|
||||
elif isinstance(arg, ast.Attribute):
|
||||
LastPart = None
|
||||
enum_class_name = None
|
||||
if isinstance(arg.value, ast.Name):
|
||||
LastPart = arg.attr
|
||||
if self.Trans.SymbolTable.has(LastPart):
|
||||
AttrInfo = self.Trans.SymbolTable[LastPart]
|
||||
if AttrInfo.IsEnumMember and AttrInfo.EnumName:
|
||||
enum_type_name = AttrInfo.EnumName
|
||||
elif isinstance(arg.value, ast.Attribute):
|
||||
attr_path = _get_attr_path(arg)
|
||||
if attr_path:
|
||||
parts = attr_path.split('.')
|
||||
if len(parts) >= 2:
|
||||
enum_class_name = parts[-2]
|
||||
LastPart = parts[-1]
|
||||
qualified_name_dot = f"{enum_class_name}.{LastPart}"
|
||||
qualified_name_under = f"{enum_class_name}_{LastPart}"
|
||||
enum_member_found = None
|
||||
for qname in (qualified_name_dot, qualified_name_under):
|
||||
if self.Trans.SymbolTable.has(qname):
|
||||
info = self.Trans.SymbolTable[qname]
|
||||
if info.IsEnumMember and info.EnumName == enum_class_name:
|
||||
enum_member_found = info
|
||||
break
|
||||
if not enum_member_found:
|
||||
for key in self.Trans.SymbolTable:
|
||||
if key == LastPart:
|
||||
info = self.Trans.SymbolTable[key]
|
||||
if info.IsEnumMember and info.EnumName == enum_class_name:
|
||||
enum_member_found = info
|
||||
break
|
||||
if enum_member_found:
|
||||
enum_type_name = enum_class_name
|
||||
if enum_type_name:
|
||||
type_str = f"<enum '{enum_type_name}' size=4 signed=true, ptr=false>"
|
||||
else:
|
||||
llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg)
|
||||
if isinstance(llvm_type, ir.PointerType):
|
||||
pointee = llvm_type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
llvm_type = pointee
|
||||
type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type)
|
||||
type_str = f"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
|
||||
return Gen.emit_constant(type_str, 'string')
|
||||
|
||||
def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str):
|
||||
prompt = Node.args[0].value
|
||||
prompt_ptr = Gen.emit_constant(prompt, 'string')
|
||||
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
Gen.builder.call(printf_func, [prompt_ptr])
|
||||
scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer")
|
||||
result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer])
|
||||
return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result")
|
||||
|
||||
def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
atoi_func: ir.Function = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))]))
|
||||
return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result")
|
||||
|
||||
def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
val: ir.Value | None = self.HandleExprLlvm(expr_node)
|
||||
if val and isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
|
||||
return Gen._load(val, name="ord_result")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
val: ir.Value | None = self.HandleExprLlvm(expr_node)
|
||||
if val:
|
||||
char_ptr = Gen._alloca(ir.IntType(8), name="chr_char")
|
||||
Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr)
|
||||
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _EmitStringFromValue(self, val: ir.Value) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2))
|
||||
null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte")
|
||||
Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr)
|
||||
Gen.builder.store(val, buf)
|
||||
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
||||
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
|
||||
snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(64),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
], var_arg=True))
|
||||
fmt_ptr = Gen.emit_constant("%d", 'string')
|
||||
Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val])
|
||||
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _HandleMallocLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
param_type: ir.Type = malloc_func.type.pointee.args[0]
|
||||
size_val: ir.Value | None = None
|
||||
if args:
|
||||
size_val = self.HandleExprLlvm(args[0])
|
||||
if size_val and isinstance(size_val.type, ir.IntType):
|
||||
if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width:
|
||||
if size_val.type.width < param_type.width:
|
||||
size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size")
|
||||
else:
|
||||
size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size")
|
||||
if not size_val:
|
||||
size_val = ir.Constant(param_type, 1)
|
||||
result: ir.Value = Gen.builder.call(malloc_func, [size_val], name="malloc_result")
|
||||
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast")
|
||||
|
||||
def _HandleReallocLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
realloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
|
||||
realloc_func: ir.Function = Gen._get_or_declare_func('realloc', realloc_type)
|
||||
size_param_type: ir.Type = realloc_func.type.pointee.args[1]
|
||||
ptr_val: ir.Value | None = None
|
||||
size_val: ir.Value | None = None
|
||||
if len(args) >= 2:
|
||||
ptr_val = self.HandleExprLlvm(args[0])
|
||||
size_val = self.HandleExprLlvm(args[1])
|
||||
elif len(args) == 1:
|
||||
size_val = self.HandleExprLlvm(args[0])
|
||||
if not ptr_val:
|
||||
ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
if isinstance(ptr_val.type, ir.PointerType) and not (isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8):
|
||||
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr")
|
||||
if size_val and isinstance(size_val.type, ir.IntType):
|
||||
if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width:
|
||||
if size_val.type.width < size_param_type.width:
|
||||
size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size")
|
||||
else:
|
||||
size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size")
|
||||
if not size_val:
|
||||
size_val = ir.Constant(size_param_type, 0)
|
||||
result: ir.Value = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result")
|
||||
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast")
|
||||
|
||||
def _HandleFreeLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
free_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
|
||||
free_func: ir.Function = Gen._get_or_declare_func('free', free_type)
|
||||
if args:
|
||||
var_name: str | None = None
|
||||
if isinstance(args[0], ast.Name):
|
||||
var_name = args[0].id
|
||||
ptr_val: ir.Value | None = self.HandleExprLlvm(args[0])
|
||||
if ptr_val is not None:
|
||||
if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr:
|
||||
registered_val = Gen._var_to_heap_ptr[var_name]
|
||||
Gen._unregister_local_heap_ptr(registered_val)
|
||||
del Gen._var_to_heap_ptr[var_name]
|
||||
if isinstance(ptr_val.type, ir.PointerType):
|
||||
if isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8:
|
||||
pass
|
||||
else:
|
||||
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr")
|
||||
elif isinstance(ptr_val.type, ir.IntType):
|
||||
ptr_val = Gen.builder.inttoptr(ptr_val, ir.PointerType(ir.IntType(8)), name="free_inttoptr")
|
||||
Gen.builder.call(free_func, [ptr_val], name="free_call")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleMemcpyLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if 'llvm.memcpy' not in Gen.functions:
|
||||
memcpy_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
|
||||
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
|
||||
if len(args) >= 3:
|
||||
dst: ir.Value | None = self.HandleExprLlvm(args[0])
|
||||
src: ir.Value | None = self.HandleExprLlvm(args[1])
|
||||
size: ir.Value | None = self.HandleExprLlvm(args[2])
|
||||
if dst and src and size:
|
||||
i8ptr: ir.PointerType = ir.PointerType(ir.IntType(8))
|
||||
if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr:
|
||||
dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast")
|
||||
elif isinstance(dst.type, ir.IntType):
|
||||
if dst.type.width < 64:
|
||||
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr")
|
||||
dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr")
|
||||
if isinstance(src.type, ir.PointerType) and src.type != i8ptr:
|
||||
src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast")
|
||||
elif isinstance(src.type, ir.IntType):
|
||||
if src.type.width < 64:
|
||||
src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr")
|
||||
src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr")
|
||||
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
||||
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size")
|
||||
isvolatile: ir.Constant = ir.Constant(ir.IntType(1), 0)
|
||||
Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleMemsetLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
memset_func: ir.Function = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]))
|
||||
if len(args) >= 3:
|
||||
dst: ir.Value | None = self.HandleExprLlvm(args[0])
|
||||
val: ir.Value | None = self.HandleExprLlvm(args[1])
|
||||
size: ir.Value | None = self.HandleExprLlvm(args[2])
|
||||
if dst and val is not None and size:
|
||||
if isinstance(dst.type, ir.PointerType) and not (isinstance(dst.type.pointee, ir.IntType) and dst.type.pointee.width == 8):
|
||||
dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast")
|
||||
elif isinstance(dst.type, ir.IntType):
|
||||
if dst.type.width < 64:
|
||||
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_memset_dst")
|
||||
elif dst.type.width > 64:
|
||||
dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst")
|
||||
dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr")
|
||||
if isinstance(val.type, ir.IntType) and val.type.width != 32:
|
||||
if val.type.width < 32:
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
|
||||
else:
|
||||
val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val")
|
||||
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
||||
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size")
|
||||
elif isinstance(size.type, ir.IntType) and size.type.width > 64:
|
||||
size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size")
|
||||
Gen.builder.call(memset_func, [dst, val, size], name="memset_call")
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleVaStartLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleVaEndLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
|
||||
def _HandleArgLlvm(self, args: list[ast.expr], CallNode: ast.Call | None = None) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
va_list_ptr: ir.Value | None = None
|
||||
variadic_info: dict | None = getattr(Gen, '_va_arg_info', None)
|
||||
if not variadic_info:
|
||||
variadic_info = getattr(Gen, '_variadic_info', None)
|
||||
if variadic_info:
|
||||
va_list_ptr = variadic_info.get('va_list_ptr')
|
||||
if not va_list_ptr:
|
||||
vararg_name: str = variadic_info.get('vararg_name', 'args') if variadic_info else 'args'
|
||||
if vararg_name in Gen._direct_values:
|
||||
va_list_ptr = Gen._direct_values[vararg_name]
|
||||
elif vararg_name in Gen.variables:
|
||||
va_list_ptr = Gen.variables[vararg_name]
|
||||
if not va_list_ptr:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
target_type: ir.Type = ir.IntType(32)
|
||||
if args:
|
||||
type_arg: ast.expr = args[0]
|
||||
if isinstance(type_arg, ast.Name):
|
||||
type_name: str = type_arg.id
|
||||
if type_name in ('str', 'bytes'):
|
||||
target_type = ir.PointerType(ir.IntType(8))
|
||||
elif type_name == 'CPtr':
|
||||
target_type = ir.PointerType(ir.IntType(8))
|
||||
elif type_name in Gen.structs:
|
||||
target_type = ir.PointerType(Gen.structs[type_name])
|
||||
else:
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
else:
|
||||
resolved: tuple | None = CTypeRegistry.ResolveName(type_name)
|
||||
if resolved is not None:
|
||||
ctype_cls, ptr_level = resolved
|
||||
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
if llvm_str:
|
||||
base: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if base is not None:
|
||||
for _ in range(ptr_level):
|
||||
if isinstance(base, ir.VoidType):
|
||||
base = ir.IntType(8).as_pointer()
|
||||
else:
|
||||
base = ir.PointerType(base)
|
||||
target_type = base
|
||||
elif isinstance(type_arg, ast.Attribute):
|
||||
if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
|
||||
attr_name: str = type_arg.attr
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
else:
|
||||
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
|
||||
if assign_node:
|
||||
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
|
||||
if ann:
|
||||
ann_name: str | None = None
|
||||
if isinstance(ann, ast.Name):
|
||||
ann_name = ann.id
|
||||
elif isinstance(ann, ast.Attribute):
|
||||
ann_name = ann.attr
|
||||
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
||||
ann_name = ExtractTypeNameFromBinOp(ann)
|
||||
if ann_name:
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
elif ann_name in Gen.structs:
|
||||
target_type = ir.PointerType(Gen.structs[ann_name])
|
||||
if not getattr(Gen, '_va_arg_counter', None):
|
||||
Gen._va_arg_counter = 0
|
||||
Gen._va_arg_counter += 1
|
||||
result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type)
|
||||
if result is not None and getattr(result, 'name', None):
|
||||
result.name = f"va_arg_result_{Gen._va_arg_counter}"
|
||||
return result
|
||||
|
||||
def _resolve_vararg_type(self, type_arg: ast.expr, Gen: LlvmGeneratorMixin) -> ir.Type:
|
||||
"""将类型表达式解析为 LLVM 类型(供 arg/va_arg 共用)。"""
|
||||
target_type: ir.Type = ir.IntType(32)
|
||||
if isinstance(type_arg, ast.Name):
|
||||
type_name: str = type_arg.id
|
||||
if type_name in ('str', 'bytes'):
|
||||
target_type = ir.PointerType(ir.IntType(8))
|
||||
elif type_name == 'CPtr':
|
||||
target_type = ir.PointerType(ir.IntType(8))
|
||||
elif type_name in Gen.structs:
|
||||
target_type = ir.PointerType(Gen.structs[type_name])
|
||||
else:
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(type_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
else:
|
||||
resolved_tuple: tuple | None = CTypeRegistry.ResolveName(type_name)
|
||||
if resolved_tuple is not None:
|
||||
ctype_cls, ptr_level = resolved_tuple
|
||||
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
if llvm_str:
|
||||
base: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if base is not None:
|
||||
for _ in range(ptr_level):
|
||||
if isinstance(base, ir.VoidType):
|
||||
base = ir.IntType(8).as_pointer()
|
||||
else:
|
||||
base = ir.PointerType(base)
|
||||
target_type = base
|
||||
elif isinstance(type_arg, ast.Attribute):
|
||||
if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
|
||||
attr_name: str = type_arg.attr
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
return target_type
|
||||
|
||||
def _infer_vararg_type_from_context(self, Gen: LlvmGeneratorMixin) -> ir.Type:
|
||||
"""从当前赋值上下文推断 va_arg/arg 的目标类型。"""
|
||||
target_type: ir.Type = ir.IntType(32)
|
||||
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
|
||||
if assign_node:
|
||||
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
|
||||
if ann:
|
||||
ann_name: str | None = None
|
||||
if isinstance(ann, ast.Name):
|
||||
ann_name = ann.id
|
||||
elif isinstance(ann, ast.Attribute):
|
||||
ann_name = ann.attr
|
||||
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
||||
ann_name = ExtractTypeNameFromBinOp(ann)
|
||||
if ann_name:
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(ann_name)
|
||||
if ctype_cls is not None:
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
target_type = resolved
|
||||
elif ann_name in Gen.structs:
|
||||
target_type = ir.PointerType(Gen.structs[ann_name])
|
||||
return target_type
|
||||
|
||||
def _HandleVaArgLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not args:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
# 求值 va_list 指针(args[0])
|
||||
va_list_ptr: ir.Value = self.HandleExprLlvm(args[0])
|
||||
if va_list_ptr is None:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
# 解析目标类型
|
||||
if len(args) >= 2:
|
||||
target_type: ir.Type = self._resolve_vararg_type(args[1], Gen)
|
||||
else:
|
||||
target_type: ir.Type = self._infer_vararg_type_from_context(Gen)
|
||||
if not getattr(Gen, '_va_arg_counter', None):
|
||||
Gen._va_arg_counter = 0
|
||||
Gen._va_arg_counter += 1
|
||||
result: ir.Value | None = Gen.emit_va_arg(va_list_ptr, target_type)
|
||||
if result is not None and getattr(result, 'name', None):
|
||||
result.name = f"va_arg_explicit_{Gen._va_arg_counter}"
|
||||
return result if result is not None else ir.Constant(ir.IntType(32), 0)
|
||||
3779
lib/core/Handles/HandlesExprCall.py
Normal file
3779
lib/core/Handles/HandlesExprCall.py
Normal file
File diff suppressed because it is too large
Load Diff
271
lib/core/Handles/HandlesExprFormat.py
Normal file
271
lib/core/Handles/HandlesExprFormat.py
Normal file
@@ -0,0 +1,271 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprFormatHandle(BaseHandle):
|
||||
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not Gen or not Gen.builder:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
format_str: str = ""
|
||||
cast_args: list[Any] = []
|
||||
for part in Node.values:
|
||||
if isinstance(part, ast.Constant) and isinstance(part.value, str):
|
||||
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
|
||||
elif isinstance(part, ast.FormattedValue):
|
||||
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
|
||||
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
|
||||
obj_val: Any = self.HandleExprLlvm(part.value)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if fmt_class in Gen.structs:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
|
||||
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
|
||||
Gen._RegisterTempPtr(val)
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%s"
|
||||
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
|
||||
continue
|
||||
val = self.HandleExprLlvm(part.value)
|
||||
if not val:
|
||||
format_str += "%d"
|
||||
cast_args.append(ir.Constant(ir.IntType(32), 0))
|
||||
continue
|
||||
# 检查 format_spec(Python f-string 格式说明符)
|
||||
if part.format_spec is not None:
|
||||
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
|
||||
if c_fmt is not None:
|
||||
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
|
||||
format_str += c_fmt
|
||||
cast_args.append(cast_val)
|
||||
continue
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
|
||||
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
|
||||
format_str += "%d"
|
||||
cast_args.append(trunc_val)
|
||||
else:
|
||||
Loaded: Any = Gen._load(val, name="fstr_deref")
|
||||
if isinstance(Loaded.type, ir.IntType):
|
||||
if Loaded.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, ir.PointerType):
|
||||
format_str += "%s"
|
||||
cast_args.append(Loaded)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
elif val.type.width == 1:
|
||||
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
|
||||
format_str += "%d"
|
||||
cast_args.append(zext)
|
||||
else:
|
||||
is_u: bool = Gen._check_node_unsigned(part.value)
|
||||
format_str += "%u" if is_u else "%d"
|
||||
cast_args.append(val)
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(val)
|
||||
if not format_str:
|
||||
return Gen.emit_constant("", 'string')
|
||||
format_ptr: Any = Gen._create_string_global(format_str)
|
||||
# 统一使用 snprintf 生成字符串,返回 i8*
|
||||
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
|
||||
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
|
||||
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(64),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
], var_arg=True)
|
||||
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
# 第一遍:获取所需长度(NULL 缓冲,size=0)
|
||||
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
|
||||
# 加 1 用于 null 终止符
|
||||
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
|
||||
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
|
||||
if in_str_method:
|
||||
# 堆分配(__str__ 返回值需跨函数生命周期)
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
Gen._RegisterTempPtr(buf_ptr)
|
||||
return buf_ptr
|
||||
# 栈分配(局部使用,自动释放)
|
||||
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
return buf_ptr
|
||||
|
||||
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
|
||||
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
|
||||
|
||||
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
|
||||
返回 None 表示无法解析,调用方应回退到类型推断。
|
||||
"""
|
||||
if isinstance(format_spec_node, ast.JoinedStr):
|
||||
parts: list[str] = []
|
||||
for v in format_spec_node.values:
|
||||
if isinstance(v, ast.Constant) and isinstance(v.value, str):
|
||||
parts.append(v.value)
|
||||
else:
|
||||
return None
|
||||
spec_str: str = ''.join(parts)
|
||||
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
|
||||
spec_str = format_spec_node.value
|
||||
else:
|
||||
return None
|
||||
|
||||
if not spec_str:
|
||||
return None
|
||||
|
||||
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
|
||||
|
||||
c_flags: str = ''
|
||||
if sign == '+':
|
||||
c_flags += '+'
|
||||
elif sign == ' ':
|
||||
c_flags += ' '
|
||||
if alt:
|
||||
c_flags += '#'
|
||||
|
||||
if fill_align:
|
||||
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
|
||||
if align_char in ('<', '^'):
|
||||
c_flags += '-'
|
||||
if zero:
|
||||
c_flags += '0'
|
||||
|
||||
c_width: str = width or ''
|
||||
c_precision: str = precision or ''
|
||||
|
||||
length_mod: str = ''
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 64:
|
||||
length_mod = 'll'
|
||||
elif val.type.width == 32:
|
||||
length_mod = 'l'
|
||||
elif val.type.width == 16:
|
||||
length_mod = 'h'
|
||||
elif val.type.width == 8:
|
||||
length_mod = 'hh'
|
||||
|
||||
c_specifier: str = ''
|
||||
if fmt_type in ('d', 'n'):
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif fmt_type == 'x':
|
||||
c_specifier = f'{length_mod}x'
|
||||
elif fmt_type == 'X':
|
||||
c_specifier = f'{length_mod}X'
|
||||
elif fmt_type == 'o':
|
||||
c_specifier = f'{length_mod}o'
|
||||
elif fmt_type == 'b':
|
||||
return None
|
||||
elif fmt_type == 'c':
|
||||
c_specifier = 'c'
|
||||
elif fmt_type in ('f', 'F'):
|
||||
c_specifier = 'f'
|
||||
elif fmt_type in ('e', 'E', 'g', 'G'):
|
||||
c_specifier = fmt_type
|
||||
elif fmt_type == 's':
|
||||
c_specifier = 's'
|
||||
elif fmt_type == '%':
|
||||
c_specifier = 'f%%'
|
||||
else:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
c_specifier = 'c'
|
||||
elif val.type.width == 1:
|
||||
c_specifier = 'd'
|
||||
else:
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
c_specifier = 'f'
|
||||
elif isinstance(val.type, ir.PointerType):
|
||||
c_specifier = 's'
|
||||
else:
|
||||
c_specifier = 'd'
|
||||
|
||||
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
|
||||
|
||||
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
|
||||
"""根据 C printf 格式说明符转换值类型。"""
|
||||
fmt_type_char: str = ''
|
||||
for ch in reversed(c_fmt):
|
||||
if ch.isalpha() and ch not in ('l', 'h'):
|
||||
fmt_type_char = ch
|
||||
break
|
||||
elif ch == '%':
|
||||
break
|
||||
|
||||
if fmt_type_char == 's':
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
return val
|
||||
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
|
||||
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
|
||||
return val
|
||||
elif fmt_type_char == 'c':
|
||||
if isinstance(val.type, ir.IntType) and val.type.width < 32:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
|
||||
return val
|
||||
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
is_u: bool = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
|
||||
elif val.type.width == 16:
|
||||
is_u = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
|
||||
elif val.type.width == 1:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
|
||||
return val
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
|
||||
return val
|
||||
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
|
||||
if isinstance(val.type, ir.FloatType):
|
||||
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
|
||||
return val
|
||||
return val
|
||||
249
lib/core/Handles/HandlesExprLambda.py
Normal file
249
lib/core/Handles/HandlesExprLambda.py
Normal file
@@ -0,0 +1,249 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprLambdaHandle(BaseHandle):
|
||||
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not getattr(Gen, '_lambda_counter', None):
|
||||
Gen._lambda_counter = 0
|
||||
lambda_id: int = Gen._lambda_counter
|
||||
Gen._lambda_counter += 1
|
||||
fn_name: str = f"lambda_fn_{lambda_id}"
|
||||
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
|
||||
env_types: list[ir.Type] = []
|
||||
env_var_names: list[str] = []
|
||||
for var_name, var_val in captured_vars:
|
||||
env_types.append(var_val.type)
|
||||
env_var_names.append(var_name)
|
||||
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
|
||||
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
|
||||
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
param_types.append(ir.IntType(32))
|
||||
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
|
||||
Gen.functions[fn_name] = fn
|
||||
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
|
||||
prev_builder: Any = Gen.builder
|
||||
prev_func: Any = Gen.func
|
||||
prev_vars: dict[str, Any] = dict(Gen.variables)
|
||||
Gen.builder = ir.IRBuilder(entry_block)
|
||||
Gen.func = fn
|
||||
Gen.variables = {}
|
||||
for i, arg in enumerate(fn.args):
|
||||
arg.name = f"arg_{i}" if i > 0 else "env"
|
||||
if env_types:
|
||||
for idx, var_name in enumerate(env_var_names):
|
||||
env_ptr: Any = fn.args[0]
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
|
||||
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
|
||||
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
|
||||
Gen._store(Loaded, temp_alloca)
|
||||
Gen.variables[var_name] = temp_alloca
|
||||
if Node.args:
|
||||
for i, arg in enumerate(Node.args.args):
|
||||
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
|
||||
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
|
||||
body_val: Any = self.HandleExprLlvm(Node.body)
|
||||
if body_val:
|
||||
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen._load(body_val, name="Load_lambda_ret")
|
||||
if body_val.type != ret_type:
|
||||
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
|
||||
if body_val.type.width < ret_type.width:
|
||||
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
|
||||
elif body_val.type.width > ret_type.width:
|
||||
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
|
||||
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
|
||||
Gen.builder.ret(body_val)
|
||||
else:
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
Gen.builder = prev_builder
|
||||
Gen.func = prev_func
|
||||
Gen.variables = prev_vars
|
||||
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.PointerType(fn_type)
|
||||
])
|
||||
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
|
||||
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
|
||||
if env_types:
|
||||
for idx, (var_name, var_val) in enumerate(captured_vars):
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
|
||||
Gen._store(var_val, member_ptr)
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
|
||||
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
|
||||
Gen._store(env_i8_ptr, env_field_ptr)
|
||||
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
|
||||
Gen._store(fn, fn_field_ptr)
|
||||
return closure_ptr
|
||||
|
||||
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
captured: list[tuple[str, Any]] = []
|
||||
free_vars: list[str] = self._get_lambda_free_vars(Node)
|
||||
for var_name in free_vars:
|
||||
if var_name in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[var_name]
|
||||
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
|
||||
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
|
||||
captured.append((var_name, Loaded))
|
||||
return captured
|
||||
|
||||
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
|
||||
bound_vars: set[str] = set()
|
||||
free_vars: set[str] = set()
|
||||
# 收集 lambda body 中的 bound 和 free 变量
|
||||
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
|
||||
# lambda 参数也是 bound 的
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
bound_vars.add(arg.arg)
|
||||
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
|
||||
result: list[str] = list(free_vars - bound_vars)
|
||||
return result
|
||||
|
||||
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
TestVal: Any = self.HandleExprLlvm(Node.test)
|
||||
if not TestVal:
|
||||
return None
|
||||
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
|
||||
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
|
||||
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
|
||||
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
|
||||
# 先在 ThenBB 中生成 BodyVal
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
BodyVal: Any = self.HandleExprLlvm(Node.body)
|
||||
if not BodyVal:
|
||||
BodyVal = ir.Constant(ir.IntType(32), 0)
|
||||
ThenEndBB: ir.Block = Gen.builder.block
|
||||
# 在 ElseBB 中生成 OrelseVal
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
|
||||
if not OrelseVal:
|
||||
OrelseVal = ir.Constant(ir.IntType(32), 0)
|
||||
ElseEndBB: ir.Block = Gen.builder.block
|
||||
# 确定 phi 节点的目标类型
|
||||
result_type: ir.Type = BodyVal.type
|
||||
if BodyVal.type != OrelseVal.type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# 指针类型,使用 BodyVal 的类型
|
||||
result_type = BodyVal.type
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# BodyVal 是整数,OrelseVal 是指针(字符串字面量)
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
# BodyVal 是指针(字符串字面量),OrelseVal 是整数
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = BodyVal.type
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ThenEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ThenEndBB)
|
||||
if BodyVal.type != result_type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if BodyVal.type.width < result_type.width:
|
||||
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
|
||||
else:
|
||||
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 Else 分支的类型转换
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 指针转整数
|
||||
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ElseEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ElseEndBB)
|
||||
if OrelseVal.type != result_type:
|
||||
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if OrelseVal.type.width < result_type.width:
|
||||
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
|
||||
else:
|
||||
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
|
||||
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
|
||||
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 如果指针指向 i8,加载字符值
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
|
||||
else:
|
||||
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
|
||||
result_phi.add_incoming(BodyVal, ThenEndBB)
|
||||
result_phi.add_incoming(OrelseVal, ElseEndBB)
|
||||
return result_phi
|
||||
|
||||
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
ValueVal: Any = self.HandleExprLlvm(Node.value)
|
||||
if not ValueVal:
|
||||
return None
|
||||
TargetName: str = Node.target.id
|
||||
if TargetName in Gen._reg_values:
|
||||
del Gen._reg_values[TargetName]
|
||||
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
|
||||
VarPtr: Any = Gen.variables[TargetName]
|
||||
if VarPtr.type.pointee == ValueVal.type:
|
||||
Gen._store(ValueVal, VarPtr)
|
||||
else:
|
||||
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
else:
|
||||
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
Gen._reg_values[TargetName] = ValueVal
|
||||
return ValueVal
|
||||
453
lib/core/Handles/HandlesExprOps.py
Normal file
453
lib/core/Handles/HandlesExprOps.py
Normal file
@@ -0,0 +1,453 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprOpsHandle(BaseHandle):
|
||||
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
Gen._set_node_info(Node, "BinOp")
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
|
||||
if not LeftVal:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
|
||||
if not RightVal:
|
||||
return None
|
||||
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if not Op:
|
||||
return None
|
||||
OP_OVERLOAD_MAP: dict[str, str] = {
|
||||
'+': '__add__', '-': '__sub__', '*': '__mul__',
|
||||
'/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
|
||||
'**': '__pow__',
|
||||
}
|
||||
if Op in OP_OVERLOAD_MAP:
|
||||
LeftClassName: str | None = None
|
||||
if isinstance(LeftVal.type, ir.PointerType):
|
||||
pointee: ir.Type = LeftVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
LeftClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName is None and isinstance(Node.left, ast.Name):
|
||||
LeftClassName = Gen.var_struct_class.get(Node.left.id)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_name: str = OP_OVERLOAD_MAP[Op]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
|
||||
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
|
||||
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
|
||||
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
|
||||
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
|
||||
return TruncResult
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
|
||||
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
|
||||
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
|
||||
if RightVal.type.width < LeftVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
|
||||
elif RightVal.type.width > LeftVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
|
||||
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
|
||||
vname: str = Node.left.id
|
||||
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
|
||||
is_unsigned = True
|
||||
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
|
||||
return result
|
||||
|
||||
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
def _to_bool(val: Any, name: str) -> Any:
|
||||
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
|
||||
return val
|
||||
|
||||
values: list[ast.expr] = Node.values
|
||||
if len(values) < 2:
|
||||
return self.HandleExprLlvm(values[0]) if values else None
|
||||
if isinstance(Node.op, ast.And):
|
||||
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
|
||||
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val: Any = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"andcond{idx}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
|
||||
Gen.builder.cbranch(val, next_bb, end_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val: Any = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 0)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "andcond_last")
|
||||
last_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
elif isinstance(Node.op, ast.Or):
|
||||
phi_incomings = []
|
||||
end_bb = Gen.func.append_basic_block(name="or.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"orcond{idx}")
|
||||
cur_bb = Gen.builder.block
|
||||
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
|
||||
Gen.builder.cbranch(val, end_bb, next_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 1)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "orcond_last")
|
||||
last_bb = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
return None
|
||||
|
||||
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
OperandVal: Any = self.HandleExprLlvm(Node.operand)
|
||||
if not OperandVal:
|
||||
return None
|
||||
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
|
||||
if not OpSymbol:
|
||||
return None
|
||||
UNARY_OVERLOAD_MAP: dict[str, str] = {
|
||||
'-': '__neg__',
|
||||
'+': '__pos__',
|
||||
'~': '__invert__',
|
||||
}
|
||||
if OpSymbol in UNARY_OVERLOAD_MAP:
|
||||
ClassName: str | None = None
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
pointee: ir.Type = OperandVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName is None and isinstance(Node.operand, ast.Name):
|
||||
ClassName = Gen.var_struct_class.get(Node.operand.id)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName:
|
||||
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
if OpSymbol == 'not':
|
||||
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
|
||||
return Gen.builder.not_(OperandVal, name="not_result")
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
|
||||
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
|
||||
elif OpSymbol == '~':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
mask: int = (1 << OperandVal.type.width) - 1
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
|
||||
elif OpSymbol == '+':
|
||||
return OperandVal
|
||||
elif OpSymbol == '-':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
return Gen.builder.neg(OperandVal, name="neg_result")
|
||||
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fneg(OperandVal, name="fneg_result")
|
||||
return None
|
||||
|
||||
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left)
|
||||
if not LeftVal:
|
||||
return None
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
|
||||
if len(Node.ops) == 1:
|
||||
Op: ast.cmpop = Node.ops[0]
|
||||
# in/not in: 调用 __contains__
|
||||
if isinstance(Op, (ast.In, ast.NotIn)):
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if RightVal:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
|
||||
# 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
|
||||
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
|
||||
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
|
||||
# 归一化为 i1
|
||||
if isinstance(result.type, ir.IntType) and result.type.width > 1:
|
||||
zero: ir.Constant = ir.Constant(result.type, 0)
|
||||
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
|
||||
if isinstance(Op, ast.NotIn):
|
||||
result = Gen.builder.not_(result, name="not_in_result")
|
||||
return result
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if not RightVal:
|
||||
return None
|
||||
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
lv: int = LeftVal.constant
|
||||
rv: int = RightVal.constant
|
||||
lw: int = LeftVal.type.width
|
||||
rw: int = RightVal.type.width
|
||||
if lw < rw:
|
||||
lv = lv if lv >= 0 else lv + (1 << lw)
|
||||
elif rw < lw:
|
||||
rv = rv if rv >= 0 else rv + (1 << rw)
|
||||
if is_unsigned:
|
||||
mask_l: int = (1 << max(lw, rw)) - 1
|
||||
lv = lv & mask_l
|
||||
rv = rv & mask_l
|
||||
cmp_map: dict[str, bool] = {
|
||||
'==': lv == rv, '!=': lv != rv,
|
||||
'<': lv < rv, '>': lv > rv,
|
||||
'<=': lv <= rv, '>=': lv >= rv,
|
||||
}
|
||||
result: bool = cmp_map.get(ComparatorSymbol, False)
|
||||
return ir.Constant(ir.IntType(1), 1 if result else 0)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
# 如果宽类型常量值超出窄类型有符号范围,则必须用zext
|
||||
# i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节)
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
|
||||
RightVal = ir.Constant(LeftVal.type, None)
|
||||
else:
|
||||
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
|
||||
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
|
||||
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
|
||||
LeftVal = ir.Constant(RightVal.type, None)
|
||||
else:
|
||||
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
|
||||
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
|
||||
# is / is not: 地址比较(指针)或值比较(int)
|
||||
if ComparatorSymbol in ('is', 'is not'):
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
|
||||
return addr_cmp
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
|
||||
return val_cmp
|
||||
# str/bytes == str/bytes: 值比较(调用 strcmp),None 比较用地址
|
||||
if ComparatorSymbol in ('==', '!='):
|
||||
if (isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8
|
||||
and isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8):
|
||||
left_is_null: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None
|
||||
right_is_null: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None
|
||||
if not (left_is_null or right_is_null):
|
||||
strcmp_func = Gen.get_or_declare_c_func('strcmp', ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer(), ir.IntType(8).as_pointer()]))
|
||||
cmp_result = Gen.builder.call(strcmp_func, [LeftVal, RightVal], name="str_eq_cmp")
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
eq_result = Gen.builder.icmp_signed('==', cmp_result, zero, name="str_eq")
|
||||
if ComparatorSymbol == '!=':
|
||||
eq_result = Gen.builder.not_(eq_result, name="str_neq")
|
||||
return eq_result
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
|
||||
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif is_unsigned:
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
else:
|
||||
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
return result
|
||||
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
|
||||
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
|
||||
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
|
||||
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
continue
|
||||
RightVal = self.HandleExprLlvm(Comparator)
|
||||
if not RightVal:
|
||||
continue
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
|
||||
if is_unsigned:
|
||||
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
|
||||
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
else:
|
||||
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
if i < len(Node.ops) - 1:
|
||||
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(NextBB)
|
||||
LeftVal = RightVal
|
||||
else:
|
||||
cur_bb = Gen.builder.block
|
||||
Gen.builder.branch(EndBB)
|
||||
phi_incomings.append((cmp_result, cur_bb))
|
||||
Gen.builder.position_at_start(EndBB)
|
||||
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
|
||||
for val, bb in phi_incomings:
|
||||
final_result.add_incoming(val, bb)
|
||||
return final_result
|
||||
266
lib/core/Handles/HandlesExprUtils.py
Normal file
266
lib/core/Handles/HandlesExprUtils.py
Normal file
@@ -0,0 +1,266 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
|
||||
|
||||
class ExprUtils:
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
self.Trans: Translator = translator
|
||||
|
||||
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
|
||||
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
|
||||
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
|
||||
ast.MatMult: '@',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
|
||||
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
|
||||
ast.In: 'in', ast.NotIn: 'not in',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
if isinstance(node, ast.Name):
|
||||
VarName: str = node.id
|
||||
return Gen.var_struct_class.get(VarName)
|
||||
if isinstance(node, ast.Attribute):
|
||||
AttrName: str = node.attr
|
||||
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
|
||||
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
|
||||
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
|
||||
BaseClass: str | None = self._get_var_class(node.value, Gen)
|
||||
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
|
||||
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
|
||||
if BaseClass and BaseClass in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[BaseClass]:
|
||||
if m_name == AttrName:
|
||||
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
found = Gen.find_struct_by_pointee(m_type.pointee)
|
||||
if found:
|
||||
return found[0]
|
||||
# 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时,
|
||||
# 从 class_member_element_class 查找泛型特化类名
|
||||
element_class_map = getattr(Gen, 'class_member_element_class', {})
|
||||
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
|
||||
if element_class:
|
||||
return element_class
|
||||
break
|
||||
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
|
||||
# 避免字段名和变量名冲突导致错误分派)
|
||||
cls: str | None = Gen.var_struct_class.get(AttrName)
|
||||
if cls:
|
||||
return cls
|
||||
return None
|
||||
return None
|
||||
|
||||
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
|
||||
FullMethodName: str = f'{ClassName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if Gen._has_function(FullMethodName):
|
||||
func: Any = Gen._get_function(FullMethodName)
|
||||
call_args: list[Any] = [obj_val]
|
||||
if other_val is not None:
|
||||
call_args.append(other_val)
|
||||
if len(func.ftype.args) == len(call_args):
|
||||
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
|
||||
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
|
||||
if expected_type != actual_val.type:
|
||||
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
|
||||
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
|
||||
return result
|
||||
return None
|
||||
|
||||
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
|
||||
info: dict[str, Any] = {
|
||||
'name': "unknown",
|
||||
'size': 0,
|
||||
'signed': False,
|
||||
'ptr': False
|
||||
}
|
||||
if isinstance(llvm_type, ir.IntType):
|
||||
info['size'] = llvm_type.width // 8
|
||||
info['signed'] = True
|
||||
if llvm_type.width == 8:
|
||||
info['name'] = "char"
|
||||
elif llvm_type.width == 16:
|
||||
info['name'] = "short"
|
||||
elif llvm_type.width == 32:
|
||||
info['name'] = "int"
|
||||
elif llvm_type.width == 64:
|
||||
info['name'] = "long long"
|
||||
else:
|
||||
info['name'] = f"int{llvm_type.width}"
|
||||
elif isinstance(llvm_type, ir.DoubleType):
|
||||
info['size'] = 8
|
||||
info['signed'] = True
|
||||
info['name'] = "double"
|
||||
elif isinstance(llvm_type, ir.FloatType):
|
||||
info['size'] = 4
|
||||
info['signed'] = True
|
||||
info['name'] = "float"
|
||||
elif isinstance(llvm_type, ir.PointerType):
|
||||
info['size'] = 8
|
||||
info['signed'] = False
|
||||
info['ptr'] = True
|
||||
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
|
||||
info['name'] = f"{pointee_info['name']}*"
|
||||
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
size: int = 0
|
||||
for elem in llvm_type.elements:
|
||||
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
|
||||
size += elem_info['size']
|
||||
info['size'] = size
|
||||
info['signed'] = False
|
||||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
info['name'] = llvm_type.name
|
||||
else:
|
||||
info['name'] = "struct"
|
||||
elif isinstance(llvm_type, ir.ArrayType):
|
||||
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
|
||||
info['size'] = elem_info['size'] * llvm_type.count
|
||||
info['signed'] = elem_info['signed']
|
||||
info['name'] = f"{elem_info['name']}[]"
|
||||
elif isinstance(llvm_type, ir.VoidType):
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = "void"
|
||||
else:
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = str(llvm_type)
|
||||
return info
|
||||
|
||||
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(node, ast.Constant):
|
||||
if isinstance(node.value, bool):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, int):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, float):
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.value, str):
|
||||
if getattr(node, 'kind', None) == 'u':
|
||||
return ir.PointerType(ir.IntType(16))
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Name):
|
||||
if node.id in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[node.id]
|
||||
if isinstance(var_ptr.type, ir.PointerType):
|
||||
return var_ptr.type.pointee
|
||||
return var_ptr.type
|
||||
if node.id in Gen._reg_values:
|
||||
return Gen._reg_values[node.id].type
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
attr_name: str = node.attr
|
||||
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
|
||||
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
|
||||
return ir.IntType(32)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.BinOp):
|
||||
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
|
||||
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
|
||||
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
|
||||
return ir.DoubleType()
|
||||
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.UnaryOp):
|
||||
return self._infer_expr_llvm_type_full(node.operand)
|
||||
elif isinstance(node, ast.Subscript):
|
||||
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
|
||||
if isinstance(val_type, ir.PointerType):
|
||||
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
|
||||
return ir.IntType(8)
|
||||
if isinstance(val_type.pointee, ir.ArrayType):
|
||||
return ir.PointerType(val_type.pointee.element)
|
||||
return val_type.pointee
|
||||
if isinstance(val_type, ir.ArrayType):
|
||||
return val_type.element
|
||||
if isinstance(val_type, ir.IntType):
|
||||
return ir.IntType(8)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Name):
|
||||
func_name: str = node.func.id
|
||||
if Gen._has_function(func_name):
|
||||
fn: Any = Gen._get_function(func_name)
|
||||
return fn.function_type.return_type
|
||||
if func_name == 'len':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'sizeof':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'ord':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'chr':
|
||||
return ir.IntType(8)
|
||||
if func_name == 'int':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'float' or func_name == 'double':
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
if node.func.attr == 'Deref':
|
||||
return ir.IntType(64)
|
||||
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
|
||||
if node.func.attr == 'CChar':
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Compare):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.BoolOp):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.IfExp):
|
||||
return self._infer_expr_llvm_type_full(node.body)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
|
||||
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
|
||||
"""收集 AST 节点中的绑定变量和自由变量
|
||||
|
||||
Args:
|
||||
node: AST 节点
|
||||
bound: 集合,收集绑定变量(ast.Store 上下文)
|
||||
free: 集合,收集自由变量(ast.Load 上下文),可为 None
|
||||
"""
|
||||
if free is None:
|
||||
free = set()
|
||||
if isinstance(node, ast.Name):
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
bound.add(node.id)
|
||||
elif isinstance(node.ctx, ast.Load):
|
||||
free.add(node.id)
|
||||
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 这些节点有自己的作用域,不递归进入
|
||||
# 但需要收集参数名作为 bound
|
||||
if hasattr(node, 'args') and node.args:
|
||||
for arg in node.args.args:
|
||||
bound.add(arg.arg)
|
||||
elif getattr(node, '_fields', None):
|
||||
for field in node._fields:
|
||||
value: Any = getattr(node, field, None)
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
if isinstance(item, (ast.stmt, ast.expr)):
|
||||
self._collect_names(item, bound, free)
|
||||
elif isinstance(value, (ast.stmt, ast.expr)):
|
||||
self._collect_names(value, bound, free)
|
||||
1046
lib/core/Handles/HandlesFor.py
Normal file
1046
lib/core/Handles/HandlesFor.py
Normal file
File diff suppressed because it is too large
Load Diff
1852
lib/core/Handles/HandlesFunctions.py
Normal file
1852
lib/core/Handles/HandlesFunctions.py
Normal file
File diff suppressed because it is too large
Load Diff
204
lib/core/Handles/HandlesIf.py
Normal file
204
lib/core/Handles/HandlesIf.py
Normal file
@@ -0,0 +1,204 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
|
||||
|
||||
|
||||
class IfHandle(BaseHandle):
|
||||
def _get_attr_full_name(self, node: ast.expr) -> str | None:
|
||||
if isinstance(node, ast.Attribute):
|
||||
parts: list[str] = []
|
||||
cur: ast.expr = node
|
||||
while isinstance(cur, ast.Attribute):
|
||||
parts.append(cur.attr)
|
||||
cur = cur.value
|
||||
if isinstance(cur, ast.Name):
|
||||
parts.append(cur.id)
|
||||
parts.reverse()
|
||||
return '.'.join(parts)
|
||||
return None
|
||||
|
||||
def _is_cif_call(self, node: ast.expr) -> bool:
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
|
||||
if isinstance(node.func, ast.Name):
|
||||
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
|
||||
return False
|
||||
|
||||
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
|
||||
if isinstance(arg, ast.Name):
|
||||
return arg.id
|
||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||
return arg.value
|
||||
if isinstance(arg, ast.Attribute):
|
||||
full_name: str | None = self._get_attr_full_name(arg)
|
||||
if full_name:
|
||||
return full_name
|
||||
return None
|
||||
|
||||
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
|
||||
if not isinstance(node, ast.Call):
|
||||
return None
|
||||
args: list[ast.expr] = node.args
|
||||
if not args:
|
||||
return 0
|
||||
kind: str | None = None
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
kind = node.func.attr
|
||||
elif isinstance(node.func, ast.Name):
|
||||
kind = node.func.id
|
||||
else:
|
||||
return None
|
||||
if kind == 'CIfdef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 0
|
||||
return 1 if self._is_macro_defined(name) else 0
|
||||
elif kind == 'CIfndef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 1
|
||||
return 0 if self._is_macro_defined(name) else 1
|
||||
elif kind == 'CIf':
|
||||
return self._eval_const_expr(args[0])
|
||||
return None
|
||||
|
||||
def _is_macro_defined(self, name: str) -> bool:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
return True
|
||||
if self.Trans.SymbolTable.is_define(name):
|
||||
return True
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
return name in platform_macros
|
||||
|
||||
def _get_macro_value(self, name: str) -> int | float | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
val: int | float | None = Gen._define_constants[name]
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
|
||||
if info:
|
||||
if info.IsDefine:
|
||||
val: int | float | None = info.DefineValue
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
if name in platform_macros:
|
||||
return platform_macros[name]
|
||||
return None
|
||||
|
||||
def _get_platform_macros(self) -> dict[str, int]:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
macros: dict[str, int] = {}
|
||||
pi: dict[str, object] = Gen._platform_info
|
||||
ptr_size: int = getattr(Gen, 'ptr_size', 8)
|
||||
# 根据目标平台设置宏(从三元组推导)
|
||||
if pi.get('is_windows'):
|
||||
macros['_WIN32'] = 1
|
||||
if not pi.get('is_32bit'):
|
||||
macros['_WIN64'] = 1
|
||||
macros['WIN64'] = 1
|
||||
macros['WIN32'] = 1
|
||||
if pi.get('is_linux'):
|
||||
macros['__linux__'] = 1
|
||||
if pi.get('is_macos'):
|
||||
macros['__APPLE__'] = 1
|
||||
macros['__MACH__'] = 1
|
||||
if pi.get('is_x86_64'):
|
||||
macros['__x86_64__'] = 1
|
||||
macros['__x86_64'] = 1
|
||||
macros['_M_X64'] = 1
|
||||
elif pi.get('is_arm64'):
|
||||
macros['__aarch64__'] = 1
|
||||
macros['_M_ARM64'] = 1
|
||||
if not pi.get('is_32bit') and pi.get('is_linux'):
|
||||
macros['__LP64__'] = 1
|
||||
elif pi.get('is_32bit'):
|
||||
macros['_ILP32'] = 1
|
||||
macros['SIZEOF_VOID_P'] = ptr_size
|
||||
macros['__SIZEOF_POINTER__'] = ptr_size
|
||||
macros['NDEBUG'] = 0
|
||||
return macros
|
||||
|
||||
def _eval_const_expr(self, node: ast.expr) -> int | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
|
||||
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
|
||||
if result is None:
|
||||
# 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑)
|
||||
if isinstance(node, ast.Call) and self._is_cif_call(node):
|
||||
return self._evaluate_cif_condition(node)
|
||||
return None
|
||||
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
|
||||
if isinstance(result, bool):
|
||||
return 1 if result else 0
|
||||
if isinstance(result, float):
|
||||
return 1 if result != 0.0 else 0
|
||||
return result
|
||||
|
||||
def _HandleIfLlvm(self, Node: ast.If) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if self._is_cif_call(Node.test):
|
||||
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
|
||||
if compile_time_val is not None:
|
||||
if compile_time_val:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if not Cond:
|
||||
return
|
||||
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
|
||||
if is_const:
|
||||
if Cond.constant:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
|
||||
obj_val: ir.Value = Cond
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
|
||||
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
|
||||
else:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if not MergeBB.is_terminated:
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
else:
|
||||
Gen.builder.position_at_end(MergeBB)
|
||||
2589
lib/core/Handles/HandlesImports.py
Normal file
2589
lib/core/Handles/HandlesImports.py
Normal file
File diff suppressed because it is too large
Load Diff
382
lib/core/Handles/HandlesMatch.py
Normal file
382
lib/core/Handles/HandlesMatch.py
Normal file
@@ -0,0 +1,382 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class MatchHandle(BaseHandle):
|
||||
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
|
||||
if not SubjectVal:
|
||||
return
|
||||
|
||||
IsRenumMatch: bool = False
|
||||
RenumName: str | None = None
|
||||
SubjectPtr: ir.Value | None = None
|
||||
if isinstance(Node.subject, ast.Name):
|
||||
VarName: str = Node.subject.id
|
||||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
|
||||
if TypeInfo and TypeInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = TypeInfo.Name
|
||||
SubjectPtr = Gen._Load_var(VarName)
|
||||
|
||||
if not IsRenumMatch:
|
||||
for case in Node.cases:
|
||||
if isinstance(case.pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = case.pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
# Extract enum name for qualified lookup to avoid collision
|
||||
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
|
||||
# collision with same-name functions (e.g., def Ptr(...))
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
|
||||
EnumName: str = SymInfo.EnumName
|
||||
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
|
||||
if EnumInfo and EnumInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = EnumName
|
||||
if SubjectPtr is None:
|
||||
SubjectPtr = self.HandleExprLlvm(Node.subject)
|
||||
break
|
||||
|
||||
if IsRenumMatch and SubjectPtr:
|
||||
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
|
||||
return
|
||||
|
||||
if not isinstance(SubjectVal.type, ir.IntType):
|
||||
try:
|
||||
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
|
||||
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
|
||||
except Exception: # 回退:ptrtoint 失败时直接返回
|
||||
return
|
||||
SwitchIntType: ir.IntType = SubjectVal.type
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchOr):
|
||||
for j, SubPattern in enumerate(pattern.patterns):
|
||||
if isinstance(SubPattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
|
||||
elif isinstance(pattern, ast.MatchSingleton):
|
||||
if pattern.value is None:
|
||||
CaseValues.append(ir.Constant(SwitchIntType, 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchOr):
|
||||
NumSubCases: int = len(pattern.patterns)
|
||||
for j in range(NumSubCases):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
|
||||
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
|
||||
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
|
||||
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
|
||||
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
|
||||
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
|
||||
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
|
||||
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
|
||||
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
|
||||
if NeedAlloca or NeedBitcast:
|
||||
RenumStructType: Any = Gen.structs.get(RenumName)
|
||||
if RenumStructType is None:
|
||||
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
|
||||
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
|
||||
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
|
||||
RenumStructType = Gen._get_or_create_struct(RenumName)
|
||||
if NeedAlloca:
|
||||
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
|
||||
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
|
||||
Gen._store(SubjectPtr, CastedPtr)
|
||||
SubjectPtr = AllocaPtr
|
||||
else:
|
||||
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
|
||||
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
|
||||
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
|
||||
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
|
||||
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
|
||||
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = []
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
TagValue: int | None = None
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember:
|
||||
TagValue = SymInfo.value
|
||||
if TagValue is not None:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
|
||||
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
|
||||
CaseBBs.append(CaseBB)
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
|
||||
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
|
||||
for j, sub_pat in enumerate(pattern.patterns):
|
||||
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
|
||||
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
|
||||
CaseBindings.append(bindings)
|
||||
else:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(ir.IntType(32), 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if VariantName:
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
NestedStructType: ir.Type = Gen.structs[NestedStructName]
|
||||
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
|
||||
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
|
||||
for bind_name, member_name, member_type, member_idx in bindings:
|
||||
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
|
||||
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
|
||||
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
|
||||
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
|
||||
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
|
||||
Gen.variables[bind_name] = elem_ptr
|
||||
self.HandleBodyLlvm(case.body)
|
||||
for bind_name, _, _, _ in bindings:
|
||||
if bind_name in Gen.variables:
|
||||
del Gen.variables[bind_name]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
155
lib/core/Handles/HandlesRaise.py
Normal file
155
lib/core/Handles/HandlesRaise.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class RaiseHandle(BaseHandle):
|
||||
def _get_exception_code(self, ExcName: str) -> int:
|
||||
if ExcName in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[ExcName]
|
||||
if ExcName in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[ExcName]
|
||||
return 1
|
||||
|
||||
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
|
||||
exc_msg: ir.Value | None = None
|
||||
IsStopIteration: bool = False
|
||||
if Node.exc:
|
||||
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
|
||||
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
|
||||
elif isinstance(Node.exc, ast.Name):
|
||||
ExcName: str = Node.exc.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
|
||||
ExcName: str = Node.exc.func.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
if Node.exc.args:
|
||||
first_arg: ast.expr = Node.exc.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
|
||||
if arg_val:
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
if self._is_char_pointer(arg_val):
|
||||
exc_msg = arg_val
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
|
||||
if val:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width != 32:
|
||||
try:
|
||||
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
|
||||
except Exception: # 回退:trunc 失败时设默认值 1
|
||||
val = ir.Constant(ir.IntType(32), 1)
|
||||
exc_val = val
|
||||
else:
|
||||
try:
|
||||
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
|
||||
exc_val = val
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if IsStopIteration:
|
||||
if Gen._stop_iter_flag_param is not None:
|
||||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
|
||||
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
|
||||
ret_type: ir.Type = Gen.func.type.pointee.return_type
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
return
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(exc_val, exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
165
lib/core/Handles/HandlesReturn.py
Normal file
165
lib/core/Handles/HandlesReturn.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ReturnHandle(BaseHandle):
|
||||
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
|
||||
for item in reversed(Gen.eh_finally_stack):
|
||||
if item is not None and item[0] is not None:
|
||||
return item
|
||||
return None
|
||||
|
||||
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
|
||||
return_values: list[ast.expr] = []
|
||||
if isinstance(Node.value, ast.Tuple):
|
||||
return_values = Node.value.elts
|
||||
else:
|
||||
return_values = [Node.value]
|
||||
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
|
||||
llvm_vals: list[ir.Value] = []
|
||||
expected_types: list[ir.Type] = []
|
||||
for i, val in enumerate(return_values):
|
||||
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
|
||||
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||||
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
|
||||
IsRetPtr = True
|
||||
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
|
||||
expected_types.append(ExpectedType)
|
||||
Val: ir.Value | None = self.HandleExprLlvm(val)
|
||||
if Val is None:
|
||||
if isinstance(ExpectedType, ir.PointerType):
|
||||
Val = ir.Constant(ExpectedType, None)
|
||||
elif isinstance(ExpectedType, ir.IntType):
|
||||
Val = ir.Constant(ExpectedType, 0)
|
||||
else:
|
||||
Val = ir.Constant(ExpectedType, ir.Undefined)
|
||||
else:
|
||||
if Val.type != ExpectedType:
|
||||
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < ExpectedType.width:
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
elif Val.type.width > ExpectedType.width:
|
||||
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
|
||||
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
|
||||
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
|
||||
llvm_vals.append(Val)
|
||||
if llvm_vals:
|
||||
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
for i, val in enumerate(llvm_vals):
|
||||
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if Node.value:
|
||||
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if Val:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(zero_val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(zero_val)
|
||||
return
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
|
||||
struct_type: ir.Type = Gen.func.ftype.return_type
|
||||
if isinstance(struct_type, ir.LiteralStructType):
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
|
||||
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
|
||||
for j in range(1, len(struct_type.elements)):
|
||||
elem_type: ir.Type = struct_type.elements[j]
|
||||
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
for j, elem_type in enumerate(struct_type.elements):
|
||||
if j == 0:
|
||||
if Val.type == elem_type:
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < elem_type.width:
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
elif Val.type.width > elem_type.width:
|
||||
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(Val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(Val)
|
||||
else:
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.ArrayType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
else:
|
||||
Gen.emit_return()
|
||||
467
lib/core/Handles/HandlesSpecialCall.py
Normal file
467
lib/core/Handles/HandlesSpecialCall.py
Normal file
@@ -0,0 +1,467 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, BuiltinTypeMap
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class CSpecialCallHandle(BaseHandle):
|
||||
def _HandleCIfLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if Node.args:
|
||||
ArgVal: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
if ArgVal:
|
||||
if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType):
|
||||
return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0)
|
||||
if isinstance(ArgVal.type, ir.IntType):
|
||||
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
|
||||
if isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
def _HandleCAddrLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not Node.args:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
Arg = Node.args[0]
|
||||
if isinstance(Arg, ast.Call):
|
||||
ClassName = None
|
||||
if isinstance(Arg.func, ast.Name):
|
||||
ClassName = Arg.func.id
|
||||
elif isinstance(Arg.func, ast.Attribute):
|
||||
ClassName = Arg.func.attr
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
StructType = Gen.structs[ClassName]
|
||||
if isinstance(StructType, ir.PointerType):
|
||||
StructType = StructType.pointee
|
||||
ObjPtr = Gen._allocaEntry(StructType, name=f"{ClassName}_obj")
|
||||
zero_val = Gen._zero_value_for_type(StructType)
|
||||
if zero_val is not None:
|
||||
Gen.builder.store(zero_val, ObjPtr)
|
||||
ConstructorName = f"{ClassName}.__init__"
|
||||
if ConstructorName in Gen.functions:
|
||||
func = Gen.functions[ConstructorName]
|
||||
InitArgs = [ObjPtr]
|
||||
for carg in Arg.args:
|
||||
ArgVal = self.HandleExprLlvm(carg)
|
||||
if ArgVal:
|
||||
InitArgs.append(ArgVal)
|
||||
for kw in Arg.keywords:
|
||||
ArgVal = self.HandleExprLlvm(kw.value)
|
||||
if ArgVal:
|
||||
InitArgs.append(ArgVal)
|
||||
if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'):
|
||||
self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen)
|
||||
adjusted = Gen._adjust_args(InitArgs, func)
|
||||
Gen.builder.call(func, adjusted, name=f"{ClassName}_construct")
|
||||
return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr")
|
||||
if isinstance(Arg, ast.Subscript):
|
||||
SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg)
|
||||
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr")
|
||||
if isinstance(Arg, ast.Attribute):
|
||||
AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg)
|
||||
if AttrPtr and isinstance(AttrPtr.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr")
|
||||
if isinstance(Arg, ast.Name):
|
||||
VarName = Arg.id
|
||||
if VarName in Gen.functions:
|
||||
func = Gen.functions[VarName]
|
||||
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr")
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
var_ptr = Gen.variables[VarName]
|
||||
if isinstance(var_ptr.type, ir.PointerType):
|
||||
# For pointer-to-pointer allocas (var_ptr is T**):
|
||||
# - If T is a named struct (@t.Object class), the variable semantically
|
||||
# IS the struct, so c.Addr should return the struct pointer value.
|
||||
# - If T is a primitive pointer type (e.g., i8*), the variable semantically
|
||||
# holds a pointer, so c.Addr should return &var (alloca address).
|
||||
if isinstance(var_ptr.type.pointee, ir.PointerType):
|
||||
pointee = var_ptr.type.pointee.pointee
|
||||
if isinstance(pointee, ir.IdentifiedStructType):
|
||||
# @t.Object class variable — return Loaded struct pointer
|
||||
ArgVal = self.HandleExprLlvm(Arg)
|
||||
if ArgVal and isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
|
||||
# Pointer-type variable — return alloca address (&var)
|
||||
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
|
||||
return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
|
||||
ArgVal = self.HandleExprLlvm(Arg)
|
||||
if ArgVal:
|
||||
if isinstance(ArgVal.type, ir.IntType):
|
||||
alloca = Gen._alloca(ArgVal.type, name="addr_tmp")
|
||||
Gen._store(ArgVal, alloca)
|
||||
return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr")
|
||||
elif isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _HandleCSetLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if len(Node.args) >= 2:
|
||||
target_arg: ast.expr = Node.args[0]
|
||||
value_arg: ast.expr = Node.args[1]
|
||||
target_ptr: ir.Value | None = None
|
||||
if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute):
|
||||
if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c':
|
||||
if target_arg.func.attr == 'Deref' and target_arg.args:
|
||||
deref_arg = target_arg.args[0]
|
||||
if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None:
|
||||
target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr")
|
||||
else:
|
||||
inner_value = self.HandleExprLlvm(deref_arg)
|
||||
if inner_value:
|
||||
if isinstance(inner_value.type, ir.PointerType):
|
||||
if isinstance(inner_value.type.pointee, ir.PointerType):
|
||||
inner_value = Gen._load(inner_value, name="cast_deref")
|
||||
target_ptr = inner_value
|
||||
elif target_arg.func.attr == 'Addr' and target_arg.args:
|
||||
target_ptr = self.HandleExprLlvm(target_arg)
|
||||
elif isinstance(target_arg.func.value, ast.Name) and IsTModule(target_arg.func.value.id, self.Trans.SymbolTable):
|
||||
type_attr = target_arg.func.attr
|
||||
resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr)
|
||||
if target_arg.args and resolved_cname is not None:
|
||||
inner_val = self.HandleExprLlvm(target_arg.args[0])
|
||||
if inner_val and isinstance(inner_val.type, ir.PointerType):
|
||||
target_llvm_type = Gen._basic_type_to_llvm(resolved_cname)
|
||||
if target_llvm_type:
|
||||
target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr")
|
||||
if not target_ptr:
|
||||
if isinstance(target_arg, ast.Subscript):
|
||||
target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg)
|
||||
else:
|
||||
target_ptr = self.HandleExprLlvm(target_arg)
|
||||
Val = self.HandleExprLlvm(value_arg)
|
||||
if target_ptr and Val:
|
||||
if isinstance(target_ptr.type, ir.PointerType):
|
||||
ValToStore = Val
|
||||
pointee = target_ptr.type.pointee
|
||||
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8:
|
||||
if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
|
||||
ValToStore = Val
|
||||
elif isinstance(Val.type, ir.IntType):
|
||||
ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set")
|
||||
elif isinstance(pointee, ir.IntType):
|
||||
if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8:
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr")
|
||||
ValToStore = Gen._load(value_ptr, name="Load_value")
|
||||
elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
|
||||
ValToStore = Gen._load(Val, name="Load_char_value")
|
||||
if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType):
|
||||
if ValToStore.type.width < pointee.width:
|
||||
ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set")
|
||||
elif ValToStore.type.width > pointee.width:
|
||||
ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set")
|
||||
elif Val.type != pointee:
|
||||
if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType):
|
||||
ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set")
|
||||
Gen._store(ValToStore, target_ptr)
|
||||
return ir.Constant(ir.IntType(32), 1)
|
||||
|
||||
def _HandleCLoadLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if len(Node.args) < 2:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
# c.Load(a, b) 语义: *a = *b(a 是目标,b 是源)
|
||||
# wiki 文档: c.Load(ptr, value) -> *ptr = *value;
|
||||
dst_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
src_val: ir.Value | None = self.HandleExprLlvm(Node.args[1])
|
||||
if not src_val or not dst_val:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType):
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
pointee = dst_val.type.pointee
|
||||
# c.Addr 统一返回 i8* 通用指针,丢失原始类型信息。
|
||||
# 若 dst 是 c.Addr(var),从 var 的 alloca 类型推断真实 pointee(如 i64),
|
||||
# 否则 c.Load 只会按 i8 加载 1 字节(IEEE 754 double→u64 位重解释 bug)。
|
||||
if (isinstance(pointee, ir.IntType) and pointee.width == 8
|
||||
and isinstance(Node.args[0], ast.Call)
|
||||
and isinstance(Node.args[0].func, ast.Attribute)
|
||||
and Node.args[0].func.attr == 'Addr'
|
||||
and Node.args[0].args
|
||||
and isinstance(Node.args[0].args[0], ast.Name)):
|
||||
var_name = Node.args[0].args[0].id
|
||||
if var_name in Gen.variables and Gen.variables[var_name] is not None:
|
||||
var_ptr = Gen.variables[var_name]
|
||||
if isinstance(var_ptr.type, ir.PointerType):
|
||||
pointee = var_ptr.type.pointee
|
||||
# 按 pointee 类型 bitcast src 加载,bitcast dst 存储
|
||||
if src_val.type.pointee != pointee:
|
||||
src_cast = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_src_cast")
|
||||
else:
|
||||
src_cast = src_val
|
||||
Loaded = Gen._load(src_cast, name="cLoad_loaded")
|
||||
if Loaded is None:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
if dst_val.type.pointee != pointee:
|
||||
dst_cast = Gen.builder.bitcast(dst_val, ir.PointerType(pointee), name="cLoad_dst_cast")
|
||||
else:
|
||||
dst_cast = dst_val
|
||||
Gen._store(Loaded, dst_cast)
|
||||
return ir.Constant(ir.IntType(32), 1)
|
||||
|
||||
def _HandleCDerefLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not Node.args:
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
# 检测嵌套 c.Deref(c.Deref(...)):设置标志让内层 Deref 加载为指针
|
||||
IsNestedDeref: bool = (
|
||||
isinstance(Node.args[0], ast.Call)
|
||||
and isinstance(Node.args[0].func, ast.Attribute)
|
||||
and Node.args[0].func.attr == 'Deref'
|
||||
)
|
||||
if IsNestedDeref:
|
||||
Gen._nested_deref_load_ptr = True
|
||||
try:
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
finally:
|
||||
if IsNestedDeref:
|
||||
Gen._nested_deref_load_ptr = False
|
||||
if arg_val is None:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
pointee: ir.Type = arg_val.type.pointee
|
||||
# 嵌套 Deref 的内层:加载为指针 (i8*),不推断目标类型
|
||||
# 因为结果会被外层 Deref 再次解引用
|
||||
NestedLoadPtr: bool = getattr(Gen, '_nested_deref_load_ptr', False)
|
||||
if NestedLoadPtr:
|
||||
PtrType: ir.Type = ir.PointerType(ir.IntType(8))
|
||||
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(PtrType), name="deref_cast")
|
||||
Loaded = Gen._load(casted, name="deref")
|
||||
if Loaded is not None:
|
||||
return Loaded
|
||||
# void* (i8*) 需要根据赋值目标类型推断加载类型
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
target_type: ir.Type | None = self._infer_deref_target_type(Gen, Node)
|
||||
if target_type is not None and not isinstance(target_type, ir.IntType):
|
||||
# bitcast i8* -> target_type* then load
|
||||
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast")
|
||||
Loaded = Gen._load(casted, name="deref")
|
||||
if Loaded is not None:
|
||||
return Loaded
|
||||
elif target_type is not None and isinstance(target_type, ir.IntType):
|
||||
# 目标是整数类型 (如 i32/i64): bitcast 并加载
|
||||
if target_type.width != 8:
|
||||
casted: ir.Value = Gen.builder.bitcast(arg_val, ir.PointerType(target_type), name="deref_cast")
|
||||
Loaded = Gen._load(casted, name="deref")
|
||||
if Loaded is not None:
|
||||
return Loaded
|
||||
Loaded = Gen._load(arg_val, name="deref")
|
||||
if Loaded is not None:
|
||||
return Loaded
|
||||
return arg_val
|
||||
|
||||
def _infer_deref_target_type(self, Gen: LlvmGeneratorMixin, DerefNode: ast.Call | None = None) -> ir.Type | None:
|
||||
"""从当前赋值上下文推断 c.Deref 的目标加载类型。
|
||||
当用户写 v: int = c.Deref(ptr) 时,从赋值注解推断目标类型。
|
||||
注意:仅当 c.Deref 是赋值的直接 RHS 时才推断;若 c.Deref 嵌套在
|
||||
ifexp/compare/binop 中(如 `a = 1 if c.Deref(p) == 65 else 0`),
|
||||
不应推断,否则会把 i8* 错误 bitcast 为 i32* 加载 4 字节。"""
|
||||
assign_node: ast.AST | None = getattr(self.Trans, '_current_assign_node', None)
|
||||
if not assign_node:
|
||||
return None
|
||||
# 仅当 c.Deref 是赋值的直接 RHS 时才推断类型
|
||||
if DerefNode is not None and getattr(assign_node, 'value', None) is not DerefNode:
|
||||
return None
|
||||
ann: ast.AST | None = getattr(assign_node, 'annotation', None)
|
||||
if not ann:
|
||||
return None
|
||||
ann_name: str | None = None
|
||||
if isinstance(ann, ast.Name):
|
||||
ann_name = ann.id
|
||||
elif isinstance(ann, ast.Attribute):
|
||||
ann_name = ann.attr
|
||||
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
||||
# 处理 int | t.CPtr 形式的联合类型注解
|
||||
for side in (ann.left, ann.right):
|
||||
if isinstance(side, ast.Name):
|
||||
ann_name = side.id
|
||||
break
|
||||
elif isinstance(side, ast.Attribute):
|
||||
ann_name = side.attr
|
||||
break
|
||||
if not ann_name:
|
||||
return None
|
||||
# 使用 BuiltinTypeMap 统一查询(同时支持 Python 类名和字符串速记)
|
||||
entry: tuple[type, int] | None = BuiltinTypeMap.Get(ann_name)
|
||||
if entry is not None:
|
||||
ctype_cls: type = entry[0]
|
||||
llvm_str: str | None = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
if llvm_str:
|
||||
resolved: ir.Type | None = Gen._type_str_to_llvm(llvm_str)
|
||||
if resolved:
|
||||
return resolved
|
||||
# 检查是否是已注册的结构体类型
|
||||
if ann_name in Gen.structs:
|
||||
return Gen.structs[ann_name]
|
||||
return None
|
||||
|
||||
def _HandleCPtrToIntLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not Node.args:
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
if arg_val is None:
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result")
|
||||
if isinstance(arg_val.type, ir.IntType):
|
||||
if arg_val.type.width < 64:
|
||||
return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint")
|
||||
elif arg_val.type.width > 64:
|
||||
return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint")
|
||||
return arg_val
|
||||
return ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
|
||||
class TSpecialCallHandle(BaseHandle):
|
||||
|
||||
@staticmethod
|
||||
def _ResolveTAttrToCName(attr: str) -> str | None:
|
||||
ctype_cls: type | None = CTypeRegistry.GetClassByName(attr)
|
||||
if ctype_cls is not None:
|
||||
try:
|
||||
inst = ctype_cls()
|
||||
cname = type(inst).__name__
|
||||
if cname:
|
||||
return cname
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理函数调用失败: {_e}", "Exception")
|
||||
return None
|
||||
|
||||
def _HandleTSpecialCallLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if not Node.args:
|
||||
return None
|
||||
attr: str = Node.func.attr
|
||||
|
||||
if attr == 'CType':
|
||||
return self._HandleCTypeLlvm(Node)
|
||||
|
||||
target_type: str | None = self._ResolveTAttrToCName(attr)
|
||||
if target_type is not None:
|
||||
IsPtr_cast = False
|
||||
if len(Node.args) >= 2:
|
||||
second_arg = Node.args[1]
|
||||
if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and IsTModule(second_arg.value.id, self.Trans.SymbolTable) and second_arg.attr == 'CPtr':
|
||||
IsPtr_cast = True
|
||||
elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr':
|
||||
IsPtr_cast = True
|
||||
if IsPtr_cast:
|
||||
return self._HandleTPtrCastLlvm(Node, attr)
|
||||
if target_type == 'void':
|
||||
target_type = 'void *'
|
||||
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type)
|
||||
return None
|
||||
|
||||
def _HandleCTypeLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
if not arg_val:
|
||||
return None
|
||||
target_type_str: str = 'unsigned long long'
|
||||
if len(Node.args) >= 2:
|
||||
type_parts: list[str] = []
|
||||
ptr_count: int = 0
|
||||
for i in range(1, len(Node.args)):
|
||||
type_arg = Node.args[i]
|
||||
if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
|
||||
type_attr = type_arg.attr
|
||||
_PREFIX_MAP: dict[str, str] = {
|
||||
'CUnsigned': 'unsigned', 'CSigned': 'signed',
|
||||
'CConst': 'const', 'CVolatile': 'volatile',
|
||||
}
|
||||
if type_attr in _PREFIX_MAP:
|
||||
type_parts.append(_PREFIX_MAP[type_attr])
|
||||
elif type_attr in ('CPtr', 'CArrayPtr'):
|
||||
ptr_count += 1
|
||||
else:
|
||||
resolved = self._ResolveTAttrToCName(type_attr)
|
||||
if resolved is not None:
|
||||
type_parts.append(resolved)
|
||||
if type_parts:
|
||||
target_type_str = ' '.join(type_parts)
|
||||
if ptr_count > 0:
|
||||
target_type_str += ' ' + '*' * ptr_count
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int")
|
||||
return int_val
|
||||
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str)
|
||||
|
||||
def _HandleTPtrCastLlvm(self, Node: ast.Call, attr: str) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if attr in ('CChar', 'CUnsignedChar'):
|
||||
first_arg = Node.args[0]
|
||||
if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and IsTModule(first_arg.func.value.id, self.Trans.SymbolTable) and first_arg.func.attr == 'CInt' and first_arg.args:
|
||||
inner_val = self.HandleExprLlvm(first_arg.args[0])
|
||||
if isinstance(inner_val.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint")
|
||||
expr_val = self.HandleExprLlvm(Node.args[0])
|
||||
if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8:
|
||||
var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr")
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr")
|
||||
Gen._store(expr_val, char_ptr)
|
||||
null_char = ir.Constant(ir.IntType(8), 0)
|
||||
null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr")
|
||||
Gen._store(null_char, null_ptr)
|
||||
return char_ptr
|
||||
elif isinstance(expr_val.type, ir.PointerType):
|
||||
if isinstance(expr_val.type.pointee, ir.PointerType):
|
||||
Loaded_ptr = Gen._load(expr_val, name="load_ptr")
|
||||
if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8:
|
||||
return Loaded_ptr
|
||||
if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8:
|
||||
return expr_val
|
||||
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr")
|
||||
elif isinstance(expr_val.type, ir.IntType):
|
||||
if expr_val.type.width == 32:
|
||||
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
|
||||
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}")
|
||||
return Gen.emit_constant(0, 'int')
|
||||
elif attr == 'CVoid':
|
||||
return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *')
|
||||
elif attr == 'CInt':
|
||||
expr_val = self.HandleExprLlvm(Node.args[0])
|
||||
if expr_val:
|
||||
if isinstance(expr_val.type, ir.IntType):
|
||||
if expr_val.type.width < 64:
|
||||
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
|
||||
return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
|
||||
return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr")
|
||||
else:
|
||||
ctype_cls = CTypeRegistry.GetClassByName(attr)
|
||||
if ctype_cls is not None:
|
||||
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||||
target_type = Gen._type_str_to_llvm(llvm_str)
|
||||
if target_type:
|
||||
# 基础类型 (int/float) → 加一层指针 → T*
|
||||
if isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)):
|
||||
target_ptr_type = ir.PointerType(target_type)
|
||||
expr_val = self.HandleExprLlvm(Node.args[0])
|
||||
if expr_val:
|
||||
if isinstance(expr_val.type, ir.IntType):
|
||||
if expr_val.type.width < 64:
|
||||
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
|
||||
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
|
||||
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
|
||||
# 指针类型 (如 CPtr → i8*) → 再加一层指针 → i8**
|
||||
elif isinstance(target_type, ir.PointerType):
|
||||
target_ptr_type = ir.PointerType(target_type)
|
||||
expr_val = self.HandleExprLlvm(Node.args[0])
|
||||
if expr_val:
|
||||
if isinstance(expr_val.type, ir.IntType):
|
||||
if expr_val.type.width < 64:
|
||||
expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64")
|
||||
return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
|
||||
return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr")
|
||||
return None
|
||||
214
lib/core/Handles/HandlesTry.py
Normal file
214
lib/core/Handles/HandlesTry.py
Normal file
@@ -0,0 +1,214 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class TryHandle(BaseHandle):
|
||||
def _get_exception_type_code(self, type_node: ast.expr) -> int:
|
||||
if isinstance(type_node, ast.Name):
|
||||
name: str = type_node.id
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
name: str = type_node.attr
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Tuple):
|
||||
for elt in type_node.elts:
|
||||
code: int = self._get_exception_type_code(elt)
|
||||
if code != 1:
|
||||
return code
|
||||
return 1
|
||||
return 1
|
||||
|
||||
def _get_exception_name(self, type_node: ast.expr) -> str | None:
|
||||
if isinstance(type_node, ast.Name):
|
||||
return type_node.id
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
return type_node.attr
|
||||
return None
|
||||
|
||||
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
|
||||
name: str | None = self._get_exception_name(type_node)
|
||||
if name is None:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
if name not in self.Trans.exception_registry:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
codes: list[int] = [self.Trans.exception_registry[name]]
|
||||
self._collect_descendant_codes(name, codes)
|
||||
return codes
|
||||
|
||||
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
|
||||
for child_name, parent in self.Trans.exception_parents.items():
|
||||
if parent == parent_name:
|
||||
child_code: int | None = self.Trans.exception_registry.get(child_name)
|
||||
if child_code is not None and child_code not in codes:
|
||||
codes.append(child_code)
|
||||
self._collect_descendant_codes(child_name, codes)
|
||||
|
||||
def _HandleTryLlvm(self, Node: ast.Try) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if not Gen.func:
|
||||
return
|
||||
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
|
||||
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
|
||||
HasFinally: bool = bool(Node.finalbody)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.append((None, None, None))
|
||||
else:
|
||||
Gen.eh_finally_stack.append(None)
|
||||
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
|
||||
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
|
||||
for i, handler in enumerate(Node.handlers):
|
||||
ExcTypeCodes: list[int] = [1]
|
||||
if handler.type:
|
||||
ExcTypeCodes = self._get_all_match_codes(handler.type)
|
||||
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
|
||||
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
|
||||
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
|
||||
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
|
||||
ElseBB: ir.Block | None = None
|
||||
if Node.orelse:
|
||||
ElseBB = Gen.func.append_basic_block(name="try.else")
|
||||
Gen.builder.branch(TryBB)
|
||||
Gen.builder.position_at_start(TryBB)
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
if ElseBB:
|
||||
Gen.builder.branch(ElseBB)
|
||||
else:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(DispatchBB)
|
||||
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
|
||||
next_check_bb: ir.Block | None = None
|
||||
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
|
||||
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
|
||||
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
|
||||
if i > 0 and next_check_bb is not None:
|
||||
Gen.builder.position_at_start(next_check_bb)
|
||||
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
|
||||
if handler.type is None:
|
||||
Gen.builder.branch(MatchBB)
|
||||
else:
|
||||
match_cond: ir.Value | None = None
|
||||
for code in ExcTypeCodes:
|
||||
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
|
||||
if match_cond is None:
|
||||
match_cond = is_code_match
|
||||
else:
|
||||
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
|
||||
if i < len(except_blocks) - 1:
|
||||
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
|
||||
else:
|
||||
next_check_bb = UnhandledBB
|
||||
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
|
||||
Gen.builder.position_at_start(MatchBB)
|
||||
if handler.name:
|
||||
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
|
||||
Gen._store(eh_msg_val, var_alloca)
|
||||
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
|
||||
Gen.builder.branch(ExceptBB)
|
||||
Gen.builder.position_at_start(UnhandledBB)
|
||||
eh_msg_out_arg: ir.Argument | None = None
|
||||
eh_code_out_arg: ir.Argument | None = None
|
||||
if Gen.func and len(Gen.func.args) > 0:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_out_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_out_arg = arg
|
||||
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
|
||||
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
|
||||
Gen._store(eh_msg_val, eh_msg_out_arg)
|
||||
Gen._store(eh_code_val_prop, eh_code_out_arg)
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 1))
|
||||
elif isinstance(ret_type, ir.VoidType):
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen.builder.branch(AfterBB)
|
||||
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
Gen.builder.position_at_start(ExceptBB)
|
||||
old_var: ir.Value | None = None
|
||||
if idx in handler_var_map:
|
||||
hname: str = handler_var_map[idx][0]
|
||||
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
|
||||
old_var = handler_var_map[idx][2]
|
||||
Gen.variables[hname] = var_alloca
|
||||
self.HandleBodyLlvm(handler.body)
|
||||
if idx in handler_var_map:
|
||||
hname = handler_var_map[idx][0]
|
||||
old_var = handler_var_map[idx][2]
|
||||
if old_var is not None:
|
||||
Gen.variables[hname] = old_var
|
||||
elif hname in Gen.variables:
|
||||
del Gen.variables[hname]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.eh_except_block_stack.pop()
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.pop()
|
||||
if Node.finalbody:
|
||||
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
|
||||
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
|
||||
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
|
||||
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
|
||||
Gen.builder.branch(FinallyBB)
|
||||
Gen.builder.position_at_start(FinallyBB)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
|
||||
self.HandleBodyLlvm(Node.finalbody)
|
||||
if Gen.eh_finally_stack:
|
||||
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
|
||||
Gen.eh_finally_stack.pop()
|
||||
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
|
||||
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
|
||||
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
|
||||
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
|
||||
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
|
||||
Gen.builder.position_at_start(RetBB)
|
||||
if pending_ret_val:
|
||||
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
|
||||
Gen.builder.ret(ret_val)
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
Gen.builder.position_at_start(ContinueBB)
|
||||
975
lib/core/Handles/HandlesTypeMerge.py
Normal file
975
lib/core/Handles/HandlesTypeMerge.py
Normal file
@@ -0,0 +1,975 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from typing import List
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
|
||||
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
|
||||
from lib.includes import t
|
||||
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
|
||||
import ast
|
||||
|
||||
|
||||
class HandlesTypeMerge(BaseHandle):
|
||||
"""处理类型合并逻辑 - 所有类型分析的核心模块"""
|
||||
|
||||
def _MakeVoidCTypeInfo(self) -> CTypeInfo:
|
||||
Info = CTypeInfo()
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
|
||||
@staticmethod
|
||||
def _MakeCTypeInfoFromName(TypeName: str) -> CTypeInfo:
|
||||
"""直接从类型名构造 CTypeInfo,不经过 FromStr/字符串解析"""
|
||||
return CTypeInfo.FromTypeName(TypeName)
|
||||
|
||||
def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo:
|
||||
"""获取 CTypeInfo 对象"""
|
||||
Result = self._GetCTypeInfoInternal(Node)
|
||||
if isinstance(Result, CTypeInfo):
|
||||
return Result
|
||||
elif isinstance(Result, str):
|
||||
return self._MakeCTypeInfoFromName(Result)
|
||||
else:
|
||||
return self._MakeVoidCTypeInfo()
|
||||
|
||||
def _GetCTypeInfoInternal(self, Node: ast.AST) -> CTypeInfo | str | None:
|
||||
"""鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo"""
|
||||
LineNum = getattr(Node, 'lineno', None)
|
||||
|
||||
self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...")
|
||||
|
||||
if isinstance(Node, ast.Constant):
|
||||
TypeName = Node.value
|
||||
return self._MakeCTypeInfoFromName(TypeName)
|
||||
|
||||
if isinstance(Node, ast.Name):
|
||||
TypeName = Node.id
|
||||
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
|
||||
if TypeName in t_c_imported:
|
||||
src_module, src_name = t_c_imported[TypeName]
|
||||
virtual_attr = ast.Attribute(
|
||||
value=ast.Name(id=src_module, ctx=ast.Load()),
|
||||
attr=src_name,
|
||||
ctx=ast.Load()
|
||||
)
|
||||
ast.copy_location(virtual_attr, Node)
|
||||
return self.GetCTypeInfo(virtual_attr)
|
||||
Entry = self.Trans.SymbolTable.lookup(TypeName)
|
||||
if Entry and Entry.IsTypedef:
|
||||
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
|
||||
if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0:
|
||||
Result = Entry.Copy()
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
if Entry.OriginalType:
|
||||
if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr:
|
||||
Result = CTypeInfo()
|
||||
Result.IsFuncPtr = True
|
||||
Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
|
||||
Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else []
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
elif isinstance(Entry.OriginalType, CTypeInfo):
|
||||
Resolved = Entry.OriginalType.Copy()
|
||||
Resolved.IsTypedef = True
|
||||
Resolved.Name = TypeName
|
||||
return Resolved
|
||||
elif isinstance(Entry.OriginalType, str):
|
||||
# 字符串 OriginalType(如 'void *')需解析为 CTypeInfo,
|
||||
# 否则返回的 Entry BaseType=None 会被下游误判为 i32
|
||||
Resolved = CTypeInfo.FromTypeName(Entry.OriginalType)
|
||||
if Resolved and Resolved.BaseType:
|
||||
Resolved.IsTypedef = True
|
||||
Resolved.Name = TypeName
|
||||
return Resolved
|
||||
return Entry
|
||||
# REnum 优先于 IsEnum 处理(REnum 同时有 IsEnum=True 和 IsStruct=True)
|
||||
# 必须设置 Name 和 PtrCount=1,否则 BinOp `LLVMType | t.CPtr` 合并后丢失 REnum 语义
|
||||
if isinstance(Entry, CTypeInfo) and Entry.IsRenum:
|
||||
Result = Entry.Copy()
|
||||
Result.Name = TypeName
|
||||
Result.PtrCount = 1 # REnum 变量默认为指针(和 struct 一致)
|
||||
return Result
|
||||
# 类名与枚举成员名冲突时(如 Constant 既是 ASTKind.Constant 枚举成员又是结构体类名),
|
||||
# 优先检查 Gen.structs:类型注解应解析为结构体而非枚举值
|
||||
_Gen = getattr(self.Trans, 'LlvmGen', None)
|
||||
if _Gen and TypeName in _Gen.structs:
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CStruct(name=TypeName)
|
||||
Result.IsStruct = True
|
||||
Result.Name = TypeName
|
||||
Result.PtrCount = 1
|
||||
return Result
|
||||
if isinstance(Entry, CTypeInfo) and Entry.IsEnum:
|
||||
return Entry.Copy()
|
||||
if isinstance(Entry, dict) and Entry.get('IsEnum'):
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CEnum(TypeName)
|
||||
Result.IsEnum = True
|
||||
return Result
|
||||
# 检测结构体类型 (CTypeInfo with IsStruct=True, 来自 _InsertClassSymbol)
|
||||
if isinstance(Entry, CTypeInfo) and Entry.IsStruct:
|
||||
Result = Entry.Copy()
|
||||
if Result.BaseType is None:
|
||||
Result.BaseType = t.CStruct(name=TypeName)
|
||||
Result.Name = TypeName
|
||||
Result.PtrCount = 1 # struct 变量默认为指针
|
||||
return Result
|
||||
return self._MakeCTypeInfoFromName(TypeName)
|
||||
|
||||
elif isinstance(Node, ast.Attribute):
|
||||
ModuleParts = []
|
||||
Current = Node
|
||||
while isinstance(Current, ast.Attribute):
|
||||
ModuleParts.insert(0, Current.attr)
|
||||
Current = Current.value
|
||||
|
||||
if isinstance(Current, ast.Name):
|
||||
ModuleParts.insert(0, Current.id)
|
||||
|
||||
if len(ModuleParts) >= 2:
|
||||
TypeName = ModuleParts[-1]
|
||||
ModulePath = '.'.join(ModuleParts[:-1])
|
||||
elif len(ModuleParts) == 1:
|
||||
TypeName = ModuleParts[0]
|
||||
ModulePath = None
|
||||
else:
|
||||
return self._MakeVoidCTypeInfo()
|
||||
|
||||
# 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types
|
||||
if ModulePath:
|
||||
import_aliases = self.Trans.SymbolTable.import_aliases
|
||||
if ModulePath in import_aliases:
|
||||
ModulePath = import_aliases[ModulePath]
|
||||
else:
|
||||
# 也尝试在符号表中查找模块别名
|
||||
entry = self.Trans.SymbolTable.lookup(ModulePath)
|
||||
if isinstance(entry, CTypeInfo) and entry.IsModuleAlias:
|
||||
resolved = entry.ResolvedModule
|
||||
if resolved:
|
||||
ModulePath = resolved
|
||||
|
||||
self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}")
|
||||
|
||||
if ModulePath == 't' and TypeName == 'State':
|
||||
Info = CTypeInfo()
|
||||
Info.BaseType = t.CVoid
|
||||
Info.IsState = True
|
||||
return Info
|
||||
|
||||
if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')):
|
||||
if self._IsTModuleType(TypeName):
|
||||
TypeClass = CTypeHelper.GetTModuleCType(TypeName) or getattr(t, TypeName, None)
|
||||
if TypeClass == t.CArrayPtr:
|
||||
Info = CTypeInfo()
|
||||
Info.IsArrayPtr = True
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CPtr:
|
||||
Info = CTypeInfo()
|
||||
Info.PtrCount = 1
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CConst:
|
||||
Info = CTypeInfo()
|
||||
Info.DataConst = True
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CVolatile:
|
||||
Info = CTypeInfo()
|
||||
Info.DataVolatile = True
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CInline:
|
||||
Info = CTypeInfo()
|
||||
Info.Storage = t.CInline()
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CStatic:
|
||||
Info = CTypeInfo()
|
||||
Info.Storage = t.CStatic()
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CExtern:
|
||||
Info = CTypeInfo()
|
||||
Info.Storage = t.CExtern()
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass == t.CExport:
|
||||
Info = CTypeInfo()
|
||||
Info.Storage = t.CExport()
|
||||
Info.BaseType = t.CVoid
|
||||
return Info
|
||||
elif TypeClass in (t.BigEndian, t.LittleEndian):
|
||||
Info = CTypeInfo()
|
||||
Info.BaseType = t.CInt()
|
||||
Info.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little'
|
||||
return Info
|
||||
elif TypeClass:
|
||||
Info = CTypeInfo()
|
||||
Info.BaseType = TypeClass
|
||||
return Info
|
||||
elif CTypeHelper.GetCName(TypeName):
|
||||
return self._MakeCTypeInfoFromName(CTypeHelper.GetCName(TypeName))
|
||||
|
||||
FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName
|
||||
|
||||
# 优先检查 Gen.structs:类名与枚举成员名冲突时(如 Import 既是 ASTKind.Import
|
||||
# 枚举成员又是 ast.Import 结构体类名),类型注解应解析为结构体而非枚举值
|
||||
# (与 ast.Name 路径 line 100-107 的逻辑一致)
|
||||
_Gen = getattr(self.Trans, 'LlvmGen', None)
|
||||
if _Gen and TypeName in _Gen.structs:
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CStruct(name=TypeName)
|
||||
Result.IsStruct = True
|
||||
Result.Name = TypeName
|
||||
Result.PtrCount = 1
|
||||
return Result
|
||||
|
||||
Entry = self.Trans.SymbolTable.lookup(TypeName)
|
||||
if Entry and Entry.IsTypedef:
|
||||
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
|
||||
if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0:
|
||||
Result = Entry.Copy()
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
if Entry.OriginalType:
|
||||
if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr:
|
||||
Result = CTypeInfo()
|
||||
Result.IsFuncPtr = True
|
||||
Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
|
||||
Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else []
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
elif isinstance(Entry.OriginalType, CTypeInfo):
|
||||
Resolved = Entry.OriginalType.Copy()
|
||||
Resolved.IsTypedef = True
|
||||
Resolved.Name = TypeName
|
||||
return Resolved
|
||||
elif isinstance(Entry.OriginalType, str):
|
||||
# 字符串 OriginalType(如 'void *')需解析为 CTypeInfo,
|
||||
# 否则返回的 Result BaseType=_CTypedef 会被下游误判为 i32
|
||||
Resolved = CTypeInfo.FromTypeName(Entry.OriginalType)
|
||||
if Resolved and Resolved.BaseType:
|
||||
Resolved.IsTypedef = True
|
||||
Resolved.Name = TypeName
|
||||
return Resolved
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t._CTypedef(TypeName)
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
if Entry:
|
||||
# If BaseType is None but this is a class/struct, set BaseType to CStruct
|
||||
Result = Entry.Copy()
|
||||
if Result.BaseType is None:
|
||||
Result.BaseType = t.CStruct(name=TypeName)
|
||||
Result.IsStruct = True
|
||||
# struct 变量默认为指针(与 ast.Name 路径一致,见 line 121)
|
||||
# 同时确保 Name 字段被设置,供 ToString() 使用
|
||||
if Result.IsStruct:
|
||||
if Result.PtrCount == 0:
|
||||
Result.PtrCount = 1
|
||||
if not Result.Name:
|
||||
Result.Name = TypeName
|
||||
return Result
|
||||
return CTypeInfo()
|
||||
|
||||
elif isinstance(Node, ast.Call):
|
||||
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
|
||||
ReturnTypeInfo = self._GetCTypeInfoInternal(Node.args[0]) if Node.args else None
|
||||
if isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnType = ReturnTypeInfo
|
||||
else:
|
||||
ReturnType = CTypeInfo()
|
||||
ReturnType.BaseType = t.CVoid()
|
||||
|
||||
ParamTypes = []
|
||||
ParamNames = []
|
||||
for kw in Node.keywords:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(kw.value)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append(kw.arg)
|
||||
|
||||
for arg in Node.args[1:]:
|
||||
if isinstance(arg, ast.Tuple):
|
||||
for elt in arg.elts:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append('')
|
||||
else:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(arg)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append('')
|
||||
|
||||
if not ParamTypes:
|
||||
ParamTypes.append(self._MakeCTypeInfoFromName('void'))
|
||||
ParamNames.append('')
|
||||
|
||||
Info = CTypeInfo()
|
||||
Info.IsFuncPtr = True
|
||||
Info.FuncPtrReturn = ReturnType
|
||||
Info.FuncPtrParams = list(zip(ParamNames, ParamTypes))
|
||||
return Info
|
||||
|
||||
if isinstance(Node.func, ast.Attribute) and isinstance(Node.func.value, ast.Name):
|
||||
ModuleName = Node.func.value.id
|
||||
TypeName = Node.func.attr
|
||||
|
||||
if ModuleName == 't' and CTypeHelper.GetTModuleCType(TypeName) == t._CTypedef and Node.args:
|
||||
TypeArg = Node.args[0]
|
||||
if isinstance(TypeArg, ast.Name):
|
||||
return TypeArg.id
|
||||
elif isinstance(TypeArg, ast.Attribute):
|
||||
AttrModule = TypeArg.value.id if isinstance(TypeArg.value, ast.Name) else None
|
||||
AttrName = TypeArg.attr
|
||||
if AttrModule == 't' and getattr(t, AttrName, None):
|
||||
TypeObj = getattr(t, AttrName)
|
||||
if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType):
|
||||
return TypeObj.__name__
|
||||
return AttrName
|
||||
elif isinstance(TypeArg, ast.Constant):
|
||||
return str(TypeArg.value)
|
||||
|
||||
if ModuleName in self.Trans._UserTypeModules:
|
||||
module = self.Trans._UserTypeModules[ModuleName]
|
||||
if getattr(module, TypeName, None):
|
||||
TypeObj = getattr(module, TypeName)
|
||||
if isinstance(TypeObj, type):
|
||||
if issubclass(TypeObj, t.CType):
|
||||
return TypeObj.__name__
|
||||
|
||||
if ModuleName == 't':
|
||||
TypeObj = CTypeHelper.GetTModuleCType(TypeName)
|
||||
if TypeObj is None:
|
||||
TypeObj = getattr(t, TypeName, None)
|
||||
if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType):
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = TypeObj
|
||||
return Result
|
||||
|
||||
if ModuleName == 't' and TypeName == 'State':
|
||||
Result = CTypeInfo()
|
||||
Result.IsState = True
|
||||
return Result
|
||||
|
||||
if ModuleName == 't' and TypeName == 'Bit':
|
||||
if Node.args and isinstance(Node.args[0], ast.Constant):
|
||||
BitWidth = Node.args[0].value
|
||||
Result = CTypeInfo()
|
||||
Result.IsBitField = True
|
||||
Result.BitWidth = BitWidth
|
||||
Result.BaseType = t.CInt
|
||||
return Result
|
||||
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CVoid
|
||||
return Result
|
||||
|
||||
elif isinstance(Node, ast.Subscript):
|
||||
if (isinstance(Node.value, ast.Attribute)
|
||||
and isinstance(Node.value.value, ast.Name)
|
||||
and IsTModule(Node.value.value.id, self.Trans.SymbolTable)
|
||||
and Node.value.attr == 'Bit'):
|
||||
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
|
||||
Result = CTypeInfo()
|
||||
Result.IsBitField = True
|
||||
Result.BitWidth = Node.slice.value
|
||||
Result.BaseType = t.CInt
|
||||
return Result
|
||||
return self._HandleSubscript(Node)
|
||||
|
||||
elif isinstance(Node, ast.BinOp):
|
||||
return self.MergeTypes(Node)
|
||||
|
||||
elif isinstance(Node, ast.List):
|
||||
if Node.elts:
|
||||
BaseTypes = []
|
||||
for elt in Node.elts:
|
||||
EltType = self._GetCTypeInfoInternal(elt)
|
||||
if isinstance(EltType, CTypeInfo) and EltType.BaseType:
|
||||
BaseTypes.append(EltType.BaseType)
|
||||
if BaseTypes:
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = tuple(BaseTypes)
|
||||
return Result
|
||||
return self._MakeVoidCTypeInfo()
|
||||
|
||||
return self._MakeVoidCTypeInfo()
|
||||
|
||||
def _HandleSubscript(self, Node: ast.Subscript) -> CTypeInfo:
|
||||
"""澶勭悊 Subscript 鑺傜偣锛屼娇鐢?CTypeInfo 鏍戝舰缁撴瀯鍒嗘瀽 AST
|
||||
|
||||
例如?
|
||||
t.CVoid[5] -> void *[5]
|
||||
t.CPtr[t.CPtr[t.CPtr]][5][6] -> void ***[5][6]
|
||||
t.CArrayPtr[t.CArrayPtr] -> void *(*)[]
|
||||
t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[]
|
||||
"""
|
||||
def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo:
|
||||
"""鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo"""
|
||||
if isinstance(node, ast.Subscript):
|
||||
value_node = node.value
|
||||
slice_node = node.slice
|
||||
|
||||
if isinstance(value_node, ast.Attribute):
|
||||
VtInfo = self.GetCTypeInfo(value_node)
|
||||
|
||||
if isinstance(value_node, ast.Attribute) and value_node.attr == 'Callable' and isinstance(value_node.value, ast.Name) and IsTModule(value_node.value.id, self.Trans.SymbolTable):
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
|
||||
params_list = slice_node.elts[0]
|
||||
return_node = slice_node.elts[1]
|
||||
ParamTypes = []
|
||||
ParamNames = []
|
||||
if isinstance(params_list, ast.List):
|
||||
for elt in params_list.elts:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
|
||||
if isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append('')
|
||||
else:
|
||||
ParamTypes.append(self._MakeCTypeInfoFromName('int'))
|
||||
ParamNames.append('')
|
||||
if not ParamTypes:
|
||||
ParamTypes.append(self._MakeCTypeInfoFromName('void'))
|
||||
ParamNames.append('')
|
||||
ReturnTypeInfo = self._GetCTypeInfoInternal(return_node)
|
||||
if isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnType = ReturnTypeInfo
|
||||
else:
|
||||
ReturnType = CTypeInfo()
|
||||
ReturnType.BaseType = t.CVoid()
|
||||
Info = CTypeInfo()
|
||||
Info.IsFuncPtr = True
|
||||
Info.FuncPtrReturn = ReturnType
|
||||
Info.FuncPtrParams = list(zip(ParamNames, ParamTypes))
|
||||
return Info
|
||||
|
||||
if VtInfo and VtInfo.IsArrayPtr:
|
||||
ResultInfo = CTypeInfo()
|
||||
ResultInfo.PtrCount = VtInfo.PtrCount
|
||||
ResultInfo.IsArrayPtr = True
|
||||
if isinstance(slice_node, ast.Attribute):
|
||||
SliceVtInfo = self.GetCTypeInfo(slice_node)
|
||||
if SliceVtInfo and SliceVtInfo.IsArrayPtr:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr.IsArrayPtr = True
|
||||
ResultInfo.ArrayPtr.PtrCount = SliceVtInfo.PtrCount
|
||||
if SliceVtInfo.ArrayPtr:
|
||||
ResultInfo.ArrayPtr.ArrayPtr = SliceVtInfo.ArrayPtr
|
||||
elif SliceVtInfo and SliceVtInfo.PtrCount > 0:
|
||||
ResultInfo.ArrayPtr = SliceVtInfo
|
||||
else:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr.IsArrayPtr = True
|
||||
elif isinstance(slice_node, ast.Subscript):
|
||||
ResultInfo.ArrayPtr = CollectAll(slice_node)
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType
|
||||
elif isinstance(slice_node, ast.BinOp):
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
try:
|
||||
ResultInfo.ArrayPtr.ArrayDims.append(ast.unparse(slice_node))
|
||||
except Exception: # 回退:unparse 失败时用 'N'
|
||||
ResultInfo.ArrayPtr.ArrayDims.append('N')
|
||||
elif isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr.ArrayDims.append(str(slice_node.value))
|
||||
else:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr.IsArrayPtr = True
|
||||
elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr:
|
||||
ResultInfo = CTypeInfo()
|
||||
ResultInfo.BaseType = t.CVoid
|
||||
ResultInfo.PtrCount = 1
|
||||
if isinstance(slice_node, ast.Subscript):
|
||||
inner_info = CollectAll(slice_node)
|
||||
if inner_info and inner_info.PtrCount > 0:
|
||||
ResultInfo.PtrCount += inner_info.PtrCount
|
||||
if inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = inner_info.BaseType
|
||||
elif inner_info and inner_info.ArrayPtr:
|
||||
ResultInfo.ArrayPtr = inner_info
|
||||
elif inner_info and inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = inner_info.BaseType
|
||||
elif isinstance(slice_node, ast.Attribute):
|
||||
SliceVtInfo = self.GetCTypeInfo(slice_node)
|
||||
if SliceVtInfo and SliceVtInfo.PtrCount == 1 and not SliceVtInfo.ArrayPtr:
|
||||
ResultInfo.PtrCount = 2
|
||||
if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = SliceVtInfo.BaseType
|
||||
elif SliceVtInfo and SliceVtInfo.IsArrayPtr:
|
||||
inner = CTypeInfo()
|
||||
inner.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr = inner
|
||||
elif SliceVtInfo and SliceVtInfo.ArrayPtr:
|
||||
ResultInfo.ArrayPtr = SliceVtInfo
|
||||
elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = SliceVtInfo.BaseType
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
SliceType = getattr(t, slice_node.id, None)
|
||||
if SliceType == t.CPtr:
|
||||
ResultInfo.PtrCount += 1
|
||||
elif SliceType == t.CArrayPtr:
|
||||
inner = CTypeInfo()
|
||||
inner.ArrayPtr = CTypeInfo()
|
||||
ResultInfo.ArrayPtr = inner
|
||||
else:
|
||||
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType
|
||||
elif isinstance(slice_node, ast.BinOp):
|
||||
merged = self.MergeTypes(slice_node)
|
||||
if merged:
|
||||
ResultInfo.PtrCount += merged.PtrCount
|
||||
if merged.BaseType and not isinstance(merged.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = merged.BaseType
|
||||
if merged.ArrayPtr:
|
||||
ResultInfo.ArrayPtr = merged.ArrayPtr
|
||||
elif isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(slice_node.value))
|
||||
elif VtInfo:
|
||||
ResultInfo = CTypeInfo()
|
||||
ResultInfo.BaseType = VtInfo.BaseType
|
||||
if isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(slice_node.value))
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
ResultInfo.ArrayDims.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.BinOp):
|
||||
try:
|
||||
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
|
||||
except Exception: # 回退:unparse 失败时用 'N'
|
||||
ResultInfo.ArrayDims.append('N')
|
||||
elif isinstance(slice_node, ast.Subscript):
|
||||
ResultInfo.ArrayPtr = CollectAll(slice_node)
|
||||
else:
|
||||
ResultInfo = CTypeInfo()
|
||||
if isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(slice_node.value))
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
SliceType = getattr(t, slice_node.id, None)
|
||||
if SliceType == t.CPtr:
|
||||
ResultInfo.PtrCount += 1
|
||||
elif SliceType == t.CArrayPtr:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
else:
|
||||
ResultInfo.ArrayDims.append(slice_node.id)
|
||||
elif isinstance(value_node, ast.Subscript):
|
||||
ResultInfo = CollectAll(value_node)
|
||||
if isinstance(slice_node, ast.Attribute):
|
||||
SliceVtInfo = self.GetCTypeInfo(slice_node)
|
||||
if SliceVtInfo and SliceVtInfo.PtrCount >= 1 and not SliceVtInfo.ArrayPtr:
|
||||
ResultInfo.PtrCount += SliceVtInfo.PtrCount
|
||||
if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = SliceVtInfo.BaseType
|
||||
elif SliceVtInfo and SliceVtInfo.IsArrayPtr:
|
||||
NewInfo = CTypeInfo()
|
||||
NewInfo.ArrayPtr = ResultInfo
|
||||
ResultInfo = NewInfo
|
||||
elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid):
|
||||
ResultInfo.BaseType = SliceVtInfo.BaseType
|
||||
elif isinstance(slice_node, ast.Subscript):
|
||||
InnerNode = CollectAll(slice_node)
|
||||
if ResultInfo.ArrayPtr is None:
|
||||
ResultInfo.ArrayPtr = InnerNode
|
||||
else:
|
||||
current = ResultInfo
|
||||
while current.ArrayPtr is not None:
|
||||
current = current.ArrayPtr
|
||||
current.ArrayPtr = InnerNode
|
||||
elif isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(slice_node.value))
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
SliceType = getattr(t, slice_node.id, None)
|
||||
if SliceType == t.CPtr:
|
||||
ResultInfo.PtrCount += 1
|
||||
elif SliceType == t.CArrayPtr:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
else:
|
||||
ResultInfo.ArrayDims.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.BinOp):
|
||||
try:
|
||||
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
|
||||
except Exception: # 回退:unparse 失败时用 'N'
|
||||
ResultInfo.ArrayDims.append('N')
|
||||
elif isinstance(value_node, ast.Name):
|
||||
ResultInfo = CTypeInfo()
|
||||
if IsListAnnotation(node):
|
||||
if not isinstance(slice_node, ast.Tuple):
|
||||
ElementType = self._GetCTypeInfoInternal(slice_node)
|
||||
if ElementType and isinstance(ElementType, CTypeInfo):
|
||||
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid()
|
||||
ResultInfo.PtrCount = ElementType.PtrCount + 1
|
||||
ResultInfo.IsFuncPtr = ElementType.IsFuncPtr
|
||||
ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn
|
||||
ResultInfo.FuncPtrParams = ElementType.FuncPtrParams
|
||||
else:
|
||||
ResultInfo.BaseType = t.CVoid()
|
||||
ResultInfo.PtrCount = 1
|
||||
elif isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
|
||||
ElementType = self._GetCTypeInfoInternal(slice_node.elts[0])
|
||||
if ElementType and isinstance(ElementType, CTypeInfo):
|
||||
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid()
|
||||
ResultInfo.PtrCount = ElementType.PtrCount
|
||||
ResultInfo.IsFuncPtr = ElementType.IsFuncPtr
|
||||
ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn
|
||||
ResultInfo.FuncPtrParams = ElementType.FuncPtrParams
|
||||
for elt in slice_node.elts[1:]:
|
||||
if isinstance(elt, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(elt.value))
|
||||
elif isinstance(elt, ast.Name):
|
||||
ResultInfo.ArrayDims.append(elt.id)
|
||||
else:
|
||||
try:
|
||||
ResultInfo.ArrayDims.append(ast.unparse(elt))
|
||||
except Exception: # 回退:unparse 失败时用 'N'
|
||||
ResultInfo.ArrayDims.append('N')
|
||||
else:
|
||||
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType
|
||||
else:
|
||||
# 检查是否为泛型类特化(如 list[str])
|
||||
_is_generic_template: bool = (
|
||||
hasattr(self.Trans, 'ClassHandler')
|
||||
and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
|
||||
and value_node.id in self.Trans.ClassHandler._generic_class_templates
|
||||
)
|
||||
if _is_generic_template:
|
||||
# 走和 _ResolveGenericSlice 同样的规范化路径(_resolve_generic_slice_type),
|
||||
# 确保字段类型名与特化名完全一致:
|
||||
# - ast.Name: 用原始名(如 'Param' → 'Param',不加 SHA1 前缀),
|
||||
# 与 _resolve_generic_slice_type 的 ast.Name 分支一致
|
||||
# - BinOp/Attribute: 走 _resolve_type_arg_str(加 SHA1 前缀 / 'ptr' 标记)
|
||||
# 避免字段类型用 'GSList[sha1.Param]' 而特化名用 'GSList[Param]' 导致
|
||||
# find_struct_by_pointee 匹配到 opaque 副本,方法分派失败
|
||||
type_arg_str: str
|
||||
if isinstance(slice_node, ast.Tuple):
|
||||
arg_parts: list[str] = []
|
||||
for elt in slice_node.elts:
|
||||
slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(elt)
|
||||
arg_parts.append(slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(elt))
|
||||
# 必须用 '][' 分隔以匹配 _mangle_generic_class_name 的格式
|
||||
# (class_name + '[' + ']['.join(mangled_args) + ']')
|
||||
type_arg_str = ']['.join(arg_parts)
|
||||
else:
|
||||
slice_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node)
|
||||
type_arg_str = slice_res[0] if slice_res else self.Trans.ExprCallHandle._resolve_type_arg_str(slice_node)
|
||||
full_spec_name: str = f'{value_node.id}[{type_arg_str}]'
|
||||
ResultInfo.BaseType = t.CStruct(name=full_spec_name)
|
||||
ResultInfo.Name = full_spec_name
|
||||
ResultInfo.IsStruct = True
|
||||
ResultInfo.PtrCount = 1
|
||||
# 触发泛型特化发射:确保特化的方法被发射 + struct sha1 注册
|
||||
# 与局部变量 AnnAssign 路径一致;否则函数参数注解路径
|
||||
# 只构建 mangled 名,方法调用分派时 class_sha1=None 导致
|
||||
# "Undefined method" 错误(如 lst.__len__() 在 list[T] | t.CPtr 参数上)
|
||||
# _specialize_generic_class 内部有 spec_key 去重,重复调用安全
|
||||
if hasattr(self.Trans, 'ExprCallHandle') and self.Trans.ExprCallHandle is not None:
|
||||
self.Trans.ExprCallHandle._ResolveGenericSlice(node)
|
||||
else:
|
||||
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType
|
||||
if isinstance(slice_node, ast.Constant):
|
||||
ResultInfo.ArrayDims.append(str(slice_node.value))
|
||||
elif isinstance(slice_node, ast.Name):
|
||||
SliceType = getattr(t, slice_node.id, None)
|
||||
if SliceType == t.CPtr:
|
||||
ResultInfo.PtrCount += 1
|
||||
elif SliceType == t.CArrayPtr:
|
||||
ResultInfo.ArrayPtr = CTypeInfo()
|
||||
else:
|
||||
ResultInfo.ArrayDims.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.BinOp):
|
||||
try:
|
||||
ResultInfo.ArrayDims.append(ast.unparse(slice_node))
|
||||
except Exception: # 回退:unparse 失败时用 'N'
|
||||
ResultInfo.ArrayDims.append('N')
|
||||
elif isinstance(slice_node, ast.Subscript):
|
||||
InnerNode = CollectAll(slice_node)
|
||||
ResultInfo.ArrayDims.extend(InnerNode.ArrayDims)
|
||||
else:
|
||||
ResultInfo = CTypeInfo()
|
||||
|
||||
return ResultInfo
|
||||
elif isinstance(node, ast.Attribute):
|
||||
VtInfo = self.GetCTypeInfo(node)
|
||||
result = CTypeInfo()
|
||||
if VtInfo and VtInfo.IsArrayPtr:
|
||||
result.ArrayPtr = CTypeInfo()
|
||||
return result
|
||||
elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr:
|
||||
result.BaseType = t.CVoid
|
||||
result.PtrCount = 1
|
||||
return result
|
||||
elif VtInfo and VtInfo.BaseType:
|
||||
result.BaseType = VtInfo.BaseType
|
||||
return result
|
||||
else:
|
||||
return CTypeInfo()
|
||||
elif isinstance(node, ast.Name):
|
||||
result = CTypeInfo()
|
||||
result.BaseType = CTypeInfo.CreateFromTypeName(node.id).BaseType
|
||||
return result
|
||||
else:
|
||||
return CTypeInfo()
|
||||
|
||||
return CollectAll(Node)
|
||||
|
||||
def _CollectAllOperandTypes(self, Node: ast.AST) -> List:
|
||||
"""递归收集所有操作数的类型(用于一次性合并)"""
|
||||
Types = []
|
||||
|
||||
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
|
||||
Types.extend(self._CollectAllOperandTypes(Node.left))
|
||||
Types.extend(self._CollectAllOperandTypes(Node.right))
|
||||
else:
|
||||
Types.append(Node)
|
||||
|
||||
return Types
|
||||
|
||||
def _GetTypeFromNode(self, Node: ast.AST) -> CTypeInfo:
|
||||
"""浠?AST 鑺傜偣鑾峰彇绫诲瀷"""
|
||||
if isinstance(Node, ast.Call):
|
||||
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
|
||||
return self.GetCTypeInfo(Node)
|
||||
elif isinstance(Node.func, ast.Attribute) and CTypeHelper.GetTModuleCType(Node.func.attr) == t._CTypedef:
|
||||
return self.GetCTypeInfo(Node)
|
||||
elif isinstance(Node.func, ast.Attribute) and Node.func.attr == 'Bit':
|
||||
if Node.args and isinstance(Node.args[0], ast.Constant):
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CInt
|
||||
Result.IsBitField = True
|
||||
Result.BitWidth = Node.args[0].value
|
||||
return Result
|
||||
return self._MakeVoidCTypeInfo()
|
||||
elif isinstance(Node, ast.Subscript):
|
||||
if (isinstance(Node.value, ast.Attribute)
|
||||
and isinstance(Node.value.value, ast.Name)
|
||||
and IsTModule(Node.value.value.id, self.Trans.SymbolTable)
|
||||
and Node.value.attr == 'Bit'):
|
||||
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CInt
|
||||
Result.IsBitField = True
|
||||
Result.BitWidth = Node.slice.value
|
||||
return Result
|
||||
return self.GetCTypeInfo(Node)
|
||||
else:
|
||||
return self.GetCTypeInfo(Node)
|
||||
|
||||
def MergeTypes(self, Node: ast.BinOp):
|
||||
"""处理类型组合,如 t.CInt | t.CPtr ?t.CStatic | t.CInt
|
||||
|
||||
这是 | 运算符的类型合并处理函数
|
||||
收集所有操作数,一次性合?
|
||||
"""
|
||||
if not isinstance(Node, ast.BinOp) or not isinstance(Node.op, ast.BitOr):
|
||||
return None
|
||||
|
||||
AllOperands = self._CollectAllOperandTypes(Node)
|
||||
|
||||
AllTypes = []
|
||||
for Operand in AllOperands:
|
||||
TypeItem = self._GetTypeFromNode(Operand)
|
||||
AllTypes.append(TypeItem)
|
||||
|
||||
if isinstance(Node.left, ast.Attribute):
|
||||
LeftParts = []
|
||||
current = Node.left
|
||||
while isinstance(current, ast.Attribute):
|
||||
attr_type = getattr(t, current.attr, None)
|
||||
if attr_type and isinstance(attr_type, type) and issubclass(attr_type, t.CType):
|
||||
LeftParts.insert(0, attr_type)
|
||||
current = current.value
|
||||
if isinstance(current, ast.Name):
|
||||
name_type = getattr(t, current.id, None)
|
||||
if name_type and isinstance(name_type, type) and issubclass(name_type, t.CType):
|
||||
LeftParts.insert(0, name_type)
|
||||
if LeftParts and LeftParts[-1] == t._CTypedef:
|
||||
for type_item in AllTypes:
|
||||
if isinstance(type_item, CTypeInfo) and type_item.IsFuncPtr:
|
||||
type_item.IsTypedef = True
|
||||
type_item.OriginalType = CTypeInfo()
|
||||
type_item.OriginalType.IsFuncPtr = True
|
||||
type_item.OriginalType.FuncPtrReturn = type_item.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
|
||||
type_item.OriginalType.FuncPtrParams = list(type_item.FuncPtrParams) if type_item.FuncPtrParams else []
|
||||
return type_item
|
||||
Result = CTypeInfo()
|
||||
if isinstance(AllTypes[-1], CTypeInfo):
|
||||
Result.BaseType = AllTypes[-1].BaseType
|
||||
else:
|
||||
Result.BaseType = t.CInt
|
||||
Result.IsTypedef = True
|
||||
return Result
|
||||
|
||||
return self._MergeAllComponentTypes(*AllTypes)
|
||||
|
||||
def _MergeAllComponentTypes(self, *Types: CTypeInfo) -> CTypeInfo:
|
||||
"""合并多个类型 - 直接使用 CTypeInfo 类"""
|
||||
if not Types:
|
||||
return CTypeInfo()
|
||||
|
||||
Result = CTypeInfo()
|
||||
# 统计 t.CPtr(CVoid + PtrCount=1)的个数,用于正确累加指针层数
|
||||
# 因为 (AST | t.CPtr) | t.CPtr 展开后会包含多个 t.CPtr,每个都需要累加
|
||||
cptr_count: int = 0
|
||||
|
||||
for TypeItem in Types:
|
||||
if TypeItem is None:
|
||||
continue
|
||||
if TypeItem.IsState:
|
||||
Result.IsState = True
|
||||
if not Result.Storage:
|
||||
Result.Storage = t.CExport()
|
||||
continue
|
||||
if TypeItem.IsBitField:
|
||||
Result.BaseType = t.CInt
|
||||
Result.IsBitField = True
|
||||
Result.BitWidth = TypeItem.BitWidth
|
||||
return Result
|
||||
if TypeItem.IsFuncPtr:
|
||||
Result.BaseType = t.CVoid
|
||||
Result.IsFuncPtr = True
|
||||
Result.FuncPtrParams = TypeItem.FuncPtrParams
|
||||
Result.FuncPtrReturn = TypeItem.FuncPtrReturn
|
||||
return Result
|
||||
if TypeItem.IsTypedef:
|
||||
if TypeItem.BaseType and (not isinstance(TypeItem.BaseType, (t._CTypedef,)) or TypeItem.PtrCount > 0):
|
||||
if Result.BaseType is None or isinstance(Result.BaseType, (t.CVoid, t._CTypedef)):
|
||||
Result.BaseType = TypeItem.BaseType
|
||||
Result.Name = TypeItem.Name
|
||||
Result.IsTypedef = True
|
||||
Result.PtrCount = max(Result.PtrCount, TypeItem.PtrCount)
|
||||
if TypeItem.OriginalType:
|
||||
Result.OriginalType = TypeItem.OriginalType
|
||||
else:
|
||||
Result.IsTypedef = True
|
||||
Result.Name = TypeItem.Name
|
||||
if TypeItem.OriginalType:
|
||||
Result.OriginalType = TypeItem.OriginalType
|
||||
continue
|
||||
# 统计 t.CPtr(CVoid + PtrCount=1)
|
||||
if TypeItem.PtrCount > 0 and TypeItem.BaseType and (TypeItem.BaseType is t.CVoid or isinstance(TypeItem.BaseType, t.CVoid)):
|
||||
cptr_count += 1
|
||||
# BaseType 保持不变,只计数,后续统一累加
|
||||
if TypeItem.IsRenum and TypeItem.Name:
|
||||
Result.IsRenum = True
|
||||
Result.IsEnum = True
|
||||
Result.IsStruct = True
|
||||
if not Result.Name:
|
||||
Result.Name = TypeItem.Name
|
||||
continue
|
||||
self._MergeCTypeInfoInto(Result, TypeItem)
|
||||
|
||||
# 对所有 t.CPtr 统一累加指针层数
|
||||
# 仅对 struct 类型吸收第一个 CPtr(struct 变量默认是指针,AST | t.CPtr = AST*)。
|
||||
# 对于本身已是指针的类型(如 bytes=CChar*),bytes | t.CPtr = i8**(不吸收)。
|
||||
base_ptr_count: int = Result.PtrCount
|
||||
Result.PtrCount += cptr_count
|
||||
if Result.IsStruct and base_ptr_count > 0 and cptr_count > 0:
|
||||
Result.PtrCount -= 1
|
||||
|
||||
if Result.BaseType is None:
|
||||
Result.BaseType = t.CVoid
|
||||
|
||||
return Result
|
||||
|
||||
def _MergeCTypeInfoInto(self, Target: CTypeInfo, Source: CTypeInfo):
|
||||
if Source.PtrCount > 0 and Source.BaseType and (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)):
|
||||
# t.CPtr 的处理已提升到 _MergeAllComponentTypes 中统一计数累加,
|
||||
# 此处保留仅作为兜底(从其他路径直接调用 _MergeCTypeInfoInto 时)
|
||||
if Target.PtrCount < Source.PtrCount:
|
||||
Target.PtrCount = Source.PtrCount
|
||||
elif Source.PtrCount > 0 and Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, t.CVoid):
|
||||
if Target.BaseType is None or Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid):
|
||||
Target.BaseType = Source.BaseType
|
||||
# 当 Target 已有 PtrCount(来自之前的 t.CPtr),累加而非替换
|
||||
Target.PtrCount = Source.PtrCount + Target.PtrCount
|
||||
elif Target.PtrCount == 0:
|
||||
Target.PtrCount = Source.PtrCount
|
||||
elif Source.PtrCount > Target.PtrCount:
|
||||
Target.PtrCount = Source.PtrCount
|
||||
elif Source.PtrCount > Target.PtrCount:
|
||||
Target.PtrCount = Source.PtrCount
|
||||
if Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, (t.CVoid, t._CTypedef)):
|
||||
if Target.BaseType is None:
|
||||
Target.BaseType = Source.BaseType
|
||||
elif (Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid)) and Target.PtrCount == 0:
|
||||
Target.BaseType = Source.BaseType
|
||||
elif (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)) and Target.BaseType is None:
|
||||
Target.BaseType = Source.BaseType
|
||||
# Struct 名称保留:BinOp `list[AST | t.CPtr] | t.CPtr` 合并时,
|
||||
# _HandleSubscript 已在 Source.Name 设置了特化名(如 'list[5dab8cb390496d22.ASTptr]'),
|
||||
# 合并后 Target.Name 必须保留此名称,否则 class_member_element_class
|
||||
# 无法获取正确的特化类名 → 方法分派 fallback 到错误的类
|
||||
if Source.IsStruct and Source.Name and not Target.Name:
|
||||
Target.Name = Source.Name
|
||||
# REnum 标志和名称保留(BinOp `LLVMType | t.CPtr` 合并时不能丢失 REnum 语义)
|
||||
# 同时传播 IsStruct=True,让 CPtr 吸收逻辑生效(REnum 在内存布局上是 struct)
|
||||
if Source.IsRenum and Source.Name:
|
||||
Target.IsRenum = True
|
||||
Target.IsEnum = True
|
||||
Target.IsStruct = True
|
||||
if not Target.Name:
|
||||
Target.Name = Source.Name
|
||||
if Source.IsTypedef and Source.Name:
|
||||
if Source.BaseType and (not isinstance(Source.BaseType, (t._CTypedef,)) or Source.PtrCount > 0):
|
||||
if Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)):
|
||||
Target.BaseType = Source.BaseType
|
||||
Target.IsTypedef = True
|
||||
Target.Name = Source.Name
|
||||
if Source.OriginalType:
|
||||
Target.OriginalType = Source.OriginalType
|
||||
elif Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)):
|
||||
if Source.OriginalType:
|
||||
if isinstance(Source.OriginalType, CTypeInfo) and Source.OriginalType.BaseType:
|
||||
Target.BaseType = Source.OriginalType.BaseType
|
||||
Target.PtrCount = max(Target.PtrCount, Source.OriginalType.PtrCount)
|
||||
Target.IsTypedef = True
|
||||
Target.Name = Source.Name
|
||||
Target.OriginalType = Source.OriginalType
|
||||
elif isinstance(Source.OriginalType, CTypeInfo):
|
||||
Target.IsTypedef = True
|
||||
Target.Name = Source.Name
|
||||
Target.OriginalType = Source.OriginalType
|
||||
else:
|
||||
Target.BaseType = t.CStruct(name=Source.Name)
|
||||
Target.IsStruct = True
|
||||
else:
|
||||
Target.BaseType = t.CStruct(name=Source.Name)
|
||||
Target.IsStruct = True
|
||||
if Source.ArrayPtr:
|
||||
if Target.ArrayPtr is None:
|
||||
Target.ArrayPtr = Source.ArrayPtr
|
||||
else:
|
||||
if Source.PtrCount > Target.PtrCount:
|
||||
Target.PtrCount = Source.PtrCount
|
||||
Target.ArrayPtr = Source.ArrayPtr
|
||||
if Source.PtrCount > 0:
|
||||
Target.ArrayDims = []
|
||||
elif Source.ArrayDims:
|
||||
Target.ArrayDims.extend(Source.ArrayDims)
|
||||
if Source.VarConst:
|
||||
Target.VarConst = True
|
||||
if Source.VarVolatile:
|
||||
Target.VarVolatile = True
|
||||
if Source.DataConst:
|
||||
Target.DataConst = True
|
||||
if Source.DataVolatile:
|
||||
Target.DataVolatile = True
|
||||
if Source.IsFuncPtr:
|
||||
Target.IsFuncPtr = True
|
||||
Target.FuncPtrParams = Source.FuncPtrParams
|
||||
Target.FuncPtrReturn = Source.FuncPtrReturn
|
||||
if Source.Storage and not Target.Storage:
|
||||
Target.Storage = Source.Storage
|
||||
if Source.ByteOrder and not Target.ByteOrder:
|
||||
Target.ByteOrder = Source.ByteOrder
|
||||
54
lib/core/Handles/HandlesWhile.py
Normal file
54
lib/core/Handles/HandlesWhile.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class WhileHandle(BaseHandle):
|
||||
def _HandleWhileLlvm(self, Node: ast.While) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if Gen._direct_values:
|
||||
for var_name in list(Gen._direct_values.keys()):
|
||||
OldVal: ir.Value = Gen._direct_values.pop(var_name)
|
||||
if var_name not in Gen.variables or Gen.variables.get(var_name) is None:
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
entry_block: ir.Block = Gen.func.entry_basic_block
|
||||
Gen.builder.position_at_start(entry_block)
|
||||
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=var_name)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
Gen.variables[var_name] = var
|
||||
CondBB: ir.Block = Gen.func.append_basic_block(name="while.cond")
|
||||
BodyBB: ir.Block = Gen.func.append_basic_block(name="while.body")
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="while.else") if Node.orelse else None
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="while.end")
|
||||
Gen.loop_break_targets.append(AfterBB)
|
||||
Gen.loop_continue_targets.append(CondBB)
|
||||
Gen.builder.branch(CondBB)
|
||||
Gen.builder.position_at_start(CondBB)
|
||||
Cond: ir.Value | None = self.HandleExprLlvm(Node.test)
|
||||
if Cond:
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond")
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="whilecond")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
|
||||
else:
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
|
||||
Gen.builder.position_at_start(BodyBB)
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(CondBB)
|
||||
Gen.loop_break_targets.pop()
|
||||
Gen.loop_continue_targets.pop()
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
172
lib/core/Handles/HandlesWith.py
Normal file
172
lib/core/Handles/HandlesWith.py
Normal file
@@ -0,0 +1,172 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class WithHandle(BaseHandle):
|
||||
def _HandleWithLlvm(self, Node: ast.With) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for item in Node.items:
|
||||
context_expr: ast.expr = item.context_expr
|
||||
asname: str | None = None
|
||||
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
|
||||
if target and isinstance(target, ast.Name):
|
||||
asname = target.id
|
||||
ClassName: str | None = None
|
||||
if isinstance(context_expr, ast.Call):
|
||||
if isinstance(context_expr.func, ast.Name):
|
||||
ClassName = context_expr.func.id
|
||||
elif isinstance(context_expr.func, ast.Attribute):
|
||||
ClassName = context_expr.func.attr
|
||||
if ClassName and ClassName not in Gen.structs:
|
||||
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
|
||||
if SymInfo:
|
||||
if SymInfo.IsStruct or SymInfo.IsRenum:
|
||||
pass
|
||||
else:
|
||||
ClassName = None
|
||||
else:
|
||||
ClassName = None
|
||||
elif isinstance(context_expr, ast.Name):
|
||||
VarName: str = context_expr.id
|
||||
if VarName in Gen.var_struct_class:
|
||||
ClassName = Gen.var_struct_class[VarName]
|
||||
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
|
||||
if not ctx_val:
|
||||
continue
|
||||
original_ctx_val: ir.Value = ctx_val
|
||||
if ClassName and isinstance(ctx_val.type, ir.PointerType):
|
||||
pointee: ir.Type = ctx_val.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
ClassName = CN
|
||||
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
|
||||
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
|
||||
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
|
||||
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
|
||||
Gen._store(ctx_val, ctx_alloca)
|
||||
Gen._UnregisterTempPtr(ctx_val)
|
||||
if ClassName:
|
||||
Gen.var_struct_class['__with_ctx'] = ClassName
|
||||
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
|
||||
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
|
||||
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
|
||||
enter_result: ir.Value | None = None
|
||||
if ClassName:
|
||||
EnterFuncName: str = f'{ClassName}.__enter__'
|
||||
if EnterFuncName in Gen.functions:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
enter_call: ir.CallInstr = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_Loaded], name="call_enter")
|
||||
enter_result = enter_call
|
||||
if isinstance(enter_call.type, ir.PointerType):
|
||||
pointee: ir.Type = enter_call.type.pointee
|
||||
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
enter_result = Gen._load(enter_call, name="enter_deref")
|
||||
elif self._is_char_pointer(enter_call) and StructPtrType:
|
||||
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
|
||||
if asname and enter_result:
|
||||
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
Gen.var_struct_class[asname] = CN
|
||||
Gen._var_to_heap_ptr[asname] = enter_result
|
||||
Gen._register_local_heap_ptr(enter_result, VarName=asname)
|
||||
if asname in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[asname]
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[asname] = var
|
||||
del Gen._reg_values[asname]
|
||||
if asname in Gen.variables and Gen.variables[asname] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[asname]
|
||||
if VarPtr.type.pointee == enter_result.type:
|
||||
Gen._store(enter_result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
|
||||
Gen._store(enter_result, NewVar)
|
||||
Gen.variables[asname] = NewVar
|
||||
else:
|
||||
Gen._reg_values[asname] = enter_result
|
||||
Gen.variables[asname] = None
|
||||
# 如果类有 __provides__,自动生成 push 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
|
||||
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
|
||||
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
|
||||
new_fields: int = len(Gen.class_provides[ClassName])
|
||||
if current_depth + new_fields > 32:
|
||||
raise SyntaxError(
|
||||
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
|
||||
f"current depth {current_depth} + new {new_fields} fields > max 32. "
|
||||
f"Class '{ClassName}' provides too many fields or with nesting too deep."
|
||||
)
|
||||
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
|
||||
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
ctx_i8: ir.Value = ctx_Loaded
|
||||
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
|
||||
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
|
||||
for field_name in Gen.class_provides[ClassName]:
|
||||
field_str: ir.Value = Gen._create_string_global(field_name)
|
||||
push_func = Gen.functions.get('_push_provider')
|
||||
if push_func:
|
||||
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
|
||||
self.Trans.VarScopes.append({})
|
||||
if asname:
|
||||
self.Trans.VarScopes[-1][asname] = True
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if self.Trans.VarScopes:
|
||||
self.Trans.VarScopes.pop()
|
||||
# 如果类有 __provides__,自动生成 pop 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
for _ in Gen.class_provides[ClassName]:
|
||||
pop_func = Gen.functions.get('_pop_provider')
|
||||
if pop_func:
|
||||
Gen.builder.call(pop_func, [], name="call_pop_provider")
|
||||
# 编译期弹栈
|
||||
if Gen._with_provides_stack:
|
||||
Gen._with_provides_stack.pop()
|
||||
if ClassName:
|
||||
ExitFuncName: str = f'{ClassName}.__exit__'
|
||||
if ExitFuncName in Gen.functions:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
Gen.builder.call(Gen.functions[ExitFuncName], [ctx_Loaded], name="call_exit")
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
if ctx_val is not original_ctx_val:
|
||||
Gen._unregister_local_heap_ptr(ctx_val)
|
||||
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
|
||||
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
|
||||
if '__with_ctx' in Gen._var_to_heap_ptr:
|
||||
del Gen._var_to_heap_ptr['__with_ctx']
|
||||
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
|
||||
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
|
||||
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
|
||||
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
|
||||
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
|
||||
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
|
||||
Gen.builder.position_at_start(with_free_bb)
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
Gen.builder.branch(with_skip_bb)
|
||||
Gen.builder.position_at_start(with_skip_bb)
|
||||
Gen._unregister_local_heap_ptr(enter_result)
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
elif isinstance(ctx_val.type, ir.PointerType):
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
32
lib/core/Handles/__init__.py
Normal file
32
lib/core/Handles/__init__.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Handles 包 - 使用 Mixin 模式组织 Handle 函数
|
||||
"""
|
||||
|
||||
from .HandlesIf import IfHandle
|
||||
from .HandlesFor import ForHandle
|
||||
from .HandlesWhile import WhileHandle
|
||||
from .HandlesAnnAssign import AnnAssignHandle
|
||||
from .HandlesTypeMerge import HandlesTypeMerge
|
||||
from .HandlesExpr import ExprHandle
|
||||
from .HandlesExprUtils import ExprUtils
|
||||
from .HandlesExprOps import ExprOpsHandle
|
||||
from .HandlesExprAttr import ExprAttrHandle
|
||||
from .HandlesExprBuiltin import ExprBuiltinHandle
|
||||
from .HandlesExprAsm import ExprAsmHandle
|
||||
from .HandlesExprFormat import ExprFormatHandle
|
||||
from .HandlesExprLambda import ExprLambdaHandle
|
||||
from .HandlesExprCall import ExprCallHandle
|
||||
from .HandlesSpecialCall import CSpecialCallHandle, TSpecialCallHandle
|
||||
from .HandlesBody import BodyHandle
|
||||
from .HandlesReturn import ReturnHandle
|
||||
from .HandlesAssign import AssignHandle
|
||||
from .HandlesAugAssign import AugAssignHandle
|
||||
from .HandlesDelete import DeleteHandle
|
||||
from .HandlesWith import WithHandle
|
||||
from .HandlesTry import TryHandle
|
||||
from .HandlesAssert import AssertHandle
|
||||
from .HandlesRaise import RaiseHandle
|
||||
from .HandlesMatch import MatchHandle
|
||||
from .HandlesClassDef import ClassHandle
|
||||
from .HandlesFunctions import FunctionHandle
|
||||
from .HandlesImports import ImportHandle
|
||||
Reference in New Issue
Block a user