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:
1 parent
3ccc37ca3f
commit
c3f554f1f5
2 files changed
+127
-1
No files matched your search
@@ -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
|
||||
@@ -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)且表已注册 → 递归展开走库
|
||||
|
||||
Reference in new issue
Block a user