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

用户 2026-10-01 定:struct 内允许叠加 struct(与 class 内写 class 同口径)。
此前类体里的嵌套 ClassDef 在两个编译器里都被**静默丢弃**(字段遍历只认 AnnAssign、
方法遍历只认 FunctionDef),现按既有 REnum/union 嵌套命名先例发射为独立结构体。

命名与引用口径(双端同源):内层结构体 = {外类}_{内类}(多层递归 A_B_C);
引用两种写法都可用 —— 限定名 `外类.内类`、扁平名 `外类_内类`。

- HandlesClassDef.py:新增 _EmitNestedClassDefs(deepcopy + 改名后递归
  _EmitClassLlvm,deepcopy 避免污染源码 AST)+ _RegisterNestedClassName
  (SymbolTable 登记裸名/点号名/扁平名,对齐 REnum 变体的三键先例)。
- TypeAnnotationResolver.py:_from_node_attribute 增加嵌套分支 —— 限定名按**扁平名**
  取条目并让 Name/BaseType 都是扁平名(否则会拼出 t.CStruct(name='内类'),
  与声明端 `%"{sha}.外类_内类"` 不同源 ⇒ 布局分叉)。
- DeclarationGenerator.py:_get_type_str 支持 `外类.内类` → `%"{sha}.外类_内类"`;
  _generate_class_decl 递归产出嵌套类型的完整声明(否则跨模块只拿到 opaque,
  指针可用但字段偏移全失效)。
- Phase1Generator.py / Phase2Translator.py:跨模块注册表按扁平名登记嵌套类。
  Phase2Translator 原先用 ast.walk 把嵌套类按**短名**登记(占住平坦命名空间、
  与定义端不同源),改为递归扁平名。

实测(TPC 侧):嵌套类名字登记 {A_B, A_C, A_C_D};`x: A.B` → CTypeInfo(A_B);
声明端 `%"cafe.A" = type { i32, %"cafe.A_B" }` + `%"cafe.A_B" = type { i32 }`
+ 多层 `%"cafe.A_C_D" = type { i32 }`。

已知缺口(下一步):TransPyV 侧跨模块走 .vpi,VpiReader 只登记顶层类 ⇒ 跨模块引用
嵌套类型仍需在 VpiReader 侧补登记(同模块路径已通)。
This commit is contained in:
TermiNexus committed 2026-10-01 23:29:54 +08:00
1 parent a8f6ca006d
commit 5eef845e5b
5 files changed
+159 -3

No files matched your search

+25
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import vast as ast
import copy
import re
from typing import List
@@ -581,6 +582,20 @@ class DeclarationGenerator:
struct_type_name: str = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}'
struct_decl: str = f'{struct_type_name} = type {{ {", ".join(member_types)} }}'
decls.append(struct_decl)
# 嵌套类 / 嵌套 struct:定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef.
# _EmitNestedClassDefs),此处同步产出同名完整类型声明 —— 否则跨模块引用
# `外类.内类` 只会得到一个 opaque 前向声明(指针可用、字段偏移全失效)。
# deepcopy 后改名再递归:本函数所有名字都派生自 node.name,改名即全链路一致;
# 判断/枚举/联合等分支在递归时会各自按内层类自身的基类重新分派。
for _nested_item in getattr(node, 'body', None) or []:
if not isinstance(_nested_item, ast.ClassDef):
continue
_nested_inner: str | None = getattr(_nested_item, 'name', None)
if not _nested_inner:
continue
_nested_node: ast.ClassDef = copy.deepcopy(_nested_item)
_nested_node.name = f'{class_name}_{_nested_inner}'
decls.extend(self._generate_class_decl(_nested_node))
if is_cpython_object or is_cvtable:
new_func_name: str = f'{class_name}.__before_init__'
if self.module_sha1:
@@ -1265,6 +1280,16 @@ class DeclarationGenerator:
module_name = annotation.value.id
elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'):
module_name = annotation.value.attr
# 嵌套类 / 嵌套 struct:限定名 `外类.内类`(module_name 是**类名**而非模块名)。
# 定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef._EmitNestedClassDefs),
# 故此处按扁平名拼类型;命中与否由 struct_names 里是否存在该扁平名裁决
# (不存在即维持下方既有路径,不改变任何既有类型名)。
if module_name and module_name != 't' and module_name != 'c':
NestedName: str = f'{module_name}_{attr_name}'
if NestedName in self.struct_names:
NestedSha1: str | None = self.struct_sha1_map.get(NestedName, self.module_sha1)
NestedStr: str = f'%"{NestedSha1}.{NestedName}"' if NestedSha1 else f'%struct.{NestedName}'
return NestedStr if embedded else f'{NestedStr}*'
if (module_name == 't' and attr_name == 'State') or attr_name == 'State':
return ''
if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable':