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:
TermiNexus committed 2026-08-25 15:17:51 +08:00
1 parent 769ffda04f
commit 1de7c8d2ca
7 files changed
+1911 -76

No files matched your search

+990
View File
@@ -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
-21
View File
@@ -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(
+163
View File
@@ -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
-8
View File
@@ -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,后续追加)。