Files
ViperC/App/lib/core/Gen/Stmt/StmtGenMixin.vp
T
TermiNexus aa52cf157d revert(transpyv): 回滚跨模块链表 Next 改访问器(改由编译器沿继承链解析字段名)
回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。

理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
  · e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
    展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
  · 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。

注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
2026-09-28 21:48:53 +08:00

710 lines
39 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 lib.core.Gen.Generator as Generator
import lib.core.Gen.Call.CallGenFd as CallGenFd
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.StmtGenDeclMixin as StmtGenDeclMixin
import lib.core.Gen.DebugInfoGen as DebugInfoGen
# ============================================================
# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组,拆分后顶层)
# ============================================================
# ============================================================
# StmtGenMixin - 语句分派中枢(顶层)
# ============================================================
novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
"""语句/流程翻译 Mixin(拆分后顶层,继承 Decl)"""
def translate_stmt(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译单条语句,返回新增的变量数(深度守卫包装器,原逻辑见 _translate_stmt_impl)"""
if trans is not None:
# --traceback: statement-level DWARF location (no-op outside a
# DI-attached define or when DI is disabled). 此后本语句生成的每条
# 指令自动带 ", !dbg !N",保证函数体内每个 call 都有合法 !dbg。
if node is not None and trans._cur_builder is not None:
DebugInfoGen.SetStatement(trans.Pool, trans._cur_builder,
node.lineno, node.col_offset + 1)
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
self.Gen.TypeGenErr.fatal_error(node, "语句翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
trans.TranslateDepth += 1
mret: int = self._translate_stmt_impl(trans, node)
if trans is not None:
trans.TranslateDepth -= 1
return mret
def _translate_stmt_impl(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译单条语句,返回新增的变量数"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Expr:
return self.translate_expr_stmt(trans, node)
elif k == ast.ASTKind.Assign:
return self.Gen.AssignGen.translate_assign(trans, node)
elif k == ast.ASTKind.AnnAssign:
return self.Gen.AssignGen.translate_annassign(trans, node)
elif k == ast.ASTKind.FunctionDef:
# 嵌套函数定义:提升为顶层函数 + 创建闭包
return self.Gen.FuncGen.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return:
return self.Gen.StmtGenCif.translate_return(trans, node)
elif k == ast.ASTKind.If:
return self.Gen.StmtGenCif.translate_if(trans, node)
elif k == ast.ASTKind.While:
return self.Gen.StmtGenCif.translate_while(trans, node)
elif k == ast.ASTKind.AugAssign:
return self.Gen.AssignGen.translate_augassign(trans, node)
elif k == ast.ASTKind.For:
return self.Gen.StmtGenCif.translate_for(trans, node)
elif k == ast.ASTKind.ClassDef:
return self.Gen.ClassGenDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import:
return self.Gen.ImportsGen.translate_import(trans, node)
elif k == ast.ASTKind.ImportFrom:
self.Gen.ImportsGen.translate_import_from_module(trans, node)
return self.Gen.ImportsGen.translate_import_from_names(trans, node)
elif k == ast.ASTKind.Global:
return self.translate_global(trans, node)
elif k == ast.ASTKind.Nonlocal:
return self.translate_nonlocal(trans, node)
elif k == ast.ASTKind.Pass:
return 0
elif k == ast.ASTKind.Break:
return self.translate_break(trans)
elif k == ast.ASTKind.Continue:
return self.translate_continue(trans)
elif k == ast.ASTKind.Match:
return self.Gen.MatchGen.translate_match(trans, node)
elif k == ast.ASTKind.Delete:
return self.translate_delete(trans, node)
elif k == ast.ASTKind.Raise:
return self.translate_raise(trans, node)
elif k == ast.ASTKind.Try:
return self.translate_try(trans, node)
elif k == ast.ASTKind.With:
return self.translate_with(trans, node)
# 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题
self.Gen.TypeGenErr.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError")
return 0
def translate_delete(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 del 语句,返回 0"""
if trans is None or node is None:
return 0
dnode: rawptr[ast.Delete] = rawptr[ast.Delete](node)
if dnode is None or dnode.targets is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
mod: llvmlite.LLVMModule* = trans.Module
builder: llvmlite.IRBuilder* = trans._cur_builder
if pool is None or mod is None or builder is None:
return 0
tn: sizet = len(dnode.targets)
for ti in range(tn):
tgt: ast.AST* = dnode.targets.get(ti)
if tgt is None:
continue
# del obj.attr → property deleter
if tgt.kind() == ast.ASTKind.Attribute:
del_at: ast.Attribute* = ast.Attribute*(tgt)
if del_at is not None:
self.Gen.CallGenProp._try_property_deleter(pool, builder, mod, del_at, trans)
# del obj[key] → __delitem__(obj, key)(对齐 TPC HandlesDelete.py)。
# 不能静默忽略 Subscript 目标——否则 del 不生效(len 不变)。
elif tgt.kind() == ast.ASTKind.Subscript:
dl_sub: ast.Subscript* = ast.Subscript*(tgt)
if dl_sub is not None and dl_sub.value is not None and dl_sub.slice is not None:
dl_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, dl_sub.value, None, 0, trans)
dl_idx: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, dl_sub.slice, None, 0, trans)
if dl_obj is not None and dl_idx is not None:
dl_st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(dl_obj)
if dl_st is not None:
dl_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, dl_st)
if dl_cls is not None:
dl_lookup: str = pool.alloc(128)
if dl_lookup is not None:
viperlib.snprintf(dl_lookup, 128, "%s.__delitem__", dl_cls)
dl_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, dl_lookup)
if dl_fn is not None:
dl_ret: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(dl_fn)
dl_fn_name: str = llvmlite.function_get_name(dl_fn)
if dl_ret is not None and dl_fn_name is not None:
# self 参数(容器)按 __delitem__ 首参类型对齐
dl_self: llvmlite.Value* = dl_obj
dl_first: llvmlite.Param* = llvmlite.function_get_param_head(dl_fn)
if dl_first is not None:
dl_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(dl_first)
if dl_self_ty is not None:
dl_self = llvmlite.build_bitcast(builder, dl_obj, dl_self_ty)
if dl_self is not None:
# 参数链表: self → key(独立 null 结尾)
dl_self.Next = dl_idx
dl_idx.Next = None
llvmlite.build_call(builder, dl_fn_name, dl_self, 2, dl_ret, 0)
return 0
# ============================================================
# translate_try - try/except 语句翻译
#
# 对齐 TPC HandlesTry.py L59-214(v1 迁移)。异常 = (i32 code, i8* msg)
# 二元组;except X 编译期静态展开 X 及全部子孙异常类编码。布局:
# pre → TryBB → DispatchBB(编码检查链)→ MatchBB → ExceptBB → AfterBB
# try 体正常结束 → store 0 →(else 若有)→ AfterBB
# DispatchBB 无匹配 → UnhandledBB:函数有 EH 输出参数则写入并返回
# (向上传播),否则 store 0 → AfterBB(吞掉)
# try 上下文(DispatchBB + 两个 alloca)写入 trans._eh_*,translate_raise
# 与调用侧 EH 检测(CallGenMixin._emit_eh_guarded_call)据此重定向;
# 退出时恢复外层上下文(嵌套 try 支持)。
# v1 未实现 finalbody(TestFBProject 未使用;finally+return 交互复杂,
# 后续按 TPC HandlesTry.py L188-214 的 pending_ret 方案扩展)。
# ============================================================
def translate_try(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 try/except 语句,返回 0"""
if trans is None or node is None:
return 0
tr: ast.Try* = ast.Try*(node)
if tr is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
if pool is None or builder is None or func is None:
return 0
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
return 0
# ---- 1. 异常编码/消息 alloca(当前 try 上下文)----
i32_ty_t: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ty_t: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty_t: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_t)
if i32_ty_t is None or i8_ptr_ty_t is None:
return 0
exception_code: llvmlite.Value* = llvmlite.build_alloca(builder, i32_ty_t)
eh_message: llvmlite.Value* = llvmlite.build_alloca(builder, i8_ptr_ty_t)
if exception_code is None or eh_message is None:
return 0
init_code_t: llvmlite.Value* = llvmlite.const_int32(pool, 0)
init_msg_t: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null")
if init_code_t is not None:
llvmlite.build_store(builder, init_code_t, exception_code)
if init_msg_t is not None:
llvmlite.build_store(builder, init_msg_t, eh_message)
# ---- 2. 块布局(块名唯一化,create_block 不自动编号)----
lc_t: int = trans._label_counter
trans._label_counter = lc_t + 1
bb_buf_t: str = pool.alloc(64)
if bb_buf_t is None:
return 0
viperlib.snprintf(bb_buf_t, 64, "try.dispatch.%d", lc_t)
dispatch_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
viperlib.snprintf(bb_buf_t, 64, "try.after.%d", lc_t)
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
viperlib.snprintf(bb_buf_t, 64, "try.unhandled.%d", lc_t)
unhandled_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
viperlib.snprintf(bb_buf_t, 64, "try.body.%d", lc_t)
try_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
if dispatch_bb is None or after_bb is None or unhandled_bb is None or try_bb is None:
return 0
else_bb: rawptr[llvmlite.BasicBlock] = None
if tr.orelse is not None and len(tr.orelse) > 0:
viperlib.snprintf(bb_buf_t, 64, "try.else.%d", lc_t)
else_bb = llvmlite.create_block(pool, func, bb_buf_t)
n_handlers_t: sizet = 0
if tr.handlers is not None:
n_handlers_t = len(tr.handlers)
# 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量!
# 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠),
# 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。
except_bbs: list[rawptr[llvmlite.BasicBlock]] | t.CPtr = \
list[rawptr[llvmlite.BasicBlock]](pool, 8)
match_bbs: list[rawptr[llvmlite.BasicBlock]] | t.CPtr = \
list[rawptr[llvmlite.BasicBlock]](pool, 8)
if except_bbs is None or match_bbs is None:
return 0
for i_t in range(n_handlers_t):
viperlib.snprintf(bb_buf_t, 64, "try.except.%d.%d", lc_t, i_t)
eb_t: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
viperlib.snprintf(bb_buf_t, 64, "try.match.%d.%d", lc_t, i_t)
mb_t: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
except_bbs.append(eb_t)
match_bbs.append(mb_t)
# ---- 3. 保存外层 try 上下文,设置本 try 上下文 ----
old_dispatch_t: rawptr[llvmlite.BasicBlock] = trans._eh_dispatch_bb
old_code_t: llvmlite.Value* = trans._eh_code_ptr
old_msg_t: llvmlite.Value* = trans._eh_msg_ptr
trans._eh_dispatch_bb = dispatch_bb
trans._eh_code_ptr = exception_code
trans._eh_msg_ptr = eh_message
# ---- 4. Try 体 ----
llvmlite.build_br(builder, try_bb)
llvmlite.position_at_end(builder, try_bb)
if tr.children is not None:
tb_n: sizet = len(tr.children)
for tbi in range(tb_n):
stmt_t: ast.AST* = tr.children.get(tbi)
if stmt_t is not None:
self.translate_stmt(trans, stmt_t)
# 正常走完 try 体:清异常码,进 else(若有)或 After
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
if init_code_t is not None:
llvmlite.build_store(builder, init_code_t, exception_code)
if else_bb is not None:
llvmlite.build_br(builder, else_bb)
else:
llvmlite.build_br(builder, after_bb)
# ---- 5. DispatchBB:编码检查链 ----
llvmlite.position_at_end(builder, dispatch_bb)
if n_handlers_t == 0:
# 无 except(非法 try,防御):直接吞掉
llvmlite.build_br(builder, unhandled_bb)
else:
eh_code_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty_t, exception_code)
next_check_t: rawptr[llvmlite.BasicBlock] = None
for i_t in range(n_handlers_t):
hdr_t: ast.ExceptHandler* = ast.ExceptHandler*(tr.handlers.get(i_t))
match_bb_t: rawptr[llvmlite.BasicBlock] = match_bbs.get(i_t)
if i_t > 0 and next_check_t is not None:
llvmlite.position_at_end(builder, next_check_t)
eh_code_val = llvmlite.build_load(builder, i32_ty_t, exception_code)
if hdr_t is None or hdr_t.type is None:
# 裸 except:无条件匹配
llvmlite.build_br(builder, match_bb_t)
else:
# 展开匹配编码集(handler.type 自身 + 全部子孙异常类)
hname_t: str = None
htype_t: ast.AST* = hdr_t.type
if htype_t.kind() == ast.ASTKind.Name:
hname_t = (ast.Name*(htype_t)).id
elif htype_t.kind() == ast.ASTKind.Attribute:
hname_t = (ast.Attribute*(htype_t)).attr
# 匹配编码缓冲:必须是 int*(i32 步长)——collect_descendant_codes 按
# out_codes[i](4 字节)写入;用 sizet*(8 字节)读会读出 64 位拼接垃圾
# (多码时 code[i+1]<<32|code[i];单码时高位恰为 0 掩盖)。
codes_buf_t: int | t.CPtr = pool.alloc(64 * 4)
if codes_buf_t is None:
return 0
n_codes_t: int = 0
if hname_t is not None and self.Gen.ClassGenBase.is_exception_name(hname_t) != 0:
n_codes_t = self.Gen.ClassGenBase.collect_descendant_codes(hname_t, codes_buf_t, 64)
else:
c0_t: int = 1
if hname_t is not None:
c0_t = self.Gen.ClassGenBase.lookup_exception_code(hname_t)
if c0_t == 0:
c0_t = 1
codes_buf_t[0] = c0_t
n_codes_t = 1
match_cond_t: llvmlite.Value* = None
for ci_t in range(n_codes_t):
code_val_t: llvmlite.Value* = llvmlite.const_int32(pool, codes_buf_t[ci_t])
is_match_t: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t)
if match_cond_t is None:
match_cond_t = is_match_t
elif is_match_t is not None:
match_cond_t = llvmlite.build_or(builder, match_cond_t, is_match_t)
if i_t < n_handlers_t - 1:
viperlib.snprintf(bb_buf_t, 64, "try.check.%d.%d", lc_t, i_t)
next_check_t = llvmlite.create_block(pool, func, bb_buf_t)
else:
next_check_t = unhandled_bb
llvmlite.build_cond_br(builder, match_cond_t, match_bb_t, next_check_t)
# MatchBB:绑定 handler 变量(e = 消息指针),跳 ExceptBB
llvmlite.position_at_end(builder, match_bb_t)
if hdr_t is not None and hdr_t.name is not None and hdr_t.name[0] != '\0':
# 同名 handler 变量复用函数入口 alloca(find_var 首条命中、
# 重复 define_var 不 shadow——多 try 共用 `as e` 时各 MatchBB
# 各自 store 消息,各 ExceptBB 读同一入口 alloca,避免
# 非支配 alloca 触发 "does not dominate all uses")。
h_ent_t: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, hdr_t.name)
if h_ent_t is not None and h_ent_t.Alloca is not None:
h_alloca_t: llvmlite.Value* = h_ent_t.Alloca
else:
h_alloca_t = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_t)
if h_alloca_t is not None:
self.Gen.VarGen.define_var(trans.SymTab, hdr_t.name, h_alloca_t)
if h_alloca_t is not None:
h_msg_t: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_t, eh_message)
if h_msg_t is not None:
llvmlite.build_store(builder, h_msg_t, h_alloca_t)
except_bb_t: rawptr[llvmlite.BasicBlock] = except_bbs.get(i_t)
llvmlite.build_br(builder, except_bb_t)
# ---- 6. UnhandledBB:无 except 匹配 → 向上传播或吞掉 ----
llvmlite.position_at_end(builder, unhandled_bb)
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
and trans._eh_code_out_param is not None:
un_msg_t: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_t, eh_message)
un_code_t: llvmlite.Value* = llvmlite.build_load(builder, i32_ty_t, exception_code)
if un_msg_t is not None:
llvmlite.build_store(builder, un_msg_t, trans._eh_msg_out_param)
if un_code_t is not None:
llvmlite.build_store(builder, un_code_t, trans._eh_code_out_param)
self._eh_ret_default(trans, pool, builder)
else:
if init_code_t is not None:
llvmlite.build_store(builder, init_code_t, exception_code)
llvmlite.build_br(builder, after_bb)
# ---- 7. Except 体 ----
for i_t in range(n_handlers_t):
hdr2_t: ast.ExceptHandler* = ast.ExceptHandler*(tr.handlers.get(i_t))
except_bb2_t: rawptr[llvmlite.BasicBlock] = except_bbs.get(i_t)
llvmlite.position_at_end(builder, except_bb2_t)
if hdr2_t is not None and hdr2_t.children is not None:
hn2_t: sizet = len(hdr2_t.children)
for hi2 in range(hn2_t):
stmt2_t: ast.AST* = hdr2_t.children.get(hi2)
if stmt2_t is not None:
self.translate_stmt(trans, stmt2_t)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, after_bb)
# ---- 8. Else 体 ----
if else_bb is not None:
llvmlite.position_at_end(builder, else_bb)
if tr.orelse is not None:
en_t: sizet = len(tr.orelse)
for ei in range(en_t):
stmt3_t: ast.AST* = tr.orelse.get(ei)
if stmt3_t is not None:
self.translate_stmt(trans, stmt3_t)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, after_bb)
# ---- 9. AfterBB + 恢复外层 try 上下文 ----
llvmlite.position_at_end(builder, after_bb)
trans._eh_dispatch_bb = old_dispatch_t
trans._eh_code_ptr = old_code_t
trans._eh_msg_ptr = old_msg_t
return 0
def translate_raise(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 raise 语句,返回 0
对齐 TPC HandlesRaise.py 的 try-except 语义(v1 迁移):
- StopIteration:置 __stop_iter_flag__ = 1 后返回默认值(迭代结束协议)
- 非 StopIteration:
1. 处于 try(trans._eh_dispatch_bb 非空):异常编码/消息写入当前
try 的 eh_code/eh_message alloca,分支到 DispatchBB 由 except 链裁决
2. 函数有 EH 输出参数(_cur_func_has_eh):编码/消息写入
__eh_code_out__/__eh_msg_out__,返回默认值(异常向调用方传播)
3. 两者皆无:仅返回默认值(v1 语义:异常被吞掉)
"""
if trans is None or node is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
mod: llvmlite.LLVMModule* = trans.Module
if pool is None or builder is None or mod is None:
return 0
rn: rawptr[ast.Raise] = rawptr[ast.Raise](node)
if rn is None or rn.exc is None:
# bare raise(无 exc):v1 无活动异常可再抛,仅返回默认值
self._eh_ret_default(trans, pool, builder)
return 0
# OOP iter 协议:raise StopIteration → 置 __stop_iter_flag__ = 1
# (对齐 TPC HandlesRaise.py L76-100),随后按迭代结束返回默认值。
ek: int = rn.exc.kind()
is_stop_iter: int = 0
if ek == ast.ASTKind.Name:
enm: ast.Name* = ast.Name*(rn.exc)
if enm.id is not None and string.strcmp(enm.id, "StopIteration") == 0:
is_stop_iter = 1
elif ek == ast.ASTKind.Call:
ecl: ast.Call* = ast.Call*(rn.exc)
if ecl.func is not None and ecl.func.kind() == ast.ASTKind.Name:
ecn: ast.Name* = ast.Name*(ecl.func)
if ecn.id is not None and string.strcmp(ecn.id, "StopIteration") == 0:
is_stop_iter = 1
if is_stop_iter != 0:
if trans._stop_iter_flag_ptr is not None:
i1_ty_r: llvmlite.LLVMType* = llvmlite.Int1(pool)
if i1_ty_r is not None:
one_i1_r: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty_r, 1, "1")
if one_i1_r is not None:
llvmlite.build_store(builder, one_i1_r, trans._stop_iter_flag_ptr)
self._eh_ret_default(trans, pool, builder)
return 0
# ---- 非 StopIteration:计算异常编码与消息 ----
exc_code: int = 1
exc_msg: llvmlite.Value* = None
if ek == ast.ASTKind.Constant:
cst_r: ast.Constant* = ast.Constant*(rn.exc)
if cst_r is not None and cst_r.const_kind == ast.CONST_INT:
exc_code = cst_r.int_val
elif ek == ast.ASTKind.Name:
enm2: ast.Name* = ast.Name*(rn.exc)
if enm2.id is not None:
exc_code = self.Gen.ClassGenBase.lookup_exception_code(enm2.id)
if exc_code == 0:
exc_code = 1
elif ek == ast.ASTKind.Call:
ecl2: ast.Call* = ast.Call*(rn.exc)
if ecl2.func is not None and ecl2.func.kind() == ast.ASTKind.Name:
ecn2: ast.Name* = ast.Name*(ecl2.func)
if ecn2.id is not None:
exc_code = self.Gen.ClassGenBase.lookup_exception_code(ecn2.id)
if exc_code == 0:
exc_code = 1
if ecl2.args is not None and len(ecl2.args) > 0:
exc_msg = self.Gen.ExprGen.translate_value(builder, pool, mod, ecl2.args.get(0), None, 0, trans)
# ---- 异常分发 ----
# 1. try 内:写入 try 的 eh_code/eh_message alloca,分支 DispatchBB
if trans._eh_dispatch_bb is not None and trans._eh_code_ptr is not None:
code_val_r: llvmlite.Value* = llvmlite.const_int32(pool, exc_code)
if code_val_r is not None:
llvmlite.build_store(builder, code_val_r, trans._eh_code_ptr)
if exc_msg is None:
exc_msg = llvmlite.ConstNull(pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
if exc_msg is not None and trans._eh_msg_ptr is not None:
llvmlite.build_store(builder, exc_msg, trans._eh_msg_ptr)
llvmlite.build_br(builder, trans._eh_dispatch_bb)
return 0
# 2. 函数有 EH 输出参数:写入 out 参数(异常向调用方传播)
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
and trans._eh_code_out_param is not None:
code_val_r2: llvmlite.Value* = llvmlite.const_int32(pool, exc_code)
if code_val_r2 is not None:
llvmlite.build_store(builder, code_val_r2, trans._eh_code_out_param)
if exc_msg is None:
exc_msg = llvmlite.ConstNull(pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
if exc_msg is not None:
llvmlite.build_store(builder, exc_msg, trans._eh_msg_out_param)
self._eh_ret_default(trans, pool, builder)
return 0
# 3. 无 try 无 EH 参数:仅返回默认值
self._eh_ret_default(trans, pool, builder)
return 0
# ============================================================
# _eh_ret_default - 异常路径返回当前函数的默认零值
#
# 对齐 TPC HandlesTry.py UnhandledBB / HandlesRaise.py 的返回生成
# (void→ret_void,ptr→null,float→0.0,其余→零值)。当前块已
# 终结(前一条是 raise/return)时跳过,避免在终止块后插指令。
# ============================================================
def _eh_ret_default(self, trans: HT.Translator*,
pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*) -> int:
"""异常路径返回当前函数默认零值,返回 0"""
if trans is None or builder is None:
return 0
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
return 0
cur_func: llvmlite.Function* = trans._cur_func
if cur_func is None:
return 0
ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(cur_func)
if ret_ty is None:
return 0
match ret_ty:
case llvmlite.LLVMType.Void():
llvmlite.build_ret_void(builder)
case llvmlite.LLVMType.Ptr(_pe):
null_v: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null")
if null_v is not None:
llvmlite.build_ret(builder, null_v)
case llvmlite.LLVMType.Float(_fb):
zero_f: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0)
if zero_f is not None:
llvmlite.build_ret(builder, zero_f)
case _:
zero_v: llvmlite.Value* = llvmlite.ConstZero(pool, ret_ty)
if zero_v is not None:
llvmlite.build_ret(builder, zero_v)
return 0
# ============================================================
# translate_with - with 语句翻译
#
# with expr() as x: body
# → 1. 构造 context 对象(expr() 调用)
# 2. 调用 __enter__()(沿继承链 MRO 解析,如 MemPool → MemManager)
# 3. x 绑定 __enter__ 返回值(缺失时退回 context 对象)
# 4. 翻译 body
# 5. 逆序调用 __exit__()(无异常传播,__exit__ 仅做清理如 reset)
#
# 实现:context 对象存入临时变量 __with_ctx,方法调用复用
# translate_call 的 Attribute 分派 + _translate_method_call 的 MRO 回退
# (与普通 obj.method() 调用一致)。嵌套 with 时保存外层 __with_ctx,
# 退出后恢复,避免内层覆盖导致外层 __exit__ 解析到错误对象。
# 对齐 TPC HandlesWith 语义(不含 __provides__ provider 机制)。
# ============================================================
def translate_with(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 with 语句,返回 0"""
if trans is None or node is None:
return 0
wt: ast.With* = ast.With*(node)
if wt is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
mod: llvmlite.LLVMModule* = trans.Module
if pool is None or builder is None or mod is None:
return 0
items: list[ast.AST*]* = wt.items
if items is None:
return 0
n: sizet = len(items)
# 保存外层 __with_ctx(嵌套 with 时退出后恢复)
old_ctx_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "__with_ctx")
# 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用)
ctx_class_buf: sizet* = pool.alloc(8 * n)
if ctx_class_buf is None:
return 0
string.memset(ctx_class_buf, 0, 8 * n)
# 1. 全部 item:构造 context 对象 + 调用 __enter__ + asname 绑定
for i in range(n):
item_node: ast.AST* = items.get(i)
if item_node is None:
continue
if item_node.kind() != ast.ASTKind.WithItem:
continue
item: rawptr[ast.WithItem] = rawptr[ast.WithItem](item_node)
if item is None or item.context_expr is None:
continue
# 翻译 context_expr(对象构造,如 MemPool(arena, 4096))
ctx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, item.context_expr, trans._funcs, trans._func_count, trans)
if ctx_val is None:
continue
# 提取类名(注解类名,Attribute 时带模块前缀,如 "memhub.MemPool"——
# 与 AnnAssign 的 extract_class_name_from_annotation 一致,跨模块
# 方法调用靠 AnnotClassName 回退按模块名查 SHA1)
cls_name: str = None
ce: ast.AST* = item.context_expr
if ce.kind() == ast.ASTKind.Call:
cfn: ast.AST* = (ast.Call*(ce)).func
if cfn is not None:
if cfn.kind() == ast.ASTKind.Attribute:
ca: ast.Attribute* = ast.Attribute*(cfn)
if ca.value is not None and ca.value.kind() == ast.ASTKind.Name:
cmn: ast.Name* = ast.Name*(ca.value)
if cmn.id is not None:
ml2: sizet = string.strlen(cmn.id) + string.strlen(ca.attr) + 2
mbuf: str = pool.alloc(ml2)
if mbuf is not None:
viperlib.snprintf(mbuf, ml2, "%s.%s", cmn.id, ca.attr)
cls_name = mbuf
if cls_name is None:
cls_name = ca.attr
elif cfn.kind() == ast.ASTKind.Name:
cls_name = (ast.Name*(cfn)).id
# context 对象存入 __with_ctx(方法调用解析 self 用)
ctx_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, ctx_val.Ty)
if ctx_alloca is None:
continue
llvmlite.build_store(builder, ctx_val, ctx_alloca)
self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", ctx_alloca)
if cls_name is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, "__with_ctx", cls_name)
ctx_class_buf[i] = sizet(cls_name)
# 调用 __enter__()
enter_val: llvmlite.Value* = self._with_ctx_call(trans, pool, builder, mod, "__enter__")
# asname 绑定(__enter__ 返回值,缺失时退回 context 对象)
if item.optional_vars is not None:
ov: ast.AST* = item.optional_vars
if ov.kind() == ast.ASTKind.Name:
asname: str = (ast.Name*(ov)).id
if asname is not None:
bind_val: llvmlite.Value* = enter_val
if bind_val is None:
bind_val = ctx_val
if bind_val is not None:
asn_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, bind_val.Ty)
if asn_alloca is not None:
llvmlite.build_store(builder, bind_val, asn_alloca)
self.Gen.VarGen.define_var(trans.SymTab, asname, asn_alloca)
if cls_name is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, asname, cls_name)
# FakeDuck: __provides__ 元数据 → 生成 _push_provider 调用
# (对齐 TPC HandlesWith.py L138-159;经 gen 单例委托 CallGenMixin。
# 类名去模块前缀后查 __provides__ 表,如 memhub.MemBuddy → MemBuddy)
fd_cls_bare: str = cls_name
if cls_name is not None:
fd_dot: str = string.strrchr(cls_name, '.')
if fd_dot is not None:
fd_cls_bare = fd_dot + 1
if fd_cls_bare is not None:
self.Gen.CallGenFd._emit_provider_push(trans, pool, builder, mod, fd_cls_bare, ctx_val)
# 2. 翻译 body
body: list[ast.AST*]* = wt.children
if body is not None:
bn: sizet = len(body)
for bi in range(bn):
st: ast.AST* = body.get(bi)
if st is not None:
self.translate_stmt(trans, st)
# 2.5 FakeDuck: __provides__ 元数据 → 生成 _pop_provider 调用
# (对齐 TPC HandlesWith.py L167-174;逆序弹栈,经 gen 单例委托)
for pi_pop in range(n):
if ctx_class_buf[pi_pop] != 0:
cls_pop: str = rawptr(ctx_class_buf[pi_pop])
fd_cls_bare_p: str = cls_pop
if cls_pop is not None:
fd_dot_p: str = string.strrchr(cls_pop, '.')
if fd_dot_p is not None:
fd_cls_bare_p = fd_dot_p + 1
if fd_cls_bare_p is not None:
self.Gen.CallGenFd._emit_provider_pop(trans, pool, builder, mod, fd_cls_bare_p)
# 3. 逆序调用 __exit__()(Python with 语义:后进先出)
for i in range(n):
ci: int = n - 1 - i
if ctx_class_buf[ci] != 0:
cls_ci: str = rawptr(ctx_class_buf[ci])
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, "__with_ctx", cls_ci)
self._with_ctx_call(trans, pool, builder, mod, "__exit__")
# 4. 恢复外层 __with_ctx
if old_ctx_alloca is not None:
self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca)
return 0
def _with_ctx_call(self, trans: HT.Translator*,
pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
method_name: str) -> llvmlite.Value*:
"""构造并翻译 __with_ctx.<method_name>() 调用(__enter__/__exit__)"""
if pool is None or method_name is None: return None
name_node: ast.AST* = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load)
if name_node is None: return None
attr_node: ast.AST* = ast.Attribute(pool, name_node, method_name, ast.ASTCtx.Load)
if attr_node is None: return None
call_node: ast.AST* = ast.Call(pool, attr_node, None, None)
if call_node is None: return None
return self.Gen.ExprGen.translate_value(builder, pool, mod, call_node, trans._funcs, trans._func_count, trans)