Files
ViperC/App/lib/core/Gen/CallGenDispatch.vp
T

1433 lines
106 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenDispatch(CallGenBase.CallGenBase):
"""translate_call 前置检测 helper(继承 Base)"""
def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""super()/ctraits 编译期检测(未命中返回 None)"""
# super() 语义(2026-08-10):super().method(args) → 静态调用父类方法
# 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method))
# 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value
# 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。
if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call:
sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value)
if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name:
sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func)
if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0:
return HandlesExprCall._translate_super_call(
pool, builder, mod, cl, func_name, trans)
# ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用,
# 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底,
# 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错)
if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name:
ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value)
if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \
and string.strcmp(func_name, "isptr") == 0:
ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if ct_args is not None and len(ct_args) >= 1:
ct_arg0: ast.AST | t.CPtr = ct_args.get(0)
if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name:
ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0)
if ct_nm0.id is not None and trans is not None:
ct_r: int = HandlesType.eval_ctraits_isptr(trans.SymTab, ct_nm0.id)
if ct_r > 0:
return llvmlite.const_int32(pool, 1)
return llvmlite.const_int32(pool, 0)
return None
def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None)"""
# 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name:
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value)
if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0:
if string.strcmp(func_name, "Deref") == 0:
return HandlesExprCall.translate_c_deref(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "DerefAs") == 0:
return HandlesExprCall.translate_c_derefas(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Addr") == 0:
return HandlesExprCall.translate_c_addr(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Set") == 0:
# c.Set(a, b) = a = b(赋值语义,非指针解引用)。
# 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。
return HandlesExprCall.translate_c_set(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Load") == 0:
return HandlesExprCall.translate_c_load(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Asm") == 0:
return HandlesExprCall.translate_c_asm(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "LLVMIR") == 0:
return HandlesExprCall.translate_c_llvmir(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0:
# c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义)
return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0")
elif string.strcmp(func_name, "CIf") == 0:
# 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1
# 对齐 TPC HandlesExprCall.py L2434-2444
cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cif_args is not None and len(cif_args) >= 1:
cif_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans)
if cif_arg_val is not None:
cif_bits: int = HandlesExpr.get_llvm_type_bits(cif_arg_val.Ty)
if cif_bits == 1:
return cif_arg_val
if HandlesExpr.is_ptr_type(cif_arg_val.Ty) != 0:
cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
pool, cif_arg_val.Ty, "null")
return llvmlite.build_icmp(
builder, llvmlite.ICMP_NE, cif_arg_val, cif_null)
cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
return llvmlite.build_icmp(
builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero)
return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0")
elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0:
# 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真
# 对齐 TPC HandlesExprCall.py L2445-2446
return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1")
return None
def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""stdarg 糖 + str/int/bool 内置强转(未命中返回 None)"""
# stdarg 糖函数处理: va_arg / arg / va_start / va_end
# 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理:
# va_arg(ap, type) → %N = va_arg <ap_ty> <ap>, <type> (LLVM 指令)
# va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32)
# arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr)
# va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic)
# va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic)
# ============================================================
if func_name is not None and trans is not None:
if string.strcmp(func_name, "va_arg") == 0:
return HandlesExprCall._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can,
funcs_ptr, func_count, trans)
elif string.strcmp(func_name, "arg") == 0:
return HandlesExprCall._translate_arg_sugar(pool, builder, mod, cl, cargs, can,
funcs_ptr, func_count, trans)
elif string.strcmp(func_name, "va_start") == 0:
return HandlesExprCall._translate_va_start_sugar(pool, builder, mod, cargs, can,
funcs_ptr, func_count, trans)
elif string.strcmp(func_name, "va_end") == 0:
return HandlesExprCall._translate_va_end_sugar(pool, builder, mod, cargs, can,
funcs_ptr, func_count, trans)
# 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32
# 等价于 (str)(x) / (t.CInt32T)(x)
# 单参数:str(val) → bitcast val to i8*
# int(val) → trunc/sext val to i32
# 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名
# (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、
# combine[T1,T2] 的 T1(b) 依赖此路径)
if func_name is not None and can == 1:
cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0:
# str(x) / bytes(x) → i8* (bitcast)
cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if cast_arg is not None:
i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
return HandlesExprCall._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
return None
elif string.strcmp(cast_fn_name, "int") == 0:
# int(x) → i32
cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if cast_arg_int is not None:
i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
return HandlesExprCall._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin)
return None
elif string.strcmp(cast_fn_name, "bool") == 0:
# bool(x) → i1(严格 != 0 归一化)
# 整数: icmp ne x, 0 → i1
# 浮点: fcmp one x, 0.0 → i1
# 指针: icmp ne x, null → i1
cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if cast_arg_bool is not None:
arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty)
arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty)
# 整数: icmp ne x, 0
if arg_bits != 0:
zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0)
if zero_int is not None:
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int)
return None
# 浮点: fcmp one x, 0.0
if arg_fbits != 0:
zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty
zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0)
if zero_flt is not None:
return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt)
return None
# 指针: icmp ne x, null
ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null")
if ptr_null is not None:
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null)
return None
return None
return None
def _tc_h4_type_casts(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""t.XXX / typedef 类型转换(未命中返回 None)"""
# 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等
# 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用)
# 支持:
# 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name)
# 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name))
# t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name:
tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value)
if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0:
target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name)
if target_ty is not None:
tc_effective_can: t.CSizeT = can
# 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty)
# 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8*
if can == 2:
tc_arg2_node: ast.AST | t.CPtr = cargs.get(1)
tc_arg2_is_cptr: int = 0
if tc_arg2_node is not None:
# 形式 1: t.CPtr(Attribute 形式)
if tc_arg2_node.kind() == ast.ASTKind.Attribute:
tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node)
if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0:
if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name:
tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value)
if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0:
tc_arg2_is_cptr = 1
# 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr))
elif tc_arg2_node.kind() == ast.ASTKind.Name:
tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node)
if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0:
tc_arg2_is_cptr = 1
if tc_arg2_is_cptr != 0:
# CVoid* → i8*(LLVM 中 void* 表示为 i8*)
match target_ty:
case llvmlite.LLVMType.Void():
target_ty = llvmlite.Int8(pool)
case _:
pass
target_ty = llvmlite.Ptr(pool, target_ty)
tc_effective_can = 1
if tc_effective_can == 1:
tc_arg_node: ast.AST | t.CPtr = cargs.get(0)
if tc_arg_node is not None:
tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, tc_arg_node, None, 0, trans)
if tc_arg_val is not None:
return HandlesExprCall._translate_t_type_cast(
pool, builder, tc_arg_val, target_ty,
func_name, tc_arg_node, trans)
# t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL
return None
# 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等
# func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用
# → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp
# L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x)
# 对齐);非 typedef 名继续走模块函数调用。
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name:
mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value)
if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \
and string.strcmp(mt_mod_nm.id, "c") != 0:
mod_td_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(
pool, func_name)
if mod_td_ty is None:
mod_td_str: str = HandlesType.lookup_ctypedef(func_name)
if mod_td_str is not None and HandlesType.is_ctypedef_found() != 0:
mod_td_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(
pool, mod_td_str, 0)
if mod_td_ast is not None:
mod_imp_td: str = None
mod_fi_td: str = None
if trans is not None:
mod_imp_td = trans._imported_modules
mod_fi_td = trans._from_imports
mod_td_ty = HandlesType.resolve_annotation_type(
pool, mod_td_ast, mod_imp_td, mod_fi_td, trans)
if mod_td_ty is not None and can == 1:
mt_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if mt_arg_val is not None:
return HandlesExprCall._translate_t_type_cast(
pool, builder, mt_arg_val, mod_td_ty,
func_name, cargs.get(0), trans)
# 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等
# 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换
# map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等)
# 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体
# 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、
# combine[T1,T2] 的 T1(b) 依赖此路径)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
bare_ty: llvmlite.LLVMType | t.CPtr = None
# 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble,
# 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致)
if string.strcmp(bare_fn_name, "double") == 0:
bare_ty = llvmlite.Double(pool)
elif string.strcmp(bare_fn_name, "float") == 0:
bare_ty = llvmlite.Float(pool)
else:
bare_ty = HandlesType.map_t_type(pool, bare_fn_name)
# 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名),
# 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。
# GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。
if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0:
gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0)
if gp_ast is not None:
imp_gp: str = None
fi_gp: str = None
if trans is not None:
imp_gp = trans._imported_modules
fi_gp = trans._from_imports
bare_ty = HandlesType.resolve_annotation_type(
pool, gp_ast, imp_gp, fi_gp, trans)
# 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T)
# (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的
# typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进
# can==1 单参数分支 → 跌落到"裸名调用未定义"误报)
if bare_ty is not None and can == 2:
bare_arg2_node: ast.AST | t.CPtr = cargs.get(1)
bare_arg2_is_cptr: int = 0
if bare_arg2_node is not None:
# 形式 1: t.CPtr(Attribute 形式)
if bare_arg2_node.kind() == ast.ASTKind.Attribute:
bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node)
if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0:
if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name:
bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value)
if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0:
bare_arg2_is_cptr = 1
# 形式 2: 裸名 CPtr(from t import CPtr 后直接使用)
elif bare_arg2_node.kind() == ast.ASTKind.Name:
bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node)
if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0:
bare_arg2_is_cptr = 1
if bare_arg2_is_cptr != 0:
# CVoid* → i8*(LLVM 中 void* 表示为 i8*)
match bare_ty:
case llvmlite.LLVMType.Void():
bare_ty = llvmlite.Int8(pool)
case _:
pass
bare_ty = llvmlite.Ptr(pool, bare_ty)
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
if bare_arg_node is not None:
bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, bare_arg_node, None, 0, trans)
if bare_arg_val is not None:
return HandlesExprCall._translate_t_type_cast(
pool, builder, bare_arg_val, bare_ty,
bare_fn_name, bare_arg_node, trans)
if bare_ty is not None and can == 1:
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
if bare_arg_node is not None:
bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, bare_arg_node, None, 0, trans)
if bare_arg_val is not None:
return HandlesExprCall._translate_t_type_cast(
pool, builder, bare_arg_val, bare_ty,
bare_fn_name, bare_arg_node, trans)
return None
def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""__sizeof__/len/isinstance 内置(未命中返回 None)"""
# 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64)
# __sizeof__ 是内置方法,不走跨模块调用路径
# 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__()
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0:
if sz_at.value is not None and can == 0:
sz_cls_name: str = None
sz_vk: int = sz_at.value.kind()
if sz_vk == ast.ASTKind.Name:
sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value)
sz_cls_name = sz_cls_nm2.id
elif sz_vk == ast.ASTKind.Attribute:
sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value)
sz_cls_name = sz_inner_at.attr
# 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj)
sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None
sz_resolved_name: str = sz_cls_name
if sz_cls_name is not None:
# 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__()
sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name)
sz_resolved_name = sz_cls_name
# 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt")
# 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量
# "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA"
dot_pos: str = string.strrchr(sz_cls_name, '.')
if dot_pos is not None:
sz_cls_name = dot_pos + 1
# 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节)
# 联合类型在 TPV 中表示指针,可以指向多种类型
# 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理
if string.strstr(sz_cls_name, "|") is not None:
return llvmlite.const_int64(pool, 8)
# 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等)
sz_builtin: int = -1
if string.strcmp(sz_cls_name, "int") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "str") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "bytes") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CInt") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CInt8T") == 0:
sz_builtin = 1
elif string.strcmp(sz_cls_name, "CInt16T") == 0:
sz_builtin = 2
elif string.strcmp(sz_cls_name, "CInt32T") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CInt64T") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CChar") == 0:
sz_builtin = 1
elif string.strcmp(sz_cls_name, "CDouble") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CFloat") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CPtr") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CSizeT") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CBool") == 0:
sz_builtin = 1
elif string.strcmp(sz_cls_name, "bool") == 0:
sz_builtin = 1
# 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回
# _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"):
# 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 →
# NameError(VectorGenericTest Vector[double].__init__ 回归根因)
elif string.strcmp(sz_cls_name, "double") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "float") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "char") == 0:
sz_builtin = 1
if sz_builtin >= 0:
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
# ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal
# 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值
return llvmlite.const_int64(pool, sz_builtin)
sz_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name)
# 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小
# (GenericTest2 Stack.type_size 依赖此路径)
if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript:
sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value)
if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name:
gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value)
if gen_nm_sz.id is not None:
gen_args_sz: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_sz.slice)
if gen_args_sz is not None and len(gen_args_sz) > 0:
gargs_resolved: list[str] | t.CPtr = list[str](pool, 8)
if gargs_resolved is not None:
gai_sz: t.CSizeT = len(gen_args_sz)
gai2_sz: t.CSizeT = 0
for gai2_sz in range(gai_sz):
gres_sz: str = HandlesType.resolve_generic_type_name(
gen_args_sz.get(gai2_sz))
gargs_resolved.append(gres_sz)
spec_sz: str = HandlesClassDef._specialize_generic_class(
trans, gen_nm_sz.id, gargs_resolved)
if spec_sz is not None:
sz_resolved_name = spec_sz
sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz)
# 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型
# (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int]))
# 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca
# 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支;
# zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖)
if sz_resolved_ty is None:
inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sz_at.value, None, 0, trans)
if inst_sz_val is not None and inst_sz_val.Ty is not None:
match inst_sz_val.Ty:
case llvmlite.LLVMType.Ptr(inst_inner_sz):
match inst_inner_sz:
case llvmlite.LLVMType.Struct(_, _, _):
sz_resolved_ty = inst_inner_sz
case llvmlite.LLVMType.Array(_, _):
sz_resolved_ty = inst_inner_sz
case _:
pass
case llvmlite.LLVMType.Struct(_, _, _):
sz_resolved_ty = inst_sz_val.Ty
case llvmlite.LLVMType.Array(_, _):
# 全局数组变量(模块级 t.CArray[T,N])translate_value
# 返回数组值 [N x T](非指针);局部数组返回 alloca
# 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。
# pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。
sz_resolved_ty = inst_sz_val.Ty
case _:
pass
if sz_resolved_ty is not None:
sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty)
if sz_val > 0:
return llvmlite.const_int64(pool, sz_val)
# 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止
HandlesType.fatal_error(
sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小",
"TypeError")
# 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出)
if sz_resolved_name is None:
sz_resolved_name = "(unknown)"
HandlesType.fatal_error(
sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小",
"TypeError")
# 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64)
# __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct
# 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value
# 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点,
# 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0:
if len_at.value is not None and can == 0:
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, len_at.value, funcs_ptr, func_count, trans)
if obj_val is not None and obj_val.Ty is not None:
# 防御性类型检查: obj_val 必须是指针类型才能做 GEP
# 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、
# 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针,
# 导致 llc 报错 "base of getelementptr must be a pointer"
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
# 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误
HandlesType.fatal_error(
len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError")
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
# ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0
# 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__)
idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty_len, obj_val, idx_one)
if count_ptr is not None:
return llvmlite.build_load(builder, i64_ty_len, count_ptr)
# 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen
# len(s) 对 str 类型调用 strlen,返回 i64
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
if func_name is not None and string.strcmp(func_name, "len") == 0:
if can == 1:
len_arg_node: ast.AST | t.CPtr = cargs.get(0)
if len_arg_node is not None:
len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, len_arg_node, None, 0, trans)
if len_val is not None:
# len(数组):t.CArray[T, N] → 常量 N(对齐 TPC
# _HandleLenLlvm 的 ArrayType.count 分支)。数组变量
# translate_value 可能返回 Ptr([N x T])(alloca 指针)
# 或 [N x T] 值,两种都识别;否则会误走 strlen 把
# 数组首元素当字符串读 → 垃圾长度。
len_is_arr: int = 0
len_arr_n: int = 0
if len_val.Ty is not None:
if HandlesExpr.is_ptr_type(len_val.Ty) != 0:
len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee
if len_ap is not None:
match len_ap:
case llvmlite.LLVMType.Array(_, len_arr_cnt):
len_is_arr = 1
len_arr_n = len_arr_cnt
case _:
pass
else:
match len_val.Ty:
case llvmlite.LLVMType.Array(_, len_arr_cnt):
len_is_arr = 1
len_arr_n = len_arr_cnt
case _:
pass
if len_is_arr != 0:
return llvmlite.const_int64(pool, len_arr_n)
# len(对象):有 __len__ 就调用,没有就编译期报错
# (用户要求 2026-08-15,不再静默 strlen 读对象首字段):
# - list 泛型内置容器:__len__ 由 list 内置分支内联
# (读 __count__,偏移 1),不生成方法函数
# (_is_list_builtin_method,通用判断非特判)
# - 普通类:调用 {Class}.__len__ 函数
# - 都没有:fatal_error
# str(Ptr(Int8))保持 strlen(内建语义)。
len_struct_ty: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type_from_value(len_val)
if len_struct_ty is not None:
len_cls_nm: str = HandlesStruct.get_class_name_by_type(
pool, len_struct_ty)
if len_cls_nm is None:
HandlesType.fatal_error(
len_arg_node, "len() 参数类型推断失败(结构体类名未知)",
"TypeError")
# list 内置 __len__:读 __count__(GEP 偏移 1,i64)
if HandlesExprCall._is_list_builtin_method(len_cls_nm, "__len__") != 0:
i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty_lb, len_val, idx_one_lb)
if cnt_ptr_lb is not None:
return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb)
len_lookup: str = pool.alloc(128)
if len_lookup is not None:
viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm)
len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module(
mod, len_lookup)
if len_fn2 is not None:
len_ret_ty2: llvmlite.LLVMType | t.CPtr = \
llvmlite.function_get_ret_ty(len_fn2)
len_fn_name2: str = \
llvmlite.function_get_name(len_fn2)
if len_ret_ty2 is not None and len_fn_name2 is not None:
# self 参数类型对齐(按方法首个形参 bitcast)
len_self_arg2: llvmlite.Value | t.CPtr = len_val
len_first_param2: llvmlite.Param | t.CPtr = \
llvmlite.function_get_param_head(len_fn2)
if len_first_param2 is not None:
len_self_ty2: llvmlite.LLVMType | t.CPtr = \
llvmlite.param_get_ty(len_first_param2)
if len_self_ty2 is not None and len_val.Ty is not None:
len_self_arg2 = llvmlite.build_bitcast(
builder, len_val, len_self_ty2)
len_self_arg2.Next = None
return llvmlite.build_call(
builder, len_fn_name2, len_self_arg2,
1, len_ret_ty2, 0)
# len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__
# 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module
# 后缀匹配查不到。用结构体所属模块 sha1 构造
# {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call
# 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析,
# _ensure_method_declare 建 declare 后调用。
len_cls_sha1_x: str = HandlesStruct.get_struct_sha1(len_cls_nm)
if len_cls_sha1_x is not None:
# 缓冲区需容纳 "{sha1}.{cls}.__len__":
# 2 个点 + "__len__"(7) + NUL = 10;+8 会截断
# 末两位 → 符号变 ".__len" 链接 undefined
# (NumpyTest test_len 链接错误根因)
len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \
+ string.strlen(len_cls_nm) + 10
len_mangled_x: str = pool.alloc(len_ml_x)
if len_mangled_x is not None:
viperlib.snprintf(len_mangled_x, len_ml_x,
"%s.%s.__len__", len_cls_sha1_x, len_cls_nm)
len_ret_x: llvmlite.LLVMType | t.CPtr = \
self._LookupMethodRetTyFromTextLL(
pool, len_cls_sha1_x, len_cls_nm, "__len__")
if len_ret_x is None:
len_ret_x = self._lookup_method_ret_ty_via_vpi(
pool, len_cls_sha1_x, len_cls_nm, "__len__")
if len_ret_x is not None:
# self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧
# 同名类型链接匹配);len_val 已是 load 后的对象指针。
# Value 链直接作 param_head(同跨模块调用模式)。
len_self_x: llvmlite.Value | t.CPtr = len_val
len_self_x.Next = None
self._ensure_method_declare(
pool, mod, len_mangled_x, len_ret_x,
len_self_x, 1)
return llvmlite.build_call(
builder, len_mangled_x, len_self_x,
1, len_ret_x, 0)
# fail-fast:类没有 __len__(用户要求编译期报错)
HandlesType.fatal_error(
len_arg_node,
f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法",
"TypeError")
# 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast
len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val)
len_is_str: int = 0
if len_arg_ty is not None and HandlesExpr.is_ptr_type(len_arg_ty) != 0:
match len_arg_ty:
case llvmlite.LLVMType.Ptr(len_pt_ty):
if len_pt_ty is not None:
match len_pt_ty:
case llvmlite.LLVMType.Int(len_pt_bits):
if len_pt_bits == 8:
len_is_str = 1
case _:
pass
case _:
pass
if len_is_str != 0:
# 确保 strlen 在模块中有声明
strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen")
if strlen_fn is None:
i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln)
if strlen_fn is not None:
llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s")
# 参数类型转换为 i8*
i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
len_coerced: llvmlite.Value | t.CPtr = len_val
if HandlesExpr.is_ptr_type(len_arg_ty) != 0:
len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2)
# 构建单参数链表并调用 strlen
len_coerced.Next = None
i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0)
# fail-fast:非字符串/数组/对象,无法求长度
HandlesType.fatal_error(
len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)",
"TypeError")
# 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较
# isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable};
# NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
if func_name is not None and string.strcmp(func_name, "isinstance") == 0:
if can >= 2:
is_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_isinstance(
pool, builder, mod, cargs.get(0), cargs.get(1), trans)
if is_res is not None:
return is_res
return None
def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None)"""
# 检测类名静态/类方法调用: ClassName.method(args)
# 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时,
# 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if st_at is not None and st_at.value is not None and trans is not None:
if st_at.value.kind() == ast.ASTKind.Name:
st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value)
if st_nm.id is not None:
# 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法
# 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名
# Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...)
# 是模块限定调用(Module.Class 构造 / Module.func 函数),不是
# ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory.
# CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp
# 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 →
# 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远
# 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定
# 构造)与跨模块函数路径正确路由。
st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, st_nm.id)
if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None \
and HandlesImports.is_module_imported(
trans._imported_modules, st_nm.id) == 0:
# REnum 变体构造优先于静态/类方法调用:
# ClassName.VariantName(args)(如 Option.Some(42))若被当
# "实例方法经类名调用"处理,会把首实参 42 当 self 传
# _call_method_on_ptr → 查 "Option.Some" 方法返回类型 →
# 跨模块 stub 未命中 → fail-fast(EnumTest "方法
# 'Option.Some' 返回类型无法确定" 根因)。REnum 变体
# 构造检测原在 translate_call 尾部(L7493),被本分支
# 拦截先执行不到,此处提前检测。
if HandlesClassDef._is_renum_class_name(st_nm.id) != 0:
rc_tag_sc: int = HandlesClassDef._lookup_renum_variant_in_class(
st_nm.id, func_name)
if rc_tag_sc >= 0:
return HandlesExprCall._translate_renum_construct(
pool, builder, mod, st_nm.id, func_name,
rc_tag_sc, cargs, can, trans)
st_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_static_class_call(
pool, builder, mod, st_nm.id, func_name, cl, trans)
if st_res is not None:
return st_res
# 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args)
# (Python 语义,首参是 self 对象;zdeflate.vp
# zdeflate_stream.find_match(s, data, ...) 根因:_translate_
# static_class_call 对非静态方法返回 None 后,ClassName 被
# 通用路径当模块名 → "跨模块调用找不到模块 SHA1")
# st_nm.id == func_name(类名==方法名,如 CompilerFactory.
# CompilerFactory(...))不是实例方法调用而是构造调用:
# 模块名与类名同名时本分支把模块限定类构造误判为
# ClassName.method(obj,args),首实参当 self 传 →
# _call_method_on_ptr 查 "X.X" 返回类型永远落空 →
# fail-fast(main.vp CompilerFactory 追加84 根因)。
# 跳过本分支,落到 translate_call 尾部的 ctor 检测
# (L7426 模块限定类构造 find_struct_by_module 正确路由)。
if can >= 1 and cargs is not None \
and string.strcmp(st_nm.id, func_name) != 0:
im_self: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
if im_self is not None:
im_rem: t.CSizeT | t.CPtr = None
if can >= 2:
im_rem = pool.alloc(t.CSizeT(can - 1) * 8)
if im_rem is not None:
ri_im: t.CSizeT
for ri_im in range(can - 1):
im_rv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans)
if im_rv is not None:
im_rem[ri_im] = t.CSizeT(im_rv)
im_res: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr(
pool, builder, mod, st_nm.id, func_name,
im_self, im_rem, can - 1, trans)
if im_res is not None:
return im_res
elif st_at.value.kind() == ast.ASTKind.Attribute:
# 模块限定静态调用: module.ClassName.static_method(args)
# cl.func = Attribute(value=Attribute(value=Name(module),
# attr=ClassName), attr=method_name)
# 此前未检测 → 走通用路径把 method_name 当裸函数解析,
# 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接
# undefined reference(CPythonTest PyLongObj.from_long 根因)
st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value)
if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None:
if st_at2.value.kind() == ast.ASTKind.Name:
# ClassName 是已注册结构体类名时尝试静态/类方法
if HandlesStruct.get_struct_type(st_at2.attr) is not None:
st_res2: llvmlite.Value | t.CPtr = HandlesExprCall._translate_static_class_call(
pool, builder, mod, st_at2.attr, func_name, cl, trans)
if st_res2 is not None:
return st_res2
# 检测方法调用: obj.method(args)
# 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if method_at is not None and method_at.value is not None:
if method_at.value.kind() == ast.ASTKind.Name and trans is not None:
method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value)
if method_obj_nm.id is not None:
# 查找对象变量
obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, method_obj_nm.id)
if obj_var is not None and obj_var.Ty is not None:
# 检查是否为 Ptr(Struct(...))(结构体值变量)
# 或 Ptr(Ptr(Struct(...)))(指针变量,需 load)
match obj_var.Ty:
case llvmlite.LLVMType.Ptr(obj_struct_ty):
class_nm: str = HandlesStruct.get_class_name_by_type(
pool, obj_struct_ty)
if class_nm is not None:
# list 泛型内置容器方法(append/get/set/pop/clear/__iter__/
# __len__/__getitem__/__setitem__)由下方 list 内置分支
# (L5848 起)内联 GEP 处理,不注册方法函数;若走
# _translate_method_call 会查 append 返回类型(函数/text.ll/
# vpi stub 均未命中)→ fail-fast。检测到 list 方法时
# 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。
if HandlesExprCall._is_list_builtin_method(class_nm, func_name) == 0:
return HandlesExprCall._translate_method_call(
pool, builder, mod, class_nm, func_name,
obj_var, cl, trans)
# 指针变量: alloca 类型是 Ptr(Ptr(Struct))
# load 获取实际指针 Ptr(Struct) 后再查找
match obj_struct_ty:
case llvmlite.LLVMType.Ptr(inner_struct_ty):
inner_nm: str = HandlesStruct.get_class_name_by_type(
pool, inner_struct_ty)
if inner_nm is not None:
# list 内置方法同样跳过(同 Ptr(Struct) 分支)
if HandlesExprCall._is_list_builtin_method(inner_nm, func_name) == 0:
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, obj_struct_ty, obj_var)
if obj_ptr is not None:
return HandlesExprCall._translate_method_call(
pool, builder, mod, inner_nm, func_name,
obj_ptr, cl, trans)
# FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空)
# 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。
# 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法
# (find_func_in_module 未命中返回 None,不影响正常路径)。
fd_name_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call(
pool, builder, mod, None, func_name, cl, trans)
if fd_name_res is not None:
return fd_name_res
# AnnotClassName 回退:联合类型简化为 Ptr(i8) 时,
# 通过原始类型注解的类名查找结构体
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, method_obj_nm.id)
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
# 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy"
dot_ptr: str = string.strrchr(annot_val, '.')
cls_nm2: str = annot_val
mod_nm2: str = None
if dot_ptr is not None:
cls_nm2 = dot_ptr + 1
total_len_av: t.CSizeT = string.strlen(annot_val)
cls_len_av: t.CSizeT = string.strlen(cls_nm2)
mod_len2: t.CSizeT = total_len_av - cls_len_av - 1
mod_nm2 = pool.alloc(mod_len2 + 1)
if mod_nm2 is not None:
string.strncpy(mod_nm2, annot_val, mod_len2)
mod_nm2[mod_len2] = '\0'
# 检查结构体是否已注册
if HandlesStruct.get_struct_type(cls_nm2) is not None:
# list 内置方法跳过 method_call(同 Ptr(Struct) 分支),
# 落到下方 list 内置分支
if HandlesExprCall._is_list_builtin_method(cls_nm2, func_name) == 0:
# 结构体已注册:load obj_ptr 走方法调用
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty2, obj_var)
if obj_ptr2 is not None:
return HandlesExprCall._translate_method_call(
pool, builder, mod, cls_nm2, func_name,
obj_ptr2, cl, trans)
else:
# list 内置方法跳过(结构体未注册路径同样不能
# 构造 {sha1}.{cls}.append 调用名——list 方法无此函数)
if HandlesExprCall._is_list_builtin_method(cls_nm2, func_name) == 0:
# FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
# a.type_id() / a.upper() / " ".isspace() 等
# AnnotClassName=="str" 且对象是 char* 时触发,
# self 用影子结构体 {a}__meta__(或临时影子)。
fd_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call(
pool, builder, mod, cls_nm2, func_name, cl, trans)
if fd_res is not None:
return fd_res
# 结构体未注册(跨模块依赖未翻译):
# 用模块名查 SHA1 构造方法调用名
sha1_fc: str = None
if mod_nm2 is not None:
sha1_fc = self._lookup_module_sha1(mod_nm2)
if sha1_fc is not None:
# 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名
mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3
mangled3: str = pool.alloc(mlen3)
if mangled3 is not None:
viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name)
# load obj_ptr (self)
i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty3, obj_var)
if obj_ptr3 is not None:
# 构建参数链表: obj_ptr3 (self) → 其他参数
llvmlite.value_set_next(obj_ptr3, None)
head3: llvmlite.Value | t.CPtr = obj_ptr3
tail3: llvmlite.Value | t.CPtr = obj_ptr3
for ai3 in range(can):
arg3: ast.AST | t.CPtr = cargs.get(ai3)
if arg3 is not None:
arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg3, None, 0, trans)
if arg_val3 is not None:
llvmlite.value_set_next(arg_val3, None)
llvmlite.value_set_next(tail3, arg_val3)
tail3 = arg_val3
total3: int = 1 + can
ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(
pool, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = self._LookupMethodRetTyFromTextLL(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
ret_ty3 = self._lookup_method_ret_ty_via_vpi(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
# 本分支仅在"注解类结构体未注册"时到达(L6932 else):
# 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。
# 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value
# 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是
# {AssignGenMixin_sha1}.AssignGenMixin.xxx,查
# {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因;
# sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断
# 只是次要因素)。必须标记 pending:等 Generator 注册后
# 下遍走 L6919 已注册分支 → _translate_method_call 沿
# MRO 链找到 AssignGenMixin → 精确解析。真正不存在的
# 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast
# 中断多遍收敛(对齐追加77/77b 类 defer 原则)。
if trans is not None:
trans._deps_pending = 1
ret_ty3 = llvmlite.Void(pool)
self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
# ============================================================
# 检测表达式接收者方法调用: (expr).method(args)
#
# 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时
# (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者,
# 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。
# ============================================================
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if expr_method_at is not None and expr_method_at.value is not None and trans is not None:
evk: int = expr_method_at.value.kind()
# Attribute 接收者区分两种形态:
# 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入
# 模块或 t/c,留给下方跨模块限定路径处理
# 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc)
# ——根名是对象(self/局部变量),必须走本方法调用路径;
# 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块
# SHA1"(zdeflate.vp write_fixed_block 根因)
is_mod_path_expr: int = 0
if evk == ast.ASTKind.Attribute:
expr_root: ast.AST | t.CPtr = expr_method_at.value
while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute:
expr_root = (ast.Attribute | t.CPtr)(expr_root).value
if expr_root is not None and expr_root.kind() == ast.ASTKind.Name:
expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id
if expr_root_nm is not None:
if string.strcmp(expr_root_nm, "t") == 0 or \
string.strcmp(expr_root_nm, "c") == 0:
is_mod_path_expr = 1
elif trans._imported_modules is not None:
if HandlesImports.is_module_imported(
trans._imported_modules, expr_root_nm) != 0:
is_mod_path_expr = 1
if evk != ast.ASTKind.Name and is_mod_path_expr == 0:
# 翻译接收者表达式(求值结果应为 Ptr(Struct))
expr_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
if expr_obj is not None and expr_obj.Ty is not None:
expr_cls_nm: str = None
# 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct))
# (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法
# 调用被当裸函数 @dot 解析 → 链接 undefined symbol
expr_struct_ty: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type_from_value(expr_obj)
if expr_struct_ty is not None:
expr_cls_nm = HandlesStruct.get_class_name_by_type(
pool, expr_struct_ty)
# 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时,
# 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...)
# 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解)
# 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例
if expr_cls_nm is None:
import lib.core.Gen.Generator as Generator
g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g3 is not None:
expr_cls_nm = g3.infer_expr_class(
pool, mod, expr_method_at.value, trans)
if expr_cls_nm is not None:
# 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段):
# 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值,
# 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 →
# 被调方把值当 this 指针解引用 → GEP 0x18 崩溃
# (s.writer.write_zlib_header 运行时 access-violation 根因;
# 本路径 evk=Attribute 先于 self.field.method() 分支命中)。
expr_is_ptr: int = 0
match expr_obj.Ty:
case llvmlite.LLVMType.Ptr(expr_ptr_inner):
expr_is_ptr = 1
case _:
expr_is_ptr = 0
if expr_is_ptr == 0:
expr_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, expr_method_at.value, trans)
if expr_addr is not None:
expr_obj = expr_addr
return HandlesExprCall._translate_method_call(
pool, builder, mod, expr_cls_nm, func_name,
expr_obj, cl, trans)
# FakeDuck: 表达式接收者解析失败且对象是 char* 时
# (如 " ".isspace()),尝试扩展类 _Type/_str 方法
# (self 用临时影子,对齐 TPC L2858-2873)
fd_expr_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call(
pool, builder, mod, None, func_name, cl, trans)
if fd_expr_res is not None:
return fd_expr_res
# ============================================================
# 检测 self.field.method() 调用
#
# 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时,
# 翻译字段值获取对象指针,然后走方法调用路径。
#
# 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager")))
# 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时)
# ============================================================
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if attr_method_at is not None and attr_method_at.value is not None:
if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None:
inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value)
if inner_attr is not None and inner_attr.attr is not None:
# 翻译 self.__pool__ 获取字段值(已 load 的对象指针)
field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans)
if field_obj is not None and field_obj.Ty is not None:
field_cls_nm: str = None
# 路径1: 从字段值的 LLVM 类型获取类名
match field_obj.Ty:
case llvmlite.LLVMType.Ptr(field_struct_ty):
field_cls_nm = HandlesStruct.get_class_name_by_type(
pool, field_struct_ty)
# 路径2: 从字段注解类名回退查找
if field_cls_nm is None:
if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name:
inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value)
if inner_name_node is not None and inner_name_node.id is not None:
inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, inner_name_node.id)
if inner_var is not None and inner_var.Ty is not None:
match inner_var.Ty:
case llvmlite.LLVMType.Ptr(field_owner_struct_ty):
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
field_owner_struct_ty, inner_attr.attr)
if field_info is not None:
field_annot: str = HandlesStruct.get_field_annot_class_name(field_info)
if field_annot is not None:
dot_p: str = string.strrchr(field_annot, 46)
if dot_p is not None:
field_cls_nm = dot_p + 1
else:
field_cls_nm = field_annot
if field_cls_nm is not None:
# 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer)
# 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值:
# 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配,
# 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃
# (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。
is_val_field: int = 0
match field_obj.Ty:
case llvmlite.LLVMType.Ptr(field_ptr_inner):
is_val_field = 0
case _:
is_val_field = 1
if is_val_field != 0:
field_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, attr_method_at.value, trans)
if field_addr is not None:
field_obj = field_addr
return HandlesExprCall._translate_method_call(
pool, builder, mod, field_cls_nm, func_name,
field_obj, cl, trans)
# ============================================================
# 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__()
# list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理,
# 需要在此特殊处理。
# list 结构布局 (6 字段 × 8 字节):
# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
# ============================================================
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if lm_at is not None and lm_at.attr is not None and lm_at.value is not None:
lm_name: str = lm_at.attr
# 判断是否是 list 方法名
lm_is_list: int = 0
if string.strcmp(lm_name, "get") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1
if lm_is_list == 1 and trans is not None:
# 翻译 list 对象
lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans)
if lm_obj is not None:
# 防御性类型检查: lm_obj 必须是指针类型才能做 GEP
# translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性)
# 可能返回 i32 0 (非指针),直接 GEP 会导致
# "base of getelementptr must be a pointer" 错误
if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0:
# translate_value 类型推断失败(目标对象非指针):
# fail-fast,绝不 VLogger.critical 后 return None 静默吞掉
HandlesType.fatal_error(
lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError")
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)
# 元素类型 T:从 list 特化类型名解析(list[int]→i32、
# list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop
# 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素
# (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0),
# pop 读回 0 → ListTest "pop FAILED expect 30" 根因。
# subscript 路径(list_getitem_inline 调用方)已用
# _list_elem_type_from_name 修正,方法调用路径漏改。
lm_esty: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type_from_value(lm_obj)
lm_ename: str = None
if lm_esty is not None:
lm_ename = llvmlite.get_struct_name(lm_esty)
lm_elem_ty: llvmlite.LLVMType | t.CPtr = None
if lm_ename is not None:
import lib.core.Gen.Generator as Generator
g_le: Generator.Generator | t.CPtr = (
Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g_le is not None:
lm_elem_ty = g_le._list_elem_type_from_name(
pool, lm_ename)
if lm_elem_ty is None:
lm_elem_ty = i8_ptr_ty
# get / __getitem__: 返回 index 处的元素
if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0:
if can >= 1:
# 加载 __data__ (偏移 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)
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)
g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
# 翻译 index
g_idx_node: ast.AST | t.CPtr = cargs.get(0)
g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, g_idx_node, None, 0, trans)
if g_data is not None and g_esize is not None and g_idx_val is not None:
g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, g_idx_val, i64_ty, g_idx_node)
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
if g_addr is not None:
g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty))
if g_ep is not None:
return llvmlite.build_load(builder, lm_elem_ty, g_ep)
# set / __setitem__: 设置 index 处的元素
elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0:
if can >= 2:
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)
s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
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)
s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
s_idx_node: ast.AST | t.CPtr = cargs.get(0)
s_val_node: ast.AST | t.CPtr = cargs.get(1)
s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, s_idx_node, None, 0, trans)
s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, s_val_node, None, 0, trans)
if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None:
s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, s_idx_val, i64_ty, s_idx_node)
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
if s_addr is not None:
s_val_elem: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, s_val_val, lm_elem_ty, s_val_node)
s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty))
if s_ep is not None:
llvmlite.build_store(builder, s_val_elem, s_ep)
return None
# pop: 返回最后一个元素,count--
elif string.strcmp(lm_name, "pop") == 0:
p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1)
p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp)
p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub(
builder, p_count, llvmlite.const_int64(pool, 1))
llvmlite.build_store(builder, p_nc, p_cpp)
p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0)
p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp)
p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4)
p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp)
if p_data is not None and p_esize is not None and p_nc is not None:
p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize)
p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset)
if p_addr is not None:
p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty))
if p_ep is not None:
return llvmlite.build_load(builder, lm_elem_ty, p_ep)
# clear: count = 0
elif string.strcmp(lm_name, "clear") == 0:
c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp)
return None
# __iter__: iter_index = 0, return self
elif string.strcmp(lm_name, "__iter__") == 0:
it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5)
it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp)
return lm_obj
# append: 直接调用 list.append(self, item)
# append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现
elif string.strcmp(lm_name, "append") == 0:
if can >= 1:
ap_sha1: str = self._lookup_module_sha1("_list")
if ap_sha1 is None:
# 依赖模块未编译(_list 未预加入编译链):fail-fast,
# 绝不静默跳过 append(元素永远不会被加入列表)
HandlesType.fatal_error(
cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)",
"InternalCompilerError")
if ap_sha1 is not None:
# 特化类名提取:list.append 的符号名是
# {sha1}.list[AST|CPtr].append(带类型参数特化名),
# 而非 {sha1}.list.append。lm_obj 类型即特化结构体
# Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名,
# 否则 ld.lld undefined symbol(定义端是特化名)。
ap_spec_nm: str = None
ap_struct_ty: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type_from_value(lm_obj)
if ap_struct_ty is not None:
ap_spec_nm = HandlesStruct.get_class_name_by_type(
pool, ap_struct_ty)
if ap_spec_nm is None:
ap_spec_nm = "list"
# 触发泛型特化翻译(幂等,MethodsEmitted 防重入):
# list[AST|CPtr].append 的 define 方法体在特化类翻译时
# 生成。仅构造调用名不触发特化会导致定义缺失
# (ld.lld undefined symbol: list[AST|CPtr].append)。
if trans is not None and ap_spec_nm is not None:
lbkt_ap: str = string.strchr(ap_spec_nm, '[')
if lbkt_ap is not None:
rbkt_ap: str = string.strrchr(ap_spec_nm, ']')
if rbkt_ap is not None and rbkt_ap > lbkt_ap:
base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm))
arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1)
if base_len_ap > 0 and arg_len_ap > 0:
base_buf_ap: str = pool.alloc(base_len_ap + 1)
arg_buf_ap: str = pool.alloc(arg_len_ap + 1)
if base_buf_ap is not None and arg_buf_ap is not None:
string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap)
base_buf_ap[base_len_ap] = '\0'
string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap)
arg_buf_ap[arg_len_ap] = '\0'
args_ap: list[str] | t.CPtr = list[str](pool, 8)
if args_ap is not None:
# 逗号分隔多类型实参(list[X] / dict[K, V])
cur_ap: str = arg_buf_ap
while cur_ap is not None:
comma_ap: str = string.strchr(cur_ap, ',')
if comma_ap is None:
args_ap.append(cur_ap)
break
seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap))
seg_buf_ap: str = pool.alloc(seg_len_ap + 1)
if seg_buf_ap is not None:
string.strncpy(seg_buf_ap, cur_ap, seg_len_ap)
seg_buf_ap[seg_len_ap] = '\0'
args_ap.append(seg_buf_ap)
cur_ap = comma_ap + 1
HandlesClassDef._specialize_generic_class(
trans, base_buf_ap, args_ap)
# 调用名 "{sha1}.{spec}.append":
# sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。
# 此前 +8 少 1 字节,snprintf 截断末尾 'd' →
# undefined symbol: ...list[AST|CPtr].appen(缺 d)。
ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \
string.strlen(ap_spec_nm) + 26
ap_mangled: str = pool.alloc(ap_mlen)
if ap_mangled is not None:
viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append",
ap_sha1, ap_spec_nm)
ap_item_node: ast.AST | t.CPtr = cargs.get(0)
ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ap_item_node, None, 0, trans)
if ap_item_val is not None:
llvmlite.value_set_next(lm_obj, None)
llvmlite.value_set_next(ap_item_val, None)
llvmlite.value_set_next(lm_obj, ap_item_val)
ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2)
return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0)
return None