回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。
理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
· e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
· 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。
注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
1512 lines
80 KiB
Plaintext
1512 lines
80 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
from . import ClassGenBase
|
||
|
||
|
||
# ============================================================
|
||
# 本地常量副本(原 HandlesEnum/HandlesClassDef 定义,拆分时随文件删除而丢失——
|
||
# 未定义名在常量上下文被 TPV 折叠为 0,会导致枚举成员收集被静默跳过、
|
||
# register_enum 永不调用 → 所有 CEnum 注册失败 → 裸名枚举访问 NameError)
|
||
# ============================================================
|
||
define ENUM_MEMBER_MAX_LOCAL = 128
|
||
define RENUM_CLASS_MAX = 64
|
||
define RENUM_VARIANT_PER_CLASS = 32
|
||
define RENUM_ALIAS_MAX = 512
|
||
|
||
# ============================================================
|
||
# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表
|
||
# ============================================================
|
||
novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||
"""enum/union/renum 定义与变体表"""
|
||
|
||
def _resolve_enum_member_type(self, pool: memhub.MemBuddy*,
|
||
ann_node: ast.AST*,
|
||
imported_modules: str,
|
||
from_imports: str) -> llvmlite.LLVMType*:
|
||
"""解析枚举成员的类型注解为 LLVM 整数类型"""
|
||
if ann_node is None:
|
||
return llvmlite.Int32(pool)
|
||
|
||
k: int = ann_node.kind()
|
||
|
||
# Attribute 节点: t.State / int / int8 等
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(ann_node)
|
||
if at.attr is None:
|
||
# [S4 fail-fast] Attribute 缺失成员名(AST 损坏),不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Attribute 缺失成员名", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
# t.State → 默认 i32
|
||
if string.strcmp(at.attr, "State") == 0:
|
||
return llvmlite.Int32(pool)
|
||
# [枚举侧 bool 口径] `t.CBool` 与裸名 `bool` 同宽(8 位),否则同一
|
||
# 枚举成员两种写法会分裂出 i1 / i8 两种宽度。全局 `t.CBool` = i1
|
||
# (map_t_type L1447-1449)保持不变,仅在**枚举成员注解**这一处按
|
||
# 8 位物化(枚举存储须可按字节寻址;TPC 侧 t.CBool.Size = 8 同口径)。
|
||
if string.strcmp(at.attr, "CBool") == 0:
|
||
return llvmlite.Int8(pool)
|
||
# 其他 t.CXxx 类型:统一口径(CTypedef 动态表优先,miss 回退 map_t_type)
|
||
ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, at.attr, imported_modules, from_imports)
|
||
if ty is not None: return ty
|
||
# [S4 fail-fast] 有注解但解析失败 → 不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: t.{at.attr}", "NameError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
|
||
# Name 节点: from-import 形式(State / CInt)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(ann_node)
|
||
if nm.id is None:
|
||
# [S4 fail-fast] Name 缺失标识符(AST 损坏),不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Name 缺失标识符", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
if string.strcmp(nm.id, "State") == 0:
|
||
return llvmlite.Int32(pool)
|
||
# 内建裸名整数类型(与 resolve_annotation_type 的 Name 分支同口径,
|
||
# TypeGenResolve.vp L2189-2203):枚举成员是整数常量,`int` / `char` /
|
||
# `bool` 裸名直通。其余裸名(含 str/bytes 指针形态与未知名)仍走
|
||
# typedef / builtins 表,miss 即下方 fail-fast(不静默当 int);
|
||
# 指针与非整数成员的统一拦截见 _translate_enum_def。
|
||
if string.strcmp(nm.id, "int") == 0:
|
||
return llvmlite.Int32(pool)
|
||
if string.strcmp(nm.id, "char") == 0:
|
||
return llvmlite.Int8(pool)
|
||
if string.strcmp(nm.id, "bool") == 0:
|
||
# [枚举侧 bool 口径] 枚举存储必须是可按字节寻址的整数类型,
|
||
# i1 不能作为独立枚举宽度 ⇒ 枚举成员注解的 bool 一律 8 位。
|
||
# **不改**全局 bool = i1(TypeGenResolve.vp L2201-2203 与
|
||
# map_t_type 的 CBool,用于普通变量/形参/字段)。
|
||
# 两侧一致:TPC 侧枚举成员 bool 经 t.CBool.Size 亦为 8。
|
||
return llvmlite.Int8(pool)
|
||
ty2: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, nm.id, imported_modules, from_imports)
|
||
if ty2 is not None:
|
||
return ty2
|
||
# [S4 fail-fast] 有注解但解析失败 → 不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {nm.id}", "NameError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
|
||
# BinOp 节点: t.State | int8(递归查找实际类型)
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(ann_node)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
left_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, bop.left, imported_modules, from_imports)
|
||
# 跳过 t.State(i32 默认),优先返回具体类型
|
||
left_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(left_ty)
|
||
if left_bits != 0 and not self._is_state_annotation(bop.left):
|
||
return left_ty
|
||
right_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, bop.right, imported_modules, from_imports)
|
||
if right_ty is not None and not self._is_state_annotation(bop.right):
|
||
return right_ty
|
||
# 两边都是 State 或无法确定,返回较宽的
|
||
right_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(right_ty)
|
||
if left_bits >= right_bits:
|
||
return left_ty
|
||
return right_ty
|
||
# fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
|
||
# fail-fast:未知注解节点 kind,不再静默回退 i32
|
||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
|
||
def _is_state_annotation(self, node: ast.AST*) -> int:
|
||
"""检查注解节点是否为 t.State,返回 1=是 / 0=否"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
if at.attr is not None and string.strcmp(at.attr, "State") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None and string.strcmp(nm.id, "State") == 0:
|
||
return 1
|
||
return 0
|
||
return 0
|
||
def _enum_annotation_name_is_ptr(self, node: ast.AST*) -> int:
|
||
"""注解节点本身(Name/Attribute/Subscript 顶名)是否指针形态,1=是 / 0=否
|
||
|
||
指针标记名集合与 resolve_annotation_type / map_t_type 的指针产出点同源:
|
||
CPtr(= rawptr/str/bytes 的底层,map_t_type L1407)、CNeedPtr / CAutoPtr
|
||
(map_t_type L1421-1424 均为 i8*)、rawptr(内建指针,_lookup_builtins_typedef
|
||
L921-923 恒返回 t.CPtr)、str / bytes(resolve_annotation_type L2190-2200 → i8*)。
|
||
"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
if at.attr is not None:
|
||
if string.strcmp(at.attr, "CPtr") == 0:
|
||
return 1
|
||
if string.strcmp(at.attr, "CNeedPtr") == 0:
|
||
return 1
|
||
if string.strcmp(at.attr, "CAutoPtr") == 0:
|
||
return 1
|
||
if string.strcmp(at.attr, "rawptr") == 0:
|
||
return 1
|
||
if string.strcmp(at.attr, "str") == 0:
|
||
return 1
|
||
if string.strcmp(at.attr, "bytes") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
if string.strcmp(nm.id, "CPtr") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "CNeedPtr") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "CAutoPtr") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "rawptr") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "str") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "bytes") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Subscript:
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
if sub.value is not None:
|
||
return self._enum_annotation_name_is_ptr(sub.value)
|
||
return 0
|
||
return 0
|
||
def _enum_member_annotation_is_ptr(self, ann_node: ast.AST*) -> int:
|
||
"""枚举成员注解(**含联合类型逐边**)是否含指针类型,1=是 / 0=否
|
||
|
||
联合形态必须逐边检查:`t.CInt | t.CPtr` 在 _resolve_enum_member_type 的
|
||
BinOp 分支会"优先返回具体整数类型"(源码 L94-105)——只看解析结果会把
|
||
含指针的联合静默当整数,故在解析前按注解树拦。
|
||
"""
|
||
if ann_node is None:
|
||
return 0
|
||
if ann_node.kind() == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(ann_node)
|
||
if bop.op != ast.OpKind.BitOr:
|
||
return 0
|
||
if self._enum_member_annotation_is_ptr(bop.left) == 1:
|
||
return 1
|
||
return self._enum_member_annotation_is_ptr(bop.right)
|
||
return self._enum_annotation_name_is_ptr(ann_node)
|
||
def _extract_int_value(self, node: ast.AST*) -> int64:
|
||
"""从 AST 节点提取整数值,失败返回 0"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
return cn.int_val
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uo: ast.UnaryOp* = ast.UnaryOp*(node)
|
||
if uo.op == ast.OpKind.USub:
|
||
inner: int64 = self._extract_int_value(uo.operand)
|
||
return -inner
|
||
return 0
|
||
return 0
|
||
|
||
# ========================================================
|
||
# 枚举成员"可见名 vs 登记名"兜底判据(与 TPC 侧
|
||
# SymbolUtils.EnumBodyMemberNames 同口径、同规则源)
|
||
#
|
||
# 背景:`enum` 成员行一旦出现"注册器不认的写法",成员会被**静默丢弃**
|
||
# (ASTKind 71→3、OpKind 32→2;与 Debugger/enum-semantics.md §15、
|
||
# rawptr-migration-and-fastfail.md §27 同族,这是第三次复发)。取全口径而非
|
||
# 逐个白名单化"已知可展开形态":成员名必然落在 Assign 的 targets / AnnAssign
|
||
# 的 target / Expr 语句的表达式这三类"名字位置"之一,把它们**全部**数进来,
|
||
# 任何漏登记的写法都会表现为"可见名数 > 登记数" ⇒ 注册处 fail-fast。
|
||
# ========================================================
|
||
def _enum_elts_visible_names(self, elts: list[ast.AST*]*) -> int:
|
||
"""元素表里的"可见名"计数(Tuple/List 共用)。"""
|
||
if elts is None:
|
||
return 0
|
||
n: int = 0
|
||
for i in range(len(elts)):
|
||
n += self._enum_target_visible_names(elts.get(i))
|
||
return n
|
||
def _enum_target_visible_names(self, node: ast.AST*) -> int:
|
||
"""成员名位置的"可见名"计数(Name / Tuple / List 逐项、Starred 解引用递归)。
|
||
|
||
与 TPC 侧 SymbolUtils._EnumMemberNameNodes 同口径:把"注册器不认的成员
|
||
写法"(逗号组 Tuple、元组目标、Starred)里的成员名照样数进来。
|
||
"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Name:
|
||
return 1
|
||
if k == ast.ASTKind.Tuple:
|
||
tup: ast.Tuple* = ast.Tuple*(node)
|
||
return self._enum_elts_visible_names(tup.elts)
|
||
if k == ast.ASTKind.List:
|
||
lst: ast.List* = ast.List*(node)
|
||
return self._enum_elts_visible_names(lst.elts)
|
||
if k == ast.ASTKind.Starred:
|
||
st: rawptr[ast.Starred] = rawptr[ast.Starred](node)
|
||
return self._enum_target_visible_names(st.value)
|
||
return 0
|
||
def _enum_body_visible_names(self, children: list[ast.AST*]*) -> int:
|
||
"""枚举类体内"源码可见的成员名"总数(含注册器不认的写法)。
|
||
|
||
Assign 的每个 target / AnnAssign 的 target / Expr 语句的表达式;
|
||
不含成员名的语句(docstring / pass / 方法定义 / 嵌套类)计 0,不误报。
|
||
"""
|
||
if children is None:
|
||
return 0
|
||
n: int = 0
|
||
for ci in range(len(children)):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
if sk == ast.ASTKind.Assign:
|
||
ag: ast.Assign* = ast.Assign*(stmt)
|
||
if ag.targets is not None:
|
||
for ti in range(len(ag.targets)):
|
||
n += self._enum_target_visible_names(ag.targets.get(ti))
|
||
elif sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
n += self._enum_target_visible_names(aa.target)
|
||
elif sk == ast.ASTKind.Expr:
|
||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
|
||
n += self._enum_target_visible_names(ex.value)
|
||
return n
|
||
def _enum_first_unregistered_node(self, children: list[ast.AST*]*) -> ast.AST*:
|
||
"""第一个"含可见成员名但注册器不认"的语句(供 fail-fast 定位真行号);无则 None。"""
|
||
if children is None:
|
||
return None
|
||
for ci in range(len(children)):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
if sk == ast.ASTKind.Expr:
|
||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
|
||
if self._enum_target_visible_names(ex.value) > 0:
|
||
return stmt
|
||
elif sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
if aa.target is not None and aa.target.kind() != ast.ASTKind.Name \
|
||
and self._enum_target_visible_names(aa.target) > 0:
|
||
return stmt
|
||
elif sk == ast.ASTKind.Assign:
|
||
ag: ast.Assign* = ast.Assign*(stmt)
|
||
if ag.targets is not None:
|
||
for ti in range(len(ag.targets)):
|
||
tgt: ast.AST* = ag.targets.get(ti)
|
||
if tgt is not None and tgt.kind() != ast.ASTKind.Name \
|
||
and self._enum_target_visible_names(tgt) > 0:
|
||
return stmt
|
||
return None
|
||
def _translate_enum_def(self, trans: HT.Translator*,
|
||
cd: ast.ClassDef*) -> int:
|
||
"""翻译枚举类定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的
|
||
# FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的
|
||
# 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry,
|
||
# add_enum_member 成员名去重,重复处理安全合并。
|
||
|
||
children: list[ast.AST*]* = cd.children
|
||
if children is None:
|
||
VLogger.warning(f"{class_name} has no body", "ENUM")
|
||
return 0
|
||
|
||
cn: sizet = len(children)
|
||
|
||
# 临时数组存储成员信息
|
||
member_names_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
member_types_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
member_values_buf: int64 | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
|
||
if member_names_buf is None or member_types_buf is None or member_values_buf is None:
|
||
return 0
|
||
string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
|
||
|
||
member_count: int = 0
|
||
next_val: int64 = 0
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
if aa is None or aa.target is None:
|
||
continue
|
||
|
||
# 获取成员名
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt: ast.Name* = ast.Name*(aa.target)
|
||
if tgt.id is None:
|
||
continue
|
||
|
||
# [枚举规格 fail-fast] 成员不允许指针类型:t.CPtr / CNeedPtr /
|
||
# CAutoPtr / rawptr[...] / str / bytes,以及**联合类型里夹带指针**
|
||
# 的形态(t.CInt | t.CPtr)。必须先于类型解析——联合分支会优先返回
|
||
# 具体整数类型、rawptr[...] 又是 Subscript(非 Name/Attribute/BinOp)
|
||
# 会在解析里报笼统的"注解解析失败",两者都盖不住"指针成员"这个真因。
|
||
if self._enum_member_annotation_is_ptr(aa.annotation) == 1:
|
||
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 不能是指针类型(枚举值只支持整数成员类型)", "TypeError")
|
||
return 0 # 不可达(fatal_error 已退出)
|
||
|
||
# 解析成员类型
|
||
member_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, aa.annotation, trans._imported_modules, trans._from_imports)
|
||
|
||
# [枚举规格 fail-fast] 成员类型必须是整数类型:浮点/void/结构体/
|
||
# 数组的位宽均为 0,无法参与"枚举宽度 = 最宽成员类型"的推导,
|
||
# 静默接受会让寄存器宽度与访问侧常量类型不一致。禁止静默降级。
|
||
member_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(member_ty)
|
||
if member_bits <= 0:
|
||
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 的类型必须为整数类型(不允许指针/浮点/void/结构体/数组),无法推导枚举宽度", "TypeError")
|
||
return 0 # 不可达(fatal_error 已退出)
|
||
|
||
# 解析成员值
|
||
has_value: int = 0
|
||
cur_val: int64 = 0
|
||
if aa.value is not None:
|
||
cur_val = self._extract_int_value(aa.value)
|
||
has_value = 1
|
||
else:
|
||
cur_val = next_val
|
||
|
||
# 下一个自动值
|
||
next_val = cur_val + 1
|
||
|
||
# 存储
|
||
if member_count < ENUM_MEMBER_MAX_LOCAL:
|
||
member_names_buf[member_count] = sizet(tgt.id)
|
||
member_types_buf[member_count] = sizet(member_ty)
|
||
member_values_buf[member_count] = cur_val
|
||
member_count += 1
|
||
|
||
elif sk == ast.ASTKind.Assign:
|
||
# 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等
|
||
# CEnum 子类中无类型注释的赋值也视为枚举成员。
|
||
# 每个 Name target 都是成员(`A = B = 1` 两个名字都登记——与 TPC
|
||
# HandlesClassDef._RegisterEnumMembers 的逐 target 口径一致;此前
|
||
# 只取 targets[0] 会让后续 target 静默漏成员)。
|
||
ag: ast.Assign* = ast.Assign*(stmt)
|
||
if ag is None or ag.targets is None:
|
||
continue
|
||
tgts: list[ast.AST*]* = ag.targets
|
||
tn: sizet = len(tgts)
|
||
if tn == 0:
|
||
continue
|
||
|
||
# Assign 无类型注释,默认使用 i32
|
||
member_ty_a: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
|
||
# 解析成员值(同一语句的所有 target 共享该值,next_val 只推进一次)
|
||
cur_val_a: int64 = 0
|
||
if ag.value is not None:
|
||
cur_val_a = self._extract_int_value(ag.value)
|
||
else:
|
||
cur_val_a = next_val
|
||
next_val = cur_val_a + 1
|
||
|
||
# 存储(逐 target;非 Name target 由注册处兜底判据拦住)
|
||
for ti in range(tn):
|
||
t0: ast.AST* = tgts.get(ti)
|
||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_a: ast.Name* = ast.Name*(t0)
|
||
if tgt_a.id is None:
|
||
continue
|
||
if member_count < ENUM_MEMBER_MAX_LOCAL:
|
||
member_names_buf[member_count] = sizet(tgt_a.id)
|
||
member_types_buf[member_count] = sizet(member_ty_a)
|
||
member_values_buf[member_count] = cur_val_a
|
||
member_count += 1
|
||
|
||
# [兜底判据 fail-fast] "源码里可见的成员名字数" vs "实际登记成员数"。
|
||
# 任何注册器不认的成员写法(逗号组带值 `A, B = 1`、逗号组带注解
|
||
# `A, B: T`、单名尾随逗号 `A,`、元组目标,以及未来出现的新形态)都会让
|
||
# 可见名数 > 登记数——此前是**静默丢成员**(ASTKind 71→3、OpKind 32→2;
|
||
# 与 Debugger/enum-semantics.md §15、rawptr-migration-and-fastfail.md §27
|
||
# 同族,这是第三次复发),此处一律 fail-fast,不再静默跳过。
|
||
# 判据口径与 TPC HandlesClassDef._RegisterEnumMembers 完全一致(同规则源)。
|
||
visible_count: int = self._enum_body_visible_names(children)
|
||
if visible_count != member_count:
|
||
diff_count: int = visible_count - member_count
|
||
bad: ast.AST* = self._enum_first_unregistered_node(children)
|
||
bad_desc: str = "(无法定位到具体语句,请检查枚举体)"
|
||
if bad is not None:
|
||
bad_desc = bad.type_name()
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
bad if bad is not None else cd,
|
||
f"枚举 '{class_name}' 成员登记数不一致:源码里可见的成员名 {visible_count} 个,"
|
||
f"实际只登记 {member_count} 个(差额 {diff_count} 个会被静默丢弃)。"
|
||
f"未识别的成员写法(首个): {bad_desc} 形态的语句——如逗号组带值 `A, B = 1`、"
|
||
f"逗号组带注解 `A, B: T`、单名尾随逗号 `A,`。"
|
||
f"期望形态: 每行一个 `Name` / `Name: T` / `Name = 值`,"
|
||
f"或多个简单标识符用逗号分隔(`A, B, C`,可带尾随逗号)。"
|
||
f"修法: 把该行改写为逐个成员一行,或改写为纯标识符逗号组(去掉 `= 值` / `: T`)。"
|
||
f"(本判据在注册处比对『可见名数 vs 登记数』,任何未识别形态都会命中,"
|
||
f"不再静默丢成员)",
|
||
"TypeError")
|
||
return 0
|
||
|
||
if member_count == 0:
|
||
VLogger.warning(f"{class_name} has no members", "ENUM")
|
||
return 0
|
||
|
||
# 确定基准类型:所有成员类型中 Bits 最大的
|
||
base_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
max_bits: int = 0
|
||
for mi in range(member_count):
|
||
ty_addr: sizet = member_types_buf[mi]
|
||
if ty_addr == 0:
|
||
continue
|
||
mty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(ty_addr)
|
||
bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(mty)
|
||
if bits > max_bits:
|
||
max_bits = bits
|
||
base_ty = mty
|
||
|
||
# 注册枚举
|
||
entry: rawptr[GenTypes.EnumEntry] = self.Gen.StmtGenDecl.register_enum(pool, class_name, base_ty)
|
||
if entry is None:
|
||
VLogger.error("failed to register {class_name}", "ENUM")
|
||
return 0
|
||
|
||
# 添加成员
|
||
for mi in range(member_count):
|
||
fname_addr: sizet = member_names_buf[mi]
|
||
if fname_addr == 0:
|
||
continue
|
||
mname: str = rawptr(fname_addr)
|
||
fty_addr2: sizet = member_types_buf[mi]
|
||
if fty_addr2 == 0:
|
||
continue
|
||
mty2: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr2)
|
||
mval: int64 = member_values_buf[mi]
|
||
if mname is not None and mty2 is not None:
|
||
self.Gen.StmtGenDecl.add_enum_member(pool, entry, mname, mval, mty2)
|
||
|
||
VLogger.info(f"registered {class_name} with {member_count} members, base_bits={max_bits}", "ENUM")
|
||
return 0
|
||
|
||
def _get_type_size(self, ty: llvmlite.LLVMType*) -> int:
|
||
"""计算 LLVM 类型的字节大小(含对齐 padding)"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
return (bits + 7) // 8
|
||
case llvmlite.LLVMType.Float(bits):
|
||
return bits // 8
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 8
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
return self._get_type_size(elem_ty) * count
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
# 计算结构体大小,考虑字段对齐 padding
|
||
# 规则: 每个字段的对齐 = 该字段类型的自然对齐
|
||
# 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1
|
||
# 结构体总大小需对齐到最大字段对齐的倍数
|
||
# packed(@c.Attribute(t.attr.packed))结构体无字段填充:
|
||
# 大小 = 字段尺寸之和(LLVM packed struct 语义)。
|
||
is_packed: int = self.Gen.StructGen.struct_type_is_packed(ty)
|
||
total: int = 0
|
||
max_align: int = 1
|
||
cur: rawptr[llvmlite.ParamNode] = fields
|
||
i: int = 0
|
||
while cur is not None and i < fcount:
|
||
if cur.Ty is not None:
|
||
fty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(cur.Ty)
|
||
fsize: int = self._get_type_size(fty)
|
||
falign: int = self._get_type_align(fty)
|
||
# 对齐当前偏移到字段对齐边界(packed 不插填充)
|
||
if is_packed == 0 and falign > 0:
|
||
rem: int = total % falign
|
||
if rem != 0:
|
||
total += falign - rem
|
||
total += fsize
|
||
if is_packed == 0 and falign > max_align:
|
||
max_align = falign
|
||
cur = cur.Next
|
||
i += 1
|
||
# packed 无尾部对齐;非 packed 总大小对齐到最大字段对齐的倍数
|
||
if is_packed != 0:
|
||
return total
|
||
rem2: int = total % max_align
|
||
if rem2 != 0:
|
||
total += max_align - rem2
|
||
return total
|
||
case _:
|
||
return 8
|
||
def _get_type_align(self, ty: llvmlite.LLVMType*) -> int:
|
||
"""返回类型的自然对齐(字节)"""
|
||
if ty is None:
|
||
return 1
|
||
match ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
if bits <= 8:
|
||
return 1
|
||
elif bits <= 16:
|
||
return 2
|
||
elif bits <= 32:
|
||
return 4
|
||
else:
|
||
return 8
|
||
case llvmlite.LLVMType.Float(bits):
|
||
if bits <= 32:
|
||
return 4
|
||
else:
|
||
return 8
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 8
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
return self._get_type_align(elem_ty)
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
# packed 结构体整体按字节对齐(对齐 1,无填充)
|
||
if self.Gen.StructGen.struct_type_is_packed(ty) != 0:
|
||
return 1
|
||
# 结构体的对齐 = 最大字段对齐
|
||
max_align: int = 1
|
||
cur: rawptr[llvmlite.ParamNode] = fields
|
||
i: int = 0
|
||
while cur is not None and i < fcount:
|
||
if cur.Ty is not None:
|
||
fty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(cur.Ty)
|
||
fa: int = self._get_type_align(fty)
|
||
if fa > max_align:
|
||
max_align = fa
|
||
cur = cur.Next
|
||
i += 1
|
||
return max_align
|
||
case _:
|
||
return 8
|
||
def _translate_union_def(self, trans: HT.Translator*,
|
||
cd: ast.ClassDef*) -> int:
|
||
"""翻译联合体定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None: return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前)
|
||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||
|
||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
|
||
if existing is not None:
|
||
# Phase B: 将已存在的命名结构体注册到当前模块
|
||
if existing.Ty is not None:
|
||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||
# SHA1 已在 register_struct 时设置,无需再补
|
||
return 0
|
||
|
||
children: list[ast.AST*]* = cd.children
|
||
if children is None:
|
||
VLogger.warning("{class_name} has no body", "UNION")
|
||
return 0
|
||
|
||
cn: sizet = len(children)
|
||
|
||
# 临时数组存储字段信息
|
||
field_names_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||
field_types_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||
if field_names_buf is None or field_types_buf is None:
|
||
return 0
|
||
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||
|
||
field_count: int = 0
|
||
max_size: int = 0
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None: continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
if aa is None or aa.target is None: continue
|
||
|
||
# 获取字段名
|
||
if aa.target.kind() != ast.ASTKind.Name: continue
|
||
tgt: ast.Name* = ast.Name*(aa.target)
|
||
if tgt.id is None: continue
|
||
|
||
# 解析字段类型
|
||
field_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if field_ty is None:
|
||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
|
||
# 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类)
|
||
if trans._declare_only == 1: return 1
|
||
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
|
||
type_name: str = self.Gen.TypeGenResolve.annotation_to_str(aa.annotation)
|
||
self.Gen.TypeGenErr.fatal_error(aa, f"'{type_name}' is not defined", "NameError")
|
||
field_ty = llvmlite.Int32(pool)
|
||
|
||
# 计算字段大小,更新 max_size
|
||
fsize: int = self._get_type_size(field_ty)
|
||
if fsize > max_size:
|
||
max_size = fsize
|
||
|
||
# 存储到数组
|
||
if field_count < GenTypes.FIELD_MAX:
|
||
field_names_buf[field_count] = sizet(tgt.id)
|
||
field_types_buf[field_count] = sizet(field_ty)
|
||
field_count += 1
|
||
|
||
if field_count == 0:
|
||
VLogger.warning(f"{class_name} has no fields", "UNION")
|
||
return 0
|
||
|
||
if max_size < 1:
|
||
max_size = 1
|
||
|
||
# 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)])
|
||
# 即 { [max_size x i8] }
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
array_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, max_size)
|
||
|
||
# 构建 ParamNode 链表(单字段:字节数组)
|
||
pnode: rawptr[llvmlite.ParamNode] = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||
if pnode is None:
|
||
return 0
|
||
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
|
||
pnode.Ty = array_ty
|
||
|
||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||
union_type_name: str = class_name
|
||
if trans.ModuleSha1 is not None:
|
||
union_name_buf: str = pool.alloc(64)
|
||
if union_name_buf is not None:
|
||
viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||
union_type_name = union_name_buf
|
||
|
||
union_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, pnode, 1, union_type_name)
|
||
if union_ty is None:
|
||
VLogger.error(f"failed to create type for {class_name}", "UNION")
|
||
return 0
|
||
|
||
# Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活)
|
||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册
|
||
# includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后
|
||
# entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃
|
||
# (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||
union_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, union_ty)
|
||
if union_copy is not None:
|
||
union_ty = union_copy
|
||
|
||
# 注册命名结构体到模块
|
||
llvmlite.module_add_named_type(trans.Module, pool, union_ty)
|
||
|
||
# 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry)
|
||
entry: GenTypes.StructEntry* = self.Gen.StructGen.register_struct(pool, class_name, union_ty, trans.ModuleSha1)
|
||
if entry is None:
|
||
VLogger.error(f"failed to register {class_name}", "UNION")
|
||
return 0
|
||
|
||
# 标记为当前文件可见(命名空间隔离)
|
||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||
|
||
# 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错)
|
||
entry.IsUnion = 1
|
||
|
||
# 添加字段信息(所有字段 Index=0,因为共享偏移 0)
|
||
for fi in range(field_count):
|
||
fname_addr: sizet = field_names_buf[fi]
|
||
if fname_addr == 0:
|
||
continue
|
||
fname: str = rawptr(fname_addr)
|
||
fty_addr2: sizet = field_types_buf[fi]
|
||
if fty_addr2 == 0:
|
||
continue
|
||
fty2: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr2)
|
||
if fname is not None and fty2 is not None:
|
||
self.Gen.StructGen.add_field(pool, entry, fname, fty2, None, None)
|
||
|
||
VLogger.info(f"registered {class_name} with {field_count} fields, max_size={max_size}", "UNION")
|
||
return 0
|
||
def _get_annotation_field_size(self, pool: memhub.MemBuddy*,
|
||
annotation: ast.AST*) -> int:
|
||
"""计算注解类型的字节大小,用于 REnum 布局计算"""
|
||
if annotation is None:
|
||
return 8
|
||
k: int = annotation.kind()
|
||
# 联合类型 A | B → 指针大小 8
|
||
if k == ast.ASTKind.BinOp:
|
||
return 8
|
||
# Name(id) 或 Attribute(attr) → 解析类型名
|
||
type_name: str = None
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(annotation)
|
||
if nm is not None:
|
||
type_name = nm.id
|
||
elif k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(annotation)
|
||
if at is not None:
|
||
type_name = at.attr
|
||
if type_name is None:
|
||
return 8
|
||
# [阶段3] 统一尺寸口径:库 typedef(BYTE/DWORD 等)先经正常库分析解析,
|
||
# miss 才走下方硬编码尺寸表(t/c 核心原语)。
|
||
dyn_sz: int = self.Gen.TypeGenResolve.get_type_size_bytes(pool, type_name, None, None)
|
||
if dyn_sz > 0:
|
||
return dyn_sz
|
||
# 内置类型
|
||
if string.strcmp(type_name, "int") == 0: return 4
|
||
if string.strcmp(type_name, "CInt") == 0: return 4
|
||
if string.strcmp(type_name, "CInt8T") == 0: return 1
|
||
if string.strcmp(type_name, "CInt16T") == 0: return 2
|
||
if string.strcmp(type_name, "CInt32T") == 0: return 4
|
||
if string.strcmp(type_name, "CInt64T") == 0: return 8
|
||
if string.strcmp(type_name, "CChar") == 0: return 1
|
||
if string.strcmp(type_name, "CDouble") == 0: return 8
|
||
if string.strcmp(type_name, "CFloat") == 0: return 4
|
||
if string.strcmp(type_name, "CPtr") == 0: return 8
|
||
if string.strcmp(type_name, "CSizeT") == 0: return 8
|
||
if string.strcmp(type_name, "str") == 0: return 8
|
||
if string.strcmp(type_name, "bytes") == 0: return 8
|
||
if string.strcmp(type_name, "bool") == 0: return 1
|
||
# 已注册的结构体类型
|
||
struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(type_name)
|
||
if struct_ty is not None:
|
||
sz: int = self._get_type_size(struct_ty)
|
||
if sz > 0:
|
||
return sz
|
||
# 未注册类型 → 默认指针大小 8(可能是自引用或前向引用)
|
||
return 8
|
||
def _translate_renum_def(self, trans: HT.Translator*,
|
||
cd: ast.ClassDef*) -> int:
|
||
"""翻译 REnum 类定义,返回 0"""
|
||
if cd is None or cd.name is None or trans is None: return 0
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
class_name: str = cd.name
|
||
|
||
# 命名空间隔离:标记为当前文件可见
|
||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||
|
||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
|
||
if existing is not None:
|
||
# existing 只保证 struct entry 在,不保证 REnum 语义(变体表)在:struct entry
|
||
# 由 register_struct 写 StructTable,跨 Phase 存活(perm_pool);而变体表是 gen
|
||
# 实例字段(InitClassGen 每个 Generator 重置)。无条件早退会使
|
||
# _register_renum_variants 永不再执行 ⇒ 变体表缺该类 ⇒ _is_renum_class_name
|
||
# 恒 0 ⇒ match 走 _handle_simple_match(无变体绑定)⇒ case 绑定名未定义。
|
||
if self._is_renum_class_name(class_name) != 0:
|
||
if existing.Ty is not None:
|
||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||
return 0
|
||
# 变体表缺失:中和旧 entry(对齐 ClassGenDef needs_rereg 先例),使
|
||
# find_struct_by_module 不再命中(按 Name 精确匹配),走下方完整注册路径
|
||
# 以同时修正 struct 布局 + 变体表。
|
||
if existing.Name is not None:
|
||
existing.Name[0] = '\0'
|
||
existing.Ty = None
|
||
existing.FieldCount = 0
|
||
|
||
children: list[ast.AST*]* = cd.children
|
||
if children is None:
|
||
# [D32 fail-fast] 此前只 warning + return 0:变体表**静默不注册** →
|
||
# _is_renum_class_name 恒 0、变体构造拿不到 tag(__types.vp L703
|
||
# `LLVMType.Metadata()` 被当外部函数根因)。禁止静默跳过。
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 缺少类体(children 为 None),无法注册变体表", "TypeError")
|
||
return 0
|
||
|
||
cn: sizet = len(children)
|
||
|
||
# 变体最多 32 个,每个变体最多 16 个字段
|
||
# variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小
|
||
variant_field_sizes: sizet* = pool.alloc(8 * 64 * 16)
|
||
if variant_field_sizes is None:
|
||
return 0
|
||
string.memset(variant_field_sizes, 0, 8 * 64 * 16)
|
||
|
||
variant_count: int = 0
|
||
max_field_count: int = 0 # 所有变体中最大字段数
|
||
|
||
for ci in range(cn):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk: int = stmt.kind()
|
||
|
||
if sk == ast.ASTKind.ClassDef:
|
||
# 嵌套变体类
|
||
variant_cd: ast.ClassDef* = ast.ClassDef*(stmt)
|
||
if variant_cd is None or variant_cd.children is None:
|
||
variant_count += 1
|
||
continue
|
||
variant_children: list[ast.AST*]* = variant_cd.children
|
||
vcn: sizet = len(variant_children)
|
||
field_idx: int = 0
|
||
for vi in range(vcn):
|
||
vstmt: ast.AST* = variant_children.get(vi)
|
||
if vstmt is None:
|
||
continue
|
||
vk: int = vstmt.kind()
|
||
if vk != ast.ASTKind.AnnAssign:
|
||
continue
|
||
vaa: ast.AnnAssign* = ast.AnnAssign*(vstmt)
|
||
if vaa is None or vaa.target is None or vaa.annotation is None:
|
||
continue
|
||
if vaa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
# 提取字段名
|
||
vnm: ast.Name* = ast.Name*(vaa.target)
|
||
# 计算字段大小
|
||
fsize: int = self._get_annotation_field_size(pool, vaa.annotation)
|
||
if variant_count < 32 and field_idx < 16:
|
||
# variant_field_sizes[variant_count][field_idx] = fsize
|
||
offset: sizet = variant_count * 16 + field_idx
|
||
variant_field_sizes[offset] = sizet(fsize)
|
||
# 直接注册变体字段名别名(避免 CSizeT→str 转换问题)
|
||
# 同时解析成员实际类型(对齐 TPC class_members,供 match
|
||
# 绑定 bitcast 槽位地址用)。自引用注解(如
|
||
# LLVMType|t.CPtr 引用自身类)此时解析失败返回 None →
|
||
# 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset
|
||
# 后悬空,注册内部会 strcpy 到 perm_pool。
|
||
if vnm is not None and vnm.id is not None:
|
||
mem_ty_l: llvmlite.LLVMType* = None
|
||
if trans is not None:
|
||
mem_ty_l = self.Gen.TypeGenResolve.resolve_annotation_type(pool, vaa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||
self._register_renum_field_alias(pool, class_name, vnm.id, field_idx + 1, mem_ty_l, variant_cd.name)
|
||
field_idx += 1
|
||
if field_idx > max_field_count:
|
||
max_field_count = field_idx
|
||
variant_count += 1
|
||
elif sk == ast.ASTKind.Assign:
|
||
# Assign 形式的**无载荷变体**(如 `Empty = 1` / `None_ = 0`):与 TPC
|
||
# HandlesClassDef._EmitREnumLlvm 同口径——它同样是变体(占一个变体序号),
|
||
# 只是无字段。不认则 variant_count 与变体表都漏掉该变体 ⇒ match 的
|
||
# `case Option.Empty():` 查表失配 tag=-1 → 硬校验 fail-fast。
|
||
# tag 值由 _register_renum_variants 按同一口径分配(显式值优先)。
|
||
ag_v: ast.Assign* = ast.Assign*(stmt)
|
||
if ag_v is None or ag_v.targets is None:
|
||
continue
|
||
tgts_v: list[ast.AST*]* = ag_v.targets
|
||
if len(tgts_v) == 0:
|
||
continue
|
||
t0_v: ast.AST* = tgts_v.get(0)
|
||
if t0_v is None or t0_v.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_v: ast.Name* = ast.Name*(t0_v)
|
||
if tgt_v.id is None:
|
||
continue
|
||
variant_count += 1
|
||
|
||
if variant_count == 0:
|
||
# [D32 fail-fast] 同上:变体数为 0 时此前静默 return → 变体表不注册。
|
||
# 对 `class X(t.REnum)` 而言变体数必 > 0,为 0 说明 AST 变体类丢失。
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 的变体数为 0(嵌套变体类丢失),无法注册变体表", "TypeError")
|
||
return 0
|
||
|
||
# 计算每个位置的最大字段大小
|
||
# 位置 0 = __tag (i32, 4 字节)
|
||
# 位置 1+ = 变体字段
|
||
total_positions: int = max_field_count + 1 # +1 for tag
|
||
if total_positions < 2:
|
||
total_positions = 2 # 至少 {i32, i32}
|
||
|
||
position_max_sizes: sizet* = pool.alloc(8 * total_positions)
|
||
if position_max_sizes is None:
|
||
return 0
|
||
string.memset(position_max_sizes, 0, 8 * total_positions)
|
||
|
||
# 位置 0 = tag = 4 字节
|
||
position_max_sizes[0] = sizet(4)
|
||
|
||
# 位置 1+ = 每个位置取所有变体的最大字段大小
|
||
for pos in range(1, total_positions):
|
||
pos_max: int = 0
|
||
for vi in range(variant_count):
|
||
if vi >= 64:
|
||
break # variant_field_sizes 64 类槽上限,防读越界
|
||
field_pos: int = pos - 1 # 变体字段从位置 0 开始
|
||
if field_pos >= 16:
|
||
continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过
|
||
offset2: sizet = vi * 16 + field_pos
|
||
fsize_val: sizet = variant_field_sizes[offset2]
|
||
if fsize_val > pos_max:
|
||
pos_max = fsize_val
|
||
position_max_sizes[pos] = sizet(pos_max)
|
||
|
||
# 构建 ParamNode 链表
|
||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
|
||
first_node: llvmlite.ParamNode* = None
|
||
tail_node: llvmlite.ParamNode* = None
|
||
|
||
for pos in range(total_positions):
|
||
psize: int = position_max_sizes[pos]
|
||
field_ty: llvmlite.LLVMType* = i32_ty
|
||
if psize > 4:
|
||
field_ty = i64_ty
|
||
pnode: llvmlite.ParamNode* = llvmlite.new_param_node(pool, field_ty)
|
||
if pnode is None:
|
||
continue
|
||
tail_node = llvmlite.param_list_append(first_node, tail_node, pnode)
|
||
if first_node is None:
|
||
first_node = tail_node
|
||
|
||
if first_node is None:
|
||
VLogger.error(f"failed to build field list for {class_name}", "RENUM")
|
||
return 0
|
||
|
||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||
renum_type_name: str = class_name
|
||
if trans.ModuleSha1 is not None:
|
||
renum_name_buf: str = pool.alloc(64)
|
||
if renum_name_buf is not None:
|
||
viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||
renum_type_name = renum_name_buf
|
||
|
||
renum_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, first_node, total_positions, renum_type_name)
|
||
if renum_ty is None:
|
||
VLogger.error(f"failed to create type for {class_name}", "RENUM")
|
||
return 0
|
||
|
||
# Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活,
|
||
# 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效)
|
||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。
|
||
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||
renum_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, renum_ty)
|
||
if renum_copy is not None:
|
||
renum_ty = renum_copy
|
||
|
||
# 注册命名结构体到模块
|
||
llvmlite.module_add_named_type(trans.Module, pool, renum_ty)
|
||
|
||
# 注册到 HandlesStruct
|
||
entry: GenTypes.StructEntry* = self.Gen.StructGen.register_struct(pool, class_name, renum_ty, trans.ModuleSha1)
|
||
if entry is None:
|
||
VLogger.error(f"failed to register {class_name}", "RENUM")
|
||
return 0
|
||
|
||
# 添加 __tag 字段(位置 0,i32)
|
||
self.Gen.StructGen.add_field(pool, entry, "__tag", i32_ty, None, None)
|
||
|
||
# 添加 payload 字段(位置 1+,i32 或 i64)
|
||
for pos in range(1, total_positions):
|
||
psize2: int = position_max_sizes[pos]
|
||
payload_ty: llvmlite.LLVMType* = i32_ty
|
||
if psize2 > 4:
|
||
payload_ty = i64_ty
|
||
field_name_buf: str = pool.alloc(16)
|
||
if field_name_buf is not None:
|
||
viperlib.snprintf(field_name_buf, 16, "_p%d", pos)
|
||
self.Gen.StructGen.add_field(pool, entry, field_name_buf, payload_ty, None, None)
|
||
|
||
# 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造)
|
||
self._register_renum_variants(pool, class_name, cd, variant_count)
|
||
|
||
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)。
|
||
# 注意:遍历发生在 register_struct 之前,注解引用本类自身(如
|
||
# LLVMType.Ptr.Pointee: rawptr[LLVMType])时类尚未注册 → 别名表类型槽
|
||
# 为 0 → match 绑定回退槽位 i64 把指针字段读成整数。此处类已注册,
|
||
# 补一遍字段类型解析回填 0 槽(详见 _refill_renum_field_types)。
|
||
self._refill_renum_field_types(trans, pool, class_name, cd)
|
||
|
||
VLogger.info(f"registered {class_name} with {variant_count} variants, {total_positions} positions", "RENUM")
|
||
return 0
|
||
def _refill_renum_field_types(self, trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
class_name: str,
|
||
cd: ast.ClassDef*):
|
||
"""REnum 注册完成后补解析变体字段类型(仅回填类型槽为 0 的别名记录)
|
||
|
||
第一遍变体字段遍历发生在 register_struct 之前:字段注解引用本 REnum 类
|
||
自身(如 LLVMType.Ptr.Pointee: rawptr[LLVMType]、Array.ElemTy:
|
||
rawptr[LLVMType]、Func.Ret: rawptr[LLVMType])时,find_struct 查不到
|
||
正在注册的类 → resolve_annotation_type 返回 None → _register_renum_field_alias
|
||
类型槽(RenumAliasTy)落 0。match 绑定时 _lookup_renum_member_ty 查不到
|
||
成员类型 → 绑定变量按 payload 槽位(i64)读取,把指针字段读成整数 →
|
||
递归传参/赋值给 rawptr[LLVMType] 形参被 int→ptr 显式拦截误报 CastError
|
||
(llvmlite __types.vp L448 根因)。
|
||
|
||
本方法在 register_struct 完成(自身类已可查)后按与第一遍相同的位置
|
||
顺序重遍历变体字段并重新解析注解;命中已存在的 (class, field) 别名
|
||
记录且类型槽为 0 时回填真实类型(非 0 槽与解析失败均保持原状,不覆盖
|
||
不误伤)。非自引用字段(ParamNode/str/int 等)第一遍已解析成功,去重
|
||
命中类型槽非 0 → 直接跳过,行为不变。
|
||
"""
|
||
if trans is None or pool is None or class_name is None or cd is None:
|
||
return
|
||
children: list[ast.AST*]* = cd.children
|
||
if children is None:
|
||
return
|
||
cn: sizet = len(children)
|
||
for ci in range(cn):
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None or stmt.kind() != ast.ASTKind.ClassDef:
|
||
continue
|
||
variant_cd: ast.ClassDef* = ast.ClassDef*(stmt)
|
||
if variant_cd is None or variant_cd.name is None \
|
||
or variant_cd.children is None:
|
||
continue
|
||
vchildren: list[ast.AST*]* = variant_cd.children
|
||
vcn: sizet = len(vchildren)
|
||
field_idx: int = 0
|
||
for vi in range(vcn):
|
||
vstmt: ast.AST* = vchildren.get(vi)
|
||
if vstmt is None:
|
||
continue
|
||
if vstmt.kind() != ast.ASTKind.AnnAssign:
|
||
continue
|
||
vaa: ast.AnnAssign* = ast.AnnAssign*(vstmt)
|
||
if vaa is None or vaa.target is None or vaa.annotation is None:
|
||
# 与第一遍同规则:无效 AnnAssign 不占用 payload 槽位
|
||
continue
|
||
if vaa.target.kind() != ast.ASTKind.Name:
|
||
continue
|
||
vnm: ast.Name* = ast.Name*(vaa.target)
|
||
if vnm.id is None:
|
||
# 与第一遍同规则:有效 AnnAssign 仍占用 payload 槽位
|
||
field_idx += 1
|
||
continue
|
||
mem_ty_l: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, vaa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||
# 解析成功 → 触发别名表去重路径(类型槽为 0 时回填;非 0 跳过)
|
||
if mem_ty_l is not None:
|
||
self._register_renum_field_alias(pool, class_name, vnm.id, field_idx + 1, mem_ty_l, variant_cd.name)
|
||
field_idx += 1
|
||
def _register_renum_variants(self, pool: memhub.MemBuddy*,
|
||
class_name: str,
|
||
cd: ast.ClassDef*,
|
||
variant_count: int):
|
||
"""注册 REnum 类的变体名和 tag 值到全局变体表"""
|
||
if pool is None or class_name is None or cd is None: return
|
||
if variant_count == 0: return
|
||
children: list[ast.AST*]* = cd.children
|
||
if children is None: return
|
||
|
||
# 懒初始化表(首次注册时分配)
|
||
# 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配,
|
||
# 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在
|
||
# parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。
|
||
if self.RenumClassNames is None:
|
||
self.RenumClassNames = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX)
|
||
self.RenumClassVariantCounts = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX)
|
||
self.RenumVariantNames = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
self.RenumVariantTags = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
if (self.RenumClassNames is None or self.RenumClassVariantCounts is None
|
||
or self.RenumVariantNames is None or self.RenumVariantTags is None):
|
||
# A None table means the perm-pool request failed (size 0 or pool
|
||
# exhausted). Returning here left the table empty while the caller
|
||
# still reported "registered", so match dispatch silently lost every
|
||
# REnum case.
|
||
self.RenumClassNames = None
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体表分配失败(class='{class_name}'):PermPool 返回 NULL,变体表不可用", "InternalCompilerError")
|
||
return
|
||
string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX)
|
||
string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX)
|
||
string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||
self.RenumClassCount = 0
|
||
# [D30 根治] 首次分配后把指针登记到编译期单例 factory(与 struct entry
|
||
# 同寿命);后续新建的 Generator 由 InitClassGen 从此处恢复,不再清零。
|
||
CompilerFactory.factory.RenumClassNames = self.RenumClassNames
|
||
CompilerFactory.factory.RenumClassVariantCounts = self.RenumClassVariantCounts
|
||
CompilerFactory.factory.RenumVariantNames = self.RenumVariantNames
|
||
CompilerFactory.factory.RenumVariantTags = self.RenumVariantTags
|
||
CompilerFactory.factory.RenumClassCount = self.RenumClassCount
|
||
|
||
#rcv_chk: uint64 = uint64(self.RenumClassVariantCounts)
|
||
#if rcv_chk == 0 or rcv_chk < 4096:
|
||
# VLogger.error(f"[RENUM-FAIL] RCV={rcv_chk} 异常(lazy init 后应为 perm_pool 地址),RenumClassCount={self.RenumClassCount} class={class_name}", "RENUM")
|
||
# stdlib.exit(1)
|
||
|
||
# 检查是否已注册(避免重复注册)
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = str(self.RenumClassNames[i])
|
||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||
return
|
||
|
||
# 表已满
|
||
if self.RenumClassCount >= RENUM_CLASS_MAX:
|
||
# Silently dropping the class made its later `match` lose every case; a
|
||
# real limit breach must be reported instead.
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类数超过上限 {RENUM_CLASS_MAX}:无法注册 class='{class_name}'", "InternalCompilerError")
|
||
return
|
||
|
||
# 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空,
|
||
# _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存)
|
||
idx: int = self.RenumClassCount
|
||
cn_len_rv: sizet = string.strlen(class_name)
|
||
cn_buf_rv: str = CompilerFactory.factory.PermPool.alloc(cn_len_rv + 1)
|
||
if cn_buf_rv is None:
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||
return
|
||
string.strcpy(cn_buf_rv, class_name)
|
||
self.RenumClassNames[idx] = sizet(cn_buf_rv)
|
||
self.RenumClassVariantCounts[idx] = variant_count
|
||
|
||
# 遍历 children,提取变体名与 tag 并注册。变体两种书写形态(对齐 TPC
|
||
# HandlesClassDef._EmitREnumLlvm L1294-1335、SymbolExtractor L225-250):
|
||
# 1) `class Some: ...` → 带载荷类变体,tag 从 max(显式值)+1 起顺序编号
|
||
# 2) `Empty = 1` → 无载荷 Assign 变体,tag = 显式整数值
|
||
# 1) 从显式值上界之后起编号是必须的:Test\EdgeCaseTest\App\main.vp:42-44
|
||
# `class Some: val / None_ = 0` 若按声明序给 Some 编 0 就与 None_ 撞号
|
||
# (match 两臂同 tag ⇒ 后写臂恒不可达)。
|
||
cn: sizet = len(children)
|
||
# 第一遍:扫出 Assign 变体的显式整数值上界(无显式值时保持 -1)
|
||
max_explicit: int = -1
|
||
for ci in range(cn):
|
||
stmt_p: ast.AST* = children.get(ci)
|
||
if stmt_p is None or stmt_p.kind() != ast.ASTKind.Assign:
|
||
continue
|
||
ag_p: ast.Assign* = ast.Assign*(stmt_p)
|
||
if ag_p is None or ag_p.targets is None or ag_p.value is None:
|
||
continue
|
||
tgts_p: list[ast.AST*]* = ag_p.targets
|
||
if len(tgts_p) == 0:
|
||
continue
|
||
t0_p: ast.AST* = tgts_p.get(0)
|
||
if t0_p is None or t0_p.kind() != ast.ASTKind.Name:
|
||
continue
|
||
if ag_p.value.kind() != ast.ASTKind.Constant:
|
||
continue
|
||
ev_v: int = int(self._extract_int_value(ag_p.value))
|
||
if ev_v > max_explicit:
|
||
max_explicit = ev_v
|
||
|
||
# 第二遍:按声明序写表。slot = 表中连续槽位序号(0..variant_count-1,
|
||
# 查找侧 _lookup_renum_variant_in_class 按槽位顺序遍历),槽内存该变体的
|
||
# tag 值——两者不再恒等,故不能再共用一个计数器(原实现 tag 兼作槽号)。
|
||
slot: int = 0
|
||
next_class_tag: int = max_explicit + 1
|
||
variant_index: int = 0
|
||
for ci in range(cn):
|
||
if slot >= variant_count:
|
||
break
|
||
if slot >= RENUM_VARIANT_PER_CLASS:
|
||
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
|
||
VLogger.error(f"REnum 变体数超过上限 {RENUM_VARIANT_PER_CLASS}: {class_name}", "RENUM")
|
||
break
|
||
stmt: ast.AST* = children.get(ci)
|
||
if stmt is None:
|
||
continue
|
||
sk_rv: int = stmt.kind()
|
||
vname_ptr: sizet = 0
|
||
tag_val: int = 0
|
||
if sk_rv == ast.ASTKind.ClassDef:
|
||
vcd: ast.ClassDef* = ast.ClassDef*(stmt)
|
||
if vcd is None or vcd.name is None:
|
||
continue
|
||
vname_ptr = sizet(vcd.name)
|
||
tag_val = next_class_tag
|
||
next_class_tag += 1
|
||
elif sk_rv == ast.ASTKind.Assign:
|
||
# Assign 形式无载荷变体(与 _translate_renum_def 首遍同过滤口径)
|
||
ag_rv: ast.Assign* = ast.Assign*(stmt)
|
||
if ag_rv is None or ag_rv.targets is None:
|
||
continue
|
||
tgts_rv: list[ast.AST*]* = ag_rv.targets
|
||
if len(tgts_rv) == 0:
|
||
continue
|
||
t0_rv: ast.AST* = tgts_rv.get(0)
|
||
if t0_rv is None or t0_rv.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_rv: ast.Name* = ast.Name*(t0_rv)
|
||
if tgt_rv.id is None:
|
||
continue
|
||
vname_ptr = sizet(tgt_rv.id)
|
||
if ag_rv.value is not None and ag_rv.value.kind() == ast.ASTKind.Constant:
|
||
tag_val = int(self._extract_int_value(ag_rv.value))
|
||
else:
|
||
# 无显式值:用独立计数器(与类变体计数器分离,对齐 TPC
|
||
# `variant_index`),避免与 next_class_tag 交叉撞号
|
||
tag_val = variant_index
|
||
variant_index += 1
|
||
else:
|
||
continue
|
||
name_offset: sizet = idx * RENUM_VARIANT_PER_CLASS + slot
|
||
# 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 AST 名悬空)
|
||
vname_src: str = str(vname_ptr)
|
||
vn_len_rv: sizet = string.strlen(vname_src)
|
||
vn_buf_rv: str = CompilerFactory.factory.PermPool.alloc(vn_len_rv + 1)
|
||
if vn_buf_rv is None:
|
||
# Breaking here registered a partial variant table: the class would
|
||
# keep some variants and silently lose every later one.
|
||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||
break
|
||
string.strcpy(vn_buf_rv, vname_src)
|
||
self.RenumVariantNames[name_offset] = sizet(vn_buf_rv)
|
||
self.RenumVariantTags[name_offset] = tag_val
|
||
slot += 1
|
||
|
||
self.RenumClassCount = idx + 1
|
||
# [D30 根治] 回写计数到编译期单例(新建 Generator 靠它恢复;不回写会导致
|
||
# 新 Generator 只看到旧计数 → 后续注册的变体不可见)
|
||
CompilerFactory.factory.RenumClassCount = self.RenumClassCount
|
||
def _lookup_renum_variant(self, variant_name: str) -> str:
|
||
"""查找变体名所属的 REnum 类名
|
||
|
||
返回: class_name (str),或 None
|
||
"""
|
||
if variant_name is None or self.RenumClassNames is None:
|
||
return None
|
||
|
||
for i in range(self.RenumClassCount):
|
||
vcount: int = self.RenumClassVariantCounts[i]
|
||
for j in range(vcount):
|
||
name_offset: sizet = i * RENUM_VARIANT_PER_CLASS + j
|
||
vname: str = str(self.RenumVariantNames[name_offset])
|
||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||
cls_nm: str = str(self.RenumClassNames[i])
|
||
return cls_nm
|
||
return None
|
||
def RenumTableDump(self) -> str:
|
||
"""诊断用:变体表摘要(类数 / 首类名 / 该变体数 / 变体首项)
|
||
|
||
用于区分「类根本没注册」与「类在但变体名没注册」两类失败。
|
||
"""
|
||
buf: str = CompilerFactory.factory.PermPool.alloc(256)
|
||
if buf is None:
|
||
return "-"
|
||
buf[0] = '\0'
|
||
cls_first: str = "-"
|
||
v_first: str = "-"
|
||
n_first_v: int = 0
|
||
if self.RenumClassNames is not None and self.RenumClassCount > 0:
|
||
cls_first = str(self.RenumClassNames[0])
|
||
if self.RenumVariantNames is not None \
|
||
and self.RenumClassVariantCounts is not None:
|
||
n_first_v = self.RenumClassVariantCounts[0]
|
||
if n_first_v > 0:
|
||
v_first = str(self.RenumVariantNames[0])
|
||
viperlib.snprintf(buf, 256, "count=%d first=%s vcount=%d vfirst=%s",
|
||
self.RenumClassCount, cls_first, n_first_v, v_first)
|
||
return buf
|
||
|
||
def _is_renum_by_entry(self, class_name: str) -> int:
|
||
"""不依赖变体表的 REnum 判定:struct 定义里带 `__tag` 字段即为 REnum
|
||
|
||
`_translate_renum_def` 必定 `add_field(entry, "__tag", i32)`,故 struct
|
||
定义本身即持久凭证(perm_pool)。用途:变体表因**任何**原因缺失时,
|
||
match 分派仍能走带变体绑定的 `_handle_renum_match` 路径,避免退化为
|
||
`_handle_simple_match`(不绑定)→ case 绑定名 NameError
|
||
(includes/llvmlite/__types.vp L407 `bits` 根因)。
|
||
"""
|
||
if class_name is None:
|
||
return 0
|
||
st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(class_name)
|
||
if st is None:
|
||
return 0
|
||
if self.Gen.StructGen.lookup_field(st, "__tag") is None:
|
||
return 0
|
||
return 1
|
||
|
||
def _is_renum_class_name(self, class_name: str) -> int:
|
||
"""检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否"""
|
||
if class_name is None or self.RenumClassNames is None:
|
||
return 0
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = str(self.RenumClassNames[i])
|
||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||
return 1
|
||
return 0
|
||
def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int:
|
||
"""在指定 REnum 类中查找变体,返回 tag 值或 -1"""
|
||
if class_name is None or variant_name is None or self.RenumClassNames is None:
|
||
return -1
|
||
for i in range(self.RenumClassCount):
|
||
existing: str = str(self.RenumClassNames[i])
|
||
if existing is None or string.strcmp(existing, class_name) != 0:
|
||
continue
|
||
vcount: int = self.RenumClassVariantCounts[i]
|
||
for j in range(vcount):
|
||
name_offset: sizet = i * RENUM_VARIANT_PER_CLASS + j
|
||
vname: str = str(self.RenumVariantNames[name_offset])
|
||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||
return self.RenumVariantTags[name_offset]
|
||
return -1
|
||
return -1
|
||
def _register_renum_field_alias(self, pool: memhub.MemBuddy*,
|
||
class_name: str,
|
||
field_name: str,
|
||
payload_idx: int,
|
||
field_ty: llvmlite.LLVMType* = None,
|
||
variant_name: str = None):
|
||
"""注册 REnum 变体字段名别名到全局表
|
||
|
||
field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如
|
||
LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。
|
||
variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员)
|
||
"""
|
||
if pool is None or class_name is None or field_name is None:
|
||
return
|
||
if payload_idx < 1:
|
||
return
|
||
|
||
# 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收)
|
||
if self.RenumAliasClass is None:
|
||
alias_pool_rfa: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||
if (self.RenumAliasClass is None or self.RenumAliasField is None
|
||
or self.RenumAliasIndex is None or self.RenumAliasTy is None
|
||
or self.RenumAliasVariant is None):
|
||
# Same as the variant table: a silent bail left the alias table empty,
|
||
# so match bindings later failed with an unrelated NameError.
|
||
self.RenumAliasClass = None
|
||
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名表分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||
return
|
||
string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX)
|
||
string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX)
|
||
self.RenumAliasCount = 0
|
||
# [D30 根治] 同上:别名表指针登记到编译期单例,跨 Generator 存活
|
||
CompilerFactory.factory.RenumAliasClass = self.RenumAliasClass
|
||
CompilerFactory.factory.RenumAliasField = self.RenumAliasField
|
||
CompilerFactory.factory.RenumAliasIndex = self.RenumAliasIndex
|
||
CompilerFactory.factory.RenumAliasTy = self.RenumAliasTy
|
||
CompilerFactory.factory.RenumAliasVariant = self.RenumAliasVariant
|
||
CompilerFactory.factory.RenumAliasCount = self.RenumAliasCount
|
||
|
||
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
|
||
# Dropping the record silently made the variant field bind to a wrong-typed
|
||
# slot (or fail with NameError) instead of reporting the limit breach.
|
||
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名数超过上限 {RENUM_ALIAS_MAX}:无法注册 {class_name}.{field_name}", "InternalCompilerError")
|
||
return
|
||
|
||
# 去重检查(去指针化):class 槽位存 perm_pool 字符串拷贝,用 strcmp 内容比较——
|
||
# 不再依赖指针值统一(注册用 AST 指针、查找用 entry.Name 池拷贝,指针恒不等)。
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
|
||
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
|
||
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
# 已存在记录:首遍注册期解析失败(自引用字段,见
|
||
# _refill_renum_field_types)类型槽为 0 时,本次解析成功则
|
||
# 回填真实类型;非 0 槽保持原样(避免重复 DeepCopy 覆盖抖动)。
|
||
if self.RenumAliasTy[i] == 0 and field_ty is not None:
|
||
ty_copy_rf2: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, field_ty)
|
||
if ty_copy_rf2 is not None:
|
||
self.RenumAliasTy[i] = sizet(ty_copy_rf2)
|
||
return
|
||
|
||
idx: int = self.RenumAliasCount
|
||
# class_name 同样 strcpy 到 perm_pool(去指针化:查找方任何来源的
|
||
# class_name 字符串都可用 strcmp 命中,无需 _update_renum_alias_class_ptr)
|
||
cls_len_rfa: sizet = string.strlen(class_name)
|
||
cls_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(cls_len_rfa + 1)
|
||
if cls_buf_rfa is None:
|
||
return
|
||
string.strcpy(cls_buf_rfa, class_name)
|
||
self.RenumAliasClass[idx] = sizet(cls_buf_rfa)
|
||
# field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias
|
||
# 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。
|
||
fn_len_rfa: sizet = string.strlen(field_name)
|
||
fn_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(fn_len_rfa + 1)
|
||
if fn_buf_rfa is None:
|
||
return
|
||
string.strcpy(fn_buf_rfa, field_name)
|
||
self.RenumAliasField[idx] = sizet(fn_buf_rfa)
|
||
self.RenumAliasIndex[idx] = sizet(payload_idx)
|
||
# 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空;
|
||
# 未解析成功(自引用等)存 0,绑定回退槽位类型)
|
||
self.RenumAliasTy[idx] = 0
|
||
if field_ty is not None:
|
||
ty_copy_rfa: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, field_ty)
|
||
if ty_copy_rfa is not None:
|
||
self.RenumAliasTy[idx] = sizet(ty_copy_rfa)
|
||
# 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空)
|
||
self.RenumAliasVariant[idx] = 0
|
||
if variant_name is not None:
|
||
vn_len_rfa: sizet = string.strlen(variant_name)
|
||
vn_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(vn_len_rfa + 1)
|
||
if vn_buf_rfa is not None:
|
||
string.strcpy(vn_buf_rfa, variant_name)
|
||
self.RenumAliasVariant[idx] = sizet(vn_buf_rfa)
|
||
self.RenumAliasCount = idx + 1
|
||
# [D30 根治] 回写计数到编译期单例(新建 Generator 靠它恢复)
|
||
CompilerFactory.factory.RenumAliasCount = self.RenumAliasCount
|
||
def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int:
|
||
"""查找 REnum 变体字段名的 payload 索引,返回索引或 -1
|
||
|
||
class_name/field_name 均用 strcmp 内容比较(去指针化:槽位存 perm_pool
|
||
字符串拷贝,任何来源的 class_name 字符串都可命中)
|
||
"""
|
||
if class_name is None or field_name is None or self.RenumAliasClass is None:
|
||
return -1
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
|
||
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
|
||
# field_name 用 strcmp 内容比较(指针不同但内容相同)
|
||
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
return self.RenumAliasIndex[i]
|
||
return -1
|
||
def _lookup_renum_field_alias_ty(self, class_name: str,
|
||
field_name: str) -> llvmlite.LLVMType*:
|
||
"""查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None
|
||
|
||
与 _lookup_renum_field_alias 同表同键(class/field 均 strcmp 内容比较)。
|
||
注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。
|
||
"""
|
||
if class_name is None or field_name is None or self.RenumAliasTy is None:
|
||
return None
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
|
||
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
|
||
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
|
||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||
if self.RenumAliasTy[i] == 0:
|
||
return None
|
||
return (llvmlite.LLVMType*)(self.RenumAliasTy[i])
|
||
return None
|
||
def _lookup_renum_member_ty(self, class_name: str,
|
||
variant_name: str,
|
||
payload_idx: int) -> llvmlite.LLVMType*:
|
||
"""按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型
|
||
|
||
match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs
|
||
Struct.Fields=Ptr),必须带变体名定位。class/变体均 strcmp 内容比较。
|
||
返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。
|
||
"""
|
||
if class_name is None or variant_name is None or self.RenumAliasVariant is None:
|
||
return None
|
||
if payload_idx < 1:
|
||
return None
|
||
for i in range(self.RenumAliasCount):
|
||
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
|
||
if cls_existing_ptr is None or string.strcmp(cls_existing_ptr, class_name) != 0:
|
||
continue
|
||
if self.RenumAliasVariant[i] == 0:
|
||
continue
|
||
vnt_ptr: str = rawptr(self.RenumAliasVariant[i])
|
||
if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0:
|
||
continue
|
||
if self.RenumAliasIndex[i] != payload_idx:
|
||
continue
|
||
if self.RenumAliasTy[i] == 0:
|
||
return None
|
||
return (llvmlite.LLVMType*)(self.RenumAliasTy[i])
|
||
return None |