回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。
理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
· e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
· 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。
注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
710 lines
39 KiB
Plaintext
710 lines
39 KiB
Plaintext
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)
|