diff --git a/TransPyV/App/lib/core/Gen/CallGenCtor.vp b/TransPyV/App/lib/core/Gen/CallGenCtor.vp new file mode 100644 index 0000000..ab23ef4 --- /dev/null +++ b/TransPyV/App/lib/core/Gen/CallGenCtor.vp @@ -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_ptr ; 写入 tag + # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 + # store , %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 \ No newline at end of file diff --git a/TransPyV/App/lib/core/Gen/CallGenMixin.vp b/TransPyV/App/lib/core/Gen/CallGenMixin.vp index 942b5ab..a8e1682 100644 --- a/TransPyV/App/lib/core/Gen/CallGenMixin.vp +++ b/TransPyV/App/lib/core/Gen/CallGenMixin.vp @@ -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( diff --git a/TransPyV/App/lib/core/Gen/ExprGenMixin.vp b/TransPyV/App/lib/core/Gen/ExprGenMixin.vp new file mode 100644 index 0000000..5b89a50 --- /dev/null +++ b/TransPyV/App/lib/core/Gen/ExprGenMixin.vp @@ -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 diff --git a/TransPyV/App/lib/core/Handles/HandlesTranslator.vp b/TransPyV/App/lib/core/Handles/HandlesTranslator.vp new file mode 100644 index 0000000..baadeec --- /dev/null +++ b/TransPyV/App/lib/core/Handles/HandlesTranslator.vp @@ -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_ 翻译上下文(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 diff --git a/TransPyV/App/main.vp b/TransPyV/App/main.vp index cbe87fe..c99a668 100644 --- a/TransPyV/App/main.vp +++ b/TransPyV/App/main.vp @@ -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,后续追加)。 diff --git a/includes/_list.vp b/includes/_list.vp index 824ba17..4c38202 100644 --- a/includes/_list.vp +++ b/includes/_list.vp @@ -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__) diff --git a/includes/memhub.vp b/includes/memhub.vp index 418523f..a7dca70 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -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 栈校验退化的连锁问题)