- ClassGenMixin: list[str](pool, 8) elem_size 修正(原 4 致 Pair[T1,T2] 重叠写),新增 GenericClassTpParams stdlib 深拷贝表,特化统一取深拷贝 - Generator: 初始化 GenericClassTpParams 防 0xBEBEBEBEBEBEBEBE - TypeGenMixin: 泛型上下文栈式管理,支持嵌套特化 - CallGenMixin: sz_builtin 补 double/float/char,修复 T.__sizeof__ NameError - StubMerger: _CommentOutGlobalInBuf 循环注释同名全局,修复 @_mbuddy 重复定义 - HandlesAssign: 无注解赋值按 RHS 推断 AnnotClassName(类实例化/源变量/ 运算符重载/字段注解/方法返回注解 vpi),修复联合类型 Ptr(i8) 属性访问失败
730 lines
42 KiB
Plaintext
730 lines
42 KiB
Plaintext
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
|
||
import lib.core.StubMerger as StubMerger
|
||
|
||
|
||
# ============================================================
|
||
# 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 值
|
||
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode
|
||
# (防残留误判 c.Deref 宽度)
|
||
self.Trans.CurAssignAnnot = None
|
||
self.Trans.CurAssignNode = None
|
||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||
if rhs_val is None:
|
||
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
|
||
fb: str = 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
|
||
# 通过 sha1 查找文件名(人类可读)
|
||
rel_path: str = None
|
||
if sha1 is not None:
|
||
rel_path = StubMerger.LookupSha1RelPath(sha1)
|
||
# 根据 AST 节点类型提取详情
|
||
if val_kind == ast.ASTKind.Attribute:
|
||
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
|
||
attr_nm: str = at_nv.attr
|
||
target_nm: str = "?"
|
||
if at_nv.value is not None:
|
||
if at_nv.value.kind() == ast.ASTKind.Name:
|
||
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
|
||
target_nm = tn_nm.id
|
||
if rel_path is not None:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
|
||
rel_path, val_line, target_nm, attr_nm)
|
||
else:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败",
|
||
sha1, val_line, target_nm, attr_nm)
|
||
elif val_kind == ast.ASTKind.Name:
|
||
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
|
||
if rel_path is not None:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: %s:%d 变量 '%s' 未找到",
|
||
rel_path, val_line, nm_nv.id)
|
||
else:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到",
|
||
sha1, val_line, nm_nv.id)
|
||
elif val_kind == ast.ASTKind.Call:
|
||
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
|
||
func_nm: str = "?"
|
||
if cl_nv.func is not None:
|
||
if cl_nv.func.kind() == ast.ASTKind.Name:
|
||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
|
||
func_nm = fn_nm.id
|
||
if rel_path is not None:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None",
|
||
rel_path, val_line, func_nm)
|
||
else:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None",
|
||
sha1, val_line, func_nm)
|
||
else:
|
||
if rel_path is not None:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: %s:%d [kind=%d]",
|
||
rel_path, val_line, val_kind)
|
||
else:
|
||
viperlib.snprintf(fb, 1024,
|
||
"赋值右侧为 None: sha1=%s:%d [kind=%d]",
|
||
sha1, val_line, val_kind)
|
||
VLogger.error(fb, "ASGN")
|
||
else:
|
||
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
|
||
return 0
|
||
|
||
new_vars: int = 0
|
||
tn: t.CSizeT = len(targets)
|
||
for ti in range(tn):
|
||
target: ast.AST | t.CPtr = targets.get(ti)
|
||
if target is None:
|
||
continue
|
||
|
||
tk: int = target.kind()
|
||
|
||
# Tuple 赋值: a, b = f() 多返回值解包
|
||
# rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca +
|
||
# store + GEP 逐字段 load → store 到各 Name 目标。
|
||
if tk == ast.ASTKind.Tuple:
|
||
tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
|
||
tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts
|
||
# 守卫:rhs 不是 struct(tuple 打包)时跳过本 target
|
||
if tgt_elts is None or rhs_val is None or rhs_val.Ty is None:
|
||
continue
|
||
match rhs_val.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
tgt_n: t.CSizeT = len(tgt_elts)
|
||
tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty)
|
||
if tmp_s is not None:
|
||
llvmlite.build_store(builder, rhs_val, tmp_s)
|
||
fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty)
|
||
fcur: llvmlite.ParamNode | t.CPtr = fchain
|
||
fti: t.CSizeT
|
||
for fti in range(tgt_n):
|
||
tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti)
|
||
if tgt_elt is None or fcur is None:
|
||
break
|
||
fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur)
|
||
fcur = llvmlite.paramnode_get_next(fcur)
|
||
if fty is None:
|
||
# fail-fast: 字段类型缺失,立即终止
|
||
HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError")
|
||
# 守卫:非 Name 元素无法解包,跳过
|
||
if tgt_elt.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt)
|
||
if tgt_nm2.id is None:
|
||
continue
|
||
fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, rhs_val.Ty, fty, tmp_s, fti)
|
||
if fp2 is None:
|
||
continue
|
||
fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2)
|
||
tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
self.Trans.SymTab, tgt_nm2.id)
|
||
if tgt_alloca is None:
|
||
tgt_alloca = HandlesVar.get_or_create_sym(
|
||
self.Trans.SymTab, pool, builder, tgt_nm2.id, fty)
|
||
if tgt_alloca is None:
|
||
continue
|
||
sval: llvmlite.Value | t.CPtr = fv2
|
||
if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None:
|
||
sval = HandlesExpr.coerce_to_type(
|
||
builder, fv2, tgt_alloca.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, sval, tgt_alloca)
|
||
case _:
|
||
pass
|
||
continue
|
||
|
||
# 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 None:
|
||
# fail-fast: list 下标翻译失败,立即终止
|
||
HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError")
|
||
HandlesExpr.list_setitem_inline(
|
||
builder, pool, list_obj, list_idx_val, rhs_val, target)
|
||
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
|
||
# 守卫短路:elem 类型完整才做类型转换
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, elem_ptr.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
continue
|
||
# 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 \
|
||
and sub_alloca.Ty.Pointee is not None \
|
||
and HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0:
|
||
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
||
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 \
|
||
and HandlesExpr.is_ptr_type(sub_pointee) != 0 \
|
||
and sub_pointee.Pointee is not None:
|
||
cls_nm_set = HandlesStruct.get_class_name_by_type(
|
||
pool, sub_pointee.Pointee)
|
||
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 \
|
||
and field_ptr_set.Ty.Pointee is not None \
|
||
and HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
|
||
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
|
||
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 \
|
||
and field_pointee_set.Pointee is not None:
|
||
cls_nm_attr = HandlesStruct.get_class_name_by_type(
|
||
pool, field_pointee_set.Pointee)
|
||
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 \
|
||
and obj_val_gen.Ty.Pointee is not None:
|
||
cls_nm_gen = HandlesStruct.get_class_name_by_type(
|
||
pool, obj_val_gen.Ty.Pointee)
|
||
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
|
||
elif HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \
|
||
and obj_val_gen.Ty.Pointee is not None:
|
||
# 非自定义结构体: 直接 GEP + store
|
||
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
|
||
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||
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:
|
||
if elem_ptr_gen.Ty.Pointee is not None:
|
||
store_val_gen = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, elem_ptr_gen.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||
setitem_done = 1
|
||
if setitem_done == 0:
|
||
HandlesType.fatal_error(target, "subscript ptr is None")
|
||
continue
|
||
|
||
# Attribute 赋值: obj.field = val
|
||
if tk == ast.ASTKind.Attribute:
|
||
# property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时,
|
||
# 生成 call Class.attr$set(obj, v),跳过字段存储
|
||
# 注意参数顺序:_try_property_setter(pool, builder, mod, ...)——
|
||
# 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数
|
||
# 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable
|
||
# 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。
|
||
if HandlesExprCall._try_property_setter(
|
||
pool, builder, mod, target, rhs_val, self.Trans) == 1:
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||
builder, pool, mod, target, self.Trans)
|
||
if field_ptr is not None:
|
||
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, field_ptr.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, field_ptr)
|
||
continue
|
||
# 守卫:field_ptr 为 None → 构造详细错误信息
|
||
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: str = 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)
|
||
# 守卫:target 名缺失时跳过
|
||
if nm.id is None:
|
||
continue
|
||
# 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 None:
|
||
# fail-fast: global 变量未注册,无法赋值
|
||
HandlesType.fatal_error(
|
||
target,
|
||
f"global 变量 '{nm.id}' 未注册,无法赋值",
|
||
"NameError")
|
||
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, node)
|
||
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 None:
|
||
# fail-fast: nonlocal 变量指针解析失败
|
||
HandlesType.fatal_error(
|
||
target,
|
||
f"nonlocal 变量 '{nm.id}' 指针解析失败",
|
||
"NameError")
|
||
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
|
||
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
|
||
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if nl_ptr.Ty is not None:
|
||
nl_target_ty = nl_ptr.Ty.Pointee
|
||
if nl_target_ty is None:
|
||
# fail-fast: nl_ptr 类型信息丢失,无法安全 store
|
||
HandlesType.fatal_error(
|
||
target,
|
||
f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入",
|
||
"TypeError")
|
||
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, nl_target_ty, node)
|
||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||
continue
|
||
|
||
# 拦截:函数内对模块级全局变量赋值但没 global 声明
|
||
# 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃
|
||
# (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃)
|
||
if HandlesVar.is_module_scope(self.Trans.SymTab) == 0:
|
||
mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
self.Trans.SymTab, nm.id)
|
||
if mod_gv is not None:
|
||
fb_g: str = VLogger.fmt_buf()
|
||
msg_g: str = "global 声明缺失"
|
||
if fb_g is not None:
|
||
viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id)
|
||
msg_g = fb_g
|
||
HandlesType.fatal_error(target, msg_g, "SyntaxError")
|
||
|
||
# 普通局部变量
|
||
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:
|
||
# 无注解赋值:从 RHS 表达式推断类名设置变量注解
|
||
# (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要
|
||
# AnnotClassName 才能定位结构体字段)
|
||
cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, self.Trans, rhs_val)
|
||
if cls_inf is not None:
|
||
HandlesVar.set_var_annot_class_name(
|
||
self.Trans.SymTab, nm.id, cls_inf)
|
||
# 按 alloca 类型对值进行转换(如 double → float)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if alloca.Ty is not None and alloca.Ty.Pointee is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, rhs_val, alloca.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, alloca)
|
||
# lambda 表达式赋给变量:注册为闭包变量名,
|
||
# 调用分派(is_closure_name)才走闭包间接调用路径;
|
||
# 否则 i8** alloca 被 _is_func_ptr_alloca 误判为
|
||
# 函数指针,无参 call 直接跳闭包数据崩溃
|
||
if asgn.value is not None \
|
||
and asgn.value.kind() == ast.ASTKind.Lambda:
|
||
HandlesExprCall.register_closure_name(nm.id)
|
||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||
self.Trans.SymTab, nm.id)
|
||
if existing is None:
|
||
new_vars += 1
|
||
else:
|
||
# fail-fast: 变量存储创建失败,立即终止
|
||
HandlesType.fatal_error(
|
||
target,
|
||
f"变量 '{nm.id}' 存储创建失败",
|
||
"TypeError")
|
||
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _infer_rhs_annot - 从 RHS 表达式推断变量注解类名
|
||
#
|
||
# 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName
|
||
# 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM
|
||
# 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。
|
||
# 此函数按 RHS 结构推断类名:
|
||
# Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标);
|
||
# func 为 Attribute 时是方法调用(a.cross()),obj 类名 +
|
||
# 方法存在 + rhs_val 为指针类型(联合对象)三条件判定
|
||
# Name → 源变量的 AnnotClassName
|
||
# BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象)
|
||
# Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class)
|
||
# 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。
|
||
# ============================================================
|
||
def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
rhs_val: llvmlite.Value | t.CPtr = None) -> str:
|
||
"""从 RHS 表达式推断类名,无法推断返回 None"""
|
||
if node is None or trans is None:
|
||
return None
|
||
k: int = node.kind()
|
||
# Call: 类实例化 / 方法调用
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl is None or cl.func is None:
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Name:
|
||
# 类实例化:func 为已注册结构体名才采用
|
||
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
|
||
if cand is None:
|
||
return None
|
||
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cand)
|
||
if se is not None:
|
||
return cand
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||
# 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名
|
||
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3',
|
||
# 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None,
|
||
# 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。
|
||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if ca is None or ca.attr is None or ca.value is None:
|
||
return None
|
||
obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans)
|
||
if obj_cls is None:
|
||
return None
|
||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||
return None
|
||
# 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1)
|
||
cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls)
|
||
if cls_sha1 is None and trans.ModuleSha1 is not None:
|
||
cls_sha1 = trans.ModuleSha1
|
||
ret_cls: str = None
|
||
if cls_sha1 is not None:
|
||
import lib.StubGen.VpiReader as VpiReader
|
||
temp_dir: str = None
|
||
import lib.core.Gen.Generator as Generator
|
||
g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||
if g2 is not None and g2.TempDir is not None:
|
||
temp_dir = g2.TempDir
|
||
if temp_dir is not None:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
|
||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
|
||
cls_sha1, obj_cls, ca.attr)
|
||
if annot_ret is not None:
|
||
ret_cls = self._extract_annot_class_name(pool, annot_ret)
|
||
return ret_cls
|
||
return None
|
||
# Name: 源变量注解
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm is None or nm.id is None:
|
||
return None
|
||
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if ve is None:
|
||
return None
|
||
return ve.AnnotClassName
|
||
# BinOp/UnaryOp: 运算符重载返回同类对象
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if bop is None or bop.left is None:
|
||
return None
|
||
dunder: str = self._op_to_dunder(bop.op)
|
||
if dunder is None:
|
||
return None
|
||
lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans)
|
||
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
|
||
return None
|
||
return lhs_cls
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uop is None or uop.operand is None:
|
||
return None
|
||
dunder: str = self._op_to_dunder(uop.op)
|
||
if dunder is None:
|
||
return None
|
||
opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans)
|
||
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
|
||
return None
|
||
return opr_cls
|
||
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
|
||
if k == ast.ASTKind.Attribute:
|
||
import lib.core.Gen.Generator as Generator
|
||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||
if g is not None:
|
||
return g._resolve_attr_field_class(pool, trans, node)
|
||
return None
|
||
return None
|
||
|
||
# ============================================================
|
||
# _extract_annot_class_name - 从返回注解文本提取结构体类名
|
||
#
|
||
# vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除
|
||
# 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/
|
||
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
|
||
# 多候选时取首个命中段。
|
||
# ============================================================
|
||
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
annot: str) -> str:
|
||
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
|
||
if pool is None or annot is None:
|
||
return None
|
||
alen: t.CSizeT = string.strlen(annot)
|
||
if alen == 0:
|
||
return None
|
||
seg: str = pool.alloc(256)
|
||
if seg is None:
|
||
return None
|
||
start: t.CSizeT = 0
|
||
i: t.CSizeT
|
||
for i in range(alen):
|
||
if annot[i] == '|':
|
||
seglen: t.CSizeT = i - start
|
||
# 段 [start, i):去除首尾空格与引号后查注册表
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = i
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg)
|
||
if se is not None:
|
||
return seg
|
||
start = i + 1
|
||
# 最后一段(无 '|' 后缀)
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = alen
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen: t.CSizeT = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg)
|
||
if se is not None:
|
||
return seg
|
||
return None
|
||
|
||
# ============================================================
|
||
# _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用)
|
||
# ============================================================
|
||
def _op_to_dunder(self, op: int) -> str:
|
||
"""BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None"""
|
||
if op == ast.OpKind.Add: return "__add__"
|
||
if op == ast.OpKind.Sub: return "__sub__"
|
||
if op == ast.OpKind.Mult: return "__mul__"
|
||
if op == ast.OpKind.Div: return "__truediv__"
|
||
if op == ast.OpKind.FloorDiv: return "__floordiv__"
|
||
if op == ast.OpKind.Mod: return "__mod__"
|
||
if op == ast.OpKind.Pow: return "__pow__"
|
||
if op == ast.OpKind.BitAnd: return "__and__"
|
||
if op == ast.OpKind.BitOr: return "__or__"
|
||
if op == ast.OpKind.BitXor: return "__xor__"
|
||
if op == ast.OpKind.LShift: return "__lshift__"
|
||
if op == ast.OpKind.RShift: return "__rshift__"
|
||
if op == ast.OpKind.USub: return "__neg__"
|
||
if op == ast.OpKind.UAdd: return "__pos__"
|
||
if op == ast.OpKind.Invert: return "__invert__"
|
||
return None
|
||
|
||
# ============================================================
|
||
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法
|
||
#
|
||
# 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义
|
||
# 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时
|
||
# 才采用运算符重载推断的类名,避免把原生运算误标为类类型。
|
||
# ============================================================
|
||
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str, dunder: str) -> int:
|
||
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
|
||
if class_name is None or dunder is None or mod is None:
|
||
return 0
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return 0
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||
if HandlesExprCall.find_func_in_module(mod, lookup_name) is not None:
|
||
return 1
|
||
# 继承链祖先查找
|
||
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
anc_lookup: str = pool.alloc(128)
|
||
if anc_lookup is not None:
|
||
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
|
||
if HandlesExprCall.find_func_in_module(mod, anc_lookup) is not None:
|
||
return 1
|
||
mi += 1
|
||
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
|
||
if HandlesStruct.get_struct_sha1(class_name) is not None:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# 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
|