597 lines
28 KiB
Plaintext
597 lines
28 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.Gen.Translator as HT
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Projectrans.Config as Config
|
||
import lib.core.Gen.Stmt.StmtGenCifMixin as StmtGenCifMixin
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenDeclMixin - StmtGen 拆分 2/3:声明/枚举/nonlocal 访问
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量
|
||
# ============================================================
|
||
define ENUM_MAX = 64
|
||
define ENUM_MEMBER_MAX = 128
|
||
|
||
# ============================================================
|
||
# StmtGenDeclMixin - 声明/枚举/nonlocal(中层级)
|
||
# ============================================================
|
||
novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||
"""声明/枚举/nonlocal 访问(StmtGen 拆分 2/3,继承 Cif)"""
|
||
|
||
def translate_global(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 global 语句:记录 global 变量名"""
|
||
gn: rawptr[ast.Global] = rawptr[ast.Global](node)
|
||
if gn is None:
|
||
return 0
|
||
names: list[ast.AST*]* = gn.names
|
||
if names is None:
|
||
return 0
|
||
n: sizet = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST* = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(nm_node)
|
||
if nm.id is not None:
|
||
GenApi.add_global_name(trans, nm.id)
|
||
return 0
|
||
|
||
def translate_nonlocal(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
|
||
|
||
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
|
||
"""
|
||
nl: rawptr[ast.Nonlocal] = rawptr[ast.Nonlocal](node)
|
||
if nl is None:
|
||
return 0
|
||
names: list[ast.AST*]* = nl.names
|
||
if names is None:
|
||
return 0
|
||
n: sizet = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST* = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(nm_node)
|
||
if nm.id is not None:
|
||
# 查找父作用域中的变量 alloca,获取类型信息
|
||
var_ty: llvmlite.LLVMType* = None
|
||
var_alloca: llvmlite.Value* = 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
|
||
GenApi.add_nonlocal_name(trans, nm.id, var_ty)
|
||
return 0
|
||
|
||
def translate_expr_stmt(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""翻译表达式语句(printf 调用等)"""
|
||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](node)
|
||
if ex is None:
|
||
return 0
|
||
call_node: ast.AST* = ex.value
|
||
if call_node is None:
|
||
return 0
|
||
ck: int = call_node.kind()
|
||
if ck != ast.ASTKind.Call:
|
||
# REPL 模式(M2):片段函数本体内的裸表达式语句(如 1+2 / x / x + 1)
|
||
# 求值后写入 ctx 结果区,由宿主回显。调用表达式仍走下方原路径
|
||
# (执行 + 丢弃返回值,同 print/printf 语义)。
|
||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ "表达式语句除调用外一律忽略"
|
||
# 的原行为逐字不变。
|
||
if trans is not None and trans.ReplCtx is not None \
|
||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||
self.Gen.VarGen.repl_expr_result(trans, call_node)
|
||
return 0
|
||
|
||
cl: ast.Call* = ast.Call*(call_node)
|
||
func_node: ast.AST* = 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:
|
||
# 通用函数调用(返回值丢弃)
|
||
# M3:裸名调用**会话函数**(跨片段)时额外把返回值写进 ctx 结果区回显
|
||
# (M2 的限制条目"调用表达式的结果不回显"对会话函数放开——用户在
|
||
# `>>> f(41)` 后期望看到 `=> 42`)。结果区的类型分类直接用会话函数表里
|
||
# 记录的返回类型 token(宿主从定义片段 IR 解析而来,是定义端 ABI 真相),
|
||
# 不用影子条目推断 ⇒ 与调用点签名同源。
|
||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 原"执行 + 丢弃返回值"逐字不变;
|
||
# 仅裸名(Name)且表中登记的会话函数走本分支(printf/print 等在上方已分流)。
|
||
if trans is not None and trans.ReplCtx is not None \
|
||
and func_node.kind() == ast.ASTKind.Name \
|
||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||
sfn_ent: rawptr[GenTypes.ReplFuncEntry] = \
|
||
self.Gen.VarGen.repl_find_func_entry(trans.ReplCtx, func_name)
|
||
if sfn_ent is not None and sfn_ent.RetTag != GenTypes.REPL_TY_VOID:
|
||
sfn_v: llvmlite.Value* = self.Gen.CallGen.translate_call(trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
if sfn_v is not None:
|
||
ctx_v: llvmlite.Value* = self.Gen.VarGen.repl_ctx_ptr(trans, trans.ReplCtx, call_node)
|
||
if ctx_v is not None:
|
||
self.Gen.VarGen.repl_emit_result(trans, ctx_v, sfn_v, sfn_ent.RetTag, sfn_ent.RetBits,
|
||
call_node)
|
||
return 0
|
||
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*,
|
||
node: ast.AST*) -> 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: rawptr[ast.If] = rawptr[ast.If](node)
|
||
if ifn.children is not None:
|
||
bn_pre_i: sizet = 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: sizet = 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* = ast.For*(node)
|
||
if for_n.children is not None:
|
||
bn_pre_f: sizet = 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: sizet = 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: rawptr[ast.While] = rawptr[ast.While](node)
|
||
if wh_n.children is not None:
|
||
bn_pre_w: sizet = 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: sizet = 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* = ast.Try*(node)
|
||
if tr_n.children is not None:
|
||
bn_pre_t: sizet = 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: sizet = len(tr_n.handlers)
|
||
for bi_pre_th in range(bn_pre_th):
|
||
eh_pre: ast.AST* = tr_n.handlers.get(bi_pre_th)
|
||
if eh_pre is not None and eh_pre.kind() == ast.ASTKind.ExceptHandler:
|
||
ehc_pre: ast.ExceptHandler* = ast.ExceptHandler*(eh_pre)
|
||
if ehc_pre.children is not None:
|
||
bn_pre_ehb: sizet = 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: sizet = 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: sizet = 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* = ast.With*(node)
|
||
if wth.children is not None:
|
||
bn_pre_wb: sizet = 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* = ast.Match*(node)
|
||
if mt_n.cases is not None:
|
||
bn_pre_mc: sizet = len(mt_n.cases)
|
||
for bi_pre_mc in range(bn_pre_mc):
|
||
mc_pre: ast.AST* = mt_n.cases.get(bi_pre_mc)
|
||
if mc_pre is not None and mc_pre.kind() == ast.ASTKind.MatchCase:
|
||
mcc_pre: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_pre)
|
||
if mcc_pre.children is not None:
|
||
bn_pre_mcb: sizet = 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*,
|
||
node: ast.AST*) -> 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*) -> int:
|
||
"""翻译 break 语句:跳转到循环 end 块"""
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
pool: memhub.MemBuddy* = 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: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||
llvmlite.position_at_end(builder, dead_bb)
|
||
return 0
|
||
|
||
def translate_continue(self, trans: HT.Translator*) -> int:
|
||
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
func: llvmlite.Function* = trans._cur_func
|
||
pool: memhub.MemBuddy* = 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: rawptr[llvmlite.BasicBlock] = 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*) -> str:
|
||
"""获取语句类型名"""
|
||
if node is None:
|
||
return None
|
||
return node.type_name()
|
||
|
||
# ============================================================
|
||
# 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp)
|
||
# ============================================================
|
||
|
||
def _is_void_type(self, ty: llvmlite.LLVMType*) -> 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*) -> llvmlite.Value*:
|
||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||
env_var: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "_env_ptr")
|
||
if env_var is not None:
|
||
return env_var
|
||
# 创建 alloca 存储 env
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
alloca: llvmlite.Value* = 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*,
|
||
name: str) -> llvmlite.Value*:
|
||
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
|
||
|
||
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
|
||
"""
|
||
idx: int = GenApi.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
|
||
# 1. 加载 env_ptr
|
||
env_alloca: llvmlite.Value* = self.get_env_ptr_var(trans)
|
||
if env_alloca is None:
|
||
return None
|
||
env_ptr: llvmlite.Value* = 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* = llvmlite.const_int32(pool, idx * 8)
|
||
addr: llvmlite.Value* = 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* = 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*,
|
||
name: str) -> llvmlite.Value*:
|
||
"""从闭包 env 加载 nonlocal 变量值
|
||
|
||
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
|
||
"""
|
||
raw_ptr: llvmlite.Value* = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
|
||
# 获取变量类型(从注册时存储的类型信息)
|
||
var_ty: llvmlite.LLVMType* = GenApi.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* = llvmlite.Ptr(pool, var_ty)
|
||
var_ptr: llvmlite.Value* = 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*,
|
||
name: str) -> llvmlite.Value*:
|
||
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
|
||
|
||
返回的指针指向父函数的 alloca,store 操作对父函数可见。
|
||
"""
|
||
raw_ptr: llvmlite.Value* = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
|
||
# 获取变量类型
|
||
var_ty: llvmlite.LLVMType* = GenApi.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* = 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*) -> 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: sizet = GenTypes.EnumEntry.__sizeof__()
|
||
self.EnumTable = CompilerFactory.factory.PermPool.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) -> rawptr[GenTypes.EnumEntry]:
|
||
"""获取第 i 个枚举条目"""
|
||
if self.EnumTable is None or i < 0 or i >= ENUM_MAX:
|
||
return None
|
||
entry_size: sizet = GenTypes.EnumEntry.__sizeof__()
|
||
addr: uint64 = uint64(self.EnumTable) + i * entry_size
|
||
return rawptr[GenTypes.EnumEntry](addr)
|
||
|
||
def _get_enum_member(self, enum_entry: rawptr[GenTypes.EnumEntry],
|
||
i: int) -> rawptr[GenTypes.EnumMember]:
|
||
"""获取枚举中第 i 个成员条目"""
|
||
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
|
||
return None
|
||
member_size: sizet = GenTypes.EnumMember.__sizeof__()
|
||
addr: uint64 = uint64(enum_entry.Members) + i * member_size
|
||
return rawptr[GenTypes.EnumMember](addr)
|
||
|
||
def register_enum(self, pool: memhub.MemBuddy*,
|
||
name: str,
|
||
base_ty: llvmlite.LLVMType*) -> rawptr[GenTypes.EnumEntry]:
|
||
"""注册枚举类型,返回 EnumEntry 指针"""
|
||
if self.init_enum_table(pool) == 0:
|
||
return None
|
||
|
||
# 检查是否已注册
|
||
existing: rawptr[GenTypes.EnumEntry] = self.find_enum(name)
|
||
if existing is not None:
|
||
return existing
|
||
|
||
if self.EnumCount >= ENUM_MAX:
|
||
VLogger.error(f"table full, cannot register {name}", "ENUM")
|
||
return None
|
||
|
||
entry: rawptr[GenTypes.EnumEntry] = self._get_enum_entry(self.EnumCount)
|
||
if entry is None:
|
||
return None
|
||
|
||
# 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化)
|
||
member_size: sizet = GenTypes.EnumMember.__sizeof__()
|
||
entry.Members = CompilerFactory.factory.PermPool.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: sizet = string.strlen(name)
|
||
name_buf: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, name)
|
||
entry.Name = name_buf
|
||
|
||
# BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1 时 reset 回收悬空 → Phase B
|
||
# 枚举访问 ConstInt(悬空 BaseTy) 生成 void 值(llc 报错)。Phase1 1a(mark1 前)
|
||
# 保持 pool 存活,无需拷贝。
|
||
# 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接 self.StdlibAlloc
|
||
# (NoVTable 按本 Mixin 字段布局编译),走模块级委托。
|
||
if self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||
base_ty_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, 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*,
|
||
enum_entry: rawptr[GenTypes.EnumEntry],
|
||
member_name: str,
|
||
member_val: int64,
|
||
member_ty: llvmlite.LLVMType*) -> 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: rawptr[GenTypes.EnumMember] = 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:
|
||
VLogger.error(f"member table full for {enum_entry.Name}", "ENUM")
|
||
return -1
|
||
|
||
idx: int = enum_entry.MemberCount
|
||
me: rawptr[GenTypes.EnumMember] = self._get_enum_member(enum_entry, idx)
|
||
if me is None:
|
||
return -1
|
||
|
||
# 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活)
|
||
name_len: sizet = string.strlen(member_name)
|
||
name_buf: str = CompilerFactory.factory.PermPool.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) -> rawptr[GenTypes.EnumEntry]:
|
||
"""按枚举类名查找,返回 EnumEntry 或 None"""
|
||
if name is None or self.EnumTable is None:
|
||
return None
|
||
for i in range(self.EnumCount):
|
||
entry: rawptr[GenTypes.EnumEntry] = 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) -> rawptr[GenTypes.EnumMember]:
|
||
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
|
||
if enum_name is None or member_name is None:
|
||
return None
|
||
entry: rawptr[GenTypes.EnumEntry] = self.find_enum(enum_name)
|
||
if entry is None:
|
||
return None
|
||
for mi in range(entry.MemberCount):
|
||
me: rawptr[GenTypes.EnumMember] = 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*:
|
||
"""按枚举类名获取基准类型"""
|
||
entry: rawptr[GenTypes.EnumEntry] = self.find_enum(enum_name)
|
||
if entry is not None:
|
||
return entry.BaseTy
|
||
return None
|