355 lines
22 KiB
Python
355 lines
22 KiB
Python
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
|
||
|
||
# ============================================================
|
||
# HandlesAssign - Assign 语句处理(Mixin 继承模式)
|
||
#
|
||
# 对应 TransPyC 的 class AssignHandle(BaseHandle):
|
||
# @t.NoVTable 继承 Mixin 获得 Trans 字段(展平嵌入,无 vtable)
|
||
# 通过 self.Trans 访问共享状态(Pool/Module/_cur_builder/SymTab/...)
|
||
# 通过 self.Trans.ExprH / self.Trans.IfH 等访问其他 Handle
|
||
# ============================================================
|
||
|
||
|
||
@t.NoVTable
|
||
class AssignHandle(HandlesBase.Mixin):
|
||
"""Assign 语句处理器:继承 Mixin 获得 Trans 回指针 + 共享方法"""
|
||
_CurrentClass: str # 模块私有状态
|
||
|
||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||
self.Trans = trans
|
||
self._CurrentClass = None
|
||
|
||
# ============================================================
|
||
# Handle - 处理 Assign 语句,返回新增变量数(0 或 1)
|
||
#
|
||
# 对应 TransPyC AssignHandle._HandleAssignLlvm
|
||
# 共享状态从 self.Trans 获取,无需 11 个参数
|
||
# ============================================================
|
||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||
if asgn is None:
|
||
VLogger.error("cast failed", "ASGN")
|
||
return 0
|
||
|
||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||
if targets is None:
|
||
VLogger.error("targets is None", "ASGN")
|
||
return 0
|
||
|
||
# 从 self.Trans 取共享状态(替代 11 个参数)
|
||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||
|
||
# 翻译 RHS 值
|
||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||
if rhs_val is None:
|
||
# 增强错误信息:包含 sha1 + lineno + AST 节点类型,便于定位
|
||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb is not None and asgn.value is not None:
|
||
sha1: str = self.Trans.ModuleSha1
|
||
val_kind: int = asgn.value.kind()
|
||
val_line: t.CInt = asgn.value.lineno
|
||
if sha1 is not None:
|
||
viperlib.snprintf(fb, 1024,
|
||
"rhs_val is None [sha1=%s lineno=%d kind=%d]",
|
||
sha1, val_line, val_kind)
|
||
else:
|
||
viperlib.snprintf(fb, 1024,
|
||
"rhs_val is None [lineno=%d kind=%d]",
|
||
val_line, val_kind)
|
||
VLogger.error(fb, "ASGN")
|
||
else:
|
||
VLogger.error("rhs_val is None", "ASGN")
|
||
return 0
|
||
|
||
new_vars: int = 0
|
||
tn: t.CSizeT = targets.__len__()
|
||
for ti in range(tn):
|
||
target: ast.AST | t.CPtr = targets.get(ti)
|
||
if target is None:
|
||
continue
|
||
|
||
tk: int = target.kind()
|
||
|
||
# Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val
|
||
if tk == ast.ASTKind.Subscript:
|
||
# 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct)
|
||
# list 的 subscript 赋值走 __setitem__ 内联路径
|
||
list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript(
|
||
target, self.Trans)
|
||
if list_obj is not None:
|
||
# list[T] 类型: 内联生成 __setitem__ 逻辑
|
||
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||
if sub_node is not None and sub_node.slice is not None:
|
||
list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub_node.slice, None, 0, self.Trans)
|
||
if list_idx_val is not None:
|
||
HandlesExpr.list_setitem_inline(
|
||
builder, pool, list_obj, list_idx_val, rhs_val)
|
||
continue
|
||
# 普通 Subscript 赋值
|
||
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
|
||
builder, pool, mod, target, self.Trans)
|
||
if elem_ptr is not None:
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if elem_ptr.Ty is not None:
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = elem_ptr.Ty.Pointee
|
||
if elem_ty is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, elem_ty)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
else:
|
||
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
|
||
# 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val))
|
||
sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||
setitem_done: int = 0
|
||
if sub_asgn is not None and sub_asgn.value is not None:
|
||
if sub_asgn.value.kind() == ast.ASTKind.Name:
|
||
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value)
|
||
if sub_nm.id is not None:
|
||
sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
self.Trans.SymTab, sub_nm.id)
|
||
if sub_alloca is not None and sub_alloca.Ty is not None:
|
||
if HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0:
|
||
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
||
if sub_pointee is not None:
|
||
cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee)
|
||
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, sub_pointee, sub_alloca)
|
||
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
|
||
# 需 load 获取 Ptr(Struct) 再检查 inner struct
|
||
if cls_nm_set is None and obj_val_set is not None:
|
||
if HandlesExpr.is_ptr_type(sub_pointee) != 0:
|
||
inner_ty_set: llvmlite.LLVMType | t.CPtr = sub_pointee.Pointee
|
||
if inner_ty_set is not None:
|
||
cls_nm_set = HandlesStruct.get_class_name_by_type(pool, inner_ty_set)
|
||
if cls_nm_set is not None and obj_val_set is not None:
|
||
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||
if key_val_set is not None:
|
||
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_set is not None:
|
||
arg_vals_set[0] = t.CSizeT(key_val_set)
|
||
arg_vals_set[1] = t.CSizeT(rhs_val)
|
||
HandlesExprCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_set, "__setitem__",
|
||
obj_val_set, arg_vals_set, 2, self.Trans)
|
||
setitem_done = 1
|
||
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
|
||
# self._ht[key] = val → self._ht.__setitem__(key, val)
|
||
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
|
||
field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||
builder, pool, mod, sub_asgn.value, self.Trans)
|
||
if field_ptr_set is not None and field_ptr_set.Ty is not None:
|
||
if HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
|
||
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
|
||
if field_pointee_set is not None:
|
||
cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set)
|
||
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
|
||
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
|
||
# load 解引用获取 Ptr(Struct)
|
||
if cls_nm_attr is None and HandlesExpr.is_ptr_type(field_pointee_set) != 0:
|
||
inner_struct_attr: llvmlite.LLVMType | t.CPtr = field_pointee_set.Pointee
|
||
if inner_struct_attr is not None:
|
||
cls_nm_attr = HandlesStruct.get_class_name_by_type(pool, inner_struct_attr)
|
||
if cls_nm_attr is not None:
|
||
obj_val_attr = llvmlite.build_load(
|
||
builder, field_pointee_set, field_ptr_set)
|
||
if cls_nm_attr is not None and obj_val_attr is not None:
|
||
key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||
if key_val_attr is not None:
|
||
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_attr is not None:
|
||
arg_vals_attr[0] = t.CSizeT(key_val_attr)
|
||
arg_vals_attr[1] = t.CSizeT(rhs_val)
|
||
HandlesExprCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_attr, "__setitem__",
|
||
obj_val_attr, arg_vals_attr, 2, self.Trans)
|
||
setitem_done = 1
|
||
if setitem_done == 0:
|
||
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
|
||
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
|
||
if sub_asgn is not None and sub_asgn.value is not None:
|
||
obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub_asgn.value, None, 0, self.Trans)
|
||
key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||
if obj_val_gen is not None and key_val_gen is not None \
|
||
and obj_val_gen.Ty is not None:
|
||
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
|
||
cls_nm_gen: str = HandlesStruct.get_class_name_by_type(
|
||
pool, obj_val_gen.Ty)
|
||
if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||
inner_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||
if inner_gen is not None:
|
||
cls_nm_gen = HandlesStruct.get_class_name_by_type(pool, inner_gen)
|
||
if cls_nm_gen is not None:
|
||
# 自定义结构体: 调用 __setitem__
|
||
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_gen is not None:
|
||
arg_vals_gen[0] = t.CSizeT(key_val_gen)
|
||
arg_vals_gen[1] = t.CSizeT(rhs_val)
|
||
HandlesExprCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_gen, "__setitem__",
|
||
obj_val_gen, arg_vals_gen, 2, self.Trans)
|
||
setitem_done = 1
|
||
else:
|
||
# 非自定义结构体: 直接 GEP + store
|
||
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
|
||
if HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||
if elem_gen is not None:
|
||
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
|
||
elem_ptr_gen: llvmlite.Value | t.CPtr = None
|
||
match elem_gen:
|
||
case llvmlite.LLVMType.Array(arr_elem_gen, _):
|
||
elem_ptr_gen = llvmlite.build_gep_array(
|
||
builder, elem_gen, arr_elem_gen,
|
||
obj_val_gen, key_val_gen)
|
||
case _:
|
||
elem_ptr_gen = llvmlite.build_gep(
|
||
builder, elem_gen, obj_val_gen, key_val_gen)
|
||
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
|
||
pt_gen: llvmlite.LLVMType | t.CPtr = elem_ptr_gen.Ty.Pointee
|
||
if pt_gen is not None:
|
||
store_val_gen = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, pt_gen)
|
||
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||
setitem_done = 1
|
||
if setitem_done == 0:
|
||
sub_vk: int = sub_asgn.value.kind()
|
||
stdio.printf("[ASGN-SUB] fallback failed: val_kind=%d\n", sub_vk)
|
||
stdio.fflush(0)
|
||
if setitem_done == 0:
|
||
HandlesType.fatal_error(target, "subscript ptr is None")
|
||
continue
|
||
|
||
# Attribute 赋值: obj.field = val
|
||
if tk == ast.ASTKind.Attribute:
|
||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||
builder, pool, mod, target, self.Trans)
|
||
if field_ptr is not None:
|
||
stdio.printf("[ASGN-ATTR] field_ptr ok ty_not_null=%d\n",
|
||
1 if field_ptr.Ty is not None else 0)
|
||
stdio.fflush(0)
|
||
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if field_ptr.Ty is not None:
|
||
field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee
|
||
if field_ty is not None:
|
||
stdio.printf("[ASGN-ATTR] coerce rhs_ty=%d field_ty=%d\n",
|
||
HandlesExpr.get_llvm_type_bits(rhs_val.Ty),
|
||
HandlesExpr.get_llvm_type_bits(field_ty))
|
||
stdio.fflush(0)
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, field_ty)
|
||
stdio.printf("[ASGN-ATTR] pre_store\n")
|
||
stdio.fflush(0)
|
||
llvmlite.build_store(builder, store_val, field_ptr)
|
||
stdio.printf("[ASGN-ATTR] post_store\n")
|
||
stdio.fflush(0)
|
||
else:
|
||
# 构造详细错误信息
|
||
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||
attr_name: str = "(unknown)"
|
||
obj_name: str = "(unknown)"
|
||
if attr_node is not None:
|
||
attr_name = attr_node.attr
|
||
if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name:
|
||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value)
|
||
obj_name = obj_nm.id
|
||
err_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||
if err_buf is not None:
|
||
viperlib.snprintf(err_buf, 256,
|
||
"attribute ptr is None: %s.%s",
|
||
obj_name, attr_name)
|
||
HandlesType.fatal_error(target, err_buf)
|
||
else:
|
||
HandlesType.fatal_error(target, "attribute ptr is None")
|
||
continue
|
||
|
||
# Name 赋值: var = val
|
||
if tk == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||
if nm.id is not None:
|
||
# global 变量:写入模块作用域中的全局变量
|
||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
self.Trans.SymTab, nm.id)
|
||
if mod_alloca is not None:
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
target_ty = mod_alloca.Ty.Pointee
|
||
if target_ty is not None:
|
||
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
|
||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||
continue
|
||
|
||
# nonlocal 变量:通过闭包 env 写入
|
||
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
|
||
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
|
||
self.Trans, nm.id)
|
||
if nl_ptr is not None:
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, i32_ty)
|
||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||
continue
|
||
|
||
# 普通局部变量
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
|
||
self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
|
||
if alloca is not None:
|
||
# 按 alloca 类型对值进行转换(如 double → float)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if alloca.Ty is not None:
|
||
alloca_ty: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if alloca_ty is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, alloca_ty)
|
||
llvmlite.build_store(builder, store_val, alloca)
|
||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||
self.Trans.SymTab, nm.id)
|
||
if existing is None:
|
||
new_vars += 1
|
||
else:
|
||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb is not None:
|
||
viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id)
|
||
VLogger.error(fb, "ASGN")
|
||
|
||
return new_vars
|
||
|
||
|
||
# ============================================================
|
||
# NewAssignHandle - 工厂函数:分配并初始化 AssignHandle
|
||
# ============================================================
|
||
def NewAssignHandle(pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> AssignHandle | t.CPtr:
|
||
h: AssignHandle | t.CPtr = pool.alloc(AssignHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, AssignHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|