- Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用 - 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等) - 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成) - 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable) - 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化
981 lines
54 KiB
Plaintext
981 lines
54 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import 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.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
|
||
import lib.core.Gen.CallGenBase as CallGenBase
|
||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||
|
||
# ============================================================
|
||
# CallGenCtor - CallGenMixin 拆分(阶段 B):结构体构造 / 枚举构造 / 泛型构造 / 类型转换
|
||
#
|
||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenCtor(CallGenBase.CallGenBase):
|
||
"""结构体构造 / 枚举构造 / 泛型构造 / 类型转换"""
|
||
|
||
# ============================================================
|
||
# _apply_struct_defaults — 应用结构体字段的默认值
|
||
#
|
||
# 在 zeroinitializer 之后、显式参数之前调用
|
||
# 遍历所有字段,对有默认值的字段翻译并 store
|
||
# 显式参数(位置/关键字)后续会覆盖默认值
|
||
# ============================================================
|
||
def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
struct_ty: llvmlite.LLVMType | t.CPtr,
|
||
class_name: str,
|
||
tmp: llvmlite.Value | t.CPtr,
|
||
trans: HT.Translator | t.CPtr):
|
||
"""应用结构体字段的默认值"""
|
||
# 用类型指针定位 entry,规避跨模块同名 find_struct 找错
|
||
entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||
if entry is None:
|
||
# fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化
|
||
VLogger.error(
|
||
f"结构体类型未注册,无法应用默认值: {class_name}",
|
||
"HandlesExprCall")
|
||
return
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
entry, fi)
|
||
if fe is None:
|
||
# fast-fail: 字段索引越界(entry.FieldCount 与实际不一致)
|
||
VLogger.error(
|
||
f"字段索引越界,无法获取字段 entry: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
if fe.DefaultVal is None:
|
||
continue # 合理跳过:无默认值的字段
|
||
# 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store
|
||
# (与 _generate_before_init 一致;translate_value 会把列表字面量
|
||
# 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。
|
||
# Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。
|
||
if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \
|
||
and fe.DefaultVal.kind() == ast.ASTKind.List:
|
||
field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr_arr2 is not None:
|
||
zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty)
|
||
if zero_arr2 is not None:
|
||
llvmlite.build_store(builder, zero_arr2, field_ptr_arr2)
|
||
self.Gen.AssignGen._init_global_array_from_list(
|
||
builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans)
|
||
continue
|
||
default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, fe.DefaultVal, None, 0, trans)
|
||
if default_val is None:
|
||
# fast-fail: 默认值翻译失败(如引用了未定义符号)
|
||
VLogger.error(
|
||
f"字段默认值翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr is None:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"字段 GEP 失败,类型不匹配: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal)
|
||
llvmlite.build_store(builder, default_val, field_ptr)
|
||
# ============================================================
|
||
# _translate_struct_ctor — 结构体构造函数 Point(10, 20)
|
||
#
|
||
# 生成:
|
||
# %tmp = alloca {i32, i32}
|
||
# store {i32, i32} zeroinitializer, {i32, i32}* %tmp
|
||
# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0
|
||
# store i32 10, i32* %f0
|
||
# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1
|
||
# store i32 20, i32* %f1
|
||
# %result = load {i32, i32}, {i32, i32}* %tmp
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
struct_ty: llvmlite.LLVMType | t.CPtr,
|
||
class_name: str,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""结构体构造函数:按字段顺序 store 参数值,返回结构体值
|
||
|
||
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
|
||
普通结构体:alloca → zero + defaults → store 参数 → load
|
||
"""
|
||
# 创建临时 alloca
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
|
||
if tmp is None:
|
||
return llvmlite.ConstZero(pool, struct_ty)
|
||
# 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的
|
||
# fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点)
|
||
diag_node_ct: ast.AST | t.CPtr = None
|
||
if cargs is not None and len(cargs) > 0:
|
||
diag_node_ct = cargs.get(0)
|
||
|
||
# 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错)
|
||
ctor_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||
is_oop: int = 0
|
||
if ctor_entry is not None:
|
||
is_oop = ctor_entry.IsOOP
|
||
|
||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||
if is_oop == 0 and class_name is not None:
|
||
init_lookup_name: str = pool.alloc(128)
|
||
if init_lookup_name is not None:
|
||
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
|
||
# 方案1: 检查当前模块的函数声明
|
||
init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name)
|
||
if init_found_func is not None:
|
||
is_oop = 1
|
||
if ctor_entry is not None:
|
||
ctor_entry.IsOOP = 1
|
||
ctor_entry.HasInit = 1
|
||
else:
|
||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||
init_defaults_entry: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(init_lookup_name)
|
||
if init_defaults_entry is not None:
|
||
is_oop = 1
|
||
if ctor_entry is not None:
|
||
ctor_entry.IsOOP = 1
|
||
ctor_entry.HasInit = 1
|
||
|
||
if is_oop != 0:
|
||
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
|
||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||
|
||
# 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针
|
||
# __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty)
|
||
has_new_flag: int = 0
|
||
if ctor_entry is not None:
|
||
has_new_flag = ctor_entry.HasNew
|
||
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
|
||
if has_new_flag != 0:
|
||
new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if new_arg_vals is not None:
|
||
string.memset(new_arg_vals, 0, 8 * 32)
|
||
new_arg_count: int = 0
|
||
for nai in range(can):
|
||
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
|
||
if new_arg_node is None:
|
||
continue
|
||
new_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, new_arg_node, None, 0, trans)
|
||
if new_av is not None:
|
||
if new_arg_count < 32:
|
||
new_arg_vals[new_arg_count] = t.CSizeT(new_av)
|
||
new_arg_count += 1
|
||
|
||
new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, class_name,
|
||
"__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
|
||
if new_ptr is not None:
|
||
storage_ptr = new_ptr
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
|
||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__before_init__", storage_ptr, None, 0, trans, diag_node_ct)
|
||
|
||
# 如果有 __init__,调用 __init__(ptr, args...)
|
||
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
|
||
# (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference)
|
||
has_init_flag: int = 0
|
||
if ctor_entry is not None:
|
||
has_init_flag = ctor_entry.HasInit
|
||
if has_init_flag != 0:
|
||
# 翻译构造函数参数
|
||
arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if arg_vals is not None:
|
||
string.memset(arg_vals, 0, 8 * 32)
|
||
real_arg_count: int = 0
|
||
for ai in range(can):
|
||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg_node is None:
|
||
continue
|
||
av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node, None, 0, trans)
|
||
if av is not None:
|
||
if real_arg_count < 32:
|
||
arg_vals[real_arg_count] = t.CSizeT(av)
|
||
real_arg_count += 1
|
||
|
||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct)
|
||
elif has_new_flag == 0:
|
||
# 无 __init__ 且无 __new__:逐字段 store 参数值
|
||
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None:
|
||
# fast-fail: 参数翻译失败
|
||
VLogger.error(
|
||
f"构造函数参数翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||
if ctor_entry is not None:
|
||
# OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位),
|
||
# 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段,
|
||
# 否则参数会覆盖 vtable 槽(对象头读到垃圾指针,
|
||
# isinstance 的 icmp 全部不匹配 + 方法分派错乱)。
|
||
# 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__
|
||
# → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。
|
||
target_idx: int = 0
|
||
for fi in range(ctor_entry.FieldCount):
|
||
cand_fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
ctor_entry, fi)
|
||
if cand_fe is None:
|
||
continue
|
||
cand_name: str = self.Gen.StructGen.get_field_name_ptr(cand_fe)
|
||
if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0:
|
||
continue
|
||
if target_idx == ai:
|
||
fe = cand_fe
|
||
break
|
||
target_idx += 1
|
||
else:
|
||
fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||
if fe is None:
|
||
# fast-fail: 字段索引越界(用户传了多余参数)
|
||
VLogger.error(
|
||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, storage_ptr, fe.Index)
|
||
if field_ptr is None:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"构造函数字段 GEP 失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, field_ptr)
|
||
|
||
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
|
||
return storage_ptr
|
||
|
||
# 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零)
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
|
||
llvmlite.build_store(builder, zero, tmp)
|
||
|
||
# 应用默认值(显式参数会覆盖默认值)
|
||
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
|
||
|
||
# 逐字段 store 参数值(覆盖默认值)
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None:
|
||
# fast-fail: 参数翻译失败
|
||
VLogger.error(
|
||
f"构造函数参数翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
# 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错)
|
||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||
if ctor_entry is not None:
|
||
fe = self.Gen.StructGen._get_field_entry(ctor_entry, ai)
|
||
else:
|
||
fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||
if fe is None:
|
||
# fast-fail: 字段索引越界(用户传了多余参数)
|
||
VLogger.error(
|
||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
# GEP 到字段 ai
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr is None:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"构造函数字段 GEP 失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
# 类型转换并 store
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, field_ptr)
|
||
|
||
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
|
||
return tmp
|
||
# ============================================================
|
||
# _translate_renum_construct — REnum 变体构造函数
|
||
#
|
||
# 语法: ClassName.VariantName(args...)
|
||
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1
|
||
#
|
||
# 生成 IR:
|
||
# %tmp = alloca {i32, i32, ...} ; REnum 类型
|
||
# store zeroinitializer, %tmp ; 清零
|
||
# %tag_ptr = gep %tmp, 0, 0 ; __tag 字段
|
||
# store i32 <tag_value>, %tag_ptr ; 写入 tag
|
||
# %p1_ptr = gep %tmp, 0, 1 ; _p1 字段
|
||
# store <coerced_arg0>, %p1_ptr ; 写入 payload[0]
|
||
# ... (更多 payload 字段)
|
||
# return %tmp ; 返回指针
|
||
#
|
||
# 对应 TPC 的 _HandleREnumConstructLlvm
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
variant_name: str,
|
||
tag_value: int,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""构造 REnum 变体实例,返回指向 alloca 的指针
|
||
|
||
class_name: REnum 类名(如 "LLVMType")
|
||
variant_name: 变体名(如 "Int")
|
||
tag_value: 变体的 tag 值(变体在类中的索引)
|
||
cargs: 参数 AST 列表
|
||
can: 参数数量
|
||
"""
|
||
if pool is None or builder is None or class_name is None:
|
||
return None
|
||
|
||
# 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名)
|
||
renum_entry: GenTypes.StructEntry | t.CPtr = None
|
||
if trans is not None:
|
||
renum_entry = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
|
||
if renum_entry is None:
|
||
renum_entry = self.Gen.StructGen.find_struct(class_name)
|
||
if renum_entry is None:
|
||
fb_re: str = VLogger.fmt_buf()
|
||
if fb_re is not None:
|
||
viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name)
|
||
VLogger.error(fb_re, "RENUM")
|
||
return None
|
||
|
||
renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty
|
||
if renum_ty is None:
|
||
return None
|
||
|
||
# alloca REnum 类型
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, renum_ty)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty)
|
||
if tmp is None:
|
||
return llvmlite.ConstZero(pool, renum_ty)
|
||
|
||
# 清零(确保未赋值的 payload 位置为零)
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty)
|
||
llvmlite.build_store(builder, zero, tmp)
|
||
|
||
# 写入 __tag 字段(索引 0)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
tag_name_buf: str = pool.alloc(32)
|
||
if tag_name_buf is not None:
|
||
viperlib.snprintf(tag_name_buf, 32, "%d", tag_value)
|
||
tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||
pool, i32_ty, tag_value,
|
||
tag_name_buf if tag_name_buf is not None else "0")
|
||
tag_field: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(renum_entry, 0)
|
||
tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if tag_field is not None and tag_field.Ty is not None:
|
||
tag_field_ty = tag_field.Ty
|
||
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, renum_ty, tag_field_ty, tmp, 0)
|
||
if tag_ptr is not None:
|
||
llvmlite.build_store(builder, tag_const, tag_ptr)
|
||
|
||
# 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...)
|
||
# 参数按位置顺序填充 payload,跳过 __tag(索引 0)
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None:
|
||
continue
|
||
# payload 字段索引 = ai + 1(跳过 __tag)
|
||
payload_idx: int = ai + 1
|
||
if payload_idx >= renum_entry.FieldCount:
|
||
break
|
||
pfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
renum_entry, payload_idx)
|
||
if pfe is None:
|
||
continue
|
||
payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, renum_ty, pfe.Ty, tmp, payload_idx)
|
||
if payload_ptr is None:
|
||
continue
|
||
# 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce)
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pfe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, payload_ptr)
|
||
|
||
# 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load)
|
||
return tmp
|
||
# ============================================================
|
||
# _translate_struct_ctor_kw — 结构体构造函数(关键字参数)
|
||
#
|
||
# 支持两种语法:
|
||
# Point(x=10, y=20) — 全关键字
|
||
# Point(10, y=20) — 混合(位置 + 关键字)
|
||
#
|
||
# 位置参数按字段索引赋值,关键字参数按字段名查找赋值
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
struct_ty: llvmlite.LLVMType | t.CPtr,
|
||
class_name: str,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
keywords: list[ast.AST | t.CPtr] | t.CPtr,
|
||
kw_count: t.CSizeT,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""结构体构造函数(关键字参数版本)"""
|
||
# 创建临时 alloca
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
|
||
if tmp is None:
|
||
return llvmlite.ConstZero(pool, struct_ty)
|
||
# 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的
|
||
# fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点)
|
||
diag_node_ct: ast.AST | t.CPtr = None
|
||
if cargs is not None and len(cargs) > 0:
|
||
diag_node_ct = cargs.get(0)
|
||
|
||
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
|
||
# 用 find_struct_by_type 规避跨模块同名 find_struct 找错
|
||
kw_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||
is_oop: int = 0
|
||
if kw_entry is not None:
|
||
is_oop = kw_entry.IsOOP
|
||
|
||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||
if is_oop == 0 and class_name is not None:
|
||
kw_init_lookup: str = pool.alloc(128)
|
||
if kw_init_lookup is not None:
|
||
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
|
||
# 方案1: 检查当前模块的函数声明
|
||
kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup)
|
||
if kw_init_found is not None:
|
||
is_oop = 1
|
||
if kw_entry is not None:
|
||
kw_entry.IsOOP = 1
|
||
kw_entry.HasInit = 1
|
||
else:
|
||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||
kw_init_defaults: FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(kw_init_lookup)
|
||
if kw_init_defaults is not None:
|
||
is_oop = 1
|
||
if kw_entry is not None:
|
||
kw_entry.IsOOP = 1
|
||
kw_entry.HasInit = 1
|
||
|
||
if is_oop != 0:
|
||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__before_init__", tmp, None, 0, trans)
|
||
else:
|
||
# 普通结构体:store zeroinitializer + 应用默认值
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
|
||
llvmlite.build_store(builder, zero, tmp)
|
||
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
|
||
|
||
# OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store
|
||
# 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行
|
||
# (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃)
|
||
has_init_flag: int = 0
|
||
has_new_flag: int = 0
|
||
if kw_entry is not None:
|
||
has_init_flag = kw_entry.HasInit
|
||
has_new_flag = kw_entry.HasNew
|
||
|
||
# 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用)
|
||
# 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在)
|
||
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
|
||
if is_oop != 0 and has_init_flag == 0:
|
||
has_init_flag = 1
|
||
|
||
if is_oop != 0 and has_init_flag != 0:
|
||
# 有 __init__:构建参数数组并调用 __init__
|
||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||
|
||
# 如果有 __new__,调用 __new__ 获取实际存储指针
|
||
if has_new_flag != 0:
|
||
new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if new_arg_vals is not None:
|
||
string.memset(new_arg_vals, 0, 8 * 32)
|
||
new_arg_count: int = 0
|
||
for nai in range(can):
|
||
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
|
||
if new_arg_node is None:
|
||
continue
|
||
new_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, new_arg_node, None, 0, trans)
|
||
if new_av is not None:
|
||
if new_arg_count < 32:
|
||
new_arg_vals[new_arg_count] = t.CSizeT(new_av)
|
||
new_arg_count += 1
|
||
# 关键字参数也传递给 __new__
|
||
for nki in range(kw_count):
|
||
nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki))
|
||
if nkw is None or nkw.value is None:
|
||
continue
|
||
nkw_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, nkw.value, None, 0, trans)
|
||
if nkw_av is not None:
|
||
if new_arg_count < 32:
|
||
new_arg_vals[new_arg_count] = t.CSizeT(nkw_av)
|
||
new_arg_count += 1
|
||
new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, class_name,
|
||
"__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
|
||
if new_ptr is not None:
|
||
storage_ptr = new_ptr
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加
|
||
init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if init_arg_vals is not None:
|
||
string.memset(init_arg_vals, 0, 8 * 32)
|
||
init_arg_count: int = 0
|
||
# 位置参数
|
||
for ai_init in range(can):
|
||
arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init)
|
||
if arg_node_init is None:
|
||
continue
|
||
av_init: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node_init, None, 0, trans)
|
||
if av_init is not None:
|
||
if init_arg_count < 32:
|
||
init_arg_vals[init_arg_count] = t.CSizeT(av_init)
|
||
init_arg_count += 1
|
||
# 关键字参数(追加到末尾,按出现顺序)
|
||
for ki_init in range(kw_count):
|
||
kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init))
|
||
if kw_init is None or kw_init.value is None:
|
||
continue
|
||
kw_av_init: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, kw_init.value, None, 0, trans)
|
||
if kw_av_init is not None:
|
||
if init_arg_count < 32:
|
||
init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init)
|
||
init_arg_count += 1
|
||
|
||
# 调用 __init__(storage_ptr, *args)
|
||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct)
|
||
|
||
# 返回指针
|
||
return storage_ptr
|
||
|
||
# 无 __init__(或非 OOP):逐字段 store 参数值
|
||
# 先处理位置参数(按字段索引,覆盖默认值)
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is None:
|
||
continue
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is None:
|
||
continue
|
||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||
if kw_entry is not None:
|
||
fe = self.Gen.StructGen._get_field_entry(kw_entry, ai)
|
||
else:
|
||
fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||
if fe is None:
|
||
# 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError")
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr is None:
|
||
continue
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, field_ptr)
|
||
|
||
# 处理关键字参数(按字段名查找)
|
||
# SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错)
|
||
kw_sha1: str = None
|
||
if kw_entry is not None:
|
||
kw_sha1 = kw_entry.ModuleSha1
|
||
for ki in range(kw_count):
|
||
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
|
||
if kw is None or kw.arg is None or kw.value is None:
|
||
continue
|
||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class(
|
||
class_name, kw.arg, kw_sha1)
|
||
if fe is None:
|
||
# 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError")
|
||
continue
|
||
kw_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, kw.value, None, 0, trans)
|
||
if kw_val is None:
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr is None:
|
||
continue
|
||
kw_val = self.Gen.ExprGenBase.coerce_to_type(builder, kw_val, fe.Ty, kw.value)
|
||
llvmlite.build_store(builder, kw_val, field_ptr)
|
||
|
||
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
|
||
return tmp
|
||
# ============================================================
|
||
# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换
|
||
#
|
||
# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时,
|
||
# 将 value 转换为目标类型:
|
||
# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64)
|
||
# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*)
|
||
# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8)
|
||
# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*)
|
||
# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double)
|
||
# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32)
|
||
# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
val: llvmlite.Value | t.CPtr,
|
||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||
target_name: str = None,
|
||
src_node: ast.AST | t.CPtr = None,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""类型转换:根据参数类型和目标类型选择转换方式
|
||
|
||
整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737):
|
||
源 i1(bool)→ zext
|
||
目标类型无符号(target_name 命中 CUIntXXT 等)→ zext
|
||
源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext
|
||
否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE)
|
||
"""
|
||
if val is None or target_ty is None:
|
||
return None
|
||
|
||
val_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||
target_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(target_ty)
|
||
val_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
||
target_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(target_ty)
|
||
|
||
# 整数 → 整数: trunc/zext/sext
|
||
if val_bits != 0 and target_bits != 0:
|
||
if val_bits == target_bits:
|
||
return val
|
||
elif val_bits < target_bits:
|
||
if val_bits == 1:
|
||
# i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
# 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737);
|
||
# 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为)
|
||
need_sext: int = 0
|
||
if target_name is not None and self.Gen.ExprGenOps._type_name_unsigned(target_name) == 0:
|
||
if src_node is None or self.Gen.ExprGenOps._node_type_unsigned(pool, src_node, trans) == 0:
|
||
need_sext = 1
|
||
if need_sext != 0:
|
||
return llvmlite.build_sext(builder, val, target_ty)
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
else:
|
||
return llvmlite.build_trunc(builder, val, target_ty)
|
||
|
||
# 整数 → 浮点: sitofp
|
||
if val_bits != 0 and target_fbits != 0:
|
||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||
|
||
# 浮点 → 整数: fptosi
|
||
if val_fbits != 0 and target_bits != 0:
|
||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||
|
||
# 浮点 → 浮点: fpext/fptrunc
|
||
if val_fbits != 0 and target_fbits != 0:
|
||
if val_fbits == target_fbits:
|
||
return val
|
||
elif val_fbits < target_fbits:
|
||
return llvmlite.build_fpext(builder, val, target_ty)
|
||
else:
|
||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||
|
||
# 指针 → 整数: ptrtoint
|
||
if val_bits == 0 and val_fbits == 0 and target_bits != 0:
|
||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||
|
||
# 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0)
|
||
if val_bits != 0 and target_bits == 0 and target_fbits == 0:
|
||
return llvmlite.build_inttoptr(builder, val, target_ty)
|
||
|
||
# 指针 → 指针: bitcast
|
||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||
# ============================================================
|
||
# 泛型实例化辅助:从 Subscript slice 提取类型实参名
|
||
# ============================================================
|
||
# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute)
|
||
# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用
|
||
|
||
|
||
# ============================================================
|
||
# 泛型实例化辅助:从 Subscript slice 提取类型实参名
|
||
# ============================================================
|
||
# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute)
|
||
# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用
|
||
|
||
def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr,
|
||
slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr:
|
||
"""从 Subscript.slice 提取类型实参名列表
|
||
|
||
list[int] -> ["int"]
|
||
dict[str, int] -> ["str", "int"]
|
||
list[AST | t.CPtr] -> ["AST|t.CPtr"]
|
||
"""
|
||
if slice_node is None or pool is None:
|
||
return None
|
||
# elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节
|
||
# 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃
|
||
result: list[str] | t.CPtr = list[str](pool, 8)
|
||
k: int = slice_node.kind()
|
||
if k == ast.ASTKind.Tuple:
|
||
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node)
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
|
||
if elts is not None:
|
||
n: t.CSizeT = len(elts)
|
||
i: t.CSizeT
|
||
for i in range(n):
|
||
elt: ast.AST | t.CPtr = elts.get(i)
|
||
tn: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, elt)
|
||
if tn is not None:
|
||
result.append(tn)
|
||
else:
|
||
tn: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, slice_node)
|
||
if tn is not None:
|
||
result.append(tn)
|
||
return result
|
||
# ============================================================
|
||
# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__
|
||
#
|
||
# 复用 translate_list_literal 的构造逻辑:
|
||
# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self)
|
||
# 2. 翻译 cl.args 为参数指针数组
|
||
# 3. call __new__(tmp, *args) → storage_ptr
|
||
# 4. call __before_init__(storage_ptr)
|
||
# 5. call __init__(storage_ptr, *args)
|
||
# 6. return storage_ptr
|
||
#
|
||
# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名,
|
||
# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1
|
||
# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr,
|
||
arg_node: ast.AST | t.CPtr,
|
||
class_name: str) -> str:
|
||
"""从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int")
|
||
|
||
裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。
|
||
对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。
|
||
注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。
|
||
"""
|
||
if pool is None or arg_node is None:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
None,
|
||
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
|
||
"TypeError")
|
||
return "int"
|
||
k: int = arg_node.kind()
|
||
# 常量: 42→int, 3.14→double, "abc"→str
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node)
|
||
if cn.const_kind == ast.CONST_FLOAT:
|
||
return "double"
|
||
if cn.const_kind == ast.CONST_STR:
|
||
return "str"
|
||
return "int"
|
||
# 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...)
|
||
if k == ast.ASTKind.Call:
|
||
cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node)
|
||
if cl_f.func is not None:
|
||
if cl_f.func.kind() == ast.ASTKind.Name:
|
||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func)
|
||
if fn_nm.id is not None:
|
||
# 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt
|
||
# 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float
|
||
# 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。
|
||
if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \
|
||
or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None:
|
||
return "double"
|
||
if string.strcmp(fn_nm.id, "int") == 0 \
|
||
or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \
|
||
or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \
|
||
or string.strstr(fn_nm.id, "Long") is not None:
|
||
return "int"
|
||
elif cl_f.func.kind() == ast.ASTKind.Attribute:
|
||
fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func)
|
||
if fn_at.attr is not None:
|
||
if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None:
|
||
return "double"
|
||
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
|
||
return "int"
|
||
# 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析,
|
||
# fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
arg_node,
|
||
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
|
||
"TypeError")
|
||
return "int"
|
||
# 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...)
|
||
# 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int"
|
||
# 逻辑将其排除,只保留 float/str 等区分性提示)。
|
||
return "int"
|
||
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
spec_name: str,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__"""
|
||
if pool is None or builder is None or mod is None or spec_name is None or cl is None:
|
||
return None
|
||
|
||
# 查找 struct entry 获取类型
|
||
struct_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||
if struct_entry is None:
|
||
self.Gen.TypeGenErr.fatal_error(cl, "泛型类构造调用: 特化类未注册")
|
||
return None
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty
|
||
if struct_ty is None:
|
||
return None
|
||
|
||
# 确保结构体定义在当前模块中可用(供 alloca 分配空间)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
|
||
# alloca tmp(self 指针)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
|
||
if tmp is None:
|
||
return None
|
||
|
||
# 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针)
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = len(cargs)
|
||
|
||
extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if extra_args is None:
|
||
return None
|
||
string.memset(extra_args, 0, 8 * 32)
|
||
|
||
ai: t.CSizeT = 0
|
||
while ai < can:
|
||
if ai >= 32:
|
||
# 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl, "泛型构造实参超过 32 个上限", "TypeError")
|
||
break
|
||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg_node is not None:
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node, None, 0, trans)
|
||
if arg_val is not None:
|
||
extra_args[ai] = t.CSizeT(arg_val)
|
||
ai += 1
|
||
|
||
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
|
||
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
|
||
# (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明)
|
||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||
has_new_flag: int = 0
|
||
if struct_entry is not None:
|
||
has_new_flag = struct_entry.HasNew
|
||
if has_new_flag != 0:
|
||
new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans)
|
||
if new_ptr is not None:
|
||
storage_ptr = new_ptr
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充)
|
||
self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
|
||
|
||
# call __init__(storage_ptr, *args)
|
||
self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans)
|
||
|
||
return storage_ptr |