拆分后主文件保留的 ExprCallHandle.HandleCall/HandlePrintfCall/ HandlePrintCall 仍裸调 translate_call/translate_printf_call/ translate_print_call → TPC 报 Undefined function: 'translate_call'。 改为 ExprCallCall. 前缀并补 import;ExprGenName.find_func_in_module 裸调用同步补 ExprCallBase. 前缀。全 App 裸调用扫描清零。
987 lines
64 KiB
Plaintext
987 lines
64 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
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.HandlesExprOps as HandlesExprOps
|
||
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.Handles.HandlesEnum as HandlesEnum
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.VLogger as VLogger
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Projectrans.Utils as Utils
|
||
|
||
|
||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||
import lib.core.Handles.ExprCallBase as ExprCallBase
|
||
import lib.core.Handles.ExprCallCtor as ExprCallCtor
|
||
|
||
# ============================================================
|
||
# ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问
|
||
#
|
||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprGenName(ExprGenBase.ExprGenBase):
|
||
"""Name/Subscript/下标访问"""
|
||
|
||
def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译变量引用(Name 节点)→ load"""
|
||
# mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被
|
||
# 解析为 None → create_global_string 的 module_add_global(None, gv) 被
|
||
# add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的
|
||
# global 定义丢失但 _label_counter/IR 引用已生成 → llc 报
|
||
# "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)"
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm is None:
|
||
return None
|
||
nm_id: str = nm.id
|
||
if nm_id is None:
|
||
return None
|
||
# CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32)
|
||
# NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表
|
||
# 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量,
|
||
# 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。
|
||
cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
if HandlesType.is_cdefine_str() != 0:
|
||
# 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"):
|
||
# 返回 global string(i8*),供 return ZLIB_VERSION 等使用。
|
||
cdef_sv: str = HandlesType.lookup_cdefine_string(nm_id)
|
||
if cdef_sv is not None:
|
||
return HandlesExpr.create_global_string(builder, pool, mod, cdef_sv, trans)
|
||
HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||
if HandlesType.is_cdefine_double() != 0:
|
||
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d)
|
||
# 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度,
|
||
# 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量)
|
||
cdef_val_c: t.CInt64T = HandlesType.lookup_cdefine_constant(nm_id)
|
||
return HandlesExpr._const_int_for_cdefine(pool, cdef_val_c)
|
||
|
||
# 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致)
|
||
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
|
||
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
|
||
if HandlesExpr._is_cdefine_name_pattern(nm_id) != 0:
|
||
if trans is not None:
|
||
cdef_val: t.CInt64T = HandlesExpr._lookup_cross_module_cdefine(
|
||
pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
if HandlesType.is_cdefine_str() != 0:
|
||
cdef_sv2: str = HandlesType.lookup_cdefine_string(nm_id)
|
||
if cdef_sv2 is not None:
|
||
return HandlesExpr.create_global_string(builder, pool, mod, cdef_sv2, trans)
|
||
HandlesType.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||
# 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double),
|
||
# 需返回浮点常量而非截断的整数
|
||
dchk_nm: double = HandlesType.lookup_cdefine_double(nm_id)
|
||
if HandlesType.is_cdefine_double() != 0:
|
||
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm)
|
||
return HandlesExpr._const_int_for_cdefine(pool, cdef_val)
|
||
|
||
# global 变量:从模块作用域查找(global 声明优先级最高)
|
||
if trans is not None:
|
||
if HT.is_global_name(trans, nm_id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
trans.SymTab, nm_id)
|
||
if mod_alloca is not None:
|
||
load_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
load_ty = mod_alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
# fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(
|
||
node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||
# 全局数组(如 pyzlib.pyzlib_error_msg: CArray[t.CChar, 512]):
|
||
# 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。
|
||
# 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy
|
||
# dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error
|
||
# 为空(test_pyzlib "error message is empty" 根因)。
|
||
match load_ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
return mod_alloca
|
||
case _:
|
||
pass
|
||
return llvmlite.build_load(builder, load_ty, mod_alloca)
|
||
|
||
# nonlocal 变量:通过闭包 env 访问
|
||
if HT.is_nonlocal_name(trans, nm_id) != 0:
|
||
return HandlesNonlocal.load_nonlocal_var(trans, nm_id)
|
||
|
||
# *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址
|
||
# (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容,
|
||
# 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args))
|
||
if trans is not None and trans._vararg_name is not None:
|
||
if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0:
|
||
if trans._va_list_ptr is not None:
|
||
return trans._va_list_ptr
|
||
|
||
# 局部变量查找(必须先于模块别名检查)
|
||
# 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名,
|
||
# 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因)
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id)
|
||
if alloca is not None:
|
||
load_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if alloca.Ty is not None:
|
||
load_ty = alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
# fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(
|
||
node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||
# 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`):
|
||
# 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。
|
||
# 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致
|
||
# `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。
|
||
match load_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
return alloca
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
# 数组变量按 C 语义退化为指针(返回数组基址),而非整体
|
||
# load 数组值——如 printf("%s", str_arr) 应传数组首地址,
|
||
# load [N x i8] 值传给 %s 会读到错误数据崩溃
|
||
# (ClassArrayTest TestCharArray 运行时崩溃根因)。
|
||
return alloca
|
||
return llvmlite.build_load(builder, load_ty, alloca)
|
||
|
||
# 模块别名检查:SymTab 查找失败后才检查
|
||
# 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量,
|
||
# 返回 None 让上层处理(用于属性访问 win32file.CreateFileA)
|
||
if trans is not None and trans._imported_modules is not None:
|
||
if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0:
|
||
return None
|
||
|
||
# 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。
|
||
# 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移
|
||
# (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。
|
||
# 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)——
|
||
# Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到
|
||
# Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR;
|
||
# 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表,
|
||
# 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的
|
||
# RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。
|
||
if trans is not None and trans.Module is not None:
|
||
fn_ref: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
|
||
trans.Module, nm_id)
|
||
if fn_ref is not None:
|
||
fn_name: str = llvmlite.function_get_name(fn_ref)
|
||
if fn_name is None:
|
||
return None
|
||
# 构造函数类型:ret_ty + 参数 ParamNode 链表
|
||
fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref)
|
||
if fn_ret_ty is None:
|
||
# fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因)
|
||
HandlesType.fatal_error(
|
||
node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError")
|
||
fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref)
|
||
fn_first_node: llvmlite.ParamNode | t.CPtr = None
|
||
fn_prev_node: llvmlite.ParamNode | t.CPtr = None
|
||
fn_pcount: int = 0
|
||
while fn_pp is not None:
|
||
fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp)
|
||
fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty)
|
||
if fn_pn is not None:
|
||
if fn_first_node is None:
|
||
fn_first_node = fn_pn
|
||
if fn_prev_node is not None:
|
||
llvmlite.paramnode_set_next(fn_prev_node, fn_pn)
|
||
fn_prev_node = fn_pn
|
||
fn_pcount += 1
|
||
fn_pp = llvmlite.param_get_next(fn_pp)
|
||
fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(
|
||
pool, fn_ret_ty, fn_first_node, fn_pcount)
|
||
if fn_ty is None:
|
||
return None
|
||
# 构造函数指针 Value(new_value 包装,避免触碰 Function.Next)
|
||
fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
|
||
if fn_ref_v is None:
|
||
return None
|
||
llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty))
|
||
llvmlite.value_set_isconst(fn_ref_v, 1)
|
||
fn_ref_name: str = pool.alloc(256)
|
||
if fn_ref_name is not None:
|
||
fn_ref_name[0] = '\0'
|
||
if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0:
|
||
viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name)
|
||
else:
|
||
viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name)
|
||
llvmlite.value_set_name(fn_ref_v, fn_ref_name)
|
||
fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty)
|
||
|
||
# ============================================================
|
||
# 跨模块 from-import 全局变量读取(如 from .tokens import _op_head)
|
||
# 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab
|
||
# 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被
|
||
# 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的
|
||
# _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。
|
||
# 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load,
|
||
# 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。
|
||
# ============================================================
|
||
if trans is not None and trans._from_imports is not None:
|
||
if trans.Module is not None:
|
||
# 是 from-import 名称(禁用 star 回退,避免误归 star 模块)
|
||
fi_mod: str = HandlesImports.lookup_from_import(
|
||
trans._from_imports, nm_id, 0)
|
||
if fi_mod is not None:
|
||
# 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取
|
||
fi_is_class: int = 0
|
||
if HandlesStruct.get_struct_type(nm_id) is not None:
|
||
fi_is_class = 1
|
||
# 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找)
|
||
if HandlesExpr._is_cdefine_name_pattern(nm_id) != 0:
|
||
fi_is_class = 1
|
||
if fi_is_class == 0:
|
||
fi_gname: str = nm_id
|
||
fi_orig: str = HandlesImports.lookup_from_import_original(
|
||
trans._from_imports, nm_id)
|
||
if fi_orig is not None:
|
||
og_len_fi: t.CSizeT = 0
|
||
while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0':
|
||
og_len_fi += 1
|
||
if og_len_fi > 0:
|
||
og_buf_fi: str = pool.alloc(og_len_fi + 1)
|
||
if og_buf_fi is not None:
|
||
string.strncpy(og_buf_fi, fi_orig, og_len_fi)
|
||
og_buf_fi[og_len_fi] = '\0'
|
||
fi_gname = og_buf_fi
|
||
# stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast
|
||
# (不再创建 external i8* 声明,否则 llc 报 "use of undefined value",
|
||
# 静默回退掩盖 stub 未注入的上游根因)
|
||
gv_fi: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module(
|
||
trans.Module, fi_gname)
|
||
ref_fi: llvmlite.Value | t.CPtr = None
|
||
if gv_fi is not None and gv_fi.Ty is not None:
|
||
ref_fi = HandlesExpr.make_global_ref(pool, fi_gname, gv_fi.Ty)
|
||
else:
|
||
HandlesType.fatal_error(
|
||
node,
|
||
f"跨模块全局变量 '{fi_gname}' 类型未知(stub 未注入)",
|
||
"TypeError")
|
||
if ref_fi is not None and ref_fi.Ty is not None:
|
||
lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee
|
||
if lty_fi is not None:
|
||
return llvmlite.build_load(builder, lty_fi, ref_fi)
|
||
return ref_fi
|
||
|
||
# 所有查找路径均失败
|
||
# fail-fast:未定义名称立即终止编译(NameError,暴露上游根因),
|
||
# 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。
|
||
# 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、
|
||
# CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义
|
||
# 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。
|
||
if nm_id is None:
|
||
return None
|
||
if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \
|
||
or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \
|
||
or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \
|
||
or string.strcmp(nm_id, "_") == 0 \
|
||
or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \
|
||
or string.strcmp(nm_id, "CIfndef") == 0:
|
||
return None
|
||
HandlesType.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError")
|
||
return None
|
||
# ============================================================
|
||
# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑
|
||
#
|
||
# list 结构布局 (6 字段 × 8 字节):
|
||
# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
|
||
# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值
|
||
# ============================================================
|
||
def list_getitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
lm_obj: llvmlite.Value | t.CPtr,
|
||
idx_val: llvmlite.Value | t.CPtr,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None:
|
||
return None
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||
g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
|
||
if g_dpp is None:
|
||
return None
|
||
g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||
g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
|
||
if g_epp is None:
|
||
return None
|
||
g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
|
||
if g_data is None or g_esize is None:
|
||
return None
|
||
g_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if g_idx_i64 is None:
|
||
return None
|
||
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
|
||
if g_offset is None:
|
||
return None
|
||
# 返回元素地址 (i8*),不 load
|
||
return llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
|
||
# ============================================================
|
||
# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型
|
||
#
|
||
# 类型名格式: <sha1>.list[<elem_type>]
|
||
# 用 strstr 检查完整模式,避免子串提取
|
||
# 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等
|
||
# 默认: i32
|
||
# ============================================================
|
||
def _list_elem_type_from_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
struct_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从 list 类型名提取元素 LLVM 类型"""
|
||
if pool is None or struct_name is None:
|
||
return None
|
||
# 用 strstr 检查完整模式
|
||
if string.strstr(struct_name, "list[int]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt8T]") is not None:
|
||
return llvmlite.Int8(pool)
|
||
if string.strstr(struct_name, "list[CInt16T]") is not None:
|
||
return llvmlite.Int16(pool)
|
||
if string.strstr(struct_name, "list[CInt32T]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt64T]") is not None:
|
||
return llvmlite.Int64(pool)
|
||
if string.strstr(struct_name, "list[CSizeT]") is not None:
|
||
return llvmlite.Int64(pool)
|
||
if string.strstr(struct_name, "list[CDouble]") is not None:
|
||
return llvmlite.Double(pool)
|
||
if string.strstr(struct_name, "list[CFloat]") is not None:
|
||
return llvmlite.Float(pool)
|
||
if string.strstr(struct_name, "list[CChar]") is not None:
|
||
return llvmlite.Int8(pool)
|
||
# str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址)
|
||
i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
if string.strstr(struct_name, "list[str]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
if string.strstr(struct_name, "list[bytes]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
if string.strstr(struct_name, "list[CPtr]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
# 未知 list[T] 元素类型(如 list[Foo]、list[AST|t.CPtr]):元素存储为
|
||
# 8 字节槽(指针或 8 字节整数),回退 Ptr(i8) 位宽一致(load 8 字节),
|
||
# 由 AnnotClassName/特化恢复机制保证语义。禁止 fail-fast(误杀合法
|
||
# 自定义类元素列表的下标访问)。
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
# ============================================================
|
||
# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
|
||
#
|
||
# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store)
|
||
# ============================================================
|
||
def list_setitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
lm_obj: llvmlite.Value | t.CPtr,
|
||
idx_val: llvmlite.Value | t.CPtr,
|
||
rhs_val: llvmlite.Value | t.CPtr,
|
||
node: ast.AST | t.CPtr = None) -> int:
|
||
"""内联生成 list __setitem__ 逻辑,返回 0"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None:
|
||
return 0
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||
s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
|
||
if s_dpp is None:
|
||
return 0
|
||
s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||
s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
|
||
if s_epp is None:
|
||
return 0
|
||
s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
|
||
if s_data is None or s_esize is None:
|
||
return 0
|
||
s_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if s_idx_i64 is None:
|
||
return 0
|
||
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
|
||
if s_offset is None:
|
||
return 0
|
||
s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
|
||
if s_addr is None:
|
||
return 0
|
||
# 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。
|
||
# 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与
|
||
# CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。
|
||
s_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lm_obj)
|
||
s_name: str = None
|
||
if s_sty is not None:
|
||
s_name = llvmlite.get_struct_name(s_sty)
|
||
s_elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if s_name is not None:
|
||
s_elem_ty = self._list_elem_type_from_name(pool, s_name)
|
||
if s_elem_ty is None:
|
||
s_elem_ty = i8_ptr_ty
|
||
s_val_ptr: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, rhs_val, s_elem_ty, node)
|
||
if s_val_ptr is None:
|
||
return 0
|
||
s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, s_addr, llvmlite.Ptr(pool, s_elem_ty))
|
||
if s_ep is not None:
|
||
llvmlite.build_store(builder, s_val_ptr, s_ep)
|
||
return 0
|
||
# ============================================================
|
||
# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型
|
||
#
|
||
# 返回 list 对象指针 (Ptr(list[T])) 或 None
|
||
# ============================================================
|
||
def is_list_subscript(self, node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None"""
|
||
if node is None or trans is None:
|
||
return None
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||
if sub is None or sub.value is None:
|
||
return None
|
||
if sub.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if nm is None or nm.id is None:
|
||
return None
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is None or alloca.Ty is None:
|
||
return None
|
||
if self.is_ptr_type(alloca.Ty) == 0:
|
||
return None
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is None:
|
||
return None
|
||
# 检查 pointee 是否是 Ptr(Struct)
|
||
inner_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match pointee:
|
||
case llvmlite.LLVMType.Ptr(it):
|
||
inner_ty = it
|
||
case _:
|
||
return None
|
||
if inner_ty is None:
|
||
return None
|
||
# 检查 inner_ty 是否是 Struct 且名称包含 "list["
|
||
struct_name: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, sname):
|
||
struct_name = sname
|
||
case _:
|
||
return None
|
||
if struct_name is None:
|
||
return None
|
||
if string.strstr(struct_name, "list[") is None:
|
||
return None
|
||
# 是 list 类型: load 出 list 对象指针
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
return llvmlite.build_load(builder, pointee, alloca)
|
||
# ============================================================
|
||
# _nonlocal_subscript_ptr - nonlocal 数组/指针的下标元素指针
|
||
#
|
||
# 嵌套函数(提升函数)体内访问 nonlocal 变量时,变量的实际存储是
|
||
# 运行时共享堆(env[ni] 存的堆地址),不能 lookup_var 找外层函数
|
||
# alloca(其 SSA 编号属于外层函数,当前函数引用错乱崩溃——
|
||
# ClosureTest2 Test 4 fill() 内 arr[i] 崩溃根因)。
|
||
# 正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP。
|
||
# ============================================================
|
||
def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
nm_id: str,
|
||
idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针"""
|
||
if trans is None or nm_id is None or idx_val is None:
|
||
return None
|
||
nl_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, nm_id)
|
||
if nl_ty is None:
|
||
return None
|
||
raw_nl: llvmlite.Value | t.CPtr = HandlesNonlocal._load_raw_var_ptr(trans, nm_id)
|
||
if raw_nl is None:
|
||
return None
|
||
match nl_ty:
|
||
case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl):
|
||
arr_ptr_nl: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
|
||
if arr_ptr_nl is None:
|
||
return None
|
||
return llvmlite.build_gep_array(
|
||
builder, nl_ty, elem_ty_nl, arr_ptr_nl,
|
||
self._zext_index_to_i32(builder, idx_val))
|
||
case llvmlite.LLVMType.Ptr(inner_nl):
|
||
arr_ptr_nl2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
|
||
if arr_ptr_nl2 is None:
|
||
return None
|
||
return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val)
|
||
case _:
|
||
arr_ptr_nl3: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
|
||
if arr_ptr_nl3 is None:
|
||
return None
|
||
return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val)
|
||
return None
|
||
# ============================================================
|
||
# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i]
|
||
#
|
||
# 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load
|
||
# 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load
|
||
# list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径
|
||
# ============================================================
|
||
def translate_subscript(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译下标表达式,返回加载的元素值"""
|
||
if node is None or builder is None:
|
||
return None
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||
if sub is None:
|
||
return None
|
||
|
||
# 翻译索引
|
||
idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub.slice, None, 0, trans)
|
||
if idx_val is None:
|
||
return None
|
||
|
||
# 如果 value 是 Name,尝试从 alloca 类型推断
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if nm.id is not None and trans is not None:
|
||
# nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能
|
||
# lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃)
|
||
# 读路径:元素指针 load 出元素值
|
||
if HT.is_nonlocal_name(trans, nm.id) != 0:
|
||
nl_ptr_r: llvmlite.Value | t.CPtr = self._nonlocal_subscript_ptr(
|
||
builder, pool, trans, nm.id, idx_val)
|
||
if nl_ptr_r is not None and nl_ptr_r.Ty is not None:
|
||
nl_elem_ty: llvmlite.LLVMType | t.CPtr = nl_ptr_r.Ty.Pointee
|
||
if nl_elem_ty is not None:
|
||
return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r)
|
||
return None
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is not None and alloca.Ty is not None:
|
||
if self.is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号
|
||
# 用 match 检查 pointee 类型
|
||
match pointee:
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
# 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx
|
||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, pointee, elem_ty, alloca,
|
||
self._zext_index_to_i32(builder, idx_val))
|
||
if elem_ptr is not None:
|
||
return llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||
return None
|
||
case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v):
|
||
# list[T] 值变量(无注解赋值 rhs 返回 list 值,
|
||
# 如 parts = s1.split(','):split 的 define 返回
|
||
# %list[str] 结构体值,alloca 直接存 list 对象)。
|
||
# alloca 即 list*,直接走 list 内联 __getitem__
|
||
#(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃)
|
||
if lsn_v is not None:
|
||
if string.strstr(lsn_v, "list[") is not None:
|
||
elem_addr_v: llvmlite.Value | t.CPtr = \
|
||
self.list_getitem_inline(
|
||
builder, pool, alloca, idx_val, node)
|
||
if elem_addr_v is not None:
|
||
elem_ty_v: llvmlite.LLVMType | t.CPtr = \
|
||
self._list_elem_type_from_name(pool, lsn_v)
|
||
if elem_ty_v is not None:
|
||
elem_ptr_ty_v: llvmlite.LLVMType | t.CPtr = \
|
||
llvmlite.Ptr(pool, elem_ty_v)
|
||
casted_v: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_bitcast(
|
||
builder, elem_addr_v, elem_ptr_ty_v)
|
||
if casted_v is not None:
|
||
return llvmlite.build_load(
|
||
builder, elem_ty_v, casted_v)
|
||
return None
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct)
|
||
# list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历
|
||
list_struct_name: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, lsn):
|
||
list_struct_name = lsn
|
||
case _:
|
||
pass
|
||
if list_struct_name is not None:
|
||
if string.strstr(list_struct_name, "list[") is not None:
|
||
# list[T] 类型: 内联生成 __getitem__ 逻辑
|
||
ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_list is not None:
|
||
elem_addr_list: llvmlite.Value | t.CPtr = self.list_getitem_inline(
|
||
builder, pool, ptr_val_list, idx_val, node)
|
||
if elem_addr_list is not None:
|
||
# 根据类型名提取元素类型,bitcast 后 load
|
||
elem_ty_list: llvmlite.LLVMType | t.CPtr = self._list_elem_type_from_name(
|
||
pool, list_struct_name)
|
||
if elem_ty_list is not None:
|
||
elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, elem_ty_list)
|
||
casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, elem_addr_list, elem_ptr_ty_list)
|
||
if casted_addr_list is not None:
|
||
return llvmlite.build_load(
|
||
builder, elem_ty_list, casted_addr_list)
|
||
return None
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))),
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用
|
||
# 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。
|
||
# 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable)
|
||
# (非 Ptr), 仍走下面的方法调用转发路径。
|
||
if self.is_ptr_type(inner_ty) != 0:
|
||
ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_pp is not None:
|
||
elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val_pp, idx_val)
|
||
if elem_ptr_pp is not None:
|
||
return llvmlite.build_load(builder, inner_ty, elem_ptr_pp)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入)
|
||
# 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问
|
||
# (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__))
|
||
cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty)
|
||
if not (cls_nm_rd_ptr is None):
|
||
gi_lookup_rd: str = pool.alloc(128)
|
||
if gi_lookup_rd is not None:
|
||
viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr)
|
||
if ExprCallBase.find_func_in_module(mod, gi_lookup_rd) is not None:
|
||
obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if not (obj_ptr_rd is None):
|
||
arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if not (arg_vals_rd_p is None):
|
||
arg_vals_rd_p[0] = t.CSizeT(idx_val)
|
||
ret_rd_p: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_rd_ptr, "__getitem__",
|
||
obj_ptr_rd, arg_vals_rd_p, 1, trans, sub)
|
||
if not (ret_rd_p is None):
|
||
return ret_rd_p
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_rd_g is not None:
|
||
elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val_rd_g, idx_val)
|
||
if elem_rd_g is not None:
|
||
return llvmlite.build_load(builder, inner_ty, elem_rd_g)
|
||
return None
|
||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||
# 直接 GEP 按 i8* 步长(8 字节),load i8*
|
||
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
|
||
if trans is not None:
|
||
ve_pe_ts: HandlesVar.VarEntry | t.CPtr = \
|
||
HandlesVar.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1:
|
||
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*),
|
||
# elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。
|
||
# 必须先 load alloca 得指针值,再 GEP i8*(步长 8)——
|
||
# 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区,
|
||
# list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。
|
||
ptr_val_pe_ts: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_pe_ts is not None:
|
||
elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, pointee, ptr_val_pe_ts, idx_val)
|
||
if elem_ptr_ts is not None:
|
||
return llvmlite.build_load(builder, pointee, elem_ptr_ts)
|
||
return None
|
||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||
ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val is not None:
|
||
elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val, idx_val)
|
||
if elem_ptr2 is not None:
|
||
return llvmlite.build_load(builder, inner_ty, elem_ptr2)
|
||
return None
|
||
case _:
|
||
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
|
||
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
|
||
# 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*——
|
||
# 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。
|
||
if trans is not None:
|
||
ve_pe_rd: HandlesVar.VarEntry | t.CPtr = \
|
||
HandlesVar.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve_pe_rd is not None and ve_pe_rd.IsPtrElement == 1:
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int8():
|
||
i8_ptr_rd: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
elem_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, i8_ptr_rd, alloca, idx_val)
|
||
if elem_ptr_rd is not None:
|
||
return llvmlite.build_load(
|
||
builder, i8_ptr_rd, elem_ptr_rd)
|
||
case _:
|
||
pass
|
||
# 自定义类(结构体类型): 仅当类定义了 __getitem__
|
||
# (当前模块定义或跨模块 stub declare 注入)才转发方法调用;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee)
|
||
if not (cls_nm_sub is None):
|
||
gi_lookup_sub: str = pool.alloc(128)
|
||
if gi_lookup_sub is not None:
|
||
viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub)
|
||
if ExprCallBase.find_func_in_module(mod, gi_lookup_sub) is not None:
|
||
obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if not (obj_val_sub is None):
|
||
arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if not (arg_vals_sub is None):
|
||
arg_vals_sub[0] = t.CSizeT(idx_val)
|
||
ret_sub: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_sub, "__getitem__",
|
||
obj_val_sub, arg_vals_sub, 1, trans, sub)
|
||
if not (ret_sub is None):
|
||
return ret_sub
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_sub_g is not None:
|
||
elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, pointee, ptr_val_sub_g, idx_val)
|
||
if elem_sub_g is not None:
|
||
return llvmlite.build_load(builder, pointee, elem_sub_g)
|
||
return None
|
||
pass
|
||
|
||
# 通用路径:翻译 value 获取指针
|
||
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub.value, None, 0, trans)
|
||
if ptr_val is None or ptr_val.Ty is None:
|
||
return None
|
||
|
||
# 检查是否是指针类型
|
||
if self.is_ptr_type(ptr_val.Ty) != 0:
|
||
elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
if elem_ty2 is not None:
|
||
# 数组类型: 双索引 GEP + load 元素
|
||
match elem_ty2:
|
||
case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2):
|
||
elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, elem_ty2, arr_elem_ty2, ptr_val,
|
||
self._zext_index_to_i32(builder, idx_val))
|
||
if elem_ptr3 is not None:
|
||
return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3)
|
||
return None
|
||
case _:
|
||
pass
|
||
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if not (cls_nm_rd_gen is None):
|
||
gi_lookup_gen: str = pool.alloc(128)
|
||
if gi_lookup_gen is not None:
|
||
viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen)
|
||
if ExprCallBase.find_func_in_module(mod, gi_lookup_gen) is not None:
|
||
arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if not (arg_vals_rd_g is None):
|
||
arg_vals_rd_g[0] = t.CSizeT(idx_val)
|
||
ret_rd_g: llvmlite.Value | t.CPtr = ExprCallCtor._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_rd_gen, "__getitem__",
|
||
ptr_val, arg_vals_rd_g, 1, trans, sub)
|
||
if not (ret_rd_g is None):
|
||
return ret_rd_g
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, elem_ty2, ptr_val, idx_val)
|
||
if elem_ptr_gen is not None:
|
||
return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen)
|
||
return None
|
||
# 指针类型: 单索引 GEP + load
|
||
elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, elem_ty2, ptr_val, idx_val)
|
||
if elem_ptr4 is not None:
|
||
return llvmlite.build_load(builder, elem_ty2, elem_ptr4)
|
||
return None
|
||
# ============================================================
|
||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||
# ============================================================
|
||
def get_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""获取下标表达式的元素指针(用于赋值 lhs)"""
|
||
if node is None or builder is None:
|
||
return None
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||
if sub is None:
|
||
return None
|
||
|
||
# 翻译索引
|
||
idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub.slice, None, 0, trans)
|
||
if idx_val is None:
|
||
return None
|
||
|
||
# 如果 value 是 Name,尝试从 alloca 类型推断
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if nm.id is not None and trans is not None:
|
||
# nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能
|
||
# lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃)
|
||
if HT.is_nonlocal_name(trans, nm.id) != 0:
|
||
return self._nonlocal_subscript_ptr(
|
||
builder, pool, trans, nm.id, idx_val)
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is not None and alloca.Ty is not None:
|
||
if self.is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 用 match 检查 pointee 类型
|
||
match pointee:
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
# 数组遍历
|
||
return llvmlite.build_gep_array(
|
||
builder, pointee, elem_ty, alloca,
|
||
self._zext_index_to_i32(builder, idx_val))
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针,
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。
|
||
if self.is_ptr_type(inner_ty) != 0:
|
||
ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_gsp is not None:
|
||
return llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val_gsp, idx_val)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入)
|
||
# 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标
|
||
# 做 GEP 数组访问(走下方指针遍历路径)
|
||
cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty)
|
||
if not (cls_nm_ptr_chk is None):
|
||
si_lookup_gsp: str = pool.alloc(128)
|
||
if si_lookup_gsp is not None:
|
||
viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk)
|
||
if ExprCallBase.find_func_in_module(mod, si_lookup_gsp) is not None:
|
||
return None
|
||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||
# 直接 GEP 按 i8* 步长(8 字节),不 load
|
||
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
|
||
if trans is not None:
|
||
ve_pe: HandlesVar.VarEntry | t.CPtr = \
|
||
HandlesVar.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve_pe is not None and ve_pe.IsPtrElement == 1:
|
||
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值,
|
||
# 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load
|
||
# alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr)
|
||
# 读到栈变量而非数据区,赋值写不进 list 数据
|
||
# (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。
|
||
ptr_val_pe: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_pe is not None:
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int8():
|
||
i8_ptr_pe: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_gep(
|
||
builder, i8_ptr_pe, ptr_val_pe, idx_val)
|
||
case _:
|
||
pass
|
||
return llvmlite.build_gep(
|
||
builder, pointee, ptr_val_pe, idx_val)
|
||
return None
|
||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||
ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val is None:
|
||
return None
|
||
gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val, idx_val)
|
||
return gep_r
|
||
case _:
|
||
# pointee 是普通标量类型 (如 i64, i32, i8):
|
||
# alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针
|
||
# 支持 arg_vals[i] = val 这类参数数组下标赋值
|
||
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
|
||
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
|
||
# 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断)
|
||
if trans is not None:
|
||
ve_pe_cs: HandlesVar.VarEntry | t.CPtr = \
|
||
HandlesVar.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve_pe_cs is not None and ve_pe_cs.IsPtrElement == 1:
|
||
# T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量
|
||
# 存数据区指针,元素为 8 字节指针:必须先 load alloca
|
||
# 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca
|
||
# (&elem_ptr)算到栈地址,赋值写不进 list 数据区
|
||
# (append 只增 count、data 全 0xbaadf00d)。
|
||
ptr_val_cs: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_cs is not None:
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int8():
|
||
i8_ptr_cs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_gep(
|
||
builder, i8_ptr_cs, ptr_val_cs, idx_val)
|
||
case _:
|
||
pass
|
||
return llvmlite.build_gep(
|
||
builder, pointee, ptr_val_cs, idx_val)
|
||
return None
|
||
return llvmlite.build_gep(builder, pointee, alloca, idx_val)
|
||
|
||
# 通用路径
|
||
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sub.value, None, 0, trans)
|
||
if ptr_val is None or ptr_val.Ty is None:
|
||
return None
|
||
if self.is_ptr_type(ptr_val.Ty) != 0:
|
||
elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
if elem_ty2 is not None:
|
||
# 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx)
|
||
match elem_ty2:
|
||
case llvmlite.LLVMType.Array(arr_elem_ty, arr_count):
|
||
return llvmlite.build_gep_array(
|
||
builder, elem_ty2, arr_elem_ty, ptr_val,
|
||
self._zext_index_to_i32(builder, idx_val))
|
||
case _:
|
||
pass
|
||
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__
|
||
# 才返回 None 触发 HandlesAssign 的 __setitem__ 重载;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if not (cls_nm_gen is None):
|
||
si_lookup_gen: str = pool.alloc(128)
|
||
if si_lookup_gen is not None:
|
||
viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen)
|
||
if ExprCallBase.find_func_in_module(mod, si_lookup_gen) is not None:
|
||
return None
|
||
# 指针类型: 单索引 GEP (getelementptr ty, ptr, idx)
|
||
return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val)
|
||
return None |