feat(struct): 嵌套 class/struct 发射为独立结构体 {外类}_{内类}

用户 2026-10-01 定:struct 内允许叠加 struct(与 class 内写 class 同口径)。
此前类体里的嵌套 ClassDef 被**静默丢弃**(字段循环只认 AnnAssign、
_translate_oop_methods 只认 FunctionDef),现按 TPC 侧 union/renum 的
`{ClassName}_{Nested}` 命名先例发射为独立结构体,与 TPC 提交 5eef845e 同源。

- ClassGenDef.vp:新增 _translate_nested_classdefs —— 在 enum/union/renum/泛型/
  异常分派之后、existing 检查之前(所有提前 return 之前,故 declare_only=1/0 都递归)
  遍历类体 ClassDef 子节点,把子节点 name 临时改写为扁平名后递归
  translate_class_def(本模块所有名字派生点都读 cd.name ⇒ 改名即全链路一致)。
  两个护栏:扁平名分配在 PermPool(跨 Phase 存活);递归后还原 CurDefModuleSha1/
  CurDefClassName(内层 mark_module_class 会覆盖,否则外层字段解析误判当前定义类)。
- TypeGenResolve.vp:新增 _resolve_nested_class_type 并在 Attribute 分支的
  "base 不是模块" 出口前接上 —— 限定名 `外类.内类` 按扁平名查结构体表即可命中
  (裸名 `外类_内类` 走既有 Name 分支天然命中)。判据两道:base 是已知类
  (find_struct 命中,或正处于该类的定义窗口内);扁平名条目存在且 Ty 非空。

引用两种写法都可用:`外类.内类`、`外类_内类`;多层嵌套递归为 A_B_C。
This commit is contained in:
TermiNexus committed 2026-10-01 23:30:15 +08:00
1 parent 3ccc37ca3f
commit c3f554f1f5
2 files changed
+127 -1

No files matched your search

