feat(stub): vpi 注入侧递归登记嵌套类为扁平名 {外类}_{内类}
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 自引用证据判错、 且 `外类.内类` 的守卫①失效。
This commit is contained in:
1 parent
c3f554f1f5
commit
b91dfef777
1 file changed
+92
-14
@@ -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, <payload>} 由
|
||||
# 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 - 跨模块「值类型」引用注册完整定义
|
||||
#
|
||||
|
||||
Reference in new issue
Block a user