- 浮点 t.CDefine 初值序列化与源恢复(gfx PI 编成 0.0) - __sizeof__ 按 packed 计算(cpu _tss memset 越界写 4B) - 数组初始化器支持 CONST_STR 单字符;模块级别名不再产出 global i32 0 假全局 - 临时缓冲/构造临时量 alloca 提升至入口块(B6 未覆盖路径) - 无符号判定补 CSizeT/小写别名/结构体字段 + udiv/urem + range 位宽与符号 + zext 扩展 - 跨模块 declare 形参按 vpi 定义侧收敛(修 _vpi_method_param_annot 拒绝 cls_name=None 导致 coerce 恒失效)
414 lines
23 KiB
Plaintext
414 lines
23 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.Gen.Translator as HT
|
||
|
||
from . import CallGenBase
|
||
|
||
|
||
# ============================================================
|
||
# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)
|
||
#
|
||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenProp(CallGenBase.CallGenBase):
|
||
"""属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)"""
|
||
|
||
# ============================================================
|
||
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
|
||
#
|
||
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
|
||
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||
#
|
||
# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充,
|
||
# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method()
|
||
# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _translate_property_call — 翻译属性方法调用
|
||
#
|
||
# 与 _translate_method_call 的调用名/返回类型解析逻辑一致:
|
||
# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入)
|
||
# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名
|
||
# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32)
|
||
#
|
||
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
|
||
# ============================================================
|
||
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
call_head: llvmlite.Value | t.CPtr,
|
||
call_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译属性/静态方法调用,返回 call 结果 Value"""
|
||
if pool is None or builder is None or class_name is None or method_name is None:
|
||
return None
|
||
|
||
# 构造查找名: ClassName.method_name
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return None
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||
|
||
# 查找函数(精确/后缀匹配)
|
||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||
|
||
# 确定调用名
|
||
call_name: str = lookup_name
|
||
if found_func is not None:
|
||
found_name: str = llvmlite.function_get_name(found_func)
|
||
if found_name is not None:
|
||
call_name = found_name
|
||
else:
|
||
# 未找到:用类所属模块的 SHA1 构造调用名
|
||
cls_sha1_pc: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if cls_sha1_pc is not None:
|
||
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
|
||
mangled_pc: str = pool.alloc(mlen_pc)
|
||
if mangled_pc is not None:
|
||
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
|
||
call_name = mangled_pc
|
||
|
||
# 确定返回类型
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if found_func is not None:
|
||
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||
if frt is not None:
|
||
call_ret_ty = frt
|
||
else:
|
||
sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
|
||
if sp_ty1 is not None:
|
||
call_ret_ty = sp_ty1
|
||
else:
|
||
cls_sha1_rt: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, cls_sha1_rt, class_name, method_name)
|
||
if looked_up_ty is not None:
|
||
call_ret_ty = looked_up_ty
|
||
else:
|
||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, cls_sha1_rt, class_name, method_name)
|
||
if vpi_ret_ty is not None:
|
||
call_ret_ty = vpi_ret_ty
|
||
else:
|
||
# Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成):
|
||
# 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790),
|
||
# 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
|
||
if cls_sha1_rt is None \
|
||
or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0:
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
# [DEPDBG] 临时诊断:属性方法依赖未就绪即 pending 的根因(用后移除)
|
||
dbg_ms8: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||
stdio.printf("[DEPDBG] pending(prop_ret): mod=%s cls=%s method=%s sha1=%s\n",
|
||
dbg_ms8, class_name, method_name,
|
||
cls_sha1_rt if cls_sha1_rt is not None else "none")
|
||
# 持久化(用后移除):供 Phase2 收敛失败最终诊断按调用方过滤
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
self.Gen.CallGenBase._AppendPhaseAPending(
|
||
trans.ModuleSha1, "prop_ret", class_name,
|
||
method_name, cls_sha1_rt, "-")
|
||
# 依赖未就绪:保持默认 i32(build_call(Void) 返回 None
|
||
# 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译)
|
||
call_ret_ty = llvmlite.Int32(pool)
|
||
else:
|
||
call_ret_ty = self._fail_method_ret_ty(method_name)
|
||
|
||
# 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call
|
||
# 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong),
|
||
# 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。
|
||
# 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。
|
||
tgt_func_pc: llvmlite.Function | t.CPtr = found_func
|
||
if tgt_func_pc is None:
|
||
tgt_func_pc = self.find_func_in_module(mod, call_name)
|
||
if tgt_func_pc is not None:
|
||
prev_pc: llvmlite.Value | t.CPtr = None
|
||
cur_arg_pc: llvmlite.Value | t.CPtr = call_head
|
||
cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc)
|
||
while cur_arg_pc is not None and cur_param_pc is not None:
|
||
param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc)
|
||
if param_ty_pc is not None and cur_arg_pc.Ty is not None:
|
||
coerced_pc: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, cur_arg_pc, param_ty_pc)
|
||
if coerced_pc is not None and coerced_pc != cur_arg_pc:
|
||
# 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点
|
||
llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next)
|
||
if prev_pc is None:
|
||
call_head = coerced_pc
|
||
else:
|
||
llvmlite.value_set_next(prev_pc, coerced_pc)
|
||
cur_arg_pc = coerced_pc
|
||
prev_pc = cur_arg_pc
|
||
cur_arg_pc = cur_arg_pc.Next
|
||
cur_param_pc = llvmlite.param_get_next(cur_param_pc)
|
||
|
||
# 确保 declare 存在,然后调用
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count)
|
||
return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0)
|
||
# ============================================================
|
||
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
|
||
#
|
||
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
|
||
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
|
||
# 供属性访问/赋值/删除识别 property 时使用。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
obj_node: ast.AST | t.CPtr) -> str:
|
||
"""解析对象表达式的类名(短名),失败返回 None"""
|
||
if pool is None or trans is None or obj_node is None:
|
||
return None
|
||
if obj_node.kind() == ast.ASTKind.Name:
|
||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
|
||
if obj_nm.id is not None:
|
||
var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, obj_nm.id)
|
||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||
annot_val: str = var_entry.AnnotClassName
|
||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||
if dot_ptr is not None:
|
||
return dot_ptr + 1
|
||
return annot_val
|
||
return None
|
||
# ============================================================
|
||
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
|
||
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
at_node: ast.Attribute | t.CPtr,
|
||
obj_ptr: llvmlite.Value | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
|
||
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
|
||
|
||
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
|
||
"""
|
||
if at_node is None or at_node.attr is None or obj_ptr is None or trans is None:
|
||
return None
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value)
|
||
if class_name is None:
|
||
class_name = fallback_class_name
|
||
if class_name is None:
|
||
return None
|
||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, at_node.attr)
|
||
if meta & GenTypes.META_PROP_GETTER == 0:
|
||
return None
|
||
# 单参数调用: obj → getter
|
||
llvmlite.value_set_next(obj_ptr, None)
|
||
return self._translate_property_call(
|
||
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
|
||
# ============================================================
|
||
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
|
||
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
target_attr: ast.Attribute | t.CPtr,
|
||
rhs_val: llvmlite.Value | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return 0
|
||
if target_attr is None or target_attr.attr is None or rhs_val is None:
|
||
return 0
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||
if class_name is None:
|
||
return 0
|
||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr)
|
||
if meta & GenTypes.META_PROP_SETTER == 0:
|
||
return 0
|
||
# 翻译对象值(self 参数)
|
||
obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||
if obj_val is None:
|
||
return 0
|
||
# 构建参数链表: obj → rhs
|
||
llvmlite.value_set_next(obj_val, None)
|
||
llvmlite.value_set_next(rhs_val, None)
|
||
llvmlite.value_set_next(obj_val, rhs_val)
|
||
# setter 函数名带 $set 后缀
|
||
setter_name_buf: str = pool.alloc(128)
|
||
if setter_name_buf is None:
|
||
return 0
|
||
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
|
||
self._translate_property_call(pool, builder, mod, class_name,
|
||
setter_name_buf, obj_val, 2, trans)
|
||
return 1
|
||
# ============================================================
|
||
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
|
||
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
target_attr: ast.Attribute | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return 0
|
||
if target_attr is None or target_attr.attr is None:
|
||
return 0
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||
if class_name is None:
|
||
return 0
|
||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr)
|
||
if meta & GenTypes.META_PROP_DELETER == 0:
|
||
return 0
|
||
# 翻译对象值(self 参数)
|
||
obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||
if obj_val is None:
|
||
return 0
|
||
llvmlite.value_set_next(obj_val, None)
|
||
# deleter 函数名带 $del 后缀
|
||
del_name_buf: str = pool.alloc(128)
|
||
if del_name_buf is None:
|
||
return 0
|
||
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
|
||
self._translate_property_call(pool, builder, mod, class_name,
|
||
del_name_buf, obj_val, 1, trans)
|
||
return 1
|
||
# ============================================================
|
||
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
|
||
#
|
||
# @staticmethod: 直接 call Class.method(args...),无 self
|
||
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return None
|
||
if class_name is None or method_name is None or cl is None:
|
||
return None
|
||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, method_name)
|
||
is_static: int = 0
|
||
is_class: int = 0
|
||
if meta & GenTypes.META_STATIC != 0:
|
||
is_static = 1
|
||
if meta & GenTypes.META_CLASS != 0:
|
||
is_class = 1
|
||
if is_static == 0 and is_class == 0:
|
||
return None
|
||
|
||
# 构建参数链表
|
||
head: llvmlite.Value | t.CPtr = None
|
||
total_count: int = 0
|
||
|
||
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
|
||
if is_class != 0:
|
||
struct_ty_cc: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name)
|
||
if struct_ty_cc is None:
|
||
return None
|
||
cls_ptr: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty_cc)
|
||
if cls_ptr is None:
|
||
return None
|
||
llvmlite.value_set_next(cls_ptr, None)
|
||
head = cls_ptr
|
||
total_count = 1
|
||
|
||
# 翻译调用参数
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = len(cargs)
|
||
tail: llvmlite.Value | t.CPtr = head
|
||
for ai in range(can):
|
||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg_node is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node, None, 0, trans)
|
||
if arg_val is None:
|
||
continue
|
||
llvmlite.value_set_next(arg_val, None)
|
||
if head is None:
|
||
head = arg_val
|
||
tail = arg_val
|
||
else:
|
||
llvmlite.value_set_next(tail, arg_val)
|
||
tail = arg_val
|
||
total_count += 1
|
||
|
||
# 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的
|
||
# 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。
|
||
# 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成
|
||
# call i32 @new() → 链接 undefined reference(CPythonTest 根因)。
|
||
# @classmethod 恒有 cls_ptr(head 非 None),不受影响。
|
||
return self._translate_property_call(pool, builder, mod, class_name,
|
||
method_name, head, total_count, trans)
|
||
# ============================================================
|
||
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
|
||
#
|
||
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
|
||
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
|
||
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
|
||
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
|
||
# _translate_method_call,会查不到 append 返回类型 → fail-fast
|
||
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
|
||
#
|
||
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _is_list_builtin_method(self, class_name: str,
|
||
method_name: str) -> int:
|
||
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
|
||
if class_name is None or method_name is None:
|
||
return 0
|
||
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
|
||
if string.strncmp(class_name, "list", 4) != 0:
|
||
return 0
|
||
# 方法名必须是 list 内置方法集合
|
||
if string.strcmp(method_name, "append") == 0: return 1
|
||
if string.strcmp(method_name, "get") == 0: return 1
|
||
if string.strcmp(method_name, "set") == 0: return 1
|
||
if string.strcmp(method_name, "pop") == 0: return 1
|
||
if string.strcmp(method_name, "clear") == 0: return 1
|
||
if string.strcmp(method_name, "__iter__") == 0: return 1
|
||
if string.strcmp(method_name, "__len__") == 0: return 1
|
||
if string.strcmp(method_name, "__getitem__") == 0: return 1
|
||
if string.strcmp(method_name, "__setitem__") == 0: return 1
|
||
return 0 |