Files
ViperC/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp
T

597 lines
28 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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