feat(tpv): 语言内协程 M1-M7 移植——async/await 状态机 + 异常传播 + 帧池

- M1: async def -> 帧结构体 + create_/resume_ 状态机 + coro.coro_run 内联
- M2: async 参数、嵌套 await 提升 __await_N、If/While 内 await
- M3: For 内 await(range->While)、coro_sleep 轮询挂起、coro_destroy 回池
- M4: raise 存码、await 子帧异常传播、coro_exception、coro_gather
- M5/M6: try/except 链式匹配 + as e 绑定 + 异常类型码
- M7: try/finally、异常消息 msg 槽、自定义异常类、帧池复用
This commit is contained in:
TermiNexus committed 2026-08-22 00:34:32 +08:00
1 parent f0a70748d7
commit 82a86761b9
11 files changed
+7722 -4575

No files matched your search

+11
View File
@@ -1352,6 +1352,17 @@ class AssignGenMixin:
# 如果有初始值,store
if aa.value is not None:
# 协程(TPV-M1):记录 async 函数调用赋值的变量名(coro.coro_run
# 内联翻译反查帧类型用)。对齐 TPC HandlesAnnAssign.py L319-326:
# value 是 Call 且 func 是 Name 且该名字是 async 函数时,
# 登记 _coro_var_async[target] = callee。
if aa.value.kind() == ast.ASTKind.Call:
val_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value)
if val_cl.func is not None and val_cl.func.kind() == ast.ASTKind.Name:
val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_cl.func)
if val_nm.id is not None:
if self.Gen.AsyncGen.is_async_func(trans, val_nm.id) != 0:
self.Gen.AsyncGen.register_coro_var(trans, nm.id, val_nm.id)
# 局部数组:列表字面量 → 逐元素 GEP + store 初始化
# 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal,
# 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+6 -6
View File
@@ -361,11 +361,11 @@ class ClassGenBase:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco)
if nm.id is not None:
if string.strcmp(nm.id, "staticmethod") == 0:
meta |= META_STATIC
meta |= GenTypes.META_STATIC
elif string.strcmp(nm.id, "property") == 0:
meta |= META_PROP_GETTER
meta |= GenTypes.META_PROP_GETTER
elif string.strcmp(nm.id, "classmethod") == 0:
meta |= META_CLASS
meta |= GenTypes.META_CLASS
elif string.strcmp(nm.id, "TLS") == 0:
meta |= META_TLS
elif k == ast.ASTKind.Attribute:
@@ -385,11 +385,11 @@ class ClassGenBase:
if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \
or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0:
if string.strcmp(at.attr, "setter") == 0:
meta |= META_PROP_SETTER
meta |= GenTypes.META_PROP_SETTER
elif string.strcmp(at.attr, "getter") == 0:
meta |= META_PROP_GETTER
meta |= GenTypes.META_PROP_GETTER
elif string.strcmp(at.attr, "deleter") == 0:
meta |= META_PROP_DELETER
meta |= GenTypes.META_PROP_DELETER
return meta
def register_class_meta(self, pool: memhub.MemBuddy | t.CPtr,
kind: int, cls: str, field: str) -> int:
File diff suppressed because it is too large. Load diff
+16
View File
@@ -118,4 +118,20 @@ class ExprGenMixin(ExprGenBase.ExprGenBase):
# 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue
# 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译
return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
elif k == ast.ASTKind.Await:
# 协程 await(TPV-M1):await 目标是 async 函数调用时内联翻译
# (子帧创建 + resume 到 DONE + 取子帧 ret 存父帧 await 槽 + 父挂起),
# 返回子协程 ret 值(i32)。顶层 await(AnnAssign/Assign 的 value 直接
# 是 Await)由 AsyncGen 段翻译特判处理,本分支覆盖表达式上下文中的
# await(M1 覆盖有限场景,详见 AsyncGenMixin._emit_await)。
aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node)
if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call:
aw_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value)
if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name:
aw_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aw_cl.func)
if aw_nm.id is not None and trans is not None:
if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0:
return self.Gen.AsyncGen._emit_await(
builder, pool, mod, trans, aw, aw_nm.id)
return None
return None
+7
View File
@@ -224,6 +224,13 @@ class FuncGenDef(CallGenBase.CallGenBase):
if fd is None or fd.name is None:
return 0
# async def(TPV-M1 协程):FLAG_IS_ASYNC=1(includes/ast/stmts.vp L342-345,
# 解析器把 async def 存为 FunctionDef 且 flags & 1)。
# → 走 AsyncGenMixin 状态机翻译(create_<name>/resume_<name>),
# 早返回不进普通函数路径(普通路径生成 ret 型普通函数,无法挂起/恢复)。
if fd.flags is not None and (fd.flags & 1) != 0:
return self.Gen.AsyncGen.translate_async_function(trans, node)
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
imported_modules: str = trans._imported_modules
+9
View File
@@ -50,6 +50,7 @@ import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin
import lib.core.Gen.StmtGenMixin as StmtGenMixin
import lib.core.Gen.MatchGenMixin as MatchGenMixin
import lib.core.Gen.AssignGenMixin as AssignGenMixin
import lib.core.Gen.AsyncGenMixin as AsyncGenMixin
import lib.core.Gen.VarGenMixin as VarGenMixin
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
@@ -111,6 +112,7 @@ class Generator:
StmtGen: StmtGenMixin.StmtGenMixin | t.CPtr
MatchGen: MatchGenMixin.MatchGenMixin | t.CPtr
AssignGen: AssignGenMixin.AssignGenMixin | t.CPtr
AsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr
VarGen: VarGenMixin.VarGenMixin | t.CPtr
TranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr
@@ -440,6 +442,13 @@ class Generator:
string.memset(SubTranslatorGen, 0, TranslatorGenMixin.TranslatorGenMixin.__sizeof__())
SubTranslatorGen.Gen = self
self.TranslatorGen = SubTranslatorGen
SubAsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(AsyncGenMixin.AsyncGenMixin.__sizeof__())
if SubAsyncGen is None:
stdio.printf("FAIL: AsyncGenMixin alloc failed\n")
stdlib.exit(1)
string.memset(SubAsyncGen, 0, AsyncGenMixin.AsyncGenMixin.__sizeof__())
SubAsyncGen.Gen = self
self.AsyncGen = SubAsyncGen
# ---- 初始化各子对象字段(Init* 方法内联调用) ----
SubBaseGen.InitBaseGen(pool)
File diff suppressed because it is too large. Load diff
+58
View File
@@ -0,0 +1,58 @@
import t, c
from stdint import *
import stdio
import coro
# TPV-M3~M7 协程综合测试:
# M3: For 内 await(range→While)、coro_sleep 挂起、coro_destroy 帧回池
# M4: raise 存码、await 子帧异常传播、coro_exception 查询
# M5/M6: try/except(链式匹配 + as e 绑定异常码 + 类型码)
# M7: try/finally、异常消息 msg 槽、自定义异常类、帧池复用
class MyError(Exception):
pass
async def leaf(x: int) -> int:
return x * 2
async def task(n: int) -> int:
s: int = 0
for i in range(3): # M3:For 内 await
s = s + await leaf(i)
if s > 4:
await coro.coro_sleep(5) # M3:coro_sleep 挂起(wake 槽 + 轮询)
try:
raise ValueError("boom") # M4/M6:raise 类型 + M7 消息
except ValueError as e: # M5/M6:as e 绑定异常码
s = s + e
return s
async def raiser() -> int:
try:
raise MyError("fin_msg") # M7:自定义异常类 + 消息
finally:
x: int = 99 # M7:finally 正常路径执行
return 0
def main() -> int:
tt: t.CPtr = task(3)
r: int = coro.coro_run(tt)
e: int = coro.coro_exception(tt)
stdio.printf("coro result = %d exc = %d\n", r, e)
coro.coro_destroy(tt) # M3/M7:destroy 回池
t1: t.CPtr = raiser()
r1: int = coro.coro_run(t1)
e1: int = coro.coro_exception(t1)
m1: t.CPtr = coro.coro_exception_msg(t1)
stdio.printf("coro result = %d exc = %d msg = %s\n", r1, e1, m1)
coro.coro_destroy(t1)
t2: t.CPtr = raiser() # 帧池复用
r2: int = coro.coro_run(t2)
e2: int = coro.coro_exception(t2)
stdio.printf("coro result = %d exc = %d\n", r2, e2)
coro.coro_destroy(t2)
return 0