chore(tpc): 移除全部临时 DBG 日志 - VDBG(ExprGenMixin)/CTORDBG(CallGenCtor)/LISTDBG(_list)/ALLOCDBG+set/get_debug_log+set/get_alloc_src(memhub)/CLDBG+[DEPDBG](CallGenMixin)/--enable-debug-log(main)/set_alloc_src(HandlesTranslator);保留 detection 机制(前后 0xCDCD 标记+记录表探测)与 MEMBUDDY_FILL_GUARD 守卫
This commit is contained in:
1 parent
769ffda04f
commit
1de7c8d2ca
7 files changed
+1911
-76
No files matched your search
@@ -0,0 +1,990 @@
|
||||
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.Stub.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, fe.Ty)
|
||||
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: GenTypes.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
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,
|
||||
# 见 translate_constant;否则 coerce inttoptr 字符值当指针崩溃)
|
||||
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
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_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, 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
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
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
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val 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
|
||||
# payload 字段索引 = ai + 1(跳过 __tag);先取字段(pfe.Ty 用于
|
||||
# char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
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
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, pfe.Ty)
|
||||
if arg_val 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: GenTypes.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
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
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
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_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
|
||||
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, fe.Ty)
|
||||
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,
|
||||
from_imports: str = None) -> list[str] | t.CPtr:
|
||||
"""从 Subscript.slice 提取类型实参名列表
|
||||
|
||||
list[int] -> ["int"]
|
||||
dict[str, int] -> ["str", "int"]
|
||||
list[AST | t.CPtr] -> ["f467978339422f32.AST|t.CPtr"]
|
||||
|
||||
from_imports 可用时,各类型实参经 TypeGenResolve._norm_type_arg_name
|
||||
规范化为 "{定义模块SHA1}.{Class}"(ast.AST/AST → f467978339422f32.AST),
|
||||
与特化注册名一致,消除跨模块特化名分裂(list[AST].set undefined symbol)。
|
||||
"""
|
||||
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_raw: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, elt)
|
||||
tn: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
|
||||
if tn is not None:
|
||||
result.append(tn)
|
||||
else:
|
||||
tn_raw: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, slice_node)
|
||||
tn: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
|
||||
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)
|
||||
|
||||
for ai in range(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)
|
||||
|
||||
# 存储指针:默认用 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
|
||||
@@ -298,21 +298,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
struct_ty = gen_ctor_entry.Ty
|
||||
func_name = co_buf
|
||||
if struct_ty is not None:
|
||||
# [CLDBG] 诊断(用后移除):打印 cl 节点与 args 字段,确认
|
||||
# use-after-free——cl 是否新分配(对比 LISTDBG/ALLOCDBG 地址)、
|
||||
# cl.args 读取是否就是 cargs(悬空旧值 vs 当前值)
|
||||
if memhub.get_debug_log() != 0:
|
||||
cl_kind_v: t.CInt = -1
|
||||
if cl is not None:
|
||||
cl_kind_v = cl.kind()
|
||||
cl_args_v: t.CUInt64T = 0
|
||||
if cl is not None and cl.args is not None:
|
||||
cl_args_v = t.CUInt64T(cl.args)
|
||||
stdio.printf("[CLDBG] mod=%s cls=%s cl=%llu kind=%d can=%d cargs=%llu args_field=%llu\n",
|
||||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||||
func_name if func_name is not None else "?",
|
||||
t.CUInt64T(cl), cl_kind_v, can,
|
||||
t.CUInt64T(cargs), cl_args_v)
|
||||
if can == 0 and kw_count == 0:
|
||||
# OOP 结构体:即使无参数也调用 __before_init__
|
||||
# 用 gen_ctor_entry 规避跨模块同名 find_struct 找错
|
||||
@@ -1242,12 +1227,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [DEPDBG] 临时诊断:跨模块函数依赖未就绪即 pending 的根因(用后移除)
|
||||
dbg_ms5: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||||
stdio.printf("[DEPDBG] pending(cross_fn): mod=%s call=%s sha1=%s text=%d\n",
|
||||
dbg_ms5, call_name,
|
||||
cf_sha1 if cf_sha1 is not None else "none",
|
||||
self._dep_text_ll_exists(pool, cf_sha1) if cf_sha1 is not None else -1)
|
||||
cf_dbg: str = VLogger.fmt_buf()
|
||||
if cf_dbg is not None:
|
||||
viperlib.snprintf(
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import string
|
||||
import llvmlite
|
||||
import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# docstring 登记表容量(__doc__ 魔法属性支持)
|
||||
#
|
||||
# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的
|
||||
# 函数/类/方法 docstring,幂等查重)
|
||||
# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度
|
||||
# DOC_VAL_SZ: docstring 内容缓冲宽度
|
||||
# ============================================================
|
||||
DOC_MAX: t.CDefine = 512
|
||||
DOC_KEY_SZ: t.CDefine = 192
|
||||
DOC_VAL_SZ: t.CDefine = 4096
|
||||
|
||||
# ============================================================
|
||||
# f-string 翻译常量(对齐 TPC HandlesExprFormat)
|
||||
#
|
||||
# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲)
|
||||
# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度
|
||||
# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度
|
||||
# ============================================================
|
||||
FSTR_BUF_SIZE: t.CDefine = 1024
|
||||
FSTR_SPEC_MAX: t.CDefine = 64
|
||||
FSTR_FMT_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md)
|
||||
#
|
||||
# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp
|
||||
# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。
|
||||
#
|
||||
# 迁移原则(与 P2 一致,行为零变化):
|
||||
# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内
|
||||
# 本模块函数调用改为 self.xxx(...)
|
||||
# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀
|
||||
# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地
|
||||
# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型
|
||||
# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式)
|
||||
#
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式/常量/下标/属性访问/运算符
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenMixin(ExprGenBase.ExprGenBase):
|
||||
"""表达式处理 Mixin(纯方法化迁移,无状态字段)"""
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译值表达式(RHS 分派)— 模块级版本
|
||||
# ============================================================
|
||||
def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value(深度守卫包装器,原逻辑见 _translate_value_impl)
|
||||
|
||||
target_ty: 目标类型上下文(如调用形参类型/赋值目标类型),用于单引号
|
||||
单字符字面量(CONST_CHAR)在字符串目标下物化为 1 字符字符串(对齐 TPC)。
|
||||
"""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "表达式翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
rv: llvmlite.Value | t.CPtr = self._translate_value_impl(
|
||||
builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return rv
|
||||
|
||||
def _translate_value_impl(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value"""
|
||||
if node is None:
|
||||
return None
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
rv: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans, target_ty)
|
||||
return rv
|
||||
elif k == ast.ASTKind.Name:
|
||||
return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans)
|
||||
elif k == ast.ASTKind.BinOp:
|
||||
return self.Gen.ExprGenOps.translate_binop(pool, builder, mod, node, trans)
|
||||
elif k == ast.ASTKind.Call:
|
||||
return self.Gen.CallGen.translate_call(pool, builder, mod, node,
|
||||
funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Compare:
|
||||
return self.Gen.ExprGenOps.translate_compare(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.UnaryOp:
|
||||
return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.BoolOp:
|
||||
return self.Gen.ExprGenOps.translate_boolop(builder, pool, mod, node,
|
||||
funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
return self.Gen.ExprGenName.translate_subscript(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Attribute:
|
||||
return self.Gen.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.List:
|
||||
return self.Gen.ExprGenConst.translate_list_literal(builder, pool, mod, node, None, trans)
|
||||
elif k == ast.ASTKind.IfExp:
|
||||
return self.Gen.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Lambda:
|
||||
# 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin
|
||||
# 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda)
|
||||
return self.Gen.FuncGen.translate_lambda(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.JoinedStr:
|
||||
return self.Gen.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.FormattedValue:
|
||||
# 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue
|
||||
# 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译
|
||||
return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Await:
|
||||
# 协程 await(TPV-M1):await 目标是 async 函数调用时内联翻译
|
||||
# (子帧创建 + resume 到 DONE + 取子帧 ret 存父帧 await 槽 + 父挂起),
|
||||
# 返回子协程 ret 值(i32)。顶层 await(AnnAssign/Assign 的 value 直接
|
||||
# 是 Await)由 AsyncGen 段翻译特判处理,本分支覆盖表达式上下文中的
|
||||
# await(M1 覆盖有限场景,详见 AsyncGenMixin._emit_await)。
|
||||
aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node)
|
||||
if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call:
|
||||
aw_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value)
|
||||
if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name:
|
||||
aw_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aw_cl.func)
|
||||
if aw_nm.id is not None and trans is not None:
|
||||
if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0:
|
||||
return self.Gen.AsyncGen._emit_await(
|
||||
builder, pool, mod, trans, aw, aw_nm.id)
|
||||
return None
|
||||
return None
|
||||
@@ -0,0 +1,758 @@
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesTranslator - 翻译器状态管理 + 主入口
|
||||
#
|
||||
# 从 translator.py 拆分出来,负责:
|
||||
# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入)
|
||||
# 2. translate() - 主翻译入口
|
||||
# 3. dump_ir() - IR 输出
|
||||
#
|
||||
# 语句/表达式翻译全部委托给 Handles 模块:
|
||||
# HandlesMain - wrapper main 创建 + children 遍历
|
||||
# HandlesBody - 语句分派
|
||||
# HandlesExpr - 表达式翻译
|
||||
# HandlesFunctions - 函数定义处理
|
||||
# 注意:str = bytes = t.CChar | t.CPtr = i8*
|
||||
#
|
||||
# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为
|
||||
# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级
|
||||
# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。
|
||||
# ============================================================
|
||||
|
||||
# 常量
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
MAX_FUNCS: t.CDefine = 1024
|
||||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||||
# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数
|
||||
MAX_CORO_FUNCS: t.CDefine = 256
|
||||
MAX_CORO_VARS: t.CDefine = 256
|
||||
MAX_CORO_TRY: t.CDefine = 16
|
||||
|
||||
# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环
|
||||
# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。
|
||||
# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式
|
||||
# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。
|
||||
TRANSLATE_MAX_DEPTH: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||||
# ============================================================
|
||||
_g_gen: Generator.Generator | t.CPtr = None
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class Translator:
|
||||
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
|
||||
|
||||
# LLVM 上下文(共享状态)
|
||||
Module: llvmlite.LLVMModule | t.CPtr
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 函数表
|
||||
_funcs: GenTypes.FuncEntry | t.CPtr
|
||||
_func_count: t.CInt
|
||||
|
||||
# 协程(TPV-M1 async def / await / coro.coro_run)
|
||||
# _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项)
|
||||
# _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项)
|
||||
# _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项)
|
||||
# _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*)
|
||||
_async_funcs: str
|
||||
_async_func_count: t.CInt
|
||||
_coro_var_async: str
|
||||
_coro_var_async_count: t.CInt
|
||||
_coro_locals: str
|
||||
_coro_local_count: t.CInt
|
||||
_coro_frames: str
|
||||
_coro_frame_count: t.CInt
|
||||
# resume_<name> 翻译上下文(AsyncGenMixin 段翻译共享)
|
||||
_coro_state_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_done_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_ret_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_exit_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_coro_await_slot: llvmlite.Value | t.CPtr
|
||||
_coro_frame: llvmlite.Value | t.CPtr
|
||||
_coro_next_state: t.CInt
|
||||
_coro_nseg: t.CInt
|
||||
# M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数
|
||||
_coro_params: str
|
||||
_coro_param_count: t.CInt
|
||||
_coro_hoist_count: t.CInt # __await_N 槽计数(预扫描与翻译共用,序一致)
|
||||
_coro_await_count: t.CInt # 总 await 数(= 恢复块数 = switch case 数)
|
||||
_coro_local_base: t.CInt # 局部槽起始 index(= 3 + nparams)
|
||||
_coro_extra_base: t.CInt # 额外槽(__await_N)起始 index
|
||||
_coro_break_bb: llvmlite.BasicBlock | t.CPtr # While break 目标(M2 单层)
|
||||
_coro_continue_bb: llvmlite.BasicBlock | t.CPtr # While continue 目标
|
||||
_coro_state_bbs: t.CSizeT | t.CPtr # 预建 state 块数组(await 恢复块定位)
|
||||
# M3-M7 协程扩展
|
||||
_coro_exc_ptr: llvmlite.Value | t.CPtr # 帧 exc 槽(i32,M4)
|
||||
_coro_msg_ptr: llvmlite.Value | t.CPtr # 帧 msg 槽(i8*,M7)
|
||||
_coro_wake_ptr: llvmlite.Value | t.CPtr # 帧 wake 槽(i64,M3 coro_sleep)
|
||||
_coro_try_stack: t.CSizeT | t.CPtr # try 栈:except/finally 块指针数组(8B/项)
|
||||
_coro_try_stack_count: t.CInt
|
||||
_coro_for_counter: t.CInt # range-For 编号(M3,翻译期递增)
|
||||
_coro_scan_for_count: t.CInt # 预扫描期 For 计数
|
||||
_coro_uses_sleep: t.CInt # 函数体是否用 coro_sleep(预扫描置位)
|
||||
_coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64)
|
||||
_coro_extra_count: t.CInt # 额外槽总数
|
||||
_coro_await_slots: t.CInt | t.CPtr # __await_N 的帧相对槽 index(预扫描填)
|
||||
_coro_for_slots: t.CInt | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
|
||||
# per-async wake 槽 index 表(coro_run/gather 轮询反查用)
|
||||
_coro_wake_names: str # char* 数组(8B/项)
|
||||
_coro_wake_idxs: t.CInt | t.CPtr # i32 数组(4B/项,-1=无 wake 槽)
|
||||
_coro_wake_count: t.CInt
|
||||
|
||||
# 导入模块跟踪
|
||||
_imported_modules: str
|
||||
_from_imports: str
|
||||
|
||||
# 当前翻译上下文
|
||||
_cur_func: llvmlite.Function | t.CPtr
|
||||
_cur_builder: llvmlite.IRBuilder | t.CPtr
|
||||
|
||||
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load,
|
||||
# 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因:
|
||||
# i8* Deref 固定读 1 字节 + sext 截断)。
|
||||
CurAssignAnnot: ast.AST | t.CPtr
|
||||
|
||||
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
|
||||
# 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用
|
||||
# CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换
|
||||
# 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断,
|
||||
# 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC
|
||||
# _infer_deref_target_type 的直接 RHS 检查)。
|
||||
CurAssignNode: ast.AST | t.CPtr
|
||||
|
||||
# 循环控制流目标(break/continue)
|
||||
_break_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_continue_bb: llvmlite.BasicBlock | t.CPtr
|
||||
|
||||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||||
_label_counter: t.CInt
|
||||
|
||||
# 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达)
|
||||
_ctrl_merge_reachable: t.CInt
|
||||
|
||||
# match 翻译递归深度(match → case body → translate_value → 嵌套 match)。
|
||||
# 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此
|
||||
# fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。
|
||||
MatchTranslateDepth: t.CInt
|
||||
|
||||
# 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫
|
||||
# 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call)
|
||||
# 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。
|
||||
TranslateDepth: t.CInt
|
||||
|
||||
# global 声明的变量名集合(当前函数内)
|
||||
_global_names: str
|
||||
_global_name_count: t.CInt
|
||||
|
||||
# nonlocal 声明的变量名集合(当前函数内)
|
||||
_nonlocal_names: str
|
||||
_nonlocal_name_count: t.CInt
|
||||
# nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||||
# 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型
|
||||
_nonlocal_types: str
|
||||
|
||||
# 闭包相关:当前函数名(用于嵌套函数提升命名)
|
||||
_cur_func_name: str
|
||||
|
||||
# *args 变长参数支持:当前函数的 va_list 指针(i8* alloca)
|
||||
# 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用
|
||||
_va_list_ptr: llvmlite.Value | t.CPtr
|
||||
# *args 参数名(如 "args"),用于符号表注册
|
||||
_vararg_name: str
|
||||
|
||||
# OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。
|
||||
# _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise
|
||||
# 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。
|
||||
# 非 __next__ 函数中为 None。
|
||||
_stop_iter_flag_ptr: llvmlite.Value | t.CPtr
|
||||
|
||||
# try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的
|
||||
# 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise
|
||||
# 与调用侧 EH 检测写入/跳转。try 外为 None。
|
||||
_eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_eh_code_ptr: llvmlite.Value | t.CPtr
|
||||
_eh_msg_ptr: llvmlite.Value | t.CPtr
|
||||
# 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数
|
||||
# (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。
|
||||
# 无 EH 参数时 _cur_func_has_eh == 0。
|
||||
_eh_msg_out_param: llvmlite.Value | t.CPtr
|
||||
_eh_code_out_param: llvmlite.Value | t.CPtr
|
||||
_cur_func_has_eh: int
|
||||
|
||||
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
|
||||
ModuleSha1: str
|
||||
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
|
||||
# None 表示当前文件是顶级模块(无包),相对导入无法解析
|
||||
CurrentPackage: str
|
||||
# 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移)
|
||||
_closure_env_offsets: t.CInt
|
||||
_closure_env_count: t.CInt
|
||||
# lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id})
|
||||
# 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置,
|
||||
# lambda ID 需跨函数全局唯一(提升函数名避免冲突)
|
||||
_lambda_count: t.CInt
|
||||
# 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。
|
||||
# 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层
|
||||
# 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。
|
||||
# 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到
|
||||
# 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。
|
||||
_nl_chain_names: t.CVoid | t.CPtr
|
||||
_nl_chain_count: t.CInt
|
||||
# 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入
|
||||
# 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数
|
||||
# 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。
|
||||
_nl_chain_done: t.CInt
|
||||
|
||||
# 泛型特化上下文:当前正在特化的类型参数名/实参名列表
|
||||
# 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型
|
||||
# None 表示不在泛型特化上下文中
|
||||
GenericTypeParamNames: list[str] | t.CPtr
|
||||
GenericTypeArgs: list[str] | t.CPtr
|
||||
|
||||
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
||||
_declare_only: t.CInt
|
||||
|
||||
# Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成
|
||||
# (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp),
|
||||
# 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。
|
||||
_deps_pending: t.CInt
|
||||
|
||||
# 嵌套作用域符号表
|
||||
SymTab: GenTypes.SymbolTable | t.CPtr
|
||||
|
||||
def __init__(self):
|
||||
self.Module = None
|
||||
self.Pool = None
|
||||
self._funcs = None
|
||||
self._func_count = 0
|
||||
self._cur_func = None
|
||||
self._cur_builder = None
|
||||
self._break_bb = None
|
||||
self._continue_bb = None
|
||||
self._label_counter = 0
|
||||
self._imported_modules = None
|
||||
self._from_imports = None
|
||||
self._global_names = None
|
||||
self._global_name_count = 0
|
||||
self._nonlocal_names = None
|
||||
self._nonlocal_name_count = 0
|
||||
self._nonlocal_types = None
|
||||
self._cur_func_name = None
|
||||
self._va_list_ptr = None
|
||||
self._vararg_name = None
|
||||
self._stop_iter_flag_ptr = None
|
||||
self._eh_dispatch_bb = None
|
||||
self._eh_code_ptr = None
|
||||
self._eh_msg_ptr = None
|
||||
self._eh_msg_out_param = None
|
||||
self._eh_code_out_param = None
|
||||
self._cur_func_has_eh = 0
|
||||
self.ModuleSha1 = None
|
||||
self.CurrentPackage = None
|
||||
self._closure_env_offsets = 0
|
||||
self._closure_env_count = 0
|
||||
self._lambda_count = 0
|
||||
self._nl_chain_names = None
|
||||
self._nl_chain_count = 0
|
||||
self._nl_chain_done = 0
|
||||
self.GenericTypeParamNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self._declare_only = 0
|
||||
self._deps_pending = 0
|
||||
self.SymTab = None
|
||||
self._async_funcs = None
|
||||
self._async_func_count = 0
|
||||
self._coro_var_async = None
|
||||
self._coro_var_async_count = 0
|
||||
self._coro_locals = None
|
||||
self._coro_local_count = 0
|
||||
self._coro_frames = None
|
||||
self._coro_frame_count = 0
|
||||
self._coro_state_ptr = None
|
||||
self._coro_done_ptr = None
|
||||
self._coro_ret_ptr = None
|
||||
self._coro_exit_bb = None
|
||||
self._coro_await_slot = None
|
||||
self._coro_frame = None
|
||||
self._coro_next_state = 1
|
||||
self._coro_nseg = 0
|
||||
self._coro_params = None
|
||||
self._coro_param_count = 0
|
||||
self._coro_hoist_count = 0
|
||||
self._coro_await_count = 0
|
||||
self._coro_local_base = 3
|
||||
self._coro_extra_base = 3
|
||||
self._coro_break_bb = None
|
||||
self._coro_continue_bb = None
|
||||
self._coro_state_bbs = None
|
||||
self._coro_exc_ptr = None
|
||||
self._coro_msg_ptr = None
|
||||
self._coro_wake_ptr = None
|
||||
self._coro_try_stack = None
|
||||
self._coro_try_stack_count = 0
|
||||
self._coro_for_counter = 0
|
||||
self._coro_scan_for_count = 0
|
||||
self._coro_uses_sleep = 0
|
||||
self._coro_extra_types = None
|
||||
self._coro_extra_count = 0
|
||||
self._coro_await_slots = None
|
||||
self._coro_for_slots = None
|
||||
self._coro_wake_names = None
|
||||
self._coro_wake_idxs = None
|
||||
self._coro_wake_count = 0
|
||||
|
||||
# ============================================================
|
||||
# 状态初始化
|
||||
# ============================================================
|
||||
def _init_state(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
"""初始化变量表、函数表和子 Handle"""
|
||||
self.Pool = pool
|
||||
if self._funcs is None:
|
||||
self._funcs = GenApi.init_func_table(pool, MAX_FUNCS)
|
||||
# 嵌套作用域符号表(新版)
|
||||
if self.SymTab is None:
|
||||
self.SymTab = GenApi.init_symbol_table(pool)
|
||||
# global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节)
|
||||
if self._global_names is None:
|
||||
self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._global_names is not None:
|
||||
string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8)
|
||||
self._global_name_count = 0
|
||||
if self._nonlocal_names is None:
|
||||
self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._nonlocal_names is not None:
|
||||
string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8)
|
||||
self._nonlocal_name_count = 0
|
||||
# nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||||
if self._nonlocal_types is None:
|
||||
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._nonlocal_types is not None:
|
||||
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
|
||||
|
||||
# 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型
|
||||
if self._async_funcs is None:
|
||||
self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||||
if self._async_funcs is not None:
|
||||
string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8)
|
||||
self._async_func_count = 0
|
||||
if self._coro_var_async is None:
|
||||
self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16)
|
||||
if self._coro_var_async is not None:
|
||||
string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16)
|
||||
self._coro_var_async_count = 0
|
||||
if self._coro_locals is None:
|
||||
self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8)
|
||||
if self._coro_locals is not None:
|
||||
string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8)
|
||||
if self._coro_params is None:
|
||||
self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8)
|
||||
if self._coro_params is not None:
|
||||
string.memset(self._coro_params, 0, MAX_CORO_VARS * 8)
|
||||
if self._coro_try_stack is None:
|
||||
self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8)
|
||||
if self._coro_try_stack is not None:
|
||||
string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8)
|
||||
if self._coro_extra_types is None:
|
||||
self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS)
|
||||
if self._coro_extra_types is not None:
|
||||
string.memset(self._coro_extra_types, 0, MAX_CORO_VARS)
|
||||
if self._coro_await_slots is None:
|
||||
self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||||
if self._coro_await_slots is not None:
|
||||
string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4)
|
||||
if self._coro_for_slots is None:
|
||||
self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||||
if self._coro_for_slots is not None:
|
||||
string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4)
|
||||
if self._coro_wake_names is None:
|
||||
self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||||
if self._coro_wake_names is not None:
|
||||
string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8)
|
||||
if self._coro_wake_idxs is None:
|
||||
self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4)
|
||||
if self._coro_wake_idxs is not None:
|
||||
string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4)
|
||||
self._coro_local_count = 0
|
||||
if self._coro_frames is None:
|
||||
self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16)
|
||||
if self._coro_frames is not None:
|
||||
string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16)
|
||||
self._coro_frame_count = 0
|
||||
|
||||
# ============================================================
|
||||
# 主翻译入口
|
||||
# ============================================================
|
||||
def translate(self, tree: ast.AST | t.CPtr) -> int:
|
||||
"""将 AST 翻译为 LLVM IR"""
|
||||
if tree is None:
|
||||
return 1
|
||||
if _mbuddy is None:
|
||||
return 1
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = _mbuddy
|
||||
|
||||
# 初始化状态
|
||||
self._init_state(pool)
|
||||
|
||||
# 创建 LLVM 模块
|
||||
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main")
|
||||
if mod is None:
|
||||
VLogger.error("NewModule returned NULL", "TR")
|
||||
return 1
|
||||
self.Module = mod
|
||||
|
||||
# 设置目标(优先使用 project.vpj 中的配置)
|
||||
triple: str = Config.TargetTriple
|
||||
if triple is None:
|
||||
triple = "x86_64-pc-windows-msvc"
|
||||
llvmlite.module_set_target(mod, triple)
|
||||
|
||||
# 类型
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
# 声明 printf
|
||||
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "printf", i32_ty)
|
||||
if printf_func is None:
|
||||
VLogger.error("CreateDeclare printf returned NULL", "TR")
|
||||
return 1
|
||||
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
|
||||
printf_func.IsVarArg = 1
|
||||
# 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用)
|
||||
# declare void @llvm.va_start(i8*)
|
||||
# declare void @llvm.va_end(i8*)
|
||||
void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "llvm.va_start", void_ty_decl)
|
||||
if va_start_func is not None:
|
||||
llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap")
|
||||
va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "llvm.va_end", void_ty_decl)
|
||||
if va_end_func is not None:
|
||||
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap")
|
||||
|
||||
# 声明 malloc(闭包分配用)
|
||||
malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "malloc", i8_ptr_ty)
|
||||
if malloc_func is not None:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
llvmlite.add_param(pool, malloc_func, i64_ty, "size")
|
||||
|
||||
# 检查用户是否定义了 main 函数
|
||||
has_user_main: int = 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = len(ch)
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is not None and child.kind() == ast.ASTKind.FunctionDef:
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
if fd is not None and fd.name is not None:
|
||||
if string.strcmp(fd.name, "main") == 0:
|
||||
has_user_main = 1
|
||||
break
|
||||
|
||||
if self._declare_only != 0:
|
||||
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
elif has_user_main == 0:
|
||||
# 无用户 main → 只翻译模块级语句,不创建 wrapper main
|
||||
# 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突
|
||||
# 只有包含 def main() 的入口文件才会有 define i32 @main()
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
else:
|
||||
# 用户已定义 main → 委托 HandlesMain 翻译模块级
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 包装 main 函数(无用户 main 时)→ 委托 HandlesMain
|
||||
# ============================================================
|
||||
def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
tree: ast.AST | t.CPtr,
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr):
|
||||
"""委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)"""
|
||||
added: int = GenApi.create_wrapper_main(self, tree, i32_ty)
|
||||
|
||||
# ============================================================
|
||||
# 模块级翻译(用户已定义 main)→ 委托 HandlesMain
|
||||
# ============================================================
|
||||
def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""委托 GenApi.translate_children() 翻译模块级语句(trans 单参)"""
|
||||
# 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题
|
||||
if self._declare_only == 0:
|
||||
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
|
||||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||||
# 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位
|
||||
cur_imp_lineno: int = 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = len(ch)
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd: int = child.kind()
|
||||
if kd == ast.ASTKind.Import:
|
||||
cur_imp_lineno = child.lineno
|
||||
GenApi.translate_import(self, child)
|
||||
elif kd == ast.ASTKind.ImportFrom:
|
||||
cur_imp_lineno = child.lineno
|
||||
GenApi.translate_import_from_module(self, child)
|
||||
GenApi.translate_import_from_names(self, child)
|
||||
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
|
||||
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
|
||||
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
|
||||
# Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入
|
||||
# import _list/_dict);TPV 用可见性机制等效替代——否则裸名
|
||||
# `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0
|
||||
# 解析失败(DictTest 的 "变量类型注解解析失败")。
|
||||
self._inject_auto_container_visibility(pool, tree)
|
||||
# 扫描当前模块的 CTypedef 声明已由 Phase1 1b 文本扫描注册
|
||||
# (RegisterCTypedefFromSource,见 Phase1Main.vp)——AST 字符串字段
|
||||
# token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描读 attr
|
||||
# 会 0xC0000005(stdint.vp 崩溃根因),故移除。
|
||||
# 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件,
|
||||
# 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题
|
||||
# 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁)
|
||||
if self._imported_modules is not None:
|
||||
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
|
||||
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
|
||||
StubMergerBuild.LoadDepVpiIntoModule(
|
||||
pool, mod, self._imported_modules, self._from_imports,
|
||||
GenApi.get_temp_dir(), self)
|
||||
GenApi.pop_trace()
|
||||
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
|
||||
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
|
||||
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
|
||||
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
|
||||
# 预处理先于 translate_children 注册所有模块级变量,
|
||||
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
|
||||
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
|
||||
if ch is not None:
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd_mv: int = child.kind()
|
||||
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
|
||||
GenApi.handle_module_level_var(self, child)
|
||||
# 创建前向声明
|
||||
GenApi.forward_declare_functions(self, tree)
|
||||
added: int = GenApi.translate_children(self, tree)
|
||||
|
||||
# ============================================================
|
||||
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
|
||||
#
|
||||
# TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件,
|
||||
# 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代:
|
||||
# _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在
|
||||
# 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。
|
||||
#
|
||||
# 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致):
|
||||
# - AnnAssign 注解裸名 Name(list/dict):d: dict
|
||||
# - 构造调用 func 裸名 Name(list/dict):dict(bd)
|
||||
# - Subscript 的 value 裸名 Name(list/dict):list[int]
|
||||
# ============================================================
|
||||
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""检测 list/dict 容器使用,注入容器类可见性"""
|
||||
if tree is None or tree.children is None:
|
||||
return
|
||||
# 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针)
|
||||
need_list_box: t.CPtr = stdlib.malloc(4)
|
||||
need_dict_box: t.CPtr = stdlib.malloc(4)
|
||||
if need_list_box is None or need_dict_box is None:
|
||||
if need_list_box is not None:
|
||||
stdlib.free(need_list_box)
|
||||
if need_dict_box is not None:
|
||||
stdlib.free(need_dict_box)
|
||||
return
|
||||
need_list_box[0] = 0
|
||||
need_dict_box[0] = 0
|
||||
self._scan_container_usage(tree, need_list_box, need_dict_box)
|
||||
if need_dict_box[0] != 0:
|
||||
# dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析)
|
||||
GenApi.add_visible_struct(pool, "dict")
|
||||
if self._imported_modules is None or \
|
||||
GenApi.is_module_imported(self._imported_modules, "_dict") == 0:
|
||||
self._imported_modules = GenApi.add_imported_module(
|
||||
pool, self._imported_modules, "_dict")
|
||||
if need_list_box[0] != 0:
|
||||
GenApi.add_visible_struct(pool, "list")
|
||||
if self._imported_modules is None or \
|
||||
GenApi.is_module_imported(self._imported_modules, "_list") == 0:
|
||||
self._imported_modules = GenApi.add_imported_module(
|
||||
pool, self._imported_modules, "_list")
|
||||
stdlib.free(need_list_box)
|
||||
stdlib.free(need_dict_box)
|
||||
|
||||
def _scan_container_usage(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""递归扫描 AST 语句结构,检测 list/dict 容器使用"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_s.annotation is not None:
|
||||
self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Call:
|
||||
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl_s.func is not None:
|
||||
self._check_container_type_node(cl_s.func, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.List:
|
||||
# [] 字面量:容器模板仍需注册
|
||||
need_list_box[0] = 1
|
||||
elif k == ast.ASTKind.Dict:
|
||||
# {} 字面量:容器模板仍需注册
|
||||
need_dict_box[0] = 1
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||||
n_s: t.CSizeT = len(ch_s)
|
||||
for ci_s in range(n_s):
|
||||
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||||
|
||||
def _check_container_type_node(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm_s.id is not None:
|
||||
if string.strcmp(nm_s.id, "dict") == 0:
|
||||
need_dict_box[0] = 1
|
||||
elif string.strcmp(nm_s.id, "list") == 0:
|
||||
need_list_box[0] = 1
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IR 输出
|
||||
# ============================================================
|
||||
def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int):
|
||||
"""将 LLVM IR 输出到缓冲区
|
||||
|
||||
mode: 0=完整, 1=stub(仅声明), 2=text(仅代码)
|
||||
"""
|
||||
if self.Module is None or buf is None:
|
||||
return
|
||||
if _mbuddy is None:
|
||||
return
|
||||
buf[0] = '\0'
|
||||
llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法)
|
||||
# ============================================================
|
||||
def add_global_name(trans: HT.Translator | t.CPtr, name: str):
|
||||
"""添加一个 global 变量名(委托到 gen.add_global_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.add_global_name(trans, name)
|
||||
|
||||
|
||||
def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.is_global_name(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = None):
|
||||
"""添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name)
|
||||
|
||||
Args:
|
||||
name: nonlocal 变量名
|
||||
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
|
||||
None 时回退为 i32)
|
||||
"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.add_nonlocal_name(trans, name, var_ty)
|
||||
|
||||
|
||||
def get_nonlocal_type(trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type)
|
||||
|
||||
Returns: 找到的类型指针,找不到返回 None
|
||||
"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.get_nonlocal_type(trans, name)
|
||||
return None
|
||||
|
||||
|
||||
def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.is_nonlocal_name(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.get_nonlocal_index(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def clear_scope_names(trans: HT.Translator | t.CPtr):
|
||||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.clear_scope_names(trans)
|
||||
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
@@ -152,7 +152,6 @@ def main() -> int:
|
||||
parser.add_argument("--asan", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "ASan mode: .ll first opt -passes=asan then link -fsanitize=address")
|
||||
parser.add_argument("--phase2command", None, argparse.STRING, 0, None, False, argparse.STORE, "Do not run llc/link: write Phase2 llc(opt+llc) and clang link commands to the given .bat path")
|
||||
parser.add_argument("--nowarn-register", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Suppress Phase A dependency WARN")
|
||||
parser.add_argument("--enable-debug-log", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Enable LISTDBG diagnostic output (list.__init__/append print)")
|
||||
parser.add_argument("--detection", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Enable MemBuddy allocation detection (0xCDCD markers + record-table probe for out-of-bounds writes; applies to both mb and perm_pool)")
|
||||
parser.add_argument("--version", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show version and exit")
|
||||
parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show help and exit")
|
||||
@@ -240,13 +239,6 @@ Target: %s
|
||||
BuildPipeline._asan_mode = False
|
||||
Config._inc_bin_suffix = ".binary"
|
||||
|
||||
# 调试日志开关:--enable-debug-log 开启 list.__init__/append 的 LISTDBG 诊断
|
||||
# (输出量大,默认静默;仅排查 list 头覆盖等运行时问题时开启)
|
||||
if args.get_bool("enable-debug-log"):
|
||||
memhub.set_debug_log(1)
|
||||
if log is not None:
|
||||
log.info("调试日志已启用(LISTDBG: list.__init__/append 诊断输出)", "dbg")
|
||||
|
||||
# === --phase2command: 只生成命令写入 bat,不执行 llc/链接 ===
|
||||
# Phase B/B+ 的 llc(含 ASan opt)与 Phase C 的 clang 链接命令写入指定
|
||||
# .bat 路径(BuildPipeline._phase2_write_cmd 首次写入 header,后续追加)。
|
||||
|
||||
@@ -42,27 +42,11 @@ class list[T]:
|
||||
self.__elem_size__ = elem_size
|
||||
self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__)
|
||||
self.__iter_index__ = 0
|
||||
# [LISTDBG] 诊断(用后移除):打印初始化结果,与 CTORDBG cargs 六字段
|
||||
# 交叉匹配:找到 cargs 对应记录即可判断 __init__ 是否执行/写入是否正确
|
||||
if memhub.get_debug_log() != 0:
|
||||
stdio.printf("[LISTDBG] list-init self=%llu data=%llu cnt=%llu cap=%llu pool=%llu es=%llu iter=%llu\n",
|
||||
t.CUInt64T(self), t.CUInt64T(self.__data__),
|
||||
t.CUInt64T(self.__count__), t.CUInt64T(self.__capacity__),
|
||||
t.CUInt64T(self.__pool__), t.CUInt64T(self.__elem_size__),
|
||||
t.CUInt64T(self.__iter_index__))
|
||||
|
||||
def __len__(self) -> t.CSizeT:
|
||||
return self.__count__
|
||||
|
||||
def append(self, item: T):
|
||||
# [LISTDBG] 诊断(用后移除):仅首次 append(Count==0)打印,确认
|
||||
# append 作用在哪个 list、Data 指针是否有效(若 cargs 覆盖发生在此
|
||||
# 前后,日志能显示 append 的 self/data 与 CTORDBG cargs/d0 的对应)
|
||||
if memhub.get_debug_log() != 0 and self.__count__ == 0:
|
||||
stdio.printf("[LISTDBG] append-first self=%llu data=%llu cnt=%llu cap=%llu es=%llu\n",
|
||||
t.CUInt64T(self), t.CUInt64T(self.__data__),
|
||||
t.CUInt64T(self.__count__), t.CUInt64T(self.__capacity__),
|
||||
t.CUInt64T(self.__elem_size__))
|
||||
if self.__count__ >= self.__capacity__:
|
||||
new_cap: t.CSizeT = self.__capacity__ * 2
|
||||
new_data: t.CPtr = self.__pool__.alloc(new_cap * self.__elem_size__)
|
||||
|
||||
@@ -54,30 +54,6 @@ def _canary_pattern() -> t.CUInt64T:
|
||||
lo: t.CUInt64T = t.CUInt64T(0xA5A5A5A5)
|
||||
return (lo << 32) | lo
|
||||
|
||||
# [LISTDBG] 调试日志全局开关(默认关;命令行 --enable-debug-log 开启):
|
||||
# list.__init__/append 的诊断 printf 输出量大,默认静默,仅排查时开启
|
||||
_g_debug_log: int = 0
|
||||
|
||||
def set_debug_log(flag: int) -> None:
|
||||
"""设置调试日志开关(1=开启 LISTDBG 诊断输出)"""
|
||||
global _g_debug_log
|
||||
_g_debug_log = flag
|
||||
|
||||
def get_debug_log() -> int:
|
||||
"""读取调试日志开关(0=关,1=开)"""
|
||||
return _g_debug_log
|
||||
|
||||
# [ALLOCDBG] 分配者记录:当前正在翻译的文件 sha1(Phase1Main/Translator
|
||||
# 每文件翻译前设置)。alloc size==48(list 对象大小)且 --enable-debug-log
|
||||
# 开启时打印块地址+src,定位"未走 list.__init__ 的异常 list"创建者
|
||||
# (SlotsBugTest KwEntry cargs 只写 Data/IterIndex 的块归属)。
|
||||
_g_alloc_src: str = None
|
||||
|
||||
def set_alloc_src(src: str) -> None:
|
||||
"""设置当前翻译文件 sha1(alloc 分配者记录用)"""
|
||||
global _g_alloc_src
|
||||
_g_alloc_src = src
|
||||
|
||||
def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT:
|
||||
if align == 0: return val
|
||||
return (val + align - 1) & ~(align - 1)
|
||||
@@ -650,13 +626,6 @@ class MemBuddy(MemManager):
|
||||
fill_size: t.CSizeT = bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY
|
||||
if fill_size > 0:
|
||||
string.memset(result, MEMBUDDY_FILL_PATTERN, fill_size)
|
||||
# [ALLOCDBG] 分配者记录:size==48(list 对象)且 --enable-debug-log
|
||||
# 开启时打印 chk_stack 序号+块地址+当前翻译文件 src。序号与
|
||||
# CTORDBG 的 cargs_in_block=idx 匹配 → 精确定位未走
|
||||
# list.__init__ 的异常 list(如 KwEntry cargs)的分配点。
|
||||
if get_debug_log() != 0 and size == 48:
|
||||
stdio.printf("[ALLOCDBG] alloc48 idx=%zu block=%llu ret=%llu src=%s\n",
|
||||
self.chk_depth, t.CUInt64T(block), t.CUInt64T(result), _g_alloc_src)
|
||||
# 记录到 checkpoint 栈(供 reset_to 回收)
|
||||
# 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失
|
||||
# → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题)
|
||||
|
||||
Reference in new issue
Block a user