From 987088fdffbf3841cf5740d812d62d8881a34e3f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 7 Aug 2026 17:30:41 +0800 Subject: [PATCH] 'fix(core): support keyword args in method calls _translate_method_call ignored cl.keywords, so keyword-style calls like add_argument("--count", short="-c", arg_type=INT) lost all keyword values (short_name/arg_type stayed default), breaking Test 4. Match keywords against function params by name, fill missing params with zero values to keep call arity consistent.' --- App/lib/StubGen/VpiReader.vp | 52 ++--- App/lib/core/Handles/HandlesExpr.vp | 17 +- App/lib/core/Handles/HandlesExprCall.vp | 244 +++++++++++++----------- App/lib/core/Handles/HandlesType.vp | 45 ++--- App/lib/core/Phase1.vp | 75 ++++++++ 5 files changed, 253 insertions(+), 180 deletions(-) diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index d5b4b13..4175df2 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -228,9 +228,6 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int: vpi_buf + rstart, rtype_len) (_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0' _g_vpi_ret_count += 1 - # [DBG-MC] 临时诊断(验证后移除) - if string.strstr(key_buf, "parse_args") is not None: - stdio.printf("[DBG-MC] cache write idx=%d key=%s\n", _g_vpi_ret_count - 1, key_buf) stdlib.free(key_buf) stdlib.free(mname_buf) pos = le + 1 @@ -245,10 +242,6 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int: # ============================================================ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str: """查找缓存的方法返回注解字符串,未找到返回 None""" - # [DBG-MC] 临时诊断(验证后移除) - if method_name is not None and string.strcmp(method_name, "parse_args") == 0: - stdio.printf("[DBG-MC] lookup parse_args keys=%d count=%d sha1=%s\n", - 1 if _g_vpi_ret_keys is not None else 0, _g_vpi_ret_count, src_sha1) if _g_vpi_ret_keys is None or _g_vpi_ret_count == 0: return None if src_sha1 is None or method_name is None: @@ -731,7 +724,15 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, ag.annotation, imported_modules, from_imports, trans) if resolved_ty is not None: - param_ty = resolved_ty + # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque + # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 + # (llc: invalid type for function argument)。Windows ABI + # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 + match resolved_ty: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Int64(pool) + case _: + param_ty = resolved_ty llvmlite.add_param(pool, func, param_ty, pname) # *args 变长参数:标记 IsVarArg=1,使调用侧走 C ABI 参数提升 # (i8/i16 → i32,float → double),避免 %d/%x 等格式因参数按 i64 @@ -811,31 +812,6 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, if ret_ty is None: ret_ty = i32_ty - # [DBG-MC] 临时诊断(验证后移除) - if cls_name is not None and string.strcmp(m_fd.name, "parse_args") == 0 and string.strcmp(cls_name, "ArgumentParser") == 0: - if ret_annot is not None: - stdio.printf("[DBG-MC] inject parse_args ret_annot='%s'\n", ret_annot) - match ret_ty: - case llvmlite.LLVMType.Ptr(pe_rt2): - match pe_rt2: - case llvmlite.LLVMType.Struct(f_rt2, c_rt2, n_rt2): - if n_rt2 is not None: - stdio.printf("[DBG-MC] inject parse_args ret_ty Ptr(Struct(%s))\n", n_rt2) - else: - stdio.printf("[DBG-MC] inject parse_args ret_ty Ptr(Struct)\n") - case llvmlite.LLVMType.Int(b_rt2): - stdio.printf("[DBG-MC] inject parse_args ret_ty Ptr(i%d)\n", b_rt2) - case _: - stdio.printf("[DBG-MC] inject parse_args ret_ty Ptr(inner-other)\n") - case llvmlite.LLVMType.Int(b_rt2): - stdio.printf("[DBG-MC] inject parse_args ret_ty i%d\n", b_rt2) - case llvmlite.LLVMType.Void(): - stdio.printf("[DBG-MC] inject parse_args ret_ty Void\n") - case _: - stdio.printf("[DBG-MC] inject parse_args ret_ty other\n") - else: - stdio.printf("[DBG-MC] inject parse_args ret_annot=None\n") - # 创建 declare func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, mangled_name, ret_ty) @@ -863,7 +839,15 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, ag.annotation, imported_modules, from_imports, trans) if resolved_ty is not None: - param_ty = resolved_ty + # 结构体按值参数 → i64:跨模块结构体在本模块是 opaque + # (未定义字段),LLVM 不允许 opaque struct 作为函数参数 + # (llc: invalid type for function argument)。Windows ABI + # 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。 + match resolved_ty: + case llvmlite.LLVMType.Struct(_, _, _): + param_ty = llvmlite.Int64(pool) + case _: + param_ty = resolved_ty llvmlite.add_param(pool, func, param_ty, pname) # 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致) diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index ced002c..fc9cc68 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -288,6 +288,10 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, if val_bits == target_bits: return val if val_bits < target_bits: + # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) + # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 + if val_bits == 1: + return llvmlite.build_zext(builder, val, target_ty) return llvmlite.build_sext(builder, val, target_ty) return llvmlite.build_trunc(builder, val, target_ty) # 浮点转换 @@ -987,14 +991,21 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, rhs = llvmlite.const_int32(pool, 0) # 类型对齐:icmp 要求两边类型相同 - # 仅对数值类型做 sext 对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) + # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) + # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) lhs_bits: int = get_llvm_type_bits(lhs.Ty) rhs_bits: int = get_llvm_type_bits(rhs.Ty) if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: if lhs_bits < rhs_bits: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + if lhs_bits == 1: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + if rhs_bits == 1: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index c9fb4e4..3677f96 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -661,17 +661,23 @@ def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, return dst_coerced # ============================================================ -# c.Deref(ptr) — 解引用指针,load i8(字符遍历用例) +# c.Deref(ptr) — 解引用指针,按指针 pointee 类型读取 # -# 生成: %N = load i8, i8* %ptr -# 返回 i8 值 +# 生成: %N = load , * %ptr +# 返回 pointee 类型的值 +# +# 注意: 必须按 ptr 的 pointee 类型决定读取宽度。 +# - i8* (str/bytes/字符遍历) → load i8 +# - i64* (t.CUInt64T, 块头部) → load i64(memhub 的 free list 链表读 8 字节头部) +# 之前固定 load i8 导致 memhub 读块头部只读到低 8 位, +# free list 的 next 指针被截断成 0x88 等垃圾值,alloc 崩溃。 # ============================================================ def translate_c_deref(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """c.Deref(ptr) → load i8 from ptr""" + """c.Deref(ptr) → load 按 ptr 的 pointee 类型""" if cl is None: return None cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args @@ -683,6 +689,11 @@ def translate_c_deref(pool: memhub.MemBuddy | t.CPtr, if ptr_val is None: return None + # 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容) + if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if pointee is not None: + return llvmlite.build_load(builder, pointee, ptr_val) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) return llvmlite.build_load(builder, i8_ty, ptr_val) @@ -2795,16 +2806,41 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) if frt is not None: call_ret_ty = frt + elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0: + # fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着 + # stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。 + err_cm1: t.CChar | t.CPtr = pool.alloc(256) + if err_cm1 is not None: + viperlib.snprintf(err_cm1, 256, + "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name) + HandlesType.fatal_error(None, err_cm1) + HandlesType.fatal_error(None, "方法返回类型无法确定") else: - # found_func 为 None(跨模块调用 stub 未注入):根据方法名推断返回类型 - # __new__ 返回 Ptr(struct_ty) - # __getitem__ 返回 Ptr(struct_ty)(自定义结构体 subscript 读取) - # 其他方法默认 void - if string.strcmp(method_name, "__new__") == 0 and cmop_struct_ty is not None: - call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) - elif string.strcmp(method_name, "__getitem__") == 0 and cmop_struct_ty is not None: - # __getitem__ 返回对象指针 (如 JsonValue|t.CPtr, HashTable|t.CPtr) - call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) + # found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。 + # __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。 + # __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__ + # -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty) + # 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。 + # fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或 + # 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。 + if string.strcmp(method_name, "__new__") == 0: + if cmop_struct_ty is not None: + call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty) + else: + err_cm2: t.CChar | t.CPtr = pool.alloc(256) + if err_cm2 is not None: + viperlib.snprintf(err_cm2, 256, + "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name) + HandlesType.fatal_error(None, err_cm2) + HandlesType.fatal_error(None, "self 结构体类型未知") + elif string.strcmp(method_name, "__getitem__") == 0: + err_cm3: t.CChar | t.CPtr = pool.alloc(256) + if err_cm3 is not None: + viperlib.snprintf(err_cm3, 256, + "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型", + class_name) + HandlesType.fatal_error(None, err_cm3) + HandlesType.fatal_error(None, "__getitem__ stub declare 未注入") # 构建参数链表: self_ptr → extra_args... llvmlite.value_set_next(self_ptr, None) @@ -3686,10 +3722,6 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, if obj_ptr is None or cl is None: return None - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(method_name, "parse_args") == 0 or string.strcmp(method_name, "get_str") == 0: - stdio.printf("[DBG-MC] method_call enter: %s.%s\n", class_name, method_name) - # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) # 用于继承链遍历、SHA1 查找和虚表分派 mc_entry: HandlesStruct.StructEntry | t.CPtr = None @@ -3756,13 +3788,6 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name) call_name = mangled_mc - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(method_name, "parse_args") == 0: - if found_func is not None: - stdio.printf("[DBG-MC] parse_args found_func=OK\n") - else: - stdio.printf("[DBG-MC] parse_args found_func=MISS cls_sha1=%s\n", cls_sha1_mc) - # 确定返回类型 i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty @@ -3780,72 +3805,96 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, else: call_ret_ty = _infer_method_ret_ty(pool, method_name) - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(method_name, "parse_args") == 0: - rt_kind: int = 0 - match call_ret_ty: - case llvmlite.LLVMType.Ptr(pe_rt): - rt_kind = 1 - match pe_rt: - case llvmlite.LLVMType.Struct(f_rt_i, c_rt_i, n_rt_i): - if n_rt_i is not None: - stdio.printf("[DBG-MC] parse_args ret Ptr(Struct(%s))\n", n_rt_i) - else: - stdio.printf("[DBG-MC] parse_args ret Ptr(Struct)\n") - case llvmlite.LLVMType.Int(b_rt_i): - stdio.printf("[DBG-MC] parse_args ret Ptr(i%d)\n", b_rt_i) - case _: - stdio.printf("[DBG-MC] parse_args ret Ptr(inner-other)\n") - case llvmlite.LLVMType.Int(b_rt): - rt_kind = 2 - stdio.printf("[DBG-MC] parse_args ret i%d\n", b_rt) - case llvmlite.LLVMType.Void(): - rt_kind = 3 - stdio.printf("[DBG-MC] parse_args ret Void\n") - case _: - rt_kind = 0 - stdio.printf("[DBG-MC] parse_args ret kind=%d\n", rt_kind) - # 翻译调用参数 cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args can: t.CSizeT = 0 if cargs is not None: can = cargs.__len__() + kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kwc: t.CSizeT = 0 + if kw_calls is not None: + kwc = kw_calls.__len__() # 构建参数链表: obj_ptr → arg1 → arg2 → ... llvmlite.value_set_next(obj_ptr, None) head: llvmlite.Value | t.CPtr = obj_ptr tail: llvmlite.Value | t.CPtr = obj_ptr + arg_count_eff: int = 0 - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is None: - continue - # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) - # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) - # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 - if found_func is not None: - pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - pi: int = 0 - while pp is not None and pi < ai + 1: - if pi == ai + 1: - break - pp = llvmlite.param_get_next(pp) - pi += 1 - if pp is not None: - pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) - if pty is not None: - arg_val = HandlesExpr.coerce_to_type( - builder, arg_val, pty, arg_node) - llvmlite.value_set_next(arg_val, None) - llvmlite.value_set_next(tail, arg_val) - tail = arg_val + if kwc > 0 and found_func is not None: + # 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配 + # 缺失参数用零值兜底,保持 call 参数数量与 define 一致 + cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + if cur_param_k is not None: + cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self + pi_k: int = 0 + while cur_param_k is not None: + arg_node_k: ast.AST | t.CPtr = None + if pi_k < can: + arg_node_k = cargs.get(pi_k) + else: + pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k) + if pname_k is not None: + ki_k: int + for ki_k in range(kwc): + kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k)) + if kw_k is None or kw_k.arg is None or kw_k.value is None: + continue + if _kwarg_name_matches(kw_k.arg, pname_k) == 1: + arg_node_k = kw_k.value + break + arg_val_k: llvmlite.Value | t.CPtr = None + if arg_node_k is not None: + arg_val_k = HandlesExpr.translate_value( + builder, pool, mod, arg_node_k, None, 0, trans) + if arg_val_k is None: + # 缺失参数:零值兜底(保持参数数量匹配) + pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) + if pty_k is not None: + arg_val_k = llvmlite.ConstZero(pool, pty_k) + if arg_val_k is not None: + pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k) + if pty_k2 is not None: + arg_val_k = HandlesExpr.coerce_to_type( + builder, arg_val_k, pty_k2, arg_node_k) + llvmlite.value_set_next(arg_val_k, None) + llvmlite.value_set_next(tail, arg_val_k) + tail = arg_val_k + arg_count_eff += 1 + pi_k += 1 + cur_param_k = llvmlite.param_get_next(cur_param_k) + else: + # 位置参数(原逻辑) + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + # 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1) + # 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT) + # 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃 + if found_func is not None: + pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + pi: int = 0 + while pp is not None and pi < ai + 1: + if pi == ai + 1: + break + pp = llvmlite.param_get_next(pp) + pi += 1 + if pp is not None: + pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) + if pty is not None: + arg_val = HandlesExpr.coerce_to_type( + builder, arg_val, pty, arg_node) + llvmlite.value_set_next(arg_val, None) + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + arg_count_eff += 1 - total_count: int = 1 + can + total_count: int = 1 + arg_count_eff # 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数 # 查找函数的 defaults 信息 @@ -3867,11 +3916,11 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, mdf_param_count = mdf_gd.ParamCount # 计算需要填充的参数(不含 self) - # can = 已提供的非 self 参数数量 + # arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建) # mdf_param_count = 函数定义的非 self 参数数量 - if mdf_param_count > can: + if mdf_param_count > arg_count_eff: mdf_offset: int = mdf_param_count - mdf_default_count - mdf_pi: int = can + mdf_pi: int = arg_count_eff while mdf_pi < mdf_param_count: # 优先用默认值 if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: @@ -4871,36 +4920,6 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, # 查找对象变量 obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, method_obj_nm.id) - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(method_obj_nm.id, "args") == 0: - if obj_var is None: - stdio.printf("[DBG-MC] args NOT in symtab\n") - elif obj_var.Ty is None: - stdio.printf("[DBG-MC] args ty=None\n") - else: - akind: int = 0 - match obj_var.Ty: - case llvmlite.LLVMType.Ptr(pe2): - akind = 1 - match pe2: - case llvmlite.LLVMType.Struct(f3, c3, n3): - if n3 is not None: - stdio.printf("[DBG-MC] args ty Ptr(Struct(%s))\n", n3) - else: - stdio.printf("[DBG-MC] args ty Ptr(Struct)\n") - case llvmlite.LLVMType.Int(b3): - stdio.printf("[DBG-MC] args ty Ptr(i%d)\n", b3) - case _: - stdio.printf("[DBG-MC] args ty Ptr(inner-other)\n") - case llvmlite.LLVMType.Int(b3b): - akind = 2 - stdio.printf("[DBG-MC] args ty i%d\n", b3b) - case llvmlite.LLVMType.Void(): - akind = 3 - stdio.printf("[DBG-MC] args ty Void\n") - case _: - akind = 0 - stdio.printf("[DBG-MC] args ty kind=%d\n", akind) if obj_var is not None and obj_var.Ty is not None: # 检查是否为 Ptr(Struct(...))(结构体值变量) # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) @@ -5488,9 +5507,6 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 # 如 string.strchr(...) → @{sha1_of_string}.strchr if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(func_name, "get_str") == 0: - stdio.printf("[DBG-MC] get_str reached cross-module path\n") xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name: xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index a8fee88..de37d59 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -722,9 +722,6 @@ def _parse_type_string(pool: memhub.MemBuddy | t.CPtr, name_buf[seg_len] = '\0' name_node: ast.AST | t.CPtr = ast.Name(pool, name_buf, ctx) stdlib.free(name_buf) - # [DBG-MC] 临时诊断(验证后移除) - if string.strstr(type_str, "ParsedArgs") is not None: - stdio.printf("[DBG-MC] pts Name id_ptr=%p kind=%d\n", name_node.id, name_node.kind()) return name_node @@ -921,6 +918,13 @@ def map_t_type(pool: memhub.MemBuddy | t.CPtr, return llvmlite.Ptr(pool, llvmlite.Int8(pool)) elif string.strcmp(type_name, "CVoid") == 0: return llvmlite.Void(pool) + # CNeedPtr/CAutoPtr: 参数自动取地址标记,LLVM 层均为通用指针 i8*。 + # (TPC 中二者继承 CPtr;TPV 未实现调用点自动取地址,非指针实参应在调用点报错, + # 而非静默降级为 i32 导致指针截断。) + elif string.strcmp(type_name, "CNeedPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CAutoPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 无符号修饰 elif string.strcmp(type_name, "CUnsigned") == 0: return llvmlite.Int32(pool) @@ -1570,10 +1574,15 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, if at.value is not None and at.value.kind() == ast.ASTKind.Name: val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) if val_name.id is not None: - # 仅当模块已导入时才解析 - mod_imp: int = HandlesImports.is_module_imported(imported_modules, val_name.id) - if mod_imp == 0: - return None + # t/c 是内建库(SHA1 豁免),显式写 t.XXX 即确指内建库, + # 不依赖 imported_modules(t 可能不在其中,如 vpi 注入上下文) + is_builtin_attr: int = 0 + if string.strcmp(val_name.id, "t") == 0 or string.strcmp(val_name.id, "c") == 0: + is_builtin_attr = 1 + if is_builtin_attr == 0: + mod_imp: int = HandlesImports.is_module_imported(imported_modules, val_name.id) + if mod_imp == 0: + return None # 先尝试内置类型映射(int 等) mapped_ty: llvmlite.LLVMType | t.CPtr = map_t_type(pool, at.attr) if mapped_ty is not None: @@ -1603,13 +1612,6 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, # 检测 t.CPtr 标记(指针包装标记,支持 t.CPtr 与 from t import CPtr 裸名) left_is_cptr: int = _is_cptr_marker(bop.left, imported_modules) right_is_cptr: int = _is_cptr_marker(bop.right, imported_modules) - # [DBG-MC] 临时诊断(验证后移除) - if bop.left is not None and bop.left.kind() == ast.ASTKind.Name: - lnm_dbg: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.left) - if lnm_dbg.id is not None and string.strcmp(lnm_dbg.id, "ParsedArgs") == 0: - stdio.printf("[DBG-MC] BinOp ParsedArgs left_cptr=%d right_cptr=%d\n", - left_is_cptr, right_is_cptr) - if left_is_cptr != 0 or right_is_cptr != 0: # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr # left 是 CPtr → other 是 right;right 是 CPtr → other 是 left @@ -1637,15 +1639,6 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, return llvmlite.Ptr(pool, llvmlite.Int8(pool)) other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( pool, other_node, imported_modules, from_imports, trans) - # [DBG-MC] 临时诊断(验证后移除) - if other_node is not None: - if other_node.kind() == ast.ASTKind.Name: - onm3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) - if onm3.id is not None and string.strcmp(onm3.id, "ParsedArgs") == 0: - stdio.printf("[DBG-MC] other_node Name(%s) ty=%p visible=%d\n", - onm3.id, other_ty, HandlesStruct.is_struct_visible("ParsedArgs")) - else: - stdio.printf("[DBG-MC] other_node kind=%d ty=%p\n", other_node.kind(), other_ty) # 仅裸名(Name)场景验证解析结果必须是已注册 struct: # 损坏节点可能解析出基础类型垃圾(如 Int8 → Ptr(i8))。 # Attribute 场景(Module.Class / t.XXX)resolve 结果直接可用 @@ -1675,12 +1668,6 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, other_cls_nm = other_nm.id if other_cls_nm is not None: other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm) - # [DBG-MC] 临时诊断(验证后移除) - if string.strcmp(other_cls_nm, "ParsedArgs") == 0: - stdio.printf("[DBG-MC] fallback ParsedArgs get_struct=%p visible=%d count=%d\n", - other_cls_ty, - HandlesStruct.is_struct_visible("ParsedArgs"), - HandlesStruct.get_struct_count()) if other_cls_ty is not None: return llvmlite.Ptr(pool, other_cls_ty) # CPtr 单独使用或其他无效类型 → i8* diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index a7ead5d..c1ae0ed 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -968,6 +968,81 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 1b 阶段新注册的 struct/enum 条目改 stdlib 分配(跨文件永久存活,不被 reset 回收) HandlesStruct.set_stdlib_alloc(1) + # ============================================================ + # Phase 1b-pre: 预生成所有待翻译文件的 .vpi stub + # + # 依赖模块的 .vpi 必须在翻译前可用:1b 主循环按扫描顺序翻译(非拓扑), + # 若 argparse 先于 hashtable 翻译,hashtable.vpi 尚未生成, + # LoadDepVpiIntoModule 读不到 → declare 未注入 → 跨模块调用 + # 返回类型推断错误(如 HashTable.__getitem__ 被推断为 Ptr(HashTable) + # 而 define 返回 i8*)→ 运行时返回值截断崩溃。 + # ============================================================ + dir_len_pv: t.CSizeT = string.strlen(temp_dir) + for i_pv in range(result.Count): + entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size + entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr)) + if entry_pv is None or entry_pv.Sha1 is None: + continue + sha1_pv: str = entry_pv.Sha1 + in_set_pv: int = 0 + if use_reachable != 0: + in_set_pv = StubMerger._is_in_sha1_set(sha1_pv, reachable_set, reachable_count) + else: + in_set_pv = StubMerger._is_in_sha1_set(sha1_pv, sha1_set, set_count) + if in_set_pv == 0: + continue + # vpi 已存在则跳过 + vpi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") + if vpi_path_pv is None: + continue + vf_pv: fileio.File | t.CPtr = fileio.File(vpi_path_pv, fileio.MODE.R) + if not vf_pv.closed: + vf_pv.close() + stdlib.free(vpi_path_pv) + continue + stdlib.free(vpi_path_pv) + # 读取文件、解析 AST、生成 vpi + file_path_pv: str = entry_pv.Path + f_pv: fileio.File | t.CPtr = fileio.File(file_path_pv, fileio.MODE.R) + if f_pv.closed: + continue + src_buf_pv: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf_pv is None: + f_pv.close() + continue + bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, SRC_BUF_SIZE) + f_pv.close() + if bytes_read_pv <= 0: + stdlib.free(src_buf_pv) + continue + if bytes_read_pv < SRC_BUF_SIZE: + src_buf_pv[bytes_read_pv] = 0 + else: + src_buf_pv[SRC_BUF_SIZE - 1] = 0 + lx_pv: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_pv is None: + stdlib.free(src_buf_pv) + continue + ast._lexer_init(lx_pv, src_buf_pv, mb) + tokens_pv: ast.Token | t.CPtr = ast.tokenize(lx_pv) + tree_pv: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_pv) + if tree_pv is None: + stdlib.free(src_buf_pv) + continue + pyi_buf_pv: bytes = stdlib.malloc(PYI_BUF_SIZE) + if pyi_buf_pv is not None: + pyi_pos_pv: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree_pv, entry_pv.RelPath, pyi_buf_pv, PYI_BUF_SIZE) + if pyi_pos_pv > 0: + pyi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi") + if pyi_path_pv is not None: + pf_pv: fileio.File | t.CPtr = fileio.File(pyi_path_pv, fileio.MODE.W) + if not pf_pv.closed: + pf_pv.write(pyi_buf_pv, pyi_pos_pv) + pf_pv.close() + stdlib.free(pyi_path_pv) + stdlib.free(pyi_buf_pv) + stdlib.free(src_buf_pv) + # 遍历每个文件 translated: int = 0 skipped: int = 0