+73 -1
View File
@@ -83,6 +83,15 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
if self.Gen.ClassGenBase._is_exception_class_def(cd) == 1:
return self.Gen.ClassGenBase._register_exception_class_def(trans, cd)
# 嵌套类 / 嵌套 struct:类体里再写 class / struct 此前被**静默丢弃**
# (字段循环只认 AnnAssign、_translate_oop_methods 只认 FunctionDef),
# 现按既有扁平命名先例发射为独立结构体 `{外类}_{内类}`(与 TPC 的
# union/renum 嵌套命名 `{ClassName}_{Nested}` 同源)。
# 放在此处(enum/union/renum/泛型/异常分派之后、existing 检查之前):
# 位于**所有提前 return 之前**,故 declare_only=1/0 两条路径都会递归;
# 而 REnum/union 的嵌套类已由各自分支按"变体"处理并提前 return,不会重复发射。
self._translate_nested_classdefs(trans, cd)
# 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
# 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段(vpi 注入/注册缺陷)。
@@ -650,4 +659,67 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
# ============================================================
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name)
return 0
return 0
# ============================================================
# _translate_nested_classdefs - 递归翻译类体内的嵌套 class / struct
#
# 命名与引用口径(用户 2026-10-01 定,与 TPC union/renum 嵌套命名同源):
# · 内层结构体 IR 名 = `{sha1}.{外类}_{内类}`(sha1 = 与外层相同的定义模块);
# · 引用两种写法都可:限定名 `外类.内类`(Attribute 兜底,见 TypeGenResolve)
# 与扁平名 `外类_内类`(裸名直查结构体表即可命中);
# · 多层嵌套自然递归为 `A_B_C`(递归时子节点名已被改写为 A_B)。
# 实现选择"临时改写子节点 name 再递归"而非另写发射器:本模块所有名字派生点
# (IR 名 {sha}.{名}、register_struct/add_field、AnnotClassName、方法符号名
# `{类}.{方法}` 的 mangling、mark_module_class 键)都读 cd.name ⇒ 改名即全链路
# 一致,且复用继承展平/packed/OOP/vtable 等全部既有逻辑,零新增判据。
# 两个必须的护栏:
# ① 扁平名字符串分配在 PermPool —— 它要跨 Phase(1a/1b)存活,trans.Pool 会随
# mark/reset 回收成悬空串(后续 strcmp 读悬空内存)。
# ② 递归返回后**还原"正在定义类"窗口**(CurDefModuleSha1/CurDefClassName 会被
# 内层 mark_module_class 覆盖)——不还原会让外层随后的字段注解解析误判
# "当前定义类"(规则 5.5 的自引用窗口据此判定,误判会冻结裸名票名)。
# ============================================================
def _translate_nested_classdefs(self, trans: HT.Translator*,
cd: ast.ClassDef*) -> None:
"""把本类体内的嵌套 ClassDef 逐个按 `{外类}_{内类}` 递归翻译"""
if trans is None or cd is None or cd.name is None:
return
children: list[ast.AST*]* = cd.children
if children is None:
return
cn: sizet = len(children)
ci: sizet = 0
while ci < cn:
child_ast: ast.AST* = children.get(ci)
ci += 1
if child_ast is None:
continue
if child_ast.kind() != ast.ASTKind.ClassDef:
continue
child: ast.ClassDef* = ast.ClassDef*(child_ast)
if child is None or child.name is None:
continue
# 扁平名 `{外类}_{内类}`(优先 PermPool:名字要跨 Phase 存活;
# PermPool 缺失时退回本遍池,行为与旧路径一致)
flat_pool: memhub.MemBuddy* = CompilerFactory.factory.PermPool
if flat_pool is None:
flat_pool = trans.Pool
if flat_pool is None:
continue
outer_len: sizet = string.strlen(cd.name)
inner_len: sizet = string.strlen(child.name)
flat_len: sizet = outer_len + 1 + inner_len
flat_buf: str = flat_pool.alloc(flat_len + 1)
if flat_buf is None:
continue
viperlib.snprintf(flat_buf, flat_len + 1, "%s_%s", cd.name, child.name)
# 改写子节点名 → 递归(内部一律以扁平名注册/发射)
old_name: str = child.name
child.name = flat_buf
saved_def_sha1: str = self.Gen.StructGen.CurDefModuleSha1
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
self.translate_class_def(trans, child_ast)
self.Gen.StructGen.CurDefModuleSha1 = saved_def_sha1
self.Gen.StructGen.CurDefClassName = saved_def_cls
child.name = old_name
+54
View File
@@ -279,6 +279,51 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
string.strncpy(b, nm, sizet(hexn))
b[sizet(hexn)] = '\0'
return b
# ============================================================
# _resolve_nested_class_type - 限定名 `外类.内类` → 嵌套类结构体类型
#
# 命名口径:嵌套 class / struct 由 ClassGenDef._translate_nested_classdefs 以
# 扁平名 `{外类}_{内类}` 发射为独立结构体(与 TPC union/renum 的
# `{ClassName}_{Nested}` 同源),故 `外类.内类` 只要拼出扁平名查结构体表即可。
#
# 判据(两道,缺一不可,避免把 `模块.类` 误判成嵌套):
# ① base 名是**已知类**:`find_struct(base)` 命中,**或**正处在 base 自己的
# 定义窗口内(CurDefClassName == base)——后者覆盖"类体内部自引用自己嵌套类"
# (此刻外层 struct 尚未 register_struct,字段注解解析早于注册)。
# ② 扁平名条目存在且 Ty 非空(先按本模块归属精确匹配,再退回裸名)。
# 两条都不满足即返回 None,交由调用方既有的"未解析"路径处理(绝不静默兜底)。
# ============================================================
def _resolve_nested_class_type(self, pool: memhub.MemBuddy*,
outer_name: str,
inner_name: str,
trans: HT.Translator*) -> llvmlite.LLVMType*:
"""`外类.内类` → 嵌套类 Ty;无证据返回 None"""
if pool is None or outer_name is None or inner_name is None:
return None
# ① base 必须是已知类(或正定义中的本类)
outer_known: int = 0
if self.Gen.StructGen.find_struct(outer_name) is not None:
outer_known = 1
if outer_known == 0:
cur_cls: str = self.Gen.StructGen.CurDefClassName
if cur_cls is not None and string.strcmp(cur_cls, outer_name) == 0:
outer_known = 1
if outer_known == 0:
return None
# ② 扁平名 `外类_内类`
flat_len: sizet = string.strlen(outer_name) + 1 + string.strlen(inner_name)
flat_buf: str = pool.alloc(flat_len + 1)
if flat_buf is None:
return None
viperlib.snprintf(flat_buf, flat_len + 1, "%s_%s", outer_name, inner_name)
if trans is not None and trans.ModuleSha1 is not None:
own_e: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(flat_buf, trans.ModuleSha1)
if own_e is not None and own_e.Ty is not None:
return own_e.Ty
any_e: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(flat_buf)
if any_e is not None and any_e.Ty is not None:
return any_e.Ty
return None
def _repl_opaque_class_ty(self, pool: memhub.MemBuddy*,
mod_sha1: str,
cls_name: str) -> llvmlite.LLVMType*:
@@ -2965,6 +3010,15 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if lib_td_v is not None:
td_known = 1
if td_known == 0:
# 嵌套类 / 嵌套 struct:限定名 `外类.内类`(base 是**类名**
# 而非模块名)。到达此处已确定 base 既非 t/c、非 SHA1
# 前缀、非已导入模块、非库 typedef ⇒ 原本必然返回 None,
# 故新增"扁平名 `外类_内类` 命中即返回"不会覆盖任何既有
# 成功路径(命名口径见 ClassGenDef._translate_nested_classdefs)。
nested_ty_q: llvmlite.LLVMType* = \
self._resolve_nested_class_type(pool, val_name.id, at.attr, trans)
if nested_ty_q is not None:
return nested_ty_q
return None
# [阶段1b] 库 typedef 动态表优先(正常库分析):attr 是库声明
# 的 typedef 名(如 stdint.INT/BYTE)且表已注册 → 递归展开走库