feat(coro): M5——协程内 try/except 捕获(raise 与 await 传播异常)
- _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
This commit is contained in:
1 parent
411e0bb774
commit
69447025a7
2 files changed
+104
-18
No files matched your search
+17
-12
@@ -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
|
||||
@@ -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):
|
||||
|
||||
Reference in new issue
Block a user