From 69447025a71582dadebfba7dc1a230eac7a28ac5 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 21 Aug 2026 14:28:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(coro):=20M5=E2=80=94=E2=80=94=E5=8D=8F?= =?UTF-8?q?=E7=A8=8B=E5=86=85=20try/except=20=E6=8D=95=E8=8E=B7=EF=BC=88ra?= =?UTF-8?q?ise=20=E4=B8=8E=20await=20=E4=BC=A0=E6=92=AD=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _HandleCoroTry:except_bb/merge_bb 控制流,单 except 捕获所有异常 - 协程内 raise 与 await 子协程异常传播:处于 try 栈内时改跳 except 处理器, 栈外维持原终止语义(done=1 + br exit) - except X as e:异常码绑定到 e(帧槽),捕获后清帧 exc - 预扫描/_CollectFrameVars 递归 Try(handler.name 进帧槽,跨挂起存活) - CoroTest 验证:try 捕获 await 传播异常 → coro result = 42, exc = 0 --- Test/CoroTest/App/main.vp | 29 ++++--- lib/core/Handles/HandlesAsyncFunctions.py | 93 +++++++++++++++++++++-- 2 files changed, 104 insertions(+), 18 deletions(-) diff --git a/Test/CoroTest/App/main.vp b/Test/CoroTest/App/main.vp index 5708dc6..ef09235 100644 --- a/Test/CoroTest/App/main.vp +++ b/Test/CoroTest/App/main.vp @@ -8,21 +8,26 @@ async def leaf(x: int) -> int: return x + 1 -async def t1() -> int: - return await leaf(1) +async def boom() -> int: + raise 42 + return 0 -async def t2() -> int: - return await leaf(2) +async def task() -> int: + caught: int = 0 + try: + a: int = await leaf(5) + b: int = await boom() + caught = a + b + except Exception as e: + caught = e + return caught def main() -> t.CInt: - a: coro.Coroutine = t1() - b: coro.Coroutine = t2() - n: t.CInt = coro.coro_gather(a, b) - r1: t.CInt = coro.coro_run(a) - r2: t.CInt = coro.coro_run(b) - stdio.printf("gather = %d, r1 = %d, r2 = %d\n", n, r1, r2) - coro.coro_destroy(a) - coro.coro_destroy(b) + tt: coro.Coroutine = task() + r: t.CInt = coro.coro_run(tt) + e: t.CInt = coro.coro_exception(tt) + stdio.printf("coro result = %d, exc = %d\n", r, e) + coro.coro_destroy(tt) return 0 \ No newline at end of file diff --git a/lib/core/Handles/HandlesAsyncFunctions.py b/lib/core/Handles/HandlesAsyncFunctions.py index f0a8031..0de65ce 100644 --- a/lib/core/Handles/HandlesAsyncFunctions.py +++ b/lib/core/Handles/HandlesAsyncFunctions.py @@ -96,6 +96,7 @@ class AsyncFunctionHandle(BaseHandle): 'for_counter': getattr(Gen, '_coro_for_counter', None), 'wake_ptr': getattr(Gen, '_coro_wake_ptr', None), 'exc_ptr': getattr(Gen, '_coro_exc_ptr', None), + 'try_stack': getattr(Gen, '_coro_try_stack', None), } try: self.Trans.VarScopes.append({}) @@ -139,6 +140,7 @@ class AsyncFunctionHandle(BaseHandle): Gen._coro_for_counter = saved_coro_state['for_counter'] Gen._coro_wake_ptr = saved_coro_state['wake_ptr'] Gen._coro_exc_ptr = saved_coro_state['exc_ptr'] + Gen._coro_try_stack = saved_coro_state['try_stack'] # ------------------------------------------------------------------ # 帧结构体与局部变量收集 @@ -195,6 +197,20 @@ class AsyncFunctionHandle(BaseHandle): if stmt.orelse: _walk(stmt.orelse) continue + elif isinstance(stmt, ast.Try): + # except X as e:e 进帧槽(异常码) + for _h in stmt.handlers: + if _h.name and _h.name not in seen: + seen.add(_h.name) + vars_.append((_h.name, ir.IntType(32))) + _walk(stmt.body) + for _h in stmt.handlers: + _walk(_h.body) + if stmt.orelse: + _walk(stmt.orelse) + if stmt.finalbody: + _walk(stmt.finalbody) + continue else: continue if target not in seen: @@ -271,6 +287,15 @@ class AsyncFunctionHandle(BaseHandle): if stmt.orelse: _walk(stmt.orelse) continue + if isinstance(stmt, ast.Try): + _walk(stmt.body) + for _h in stmt.handlers: + _walk(_h.body) + if stmt.orelse: + _walk(stmt.orelse) + if stmt.finalbody: + _walk(stmt.finalbody) + continue if isinstance(stmt, ast.For): if not any(isinstance(n, ast.Await) for n in ast.walk(stmt)): continue # 无 await:委托 ForHandler,不需额外槽 @@ -449,6 +474,9 @@ class AsyncFunctionHandle(BaseHandle): if isinstance(stmt, ast.While): self._HandleCoroWhile(stmt, Gen) continue + if isinstance(stmt, ast.Try): + self._HandleCoroTry(stmt, Gen) + continue if isinstance(stmt, ast.For): self._HandleCoroFor(stmt, Gen) continue @@ -678,6 +706,10 @@ class AsyncFunctionHandle(BaseHandle): exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None) if exc_ptr is not None: Gen._store(exc_code, exc_ptr) + coro_try_stack: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None) + if coro_try_stack: + Gen.builder.branch(coro_try_stack[-1]) + return done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None) if done_ptr_r is not None: Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r) @@ -783,12 +815,16 @@ class AsyncFunctionHandle(BaseHandle): parent_exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None) if parent_exc_ptr is not None: Gen._store(child_exc, parent_exc_ptr) - parent_done_ptr: ir.Value | None = getattr(Gen, '_coro_done_ptr', None) - if parent_done_ptr is not None: - Gen._store(ir.Constant(ir.IntType(32), 1), parent_done_ptr) - exit_bb_ref: ir.Block | None = getattr(Gen, '_coro_exit_bb', None) - if exit_bb_ref is not None: - Gen.builder.branch(exit_bb_ref) + coro_try: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None) + if coro_try: + Gen.builder.branch(coro_try[-1]) + else: + parent_done_ptr: ir.Value | None = getattr(Gen, '_coro_done_ptr', None) + if parent_done_ptr is not None: + Gen._store(ir.Constant(ir.IntType(32), 1), parent_done_ptr) + exit_bb_ref: ir.Block | None = getattr(Gen, '_coro_exit_bb', None) + if exit_bb_ref is not None: + Gen.builder.branch(exit_bb_ref) # 正常路径:存父帧局部变量槽 + 挂起 Gen.builder.position_at_start(normal_bb) slot: ir.Value | None = getattr(Gen, '_coro_await_slot_ptr', None) @@ -918,6 +954,51 @@ class AsyncFunctionHandle(BaseHandle): else: Gen.builder.position_at_end(AfterBB) + def _HandleCoroTry(self, Node: ast.Try, Gen: LlvmCodeGenerator) -> None: + """协程内 try/except:捕获 raise 与 await 传播的异常(M5:单 except、捕获所有)。""" + if not Node.handlers: + raise SyntaxError( + f"[coro-M5] 协程内 try 需要 except 子句 (line {getattr(Node, 'lineno', 0)})" + ) + if len(Node.handlers) > 1: + raise SyntaxError( + f"[coro-M5] 协程内仅支持单个 except(多 except 留待扩展)" + f"(line {getattr(Node, 'lineno', 0)})" + ) + if Node.finalbody: + raise SyntaxError( + f"[coro-M5] 协程内暂不支持 try/finally (line {getattr(Node, 'lineno', 0)})" + ) + except_bb: ir.Block = Gen.func.append_basic_block('coro_try_except') + merge_bb: ir.Block = Gen.func.append_basic_block('coro_try_merge') + if not getattr(Gen, '_coro_try_stack', None): + Gen._coro_try_stack = [] + Gen._coro_try_stack.append(except_bb) + # try body + self._HandleCoroSegment(Node.body, Gen) + if Gen.builder is not None and not Gen.builder.block.is_terminated: + Gen.builder.branch(merge_bb) + Gen._coro_try_stack.pop() + # except handler:异常码已在帧 exc 槽,绑定到 handler.name 后清异常 + Gen.builder.position_at_start(except_bb) + handler: Any = Node.handlers[0] + exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None) + if handler.name: + e_slot: ir.Value | None = Gen.variables.get(handler.name) + if e_slot is not None and exc_ptr is not None: + exc_val: ir.Value = Gen._load(exc_ptr, name='coro_exc_val') + Gen._store(exc_val, e_slot) + Gen._record_var_signedness(handler.name, False) + if exc_ptr is not None: + Gen._store(ir.Constant(ir.IntType(32), 0), exc_ptr) + self._HandleCoroSegment(handler.body, Gen) + if Gen.builder is not None and not Gen.builder.block.is_terminated: + Gen.builder.branch(merge_bb) + if not merge_bb.is_terminated: + Gen.builder.position_at_start(merge_bb) + else: + Gen.builder.position_at_end(merge_bb) + def _HandleCoroFor(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None: if any(isinstance(n, ast.Await) for n in ast.walk(Node)): if not self._IsRangeFor(Node):