591 lines
27 KiB
Plaintext
591 lines
27 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Projectrans.Config as Config
|
||
import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenDeclMixin - StmtGen 拆分 2/3:声明/枚举/nonlocal 访问
|
||
#
|
||
# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点):
|
||
# translate_global/nonlocal/expr_stmt/pre_scan、break/continue、
|
||
# nonlocal 闭包 env 访问、枚举注册表。继承 StmtGenCifMixin。
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
ENUM_MAX: t.CDefine = 64
|
||
ENUM_MEMBER_MAX: t.CDefine = 128
|
||
|
||
# ============================================================
|
||
# StmtGenDeclMixin - 声明/枚举/nonlocal(中层级)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||
"""声明/枚举/nonlocal 访问(StmtGen 拆分 2/3,继承 Cif)"""
|
||
|
||
def translate_global(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 global 语句:记录 global 变量名"""
|
||
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
|
||
if gn is None:
|
||
return 0
|
||
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
|
||
if names is None:
|
||
return 0
|
||
n: t.CSizeT = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||
if nm.id is not None:
|
||
HT.add_global_name(trans, nm.id)
|
||
return 0
|
||
|
||
def translate_nonlocal(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
|
||
|
||
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
|
||
"""
|
||
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
|
||
if nl is None:
|
||
return 0
|
||
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
|
||
if names is None:
|
||
return 0
|
||
n: t.CSizeT = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||
if nm.id is not None:
|
||
# 查找父作用域中的变量 alloca,获取类型信息
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||
var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if var_alloca is not None and var_alloca.Ty is not None:
|
||
var_ty = var_alloca.Ty.Pointee
|
||
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
|
||
# 类型无效直接报错终止(fail-fast),避免生成
|
||
# "bitcast ... to void*" / "load void, void*" 非法 IR
|
||
if var_ty is not None:
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Void():
|
||
self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError")
|
||
case _:
|
||
pass
|
||
HT.add_nonlocal_name(trans, nm.id, var_ty)
|
||
return 0
|
||
|
||
def translate_expr_stmt(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译表达式语句(printf 调用等)"""
|
||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||
if ex is None:
|
||
return 0
|
||
call_node: ast.AST | t.CPtr = ex.value
|
||
if call_node is None:
|
||
return 0
|
||
ck: int = call_node.kind()
|
||
if ck != ast.ASTKind.Call:
|
||
return 0
|
||
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
|
||
func_node: ast.AST | t.CPtr = cl.func
|
||
if func_node is None:
|
||
return 0
|
||
|
||
func_name: str = self.Gen.ExprGenBase.get_func_name(func_node)
|
||
if func_name is None:
|
||
# 函数名解析失败:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError")
|
||
|
||
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
|
||
if string.strcmp(func_name, "printf") == 0:
|
||
self.Gen.CallGenLeafKit.translate_printf_call(
|
||
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||
elif string.strcmp(func_name, "print") == 0:
|
||
self.Gen.CallGenLeafKit.translate_print_call(
|
||
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||
else:
|
||
# 通用函数调用(返回值丢弃)
|
||
self.Gen.CallGen.translate_call(
|
||
trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
return 0
|
||
|
||
def pre_scan_allocas(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预扫描语句中的 AnnAssign,提前创建 alloca
|
||
|
||
递归分支/循环/异常体:if/else/for/while/try 分支内的 AnnAssign 局部
|
||
也必须提前注册到 entry alloca——否则闭包隐式捕获扫描(step 8c)
|
||
在分支局部未注册时会误判为外层函数捕获(Terminal _build_path 的
|
||
i/j/cwd_len 被当 nonlocal 捕获 → 循环计数器走 env/父函数存储 →
|
||
跨函数 SSA 错乱,llc "instruction expected to be numbered")。
|
||
|
||
返回新增的变量数(调用方均忽略返回值)。
|
||
"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.AnnAssign:
|
||
return self.Gen.AssignGen.translate_annassign_prescan(trans, node)
|
||
if k == ast.ASTKind.If:
|
||
ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||
if ifn.children is not None:
|
||
bn_pre_i: t.CSizeT = len(ifn.children)
|
||
for bi_pre_i in range(bn_pre_i):
|
||
self.pre_scan_allocas(trans, ifn.children.get(bi_pre_i))
|
||
if ifn.orelse is not None:
|
||
bn_pre_e: t.CSizeT = len(ifn.orelse)
|
||
for bi_pre_e in range(bn_pre_e):
|
||
self.pre_scan_allocas(trans, ifn.orelse.get(bi_pre_e))
|
||
return 0
|
||
if k == ast.ASTKind.For:
|
||
for_n: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
|
||
if for_n.children is not None:
|
||
bn_pre_f: t.CSizeT = len(for_n.children)
|
||
for bi_pre_f in range(bn_pre_f):
|
||
self.pre_scan_allocas(trans, for_n.children.get(bi_pre_f))
|
||
if for_n.orelse is not None:
|
||
bn_pre_fe: t.CSizeT = len(for_n.orelse)
|
||
for bi_pre_fe in range(bn_pre_fe):
|
||
self.pre_scan_allocas(trans, for_n.orelse.get(bi_pre_fe))
|
||
return 0
|
||
if k == ast.ASTKind.While:
|
||
wh_n: ast.While | t.CPtr = (ast.While | t.CPtr)(node)
|
||
if wh_n.children is not None:
|
||
bn_pre_w: t.CSizeT = len(wh_n.children)
|
||
for bi_pre_w in range(bn_pre_w):
|
||
self.pre_scan_allocas(trans, wh_n.children.get(bi_pre_w))
|
||
if wh_n.orelse is not None:
|
||
bn_pre_we: t.CSizeT = len(wh_n.orelse)
|
||
for bi_pre_we in range(bn_pre_we):
|
||
self.pre_scan_allocas(trans, wh_n.orelse.get(bi_pre_we))
|
||
return 0
|
||
if k == ast.ASTKind.Try:
|
||
tr_n: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node)
|
||
if tr_n.children is not None:
|
||
bn_pre_t: t.CSizeT = len(tr_n.children)
|
||
for bi_pre_t in range(bn_pre_t):
|
||
self.pre_scan_allocas(trans, tr_n.children.get(bi_pre_t))
|
||
if tr_n.handlers is not None:
|
||
bn_pre_th: t.CSizeT = len(tr_n.handlers)
|
||
for bi_pre_th in range(bn_pre_th):
|
||
eh_pre: ast.AST | t.CPtr = tr_n.handlers.get(bi_pre_th)
|
||
if eh_pre is not None and eh_pre.kind() == ast.ASTKind.ExceptHandler:
|
||
ehc_pre: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(eh_pre)
|
||
if ehc_pre.children is not None:
|
||
bn_pre_ehb: t.CSizeT = len(ehc_pre.children)
|
||
for bi_pre_ehb in range(bn_pre_ehb):
|
||
self.pre_scan_allocas(trans, ehc_pre.children.get(bi_pre_ehb))
|
||
if tr_n.orelse is not None:
|
||
bn_pre_to: t.CSizeT = len(tr_n.orelse)
|
||
for bi_pre_to in range(bn_pre_to):
|
||
self.pre_scan_allocas(trans, tr_n.orelse.get(bi_pre_to))
|
||
if tr_n.finalbody is not None:
|
||
bn_pre_tf: t.CSizeT = len(tr_n.finalbody)
|
||
for bi_pre_tf in range(bn_pre_tf):
|
||
self.pre_scan_allocas(trans, tr_n.finalbody.get(bi_pre_tf))
|
||
return 0
|
||
if k == ast.ASTKind.With:
|
||
wth: ast.With | t.CPtr = (ast.With | t.CPtr)(node)
|
||
if wth.children is not None:
|
||
bn_pre_wb: t.CSizeT = len(wth.children)
|
||
for bi_pre_wb in range(bn_pre_wb):
|
||
self.pre_scan_allocas(trans, wth.children.get(bi_pre_wb))
|
||
return 0
|
||
if k == ast.ASTKind.Match:
|
||
mt_n: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node)
|
||
if mt_n.cases is not None:
|
||
bn_pre_mc: t.CSizeT = len(mt_n.cases)
|
||
for bi_pre_mc in range(bn_pre_mc):
|
||
mc_pre: ast.AST | t.CPtr = mt_n.cases.get(bi_pre_mc)
|
||
if mc_pre is not None and mc_pre.kind() == ast.ASTKind.MatchCase:
|
||
mcc_pre: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(mc_pre)
|
||
if mcc_pre.children is not None:
|
||
bn_pre_mcb: t.CSizeT = len(mcc_pre.children)
|
||
for bi_pre_mcb in range(bn_pre_mcb):
|
||
self.pre_scan_allocas(trans, mcc_pre.children.get(bi_pre_mcb))
|
||
return 0
|
||
return 0
|
||
|
||
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Global:
|
||
return self.translate_global(trans, node)
|
||
if k == ast.ASTKind.Nonlocal:
|
||
return self.translate_nonlocal(trans, node)
|
||
return 0
|
||
|
||
def translate_break(self, trans: HT.Translator | t.CPtr) -> int:
|
||
"""翻译 break 语句:跳转到循环 end 块"""
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
# 发射 br 到 break 目标
|
||
if trans._break_bb is not None:
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, trans._break_bb)
|
||
|
||
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
llvmlite.position_at_end(builder, dead_bb)
|
||
return 0
|
||
|
||
def translate_continue(self, trans: HT.Translator | t.CPtr) -> int:
|
||
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
# 发射 br 到 continue 目标
|
||
if trans._continue_bb is not None:
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, trans._continue_bb)
|
||
|
||
# 创建死代码 BB,用于后续语句
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
llvmlite.position_at_end(builder, dead_bb)
|
||
return 0
|
||
|
||
def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str:
|
||
"""获取语句类型名"""
|
||
if node is None:
|
||
return None
|
||
return node.type_name()
|
||
|
||
# ============================================================
|
||
# 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp)
|
||
# ============================================================
|
||
|
||
def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""判断是否为 Void 类型,是则返回 1,否则 0"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Void():
|
||
return 1
|
||
case _:
|
||
return 0
|
||
|
||
def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||
env_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, "_env_ptr")
|
||
if env_var is not None:
|
||
return env_var
|
||
# 创建 alloca 存储 env
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
|
||
if alloca is None:
|
||
return None
|
||
self.Gen.VarGen.define_var(trans.SymTab, "_env_ptr", alloca)
|
||
return alloca
|
||
|
||
def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
|
||
|
||
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
|
||
"""
|
||
idx: int = HT.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
|
||
# 1. 加载 env_ptr
|
||
env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans)
|
||
if env_alloca is None:
|
||
return None
|
||
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
|
||
if env_ptr is None:
|
||
return None
|
||
|
||
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
|
||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
|
||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||
if addr is None:
|
||
return None
|
||
|
||
# 3. Bitcast to i8** and load the raw pointer
|
||
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
|
||
if ptr_addr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
|
||
|
||
def load_nonlocal_var(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量值
|
||
|
||
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型(从注册时存储的类型信息)
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR
|
||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||
if var_ptr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, var_ty, var_ptr)
|
||
|
||
def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
|
||
|
||
返回的指针指向父函数的 alloca,store 操作对父函数可见。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR
|
||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||
|
||
# ============================================================
|
||
# 簇 E:枚举注册表(迁移自 HandlesEnum.vp)
|
||
# ============================================================
|
||
|
||
def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||
"""初始化枚举注册表,返回 1 成功
|
||
|
||
表用 stdlib 分配(跨 Phase1 1b 的 mark/reset_to 存活——枚举表是
|
||
跨文件持久表,pool 分配会被 reset 回收导致 Phase B 读垃圾,
|
||
enum_count 出现 512 等垃圾值 / entry.Name 解引用崩溃)。
|
||
"""
|
||
if self.EnumTable is not None:
|
||
return 1
|
||
|
||
entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__()
|
||
self.EnumTable = CompilerFactory.get_perm_pool().alloc(entry_size * ENUM_MAX)
|
||
if self.EnumTable is None:
|
||
return 0
|
||
string.memset(self.EnumTable, 0, entry_size * ENUM_MAX)
|
||
self.EnumCount = 0
|
||
return 1
|
||
|
||
def _get_enum_entry(self, i: int) -> GenTypes.EnumEntry | t.CPtr:
|
||
"""获取第 i 个枚举条目"""
|
||
if self.EnumTable is None or i < 0 or i >= ENUM_MAX:
|
||
return None
|
||
entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size
|
||
return (GenTypes.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def _get_enum_member(self, enum_entry: GenTypes.EnumEntry | t.CPtr,
|
||
i: int) -> GenTypes.EnumMember | t.CPtr:
|
||
"""获取枚举中第 i 个成员条目"""
|
||
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
|
||
return None
|
||
member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
|
||
return (GenTypes.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def register_enum(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str,
|
||
base_ty: llvmlite.LLVMType | t.CPtr) -> GenTypes.EnumEntry | t.CPtr:
|
||
"""注册枚举类型,返回 EnumEntry 指针"""
|
||
if self.init_enum_table(pool) == 0:
|
||
return None
|
||
|
||
# 检查是否已注册
|
||
existing: GenTypes.EnumEntry | t.CPtr = self.find_enum(name)
|
||
if existing is not None:
|
||
return existing
|
||
|
||
if self.EnumCount >= ENUM_MAX:
|
||
fb_et: str = VLogger.fmt_buf()
|
||
if fb_et is not None:
|
||
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
|
||
VLogger.error(fb_et, "ENUM")
|
||
return None
|
||
|
||
entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount)
|
||
if entry is None:
|
||
return None
|
||
|
||
# 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化)
|
||
member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__()
|
||
entry.Members = CompilerFactory.get_perm_pool().alloc(member_size * ENUM_MEMBER_MAX)
|
||
if entry.Members is None:
|
||
return None
|
||
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
|
||
|
||
# 复制类名(永久池深拷贝)
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, name)
|
||
entry.Name = name_buf
|
||
|
||
# BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1(Phase2 mark2 后)
|
||
# 时 reset 回收悬空 → Phase B 枚举访问 ConstInt(悬空 BaseTy) 生成 void
|
||
# 值(DecoratorMarkerTest `store void 2` llc 报错根因)。Phase1 1a
|
||
# (StdlibAlloc=0,mark1 前)保持 pool 存活,无需拷贝。
|
||
# 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接
|
||
# self.StdlibAlloc(NoVTable 按本 Mixin 字段布局编译),走模块级委托。
|
||
if self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||
base_ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||
CompilerFactory.get_perm_pool(), base_ty)
|
||
if base_ty_copy is not None:
|
||
entry.BaseTy = base_ty_copy
|
||
else:
|
||
entry.BaseTy = base_ty
|
||
else:
|
||
entry.BaseTy = base_ty
|
||
entry.MemberCount = 0
|
||
|
||
self.EnumCount += 1
|
||
return entry
|
||
|
||
def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr,
|
||
enum_entry: GenTypes.EnumEntry | t.CPtr,
|
||
member_name: str,
|
||
member_val: t.CInt64T,
|
||
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""向枚举添加成员,返回成员索引(-1 失败)"""
|
||
if enum_entry is None or member_name is None or member_ty is None:
|
||
return -1
|
||
|
||
# 去重:同名成员已存在则跳过(跨模块同名枚举合并注册 / 同模块
|
||
# 重复处理幂等——如 w32.fileio 与 fat32_types 都有 FRESULT)
|
||
for ei_d in range(enum_entry.MemberCount):
|
||
ex_d: GenTypes.EnumMember | t.CPtr = self._get_enum_member(
|
||
enum_entry, ei_d)
|
||
if ex_d is not None and ex_d.Name is not None:
|
||
if string.strcmp(ex_d.Name, member_name) == 0:
|
||
return ei_d
|
||
|
||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||
fb_em: str = VLogger.fmt_buf()
|
||
if fb_em is not None:
|
||
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
|
||
VLogger.error(fb_em, "ENUM")
|
||
return -1
|
||
|
||
idx: int = enum_entry.MemberCount
|
||
me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx)
|
||
if me is None:
|
||
return -1
|
||
|
||
# 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活)
|
||
name_len: t.CSizeT = string.strlen(member_name)
|
||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, member_name)
|
||
me.Name = name_buf
|
||
|
||
me.Value = member_val
|
||
me.Ty = member_ty
|
||
|
||
enum_entry.MemberCount = idx + 1
|
||
return idx
|
||
|
||
def find_enum(self, name: str) -> GenTypes.EnumEntry | t.CPtr:
|
||
"""按枚举类名查找,返回 EnumEntry 或 None"""
|
||
if name is None or self.EnumTable is None:
|
||
return None
|
||
for i in range(self.EnumCount):
|
||
entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def lookup_enum_member(self, enum_name: str,
|
||
member_name: str) -> GenTypes.EnumMember | t.CPtr:
|
||
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
|
||
if enum_name is None or member_name is None:
|
||
return None
|
||
entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||
if entry is None:
|
||
return None
|
||
for mi in range(entry.MemberCount):
|
||
me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(entry, mi)
|
||
if me is not None and me.Name is not None:
|
||
if string.strcmp(me.Name, member_name) == 0:
|
||
return me
|
||
return None
|
||
|
||
def is_enum_class(self, name: str) -> int:
|
||
"""检查类名是否为已注册枚举,返回 1=是 / 0=否"""
|
||
if name is None:
|
||
return 0
|
||
if self.find_enum(name) is not None:
|
||
return 1
|
||
return 0
|
||
|
||
def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""按枚举类名获取基准类型"""
|
||
entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||
if entry is not None:
|
||
return entry.BaseTy
|
||
return None
|