From b91dfef7771215c867620045377adf3d3c87fee1 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 1 Oct 2026 23:39:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(stub):=20vpi=20=E6=B3=A8=E5=85=A5=E4=BE=A7?= =?UTF-8?q?=E9=80=92=E5=BD=92=E7=99=BB=E8=AE=B0=E5=B5=8C=E5=A5=97=E7=B1=BB?= =?UTF-8?q?=E4=B8=BA=E6=89=81=E5=B9=B3=E5=90=8D=20{=E5=A4=96=E7=B1=BB}=5F{?= =?UTF-8?q?=E5=86=85=E7=B1=BB}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VpiReader 此前只登记顶层 ClassDef,跨模块引用 `外类.内类` 拿不到类型 (TPC 侧 stub.ll 已递归声明,双端不对齐)。现按定义端 ClassGenDef._translate_nested_classdefs 的命名口径补上: - _inject_class_struct_declare 增加 name_prefix 形参,非空时算出扁平名 real_name;REPL 分支、已注册检查、命名结构体类型名、register_struct、 add_visible_struct 一律改用 real_name。 - 新增 _inject_nested_class_declares:遍历类体内缩进 ClassDef 子节点, 以 real_name 为前缀递归调用(多层嵌套自然展开为 A_B_C)。 - 嵌套登记后再次调用 mark_module_class 复原"正在定义类"窗口:否则内层 类名会顶掉 CurDefClassName,使外层字段注解的规则 5.5 自引用证据判错、 且 `外类.内类` 的守卫①失效。 --- App/lib/Stub/StubGen/VpiReader.vp | 106 ++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 14 deletions(-) diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index b23f081..4944b13 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -2680,10 +2680,28 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, trans: HT.Translator*, src_sha1: str, imported_modules: str, - from_imports: str) -> int: - """从 vpi ClassDef 注册类为 struct 类型(含字段),使同 vpi 内裸类名注解可解析""" + from_imports: str, + name_prefix: str = None) -> int: + """从 vpi ClassDef 注册类为 struct 类型(含字段),使同 vpi 内裸类名注解可解析 + + name_prefix:非 None 表示"本类是 prefix 类的嵌套类",注册名取扁平名 + `{prefix}_{cls_name}`(多层嵌套自然递归为 A_B_C)——与定义端 + ClassGenDef._translate_nested_classdefs 的命名口径逐字一致。 + """ if pool is None or mod is None or class_cd is None or cls_name is None: return 0 + # 扁平名(嵌套类):`{外类}_{内类}`。父类未注册时也照常登记(本函数自带 + # "字段解析失败即不注册"的既有口径,交给多遍收敛)。 + real_name: str = cls_name + if name_prefix is not None and name_prefix[0] != '\0': + p_len: sizet = string.strlen(name_prefix) + c_len: sizet = string.strlen(cls_name) + flat_buf_c: str = pool.alloc(p_len + 1 + c_len + 1) + if flat_buf_c is not None: + string.strcpy(flat_buf_c, name_prefix) + flat_buf_c[p_len] = '_' + string.strcpy(flat_buf_c + p_len + 1, cls_name) + real_name = flat_buf_c # REPL(ReplStubLayoutMode,见文件末"REPL:includes 类完整布局与虚表恢复"): # 本类若已由 .stub.ll 驱动的路径接管 ⇒ 这里整类让位——已登记(或本遍就地 # 登记成功)只标可见;父类未就绪 ⇒ 本遍不登记(收尾遍补齐);布局不可信 ⇒ @@ -2691,18 +2709,18 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, # State=EMPTY 的类(无父类/无虚表/字段类型不可解析)不在此列,仍走下方既有口径。 if ReplStubLayoutMode != 0: se: rawptr[ReplStubClass] = _repl_stub_find( - _repl_stub_key(pool, src_sha1, cls_name)) + _repl_stub_key(pool, src_sha1, real_name)) if se is not None and se.State != _REPL_SS_EMPTY: if se.State == _REPL_SS_PENDING: _repl_stub_try(se, mod) if se.State == _REPL_SS_OK: - GenApi.add_visible_struct(pool, cls_name) + GenApi.add_visible_struct(pool, real_name) return 1 # 1. 已注册检查(含源模块编译时注册的 entry):仅标记可见,避免重复注册 if src_sha1 is not None and src_sha1[0] != '\0': - existing_c: GenTypes.StructEntry* = GenApi.find_struct_by_module(cls_name, src_sha1) + existing_c: GenTypes.StructEntry* = GenApi.find_struct_by_module(real_name, src_sha1) if existing_c is not None and existing_c.Ty is not None: - GenApi.add_visible_struct(pool, cls_name) + GenApi.add_visible_struct(pool, real_name) return 1 # REnum 类(class X(t.REnum))跳过:布局 {i32 __tag, } 由 # ClassGenEnum._translate_renum_def 按变体计算;vpi 侧按普通 struct 注册 @@ -2722,9 +2740,21 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, # includes/ast/base.vp:359 `_append_child(self.children, node, self.pool)` # 源 %"…list[rawptr[AST]]"* vs 目标 %"…list[rawptr<定义模块SHA1>.AST]"*。 # mark_module_class 一次调用同时完成两件事: - # ① 登记"{src_sha1}.{cls_name}"(名字归属,与 struct 注册状态无关); + # ① 登记"{src_sha1}.{real_name}"(名字归属,与 struct 注册状态无关); # ② 把 CurDefModuleSha1/CurDefClassName 指向本次注入的模块与类(规则 5.5 的闸门)。 - GenApi.mark_module_class(pool, src_sha1, cls_name) + GenApi.mark_module_class(pool, src_sha1, real_name) + # 1.5 嵌套类 / 嵌套 struct:vpi 里的嵌套类是**缩进 ClassDef**(Converter 原样写出, + # 见 Converter._PyiClass 的嵌套类分支),定义端以扁平名 `{外类}_{内类}` 发射 + # (ClassGenDef._translate_nested_classdefs)⇒ 此处按同一命名**先**递归登记。 + # 必须早于下方字段注解解析:外层字段可能写成 `外类.内类`,只有扁平名条目已在 + # 结构体表里,TypeGenResolve._resolve_nested_class_type 才解析得出类型。 + _inject_nested_class_declares(pool, mod, class_cd, real_name, trans, + src_sha1, imported_modules, from_imports) + # 还原"正在定义类"窗口:嵌套递归内的 mark_module_class 会把 CurDefClassName 改成 + # 嵌套类名(A_B)。不还原会让外层字段注解的规则 5.5 自引用证据判错(裸类名票名冻结 + # 成裸名版本、与定义侧带前缀形式分裂),也会让 `外类.内类` 的守卫①(CurDefClassName + # == 外类名)失效。 + GenApi.mark_module_class(pool, src_sha1, real_name) # 2. 收集字段类型(AnnAssign 子节点,仿 ClassGenDef.translate_class_def) field_names_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX) field_types_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX) @@ -2778,20 +2808,22 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, if prev_node_c is not None: prev_node_c.Next = pnode_c prev_node_c = pnode_c - # 4. 命名结构体类型名 "sha1.ClassName"(与定义侧 ClassGenDef 一致) - type_name_c: str = cls_name + # 4. 命名结构体类型名 "sha1.ClassName"(与定义侧 ClassGenDef 一致)。 + # 嵌套类用扁平名 real_name(`外类_内类`),与定义端 + # ClassGenDef._translate_nested_classdefs 发射的 "sha1.外类_内类" 逐字一致。 + type_name_c: str = real_name if src_sha1 is not None and src_sha1[0] != '\0': # [D7·截断纪律] 旧实现固定 64 缓冲 + snprintf("%s.%s"):sha1(16)+'.' 占 17 # 字节,类名超过 46 字符即被**静默截断** ⇒ 命名结构体名与定义侧 # ClassGenDef 的 "sha1.ClassName" 不一致 → find_struct_by_module / # lookup_field_by_class 查不到(误判"未注册")。改为精确长度分配。 sh_len_c: sizet = string.strlen(src_sha1) - cn_len_c: sizet = string.strlen(cls_name) + cn_len_c: sizet = string.strlen(real_name) name_buf_c: str = pool.alloc(sh_len_c + 1 + cn_len_c + 1) if name_buf_c is not None: string.strcpy(name_buf_c, src_sha1) name_buf_c[sh_len_c] = '.' - string.strcpy(name_buf_c + sh_len_c + 1, cls_name) + string.strcpy(name_buf_c + sh_len_c + 1, real_name) type_name_c = name_buf_c struct_ty_c: llvmlite.LLVMType* = llvmlite.Struct( pool, first_node_c, field_count, type_name_c) @@ -2811,8 +2843,10 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, # 算偏移,与定义侧 packed 布局错位(gdt/elf/fat32 二进制格式字段错读)。 if _vpi_class_has_packed(class_cd.decorator_list) != 0: llvmlite.module_set_named_type_packed(mod, pool, struct_ty_c, 1) + # 注册名用扁平名 real_name:跨模块引用 `外类.内类` 时 TypeGenResolve 查的是 + # 扁平名条目(与定义端 StructGen 的登记名同源)。 entry_c: GenTypes.StructEntry* = GenApi.register_struct( - pool, cls_name, struct_ty_c, src_sha1) + pool, real_name, struct_ty_c, src_sha1) if entry_c is None: return 0 # B5:vpi 注入注册的 entry 同步 IsPacked——后续跨模块 stub 注入 @@ -2828,10 +2862,54 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*, af_name_c: str = str(field_names_buf[afi_c]) af_ty_c: llvmlite.LLVMType* = (llvmlite.LLVMType*)(field_types_buf[afi_c]) GenApi.add_field(pool, entry_c, af_name_c, af_ty_c) - GenApi.add_visible_struct(pool, cls_name) + GenApi.add_visible_struct(pool, real_name) return 1 +# ============================================================ +# _inject_nested_class_declares - 递归登记 vpi 类里的嵌套类 +# +# vpi 里的嵌套类是缩进的 ClassDef(Converter._PyiClass 原样写出),定义端以 +# 扁平名 `{外类}_{内类}` 发射(ClassGenDef._translate_nested_classdefs)⇒ 注入侧 +# 必须按同一命名登记,跨模块引用 `外类.内类` 才解析得出类型(否则与 TPC 侧 +# stub.ll 的递归声明不对齐,引用模块拿到 None)。 +# +# 多层嵌套靠递归自然展开(A.B.C → prefix=A_B、cls=C ⇒ A_B_C)。这里**不**过滤 +# REnum / 空字段:把判定统一交给 _inject_class_struct_declare 既有的守卫 +# (REnum 跳过、field_count==0 不注册、已注册只标可见)。 +# 每个内层类登记后,_inject_class_struct_declare 会把自己的 +# mark_module_class 窗口留在嵌套类上;故外层调用点在其后**再调一次** +# mark_module_class 还原(见 _inject_class_struct_declare 内注释)。 +# ============================================================ +def _inject_nested_class_declares(pool: memhub.MemBuddy*, + mod: llvmlite.LLVMModule*, + class_cd: ast.ClassDef*, + prefix_name: str, + trans: HT.Translator*, + src_sha1: str, + imported_modules: str, + from_imports: str) -> None: + """递归登记 class_cd 的所有嵌套 ClassDef 为扁平名类型(前缀 = prefix_name)""" + if pool is None or mod is None or class_cd is None or prefix_name is None: + return + children: list[ast.AST*]* = class_cd.children + if children is None: + return + cn: sizet = len(children) + for ci in range(cn): + child_ast: ast.AST* = children.get(ci) + if child_ast is None: + continue + if child_ast.kind() != ast.ASTKind.ClassDef: + continue + child_cd: ast.ClassDef* = ast.ClassDef*(child_ast) + if child_cd is None or child_cd.name is None or child_cd.name[0] == '\0': + continue + _inject_class_struct_declare(pool, mod, child_cd, child_cd.name, trans, + src_sha1, imported_modules, from_imports, + prefix_name) + + # ============================================================ # _ensure_full_value_types - 跨模块「值类型」引用注册完整定义 #