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

+26 -3
View File
@@ -1384,7 +1384,7 @@ class Phase2Translator:
_, tree = parse_python_file(pyi_path)
if tree is None:
continue
for node in ast.walk(tree):
for node in ast.iter_child_nodes(tree):
# 每类只登记一次,**先扫到的为准**:判据必须是**类名**。
# 原实现写成 `if sha1_key in struct_sha1_map` —— 用模块 SHA1 去查一张
# 按**类名**建的表,判据恒假 ⇒ 实际是"后扫到的覆盖先扫到的",
@@ -1392,10 +1392,33 @@ class Phase2Translator:
# includes/ast/tokens.vp 各有一个 `class Keyword`,定义端拿到的前缀
# 可能是**另一个模块**的 sha1 ⇒ 同一类出现两个 struct 实例、
# `__before_init__` 声明与调用点分叉)。
if isinstance(node, ast.ClassDef) and node.name not in struct_sha1_map:
struct_sha1_map[node.name] = sha1_key
if isinstance(node, ast.ClassDef):
# 嵌套类按扁平名 `{外类}_{内类}` 登记(与定义端
# HandlesClassDef._EmitNestedClassDefs、Phase1Generator.
# _RegisterNestedStructNames 同源)。此前用 ast.walk 会把嵌套类按
# **短名** `Inner` 登记 —— 既占住平坦命名空间,又与定义端的
# `外类_内类` 不同源(跨模块前缀分裂)。
self._RegisterStructSha1Rec(node, node.name, sha1_key, struct_sha1_map)
return struct_sha1_map
def _RegisterStructSha1Rec(self, Node, FlatName: str, Sha1Key: str,
StructSha1Map: dict) -> None:
"""递归登记"类名 → 定义模块 SHA1"(嵌套类用扁平名 `{外类}_{内类}`)"""
if not FlatName:
return
if FlatName not in StructSha1Map:
StructSha1Map[FlatName] = Sha1Key
Body = getattr(Node, 'body', None)
if not Body:
return
for Item in Body:
if not isinstance(Item, ast.ClassDef):
continue
InnerName: str | None = getattr(Item, 'name', None)
if not InnerName:
continue
self._RegisterStructSha1Rec(Item, f'{FlatName}_{InnerName}', Sha1Key, StructSha1Map)
def run(self) -> None:
"""扫描源目录,翻译并生成 .ll 含代码文件(导入遍历)"""
import sys as _sys