From a6d1a6f9aea09e33eef8341177f9e7c045a8c43c Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 13 Aug 2026 07:07:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(stmt):=20=E6=94=AF=E6=8C=81=20with=20?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5=E7=BF=BB=E8=AF=91=EF=BC=88=5F=5Fenter=5F=5F/?= =?UTF-8?q?=5F=5Fexit=5F=5F=20+=20MRO=20=E8=A7=A3=E6=9E=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对齐 TPC HandlesWith 核心语义:构造 context 对象 → 调用 __enter__() (沿继承链 MRO 回退,如 MemPool → MemManager)→ asname 绑定返回值 → 翻译 body → 逆序调用 __exit__()。context 对象存入临时变量 __with_ctx,方法调用复用 translate_call 的 Attribute 分派 + _translate_method_call 的 MRO 回退;嵌套 with 时保存/恢复外层 __with_ctx 避免类型串扰。修复 "with memhub.MemPool(...) as pool:" 报 SyntaxError 未知语句类型 kind=21。 --- App/lib/core/Gen/StmtGenMixin.vp | 150 +++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/App/lib/core/Gen/StmtGenMixin.vp b/App/lib/core/Gen/StmtGenMixin.vp index 4b79c34..38593eb 100644 --- a/App/lib/core/Gen/StmtGenMixin.vp +++ b/App/lib/core/Gen/StmtGenMixin.vp @@ -125,6 +125,8 @@ class StmtGenMixin: return self.translate_delete(trans, node) elif k == ast.ASTKind.Raise: return self.translate_raise(trans, node) + elif k == ast.ASTKind.With: + return self.translate_with(trans, node) # 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题 HandlesType.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError") return 0 @@ -193,6 +195,154 @@ class StmtGenMixin: 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 | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 with 语句,返回 0""" + if trans is None or node is None: + return 0 + wt: ast.With | t.CPtr = (ast.With | t.CPtr)(node) + if wt is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or builder is None or mod is None: + return 0 + items: list[ast.AST | t.CPtr] | t.CPtr = wt.items + if items is None: + return 0 + n: t.CSizeT = len(items) + + # 保存外层 __with_ctx(嵌套 with 时退出后恢复) + old_ctx_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, "__with_ctx") + + # 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用) + ctx_class_buf: t.CSizeT | t.CPtr = 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 | t.CPtr = items.get(i) + if item_node is None: + continue + if item_node.kind() != ast.ASTKind.WithItem: + continue + item: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(item_node) + if item is None or item.context_expr is None: + continue + # 翻译 context_expr(对象构造,如 MemPool(arena, 4096)) + ctx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, item.context_expr, + trans._funcs, trans._func_count, trans) + if ctx_val is None: + continue + # 提取类名:Call(func=Attribute("memhub"."MemPool") / Name("MemPool")) + cls_name: str = None + ce: ast.AST | t.CPtr = item.context_expr + if ce.kind() == ast.ASTKind.Call: + cfn: ast.AST | t.CPtr = ((ast.Call | t.CPtr)(ce)).func + if cfn is not None: + if cfn.kind() == ast.ASTKind.Attribute: + cls_name = ((ast.Attribute | t.CPtr)(cfn)).attr + elif cfn.kind() == ast.ASTKind.Name: + cls_name = ((ast.Name | t.CPtr)(cfn)).id + # context 对象存入 __with_ctx(方法调用解析 self 用) + ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + builder, ctx_val.Ty) + if ctx_alloca is None: + continue + llvmlite.build_store(builder, ctx_val, ctx_alloca) + HandlesVar.define_var(trans.SymTab, "__with_ctx", ctx_alloca) + if cls_name is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, "__with_ctx", cls_name) + ctx_class_buf[i] = t.CSizeT(cls_name) + # 调用 __enter__() + enter_val: llvmlite.Value | t.CPtr = self._with_ctx_call( + trans, pool, builder, mod, "__enter__") + # asname 绑定(__enter__ 返回值,缺失时退回 context 对象) + if item.optional_vars is not None: + ov: ast.AST | t.CPtr = item.optional_vars + if ov.kind() == ast.ASTKind.Name: + asname: str = ((ast.Name | t.CPtr)(ov)).id + if asname is not None: + bind_val: llvmlite.Value | t.CPtr = enter_val + if bind_val is None: + bind_val = ctx_val + if bind_val is not None: + asn_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + builder, bind_val.Ty) + if asn_alloca is not None: + llvmlite.build_store(builder, bind_val, asn_alloca) + HandlesVar.define_var(trans.SymTab, asname, asn_alloca) + if cls_name is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, asname, cls_name) + + # 2. 翻译 body + body: list[ast.AST | t.CPtr] | t.CPtr = wt.children + if body is not None: + bn: t.CSizeT = len(body) + for bi in range(bn): + st: ast.AST | t.CPtr = body.get(bi) + if st is not None: + self.translate_stmt(trans, st) + + # 3. 逆序调用 __exit__()(Python with 语义:后进先出) + for i in range(n): + ci: int = n - 1 - i + if ctx_class_buf[ci] != 0: + cls_ci: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[ci], t.CPtr)) + HandlesVar.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: + HandlesVar.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca) + return 0 + + def _with_ctx_call(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + method_name: str) -> llvmlite.Value | t.CPtr: + """构造并翻译 __with_ctx.() 调用(__enter__/__exit__)""" + if pool is None or method_name is None: + return None + name_node: ast.AST | t.CPtr = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load) + if name_node is None: + return None + attr_node: ast.AST | t.CPtr = ast.Attribute( + pool, name_node, method_name, ast.ASTCtx.Load) + if attr_node is None: + return None + call_node: ast.AST | t.CPtr = ast.Call(pool, attr_node, None, None) + if call_node is None: + return None + return HandlesExpr.translate_value( + builder, pool, mod, call_node, + trans._funcs, trans._func_count, trans) + def translate_global(self, trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: """翻译 global 语句:记录 global 变量名"""