Files
ViperC/App/lib/core/Gen/AsyncGenMixin.vp
T
TermiNexus c2d7480f3d fix(transpyv): 槽视图统一 cast 到声明类型(47 处,含 codegen 自身)
同 includes 的同类修正:把一级指针 i8* 隐式塞进二级注解(i8** / str*)。
TransPyV 侧 coerce(ExprGenBase._ptr_cast_reason)没有 TPC 那样的「值侧是显式
指针 cast ⇒ 按 bitcast 重解释」豁免,故一旦用新构建的 TransPyV 编到这些文件
必然 fail-fast(回归测试首爆点在 includes/llvmlite 侧,本仓同形态站点随后必然
同样触发)。

涉及的两种形态:
  · `slot: str | t.CPtr = (t.CPtr)(addr)`   —— cast 目标是一级 t.CPtr
  · `nm_slot: str* = (t.CPtr)(addr)`        —— 注解 str* 即 i8**
统一改为 cast 到声明类型:`(str | t.CPtr)(addr)` / `str*(addr)`(后者与
includes/sys.vp `argv_arr: str* = str*(...)` 同一写法)。

本仓 47 处 / 6 文件:
  App/lib/core/Gen/VarGenMixin.vp 3
  App/lib/core/Gen/TranslatorGenMixin.vp 8
  App/lib/core/Gen/Func/FuncGenMixin.vp 13
  App/lib/core/Gen/AsyncGenMixin.vp 15
  App/lib/core/Gen/DebugInfoGen.vp 6
  App/lib/Stub/StubGen/Converter.vp 2
Converter.vp:107 的 `_g_pyi_cdef_names: str | t.CPtr = None` 保持原样
(None 即空指针,任何指针类型均可,不属本类问题)。

只提交本 6 个文件;本仓其余未提交改动(CallGenBase/CallGenDispatch/CallGenFd/
CallGenProp/Generator/Translator/VLogger)与本迁移无关,保持不动。
2026-09-29 15:10:33 +08:00

2660 lines
131 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import lib.core.Gen.GenTypes as GenTypes
import t, c
from stdint import *
import ast
import llvmlite
from llvmlite import LLVMType
import memhub
import string
import viperlib
import stdio
import stdlib
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HT
import lib.core.Gen.Call.CallGenBase as CallGenBase
# ============================================================
# AsyncGenMixin - TPV-M1 协程翻译(async def / await / coro.coro_run)
# ============================================================
define SCOPE_FUNCTION = 1
novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
"""协程翻译 Mixin(TPV-M1 状态机)"""
# ============================================================
# 入口:async 函数定义
#
# 由 FuncGenDef.translate_function_def 检测 fd.flags & FLAG_IS_ASYNC
# (=1,见 includes/ast/stmts.vp L342-345)后调用,早返回不进普通函数路径。
# ============================================================
def translate_async_function(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 async 函数定义,返回 0 成功
生成 create_<name>(帧分配,M2 带参数)与 resume_<name>(状态机),
并把裸名注册进 trans._async_funcs(is_async_func / coro_run 反查)。
M2 帧布局:{ i32 state, i32 done, i32 ret,
参数槽(3..3+nparams), 局部槽(3+nparams..), __await_N 额外槽 }
- 参数槽:create_<name>(args) 收值入帧(M2 参数)
- 局部槽:顶层 AnnAssign/Assign 的 Name 目标
- 额外槽:嵌套 await 提升临时变量 __await_N(预扫描分配,与翻译同序)
恢复块状态号:state0 = 入口,每个 await(顶层或嵌套)按 DFS 顺序
分配 state1..,switch case 预建(TPV build_switch 一次性生成,无法动态 add_case)。
"""
fd: ast.FunctionDef* = ast.FunctionDef*(node)
if fd is None or fd.name is None or trans is None:
return 0
name: str = fd.name
pool: memhub.MemBuddy* = trans.Pool
mod: llvmlite.LLVMModule* = trans.Module
if pool is None or mod is None:
return 0
# 防重复生成:create_<name> 已存在(模块多遍编译/重复定义)
cname_buf: str = pool.alloc(64)
if cname_buf is not None:
viperlib.snprintf(cname_buf, 64, "create_%s", name)
create_mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, cname_buf, 0)
if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is not None:
return 0
# 注册 async 裸名(供 await 目标校验 / coro_run 反查)
self._register_async_func(trans, name)
# M2:参数收集 → trans._coro_params(char* 数组,8 字节/项)
trans._coro_param_count = 0
nparams: int = self._collect_param_names(trans, fd)
# 局部变量收集(顶层 AnnAssign/Assign 的 Name 目标 → 帧槽)
trans._coro_local_count = 0
nlocals: int = self._collect_local_names(trans, fd)
# M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号
# _coro_await_count = 恢复块数;nseg = 1 入口 + await_count
trans._coro_extra_count = 0
trans._coro_hoist_count = 0
trans._coro_await_count = 0
trans._coro_uses_sleep = 0
trans._coro_scan_for_count = 0
trans._coro_for_counter = 0
self._scan_sleep_usage(trans, fd)
self._pre_scan_awaits(trans, fd)
nextra: int = trans._coro_extra_count
trans._coro_nseg = 1 + trans._coro_await_count
# 帧结构体 %Coro_<name>
frame_ty: llvmlite.LLVMType* = self._build_frame_ty(pool, mod, trans, name, nparams, nlocals, nextra)
if frame_ty is None:
return 0
self._register_coro_frame(trans, name, frame_ty)
# M3:wake 槽 index 注册(coro_run 轮询反查;wake 在额外槽相对 0)
if trans._coro_uses_sleep != 0:
self._register_coro_wake(trans, name, trans._coro_extra_base + 0)
# 进入函数作用域:resume 局部槽注册隔离,翻译完退出不污染模块作用域
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION)
self._emit_create(pool, mod, trans, name, frame_ty, nparams)
self._emit_resume(pool, mod, trans, name, fd, frame_ty,
nparams, nlocals, nextra)
self.Gen.VarGen.exit_scope(trans.SymTab)
return 0
# ============================================================
# M2:参数收集(帧参数槽 index 3+i)
# ============================================================
def _collect_param_names(self, trans: HT.Translator*,
fd: ast.FunctionDef*) -> int:
"""收集 async 函数参数名到 trans._coro_params(char* 数组,8 字节/项)。
参数槽 index = 3 + i,create_<name> 按参数顺序收值入帧。"""
if fd is None or fd.args is None or trans is None:
return 0
if trans._coro_params is None:
return 0
ags: ast.Arguments* = ast.Arguments*(fd.args)
cnt: int = 0
if ags.args is None:
return 0
bn: sizet = len(ags.args)
i: sizet = 0
for i in range(bn):
a0: ast.AST* = ags.args.get(i)
if a0 is None:
continue
aname: str = None
if a0.kind() == ast.ASTKind.Arg:
ar: ast.Arg* = ast.Arg*(a0)
aname = ar.arg
elif a0.kind() == ast.ASTKind.Name:
anm: ast.Name* = ast.Name*(a0)
aname = anm.id
if aname is None:
continue
if cnt >= HT.MAX_CORO_VARS:
break
addr: uint64 = uint64(trans._coro_params) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot[0] = aname
cnt = cnt + 1
trans._coro_param_count = cnt
return cnt
# ============================================================
# M3-M7:预扫描额外槽(wake/for/await 类型表 + 位置数组)+ 状态号
#
# 与翻译端同一 DFS 顺序。额外槽表 _coro_extra_types(i8:1=i32 2=i64):
# [0] __coro_wake_us(若用 coro_sleep,i64)
# 随后按 DFS:__f_idx_N/__f_len_N(range-For 含 await,i32)、
# __await_N(嵌套 await,i32)
# 位置数组:_coro_await_slots[M]=__await_M 相对序号;_coro_for_slots[N]=__f_idx_N 相对序号
# _coro_await_count = 恢复块数(顶层 + 嵌套 await)
# ============================================================
def _pre_scan_awaits(self, trans: HT.Translator*,
fd: ast.FunctionDef*) -> int:
"""DFS 预扫描协程体,填额外槽表并返回额外槽总数"""
if fd is None or fd.children is None or trans is None:
return 0
trans._coro_extra_count = 0
trans._coro_hoist_count = 0
trans._coro_await_count = 0
trans._coro_scan_for_count = 0
if trans._coro_uses_sleep != 0:
trans._coro_extra_types[0] = 2 # __coro_wake_us(i64)相对序号 0
trans._coro_extra_count = 1
self._scan_stmts(trans, fd.children)
return trans._coro_extra_count
# ---------- 第一遍:coro_sleep 检测(wake 槽决定) ----------
def _scan_sleep_usage(self, trans: HT.Translator*,
fd: ast.FunctionDef*):
if fd is None or fd.children is None or trans is None:
return
self._scan_sleep_stmts(trans, fd.children)
def _scan_sleep_stmts(self, trans: HT.Translator*,
stmts: list[ast.AST*]*):
if stmts is None or trans._coro_uses_sleep != 0:
return
bn: sizet = len(stmts)
i: sizet = 0
for i in range(bn):
self._scan_sleep_stmt(trans, stmts.get(i))
def _scan_sleep_stmt(self, trans: HT.Translator*,
stmt: ast.AST*):
if stmt is None or trans._coro_uses_sleep != 0:
return
sk: int = stmt.kind()
if sk == ast.ASTKind.If:
ifn: rawptr[ast.If] = rawptr[ast.If](stmt)
self._scan_sleep_expr(trans, ifn.test)
self._scan_sleep_stmts(trans, stmt.children)
self._scan_sleep_stmts(trans, ifn.orelse)
return
if sk == ast.ASTKind.While:
whn: rawptr[ast.While] = rawptr[ast.While](stmt)
self._scan_sleep_expr(trans, whn.test)
self._scan_sleep_stmts(trans, stmt.children)
self._scan_sleep_stmts(trans, whn.orelse)
return
if sk == ast.ASTKind.For:
fn2: ast.For* = ast.For*(stmt)
self._scan_sleep_expr(trans, fn2.iter)
self._scan_sleep_stmts(trans, stmt.children)
self._scan_sleep_stmts(trans, fn2.orelse)
return
if sk == ast.ASTKind.Try:
trn: ast.Try* = ast.Try*(stmt)
self._scan_sleep_stmts(trans, stmt.children)
if trn.handlers is not None:
nh: sizet = len(trn.handlers)
hh: sizet = 0
for hh in range(nh):
h0: ast.AST* = trn.handlers.get(hh)
if h0 is not None:
self._scan_sleep_stmts(trans, h0.children)
self._scan_sleep_stmts(trans, trn.orelse)
self._scan_sleep_stmts(trans, trn.finalbody)
return
if sk == ast.ASTKind.Return:
rv: rawptr[ast.Return] = rawptr[ast.Return](stmt)
self._scan_sleep_expr(trans, rv.value)
return
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
self._scan_sleep_expr(trans, aa.value)
return
if sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
self._scan_sleep_expr(trans, as_.value)
return
if sk == ast.ASTKind.Expr:
e: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
self._scan_sleep_expr(trans, e.value)
return
def _scan_sleep_expr(self, trans: HT.Translator*,
node: ast.AST*):
if node is None or trans._coro_uses_sleep != 0:
return
k: int = node.kind()
if k == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(node)
if cl.func is not None:
if cl.func.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(cl.func)
if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0:
trans._coro_uses_sleep = 1
return
elif cl.func.kind() == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0:
trans._coro_uses_sleep = 1
return
self._scan_sleep_expr(trans, cl.func)
if cl.args is not None:
nb: sizet = len(cl.args)
j: sizet = 0
for j in range(nb):
self._scan_sleep_expr(trans, cl.args.get(j))
return
if k == ast.ASTKind.BinOp:
b: ast.BinOp* = ast.BinOp*(node)
self._scan_sleep_expr(trans, b.left)
self._scan_sleep_expr(trans, b.right)
return
if k == ast.ASTKind.UnaryOp:
u: ast.UnaryOp* = ast.UnaryOp*(node)
self._scan_sleep_expr(trans, u.operand)
return
if k == ast.ASTKind.Compare:
cm: rawptr[ast.Compare] = rawptr[ast.Compare](node)
self._scan_sleep_expr(trans, cm.left)
if cm.comparators is not None:
nb2: sizet = len(cm.comparators)
j2: sizet = 0
for j2 in range(nb2):
self._scan_sleep_expr(trans, cm.comparators.get(j2))
return
if k == ast.ASTKind.BoolOp:
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
if bo.values is not None:
nb3: sizet = len(bo.values)
j3: sizet = 0
for j3 in range(nb3):
self._scan_sleep_expr(trans, bo.values.get(j3))
return
if k == ast.ASTKind.IfExp:
ie: rawptr[ast.IfExp] = rawptr[ast.IfExp](node)
self._scan_sleep_expr(trans, ie.test)
self._scan_sleep_expr(trans, ie.body)
self._scan_sleep_expr(trans, ie.orelse)
return
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
self._scan_sleep_expr(trans, at.value)
return
if k == ast.ASTKind.Subscript:
sb: ast.Subscript* = ast.Subscript*(node)
self._scan_sleep_expr(trans, sb.value)
self._scan_sleep_expr(trans, sb.slice)
return
if k == ast.ASTKind.Await:
aw: rawptr[ast.Await] = rawptr[ast.Await](node)
self._scan_sleep_expr(trans, aw.value)
return
# ---------- 第二遍:填额外槽表 + 状态号计数 ----------
def _scan_stmts(self, trans: HT.Translator*,
stmts: list[ast.AST*]*):
if stmts is None:
return
bn: sizet = len(stmts)
i: sizet = 0
for i in range(bn):
self._scan_stmt(trans, stmts.get(i))
def _scan_stmt(self, trans: HT.Translator*,
stmt: ast.AST*):
if stmt is None:
return
sk: int = stmt.kind()
if sk == ast.ASTKind.If:
ifn: rawptr[ast.If] = rawptr[ast.If](stmt)
if ifn.test is not None:
self._scan_expr(trans, ifn.test)
self._scan_stmts(trans, stmt.children)
self._scan_stmts(trans, ifn.orelse)
return
if sk == ast.ASTKind.While:
whn: rawptr[ast.While] = rawptr[ast.While](stmt)
if whn.test is not None:
self._scan_expr(trans, whn.test)
self._scan_stmts(trans, stmt.children)
self._scan_stmts(trans, whn.orelse)
return
if sk == ast.ASTKind.For:
fn_: ast.For* = ast.For*(stmt)
if self._for_deep_await(stmt) != 0:
# 含 await:必须是 range-For(M3)
if self._is_range_for(stmt) == 0:
err_b2: str = trans.Pool.alloc(256)
if err_b2 is not None:
viperlib.snprintf(err_b2, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)")
self.Gen.TypeGenErr.fatal_error(stmt, err_b2, "SyntaxError")
return
# 填 __f_idx_N / __f_len_N(i32)
if trans._coro_scan_for_count < HT.MAX_CORO_VARS:
trans._coro_for_slots[trans._coro_scan_for_count] = trans._coro_extra_count
trans._coro_extra_types[trans._coro_extra_count] = 1
trans._coro_extra_count = trans._coro_extra_count + 1
trans._coro_extra_types[trans._coro_extra_count] = 1
trans._coro_extra_count = trans._coro_extra_count + 1
trans._coro_scan_for_count = trans._coro_scan_for_count + 1
self._scan_stmts(trans, stmt.children)
self._scan_stmts(trans, fn_.orelse)
return
# 无 await:委托标准 For;递归扫描(嵌套 For/Try 可能含 await)
self._scan_stmts(trans, stmt.children)
self._scan_stmts(trans, fn_.orelse)
return
if sk == ast.ASTKind.Try:
tr2: ast.Try* = ast.Try*(stmt)
self._scan_stmts(trans, stmt.children)
if tr2.handlers is not None:
nh2: sizet = len(tr2.handlers)
hh2: sizet = 0
for hh2 in range(nh2):
h2: ast.AST* = tr2.handlers.get(hh2)
if h2 is not None:
self._scan_stmts(trans, h2.children)
self._scan_stmts(trans, tr2.orelse)
self._scan_stmts(trans, tr2.finalbody)
return
if sk == ast.ASTKind.Raise:
rz: rawptr[ast.Raise] = rawptr[ast.Raise](stmt)
if rz.exc is not None:
self._scan_expr(trans, rz.exc)
return
if sk == ast.ASTKind.Return:
rv: rawptr[ast.Return] = rawptr[ast.Return](stmt)
if rv.value is not None:
self._scan_expr(trans, rv.value)
return
if sk == ast.ASTKind.Break or sk == ast.ASTKind.Continue:
return
# 顶层 await(AnnAssign/Assign/Expr value 直接 Await):计数不提升
if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr:
if self._is_await_tail(stmt) != 0:
trans._coro_await_count = trans._coro_await_count + 1
return
# 语句内嵌套 await:DFS 表达式(AnnAssign.value / Assign.value / Expr.value)
self._scan_stmt_exprs(trans, stmt)
def _scan_stmt_exprs(self, trans: HT.Translator*,
stmt: ast.AST*):
"""扫描语句的值表达式找嵌套 await"""
if stmt is None:
return
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.value is not None:
self._scan_expr(trans, aa.value)
return
if sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.value is not None:
self._scan_expr(trans, as_.value)
return
if sk == ast.ASTKind.Expr:
e: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
if e.value is not None:
self._scan_expr(trans, e.value)
return
# 其它语句类型:翻译端 fail-fast
def _scan_expr(self, trans: HT.Translator*,
node: ast.AST*):
"""DFS 扫描表达式找 Await:命中分配 __await_N 槽并计数状态号"""
if node is None:
return
k: int = node.kind()
if k == ast.ASTKind.Await:
# M3:await coro_sleep 用 wake 槽挂起,不占 __await_N 槽(仅计状态号)
aw_s: rawptr[ast.Await] = rawptr[ast.Await](node)
if self._expr_await_is_sleep(aw_s) != 0:
trans._coro_await_count = trans._coro_await_count + 1
return
if trans._coro_hoist_count < HT.MAX_CORO_VARS:
trans._coro_await_slots[trans._coro_hoist_count] = trans._coro_extra_count
trans._coro_extra_types[trans._coro_extra_count] = 1
trans._coro_extra_count = trans._coro_extra_count + 1
trans._coro_hoist_count = trans._coro_hoist_count + 1
trans._coro_await_count = trans._coro_await_count + 1
return
if k == ast.ASTKind.BinOp:
b: ast.BinOp* = ast.BinOp*(node)
self._scan_expr(trans, b.left)
self._scan_expr(trans, b.right)
return
if k == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(node)
if cl.func is not None:
self._scan_expr(trans, cl.func)
if cl.args is not None:
nb: sizet = len(cl.args)
j: sizet = 0
for j in range(nb):
self._scan_expr(trans, cl.args.get(j))
return
if k == ast.ASTKind.UnaryOp:
u: ast.UnaryOp* = ast.UnaryOp*(node)
if u.operand is not None:
self._scan_expr(trans, u.operand)
return
if k == ast.ASTKind.Compare:
cm: rawptr[ast.Compare] = rawptr[ast.Compare](node)
if cm.left is not None:
self._scan_expr(trans, cm.left)
if cm.comparators is not None:
nb2: sizet = len(cm.comparators)
j2: sizet = 0
for j2 in range(nb2):
self._scan_expr(trans, cm.comparators.get(j2))
return
if k == ast.ASTKind.BoolOp:
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
if bo.values is not None:
nb3: sizet = len(bo.values)
j3: sizet = 0
for j3 in range(nb3):
self._scan_expr(trans, bo.values.get(j3))
return
if k == ast.ASTKind.IfExp:
ie: rawptr[ast.IfExp] = rawptr[ast.IfExp](node)
self._scan_expr(trans, ie.test)
self._scan_expr(trans, ie.body)
self._scan_expr(trans, ie.orelse)
return
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
if at.value is not None:
self._scan_expr(trans, at.value)
return
if k == ast.ASTKind.Subscript:
sb: ast.Subscript* = ast.Subscript*(node)
if sb.value is not None:
self._scan_expr(trans, sb.value)
if sb.slice is not None:
self._scan_expr(trans, sb.slice)
return
# Name / Constant 等叶子:无嵌套 await
# ---------- For 判定辅助(M3) ----------
def _for_deep_await(self, stmt: ast.AST*) -> int:
"""For 语句树(含嵌套 If/While/For/Try/body/orelse)是否含 await"""
if stmt is None:
return 0
fn3: ast.For* = ast.For*(stmt)
if fn3.iter is not None and self._find_expr_await(fn3.iter) is not None:
return 1
if stmt.children is not None:
bn4: sizet = len(stmt.children)
i4: sizet = 0
for i4 in range(bn4):
if self._stmt_deep_await(stmt.children.get(i4)) != 0:
return 1
if fn3.orelse is not None:
bn5: sizet = len(fn3.orelse)
i5: sizet = 0
for i5 in range(bn5):
if self._stmt_deep_await(fn3.orelse.get(i5)) != 0:
return 1
return 0
def _stmt_deep_await(self, stmt: ast.AST*) -> int:
"""语句树(含嵌套 If/While/For/Try)是否含 await"""
if stmt is None:
return 0
sk2: int = stmt.kind()
if sk2 == ast.ASTKind.If:
ifn2: rawptr[ast.If] = rawptr[ast.If](stmt)
if ifn2.test is not None and self._find_expr_await(ifn2.test) is not None:
return 1
if self._stmts_deep_await(stmt.children) != 0:
return 1
return self._stmts_deep_await(ifn2.orelse)
if sk2 == ast.ASTKind.While:
whn2: rawptr[ast.While] = rawptr[ast.While](stmt)
if whn2.test is not None and self._find_expr_await(whn2.test) is not None:
return 1
if self._stmts_deep_await(stmt.children) != 0:
return 1
return self._stmts_deep_await(whn2.orelse)
if sk2 == ast.ASTKind.For:
return self._for_deep_await(stmt)
if sk2 == ast.ASTKind.Try:
tr3: ast.Try* = ast.Try*(stmt)
if self._stmts_deep_await(stmt.children) != 0:
return 1
if tr3.handlers is not None:
nh3: sizet = len(tr3.handlers)
hh3: sizet = 0
for hh3 in range(nh3):
h3: ast.AST* = tr3.handlers.get(hh3)
if h3 is not None and self._stmts_deep_await(h3.children) != 0:
return 1
if self._stmts_deep_await(tr3.orelse) != 0:
return 1
return self._stmts_deep_await(tr3.finalbody)
return self._stmt_has_await(stmt)
def _stmts_deep_await(self, stmts: list[ast.AST*]*) -> int:
if stmts is None:
return 0
bn6: sizet = len(stmts)
i6: sizet = 0
for i6 in range(bn6):
if self._stmt_deep_await(stmts.get(i6)) != 0:
return 1
return 0
def _is_range_for(self, stmt: ast.AST*) -> int:
"""range-For:单 Name target + iter 是 range(x) 或 range(a, b),参数无 await"""
if stmt is None:
return 0
fn4: ast.For* = ast.For*(stmt)
if fn4.target is None or fn4.target.kind() != ast.ASTKind.Name:
return 0
if fn4.iter is None or fn4.iter.kind() != ast.ASTKind.Call:
return 0
cl4: ast.Call* = ast.Call*(fn4.iter)
if cl4.func is None or cl4.func.kind() != ast.ASTKind.Name:
return 0
nm4: ast.Name* = ast.Name*(cl4.func)
if nm4.id is None or string.strcmp(nm4.id, "range") != 0:
return 0
if cl4.args is None:
return 0
nb7: sizet = len(cl4.args)
if nb7 != 1 and nb7 != 2:
return 0
j7: sizet = 0
for j7 in range(nb7):
if self._find_expr_await(cl4.args.get(j7)) is not None:
return 0
return 1
# ============================================================
# 局部变量收集(顶层 AnnAssign / Assign 的 Name 目标)
# ============================================================
def _collect_local_names(self, trans: HT.Translator*,
fd: ast.FunctionDef*) -> int:
"""收集帧局部变量名(_coro_locals,8 字节/项):
- 顶层 AnnAssign/Assign 的 Name 目标(M2)
- try 的 except as e 绑定名(M5/M6,跨 handler 需要帧槽)
- 含 await 的 range-For 迭代目标(M3)
递归扫描(If/While/For/Try 嵌套)。"""
if fd is None or fd.children is None or trans is None:
return 0
if trans._coro_locals is None:
return 0
trans._coro_local_count = 0
self._collect_locals_stmts(trans, fd.children)
return trans._coro_local_count
def _collect_locals_stmts(self, trans: HT.Translator*,
stmts: list[ast.AST*]*):
if stmts is None:
return
bn: sizet = len(stmts)
i: sizet = 0
for i in range(bn):
self._collect_locals_stmt(trans, stmts.get(i))
def _collect_locals_stmt(self, trans: HT.Translator*,
stmt: ast.AST*):
if stmt is None:
return
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
tn: ast.Name* = ast.Name*(aa.target)
self._add_local(trans, tn.id)
return
if sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.targets is not None and len(as_.targets) == 1:
t0: ast.AST* = as_.targets.get(0)
if t0 is not None and t0.kind() == ast.ASTKind.Name:
tn2: ast.Name* = ast.Name*(t0)
self._add_local(trans, tn2.id)
return
if sk == ast.ASTKind.If:
self._collect_locals_stmts(trans, stmt.children)
ifn: rawptr[ast.If] = rawptr[ast.If](stmt)
self._collect_locals_stmts(trans, ifn.orelse)
return
if sk == ast.ASTKind.While:
self._collect_locals_stmts(trans, stmt.children)
whn: rawptr[ast.While] = rawptr[ast.While](stmt)
self._collect_locals_stmts(trans, whn.orelse)
return
if sk == ast.ASTKind.For:
fn: ast.For* = ast.For*(stmt)
if self._for_deep_await(stmt) != 0:
if fn.target is not None and fn.target.kind() == ast.ASTKind.Name:
tn3: ast.Name* = ast.Name*(fn.target)
self._add_local(trans, tn3.id)
self._collect_locals_stmts(trans, stmt.children)
self._collect_locals_stmts(trans, fn.orelse)
return
if sk == ast.ASTKind.Try:
tr: ast.Try* = ast.Try*(stmt)
self._collect_locals_stmts(trans, stmt.children)
if tr.handlers is not None:
nh: sizet = len(tr.handlers)
hh: sizet = 0
for hh in range(nh):
h0: ast.AST* = tr.handlers.get(hh)
if h0 is None:
continue
hd: ast.ExceptHandler* = ast.ExceptHandler*(h0)
self._add_local(trans, hd.name)
self._collect_locals_stmts(trans, h0.children)
self._collect_locals_stmts(trans, tr.orelse)
self._collect_locals_stmts(trans, tr.finalbody)
return
def _add_local(self, trans: HT.Translator*,
name: str):
if name is None:
return
cnt: int = trans._coro_local_count
if cnt >= HT.MAX_CORO_VARS:
return
addr: uint64 = uint64(trans._coro_locals) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot[0] = name
trans._coro_local_count = cnt + 1
# ============================================================
# 帧结构体 %Coro_<name> = { i32 state, i32 done, i32 ret, <局部槽>* }
# 槽索引: 0=state 1=done 2=ret 3..3+nlocals-1=局部变量
# ============================================================
def _build_frame_ty(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
name: str,
nparams: int, nlocals: int,
nextra: int) -> llvmlite.LLVMType*:
"""构造帧结构体并注册到模块与结构体表,返回 LLVMType
M7 布局:{i32 state, i32 done, i32 ret, i32 exc, i8* msg,
参数槽(5+i), 局部槽(5+nparams+i), 额外槽(extra_base+i, 按类型表 1=i32 2=i64)}"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
# 槽基址(供 resume/await 计算槽 index)
trans._coro_local_base = 5 + nparams
trans._coro_extra_base = trans._coro_local_base + nlocals
total: int = 5 + nparams + nlocals + nextra
head: rawptr[llvmlite.ParamNode] = None
prev: rawptr[llvmlite.ParamNode] = None
fi: int = 0
for fi in range(total):
fty: llvmlite.LLVMType* = i32_ty
if fi == 4:
fty = i8_ptr_ty
elif fi >= trans._coro_extra_base:
tidx: int = fi - trans._coro_extra_base
if tidx < nextra and trans._coro_extra_types is not None:
if trans._coro_extra_types[tidx] == 2:
fty = i64_ty
pnode: rawptr[llvmlite.ParamNode] = pool.alloc(llvmlite.ParamNode.__sizeof__())
if pnode is None:
continue
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
pnode.Ty = fty
if head is None:
head = pnode
if prev is not None:
prev.Next = pnode
prev = pnode
ty_name: str = pool.alloc(128)
if ty_name is not None:
viperlib.snprintf(ty_name, 128, "Coro_%s", name)
frame_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, head, total, ty_name)
if frame_ty is None:
return None
llvmlite.module_add_named_type(mod, pool, frame_ty)
self.Gen.StructGen.register_struct(pool, ty_name, frame_ty, trans.ModuleSha1)
return frame_ty
# ============================================================
# create_<name>() -> %Coro_<name>*
# ============================================================
def _emit_create(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
name: str,
frame_ty: llvmlite.LLVMType*,
nparams: int) -> int:
"""生成 create_<name>(args...):M7 帧池弹帧(i64 池头 free-list)或 malloc,
5 头清零 + 参数存槽(帧槽 5+i)+ ret 帧指针"""
if frame_ty is None:
return 0
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
i64_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i64_ty)
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
cname_buf2: str = pool.alloc(64)
if cname_buf2 is not None:
viperlib.snprintf(cname_buf2, 64, "create_%s", name)
mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, cname_buf2, 0)
if self.Gen.CallGenBase.find_func_in_module(mod, mangled) is not None:
return 0
func: llvmlite.Function* = llvmlite.create_function(pool, mod, mangled, frame_ptr_ty)
if func is None:
return 0
# 参数(i32,帧槽 5+i)。TPV 无 Python % 格式化(% 是取模),
# 参数名用 snprintf 生成("%%arg" → "%arg",与 resume "%frame" 命名一致)。
pi: int = 0
argn_buf: str = pool.alloc(16)
for pi in range(nparams):
if argn_buf is not None:
viperlib.snprintf(argn_buf, 16, "%%arg%d", pi)
llvmlite.add_param(pool, func, i32_ty, argn_buf)
# 注册到函数表(裸名 create_<name>)
funcs_ptr: GenTypes.FuncEntry* = trans._funcs
cur_count: int = trans._func_count
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, cur_count, cname_buf2, func, 1024, None, 0, 0, trans.Pool) == 0:
trans._func_count = cur_count + 1
entry: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "entry")
if entry is None:
return 0
builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, func)
if builder is None:
return 0
llvmlite.position_at_end(builder, entry)
frame_size: int = self.Gen.ClassGenEnum._get_type_size(frame_ty)
size_val: llvmlite.Value* = llvmlite.const_int64(pool, frame_size)
if size_val is None:
return 0
size_val.Next = None
# M7 帧池:i64 池头(0 = 空);帧首 8 字节存 next(覆盖 state/done,弹池后统一清零)
pool_gv: llvmlite.GlobalVariable* = self._get_coro_pool(pool, mod, trans, name)
# GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_<name>")
pool_ref_name: str = pool.alloc(96)
if pool_ref_name is not None:
viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", name)
pool_ref: llvmlite.Value* = llvmlite.SSAValue(pool, i64_ptr_ty, pool_ref_name)
pool_head: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, pool_ref)
if pool_head is None: return 0
zero64: llvmlite.Value* = llvmlite.const_int64(pool, 0)
empty_cond: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, pool_head, zero64)
if empty_cond is None: return 0
hit_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "pool.hit")
miss_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "pool.miss")
join_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "pool.join")
if hit_bb is None or miss_bb is None or join_bb is None:
return 0
llvmlite.build_cond_br(builder, empty_cond, miss_bb, hit_bb)
# hit:弹池(帧首 8 字节是 next)
llvmlite.position_at_end(builder, hit_bb)
node_next_ptr: llvmlite.Value* = llvmlite.build_inttoptr(builder, pool_head, i64_ptr_ty)
next_head: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, node_next_ptr)
if next_head is None:
return 0
llvmlite.build_store(builder, next_head, pool_ref)
hit_frame: llvmlite.Value* = llvmlite.build_inttoptr(builder, pool_head, frame_ptr_ty)
if hit_frame is None:
return 0
llvmlite.build_br(builder, join_bb)
# miss:malloc + 帧首 8 字节置 0(弹池帧的 next 残留清零)
llvmlite.position_at_end(builder, miss_bb)
raw: llvmlite.Value* = llvmlite.build_call(builder, "malloc", size_val, 1, i8_ptr_ty, 0)
if raw is None:
return 0
miss_frame: llvmlite.Value* = llvmlite.build_bitcast(builder, raw, frame_ptr_ty)
if miss_frame is None:
return 0
miss_head_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, miss_frame, i64_ptr_ty)
if miss_head_ptr is not None:
llvmlite.build_store(builder, zero64, miss_head_ptr)
llvmlite.build_br(builder, join_bb)
# join:phi 选帧 + 5 头清零(弹池复用帧必须重置 state/done/ret/exc/msg)+ 参数存槽
llvmlite.position_at_end(builder, join_bb)
inc1: llvmlite.PhiIncoming* = llvmlite.new_phi_incoming(pool, hit_frame, hit_bb)
inc2: llvmlite.PhiIncoming* = llvmlite.new_phi_incoming(pool, miss_frame, miss_bb)
if inc1 is None or inc2 is None:
return 0
inc1.Next = inc2
frame_ref: llvmlite.Value* = llvmlite.build_phi(builder, frame_ptr_ty, inc1, 2)
if frame_ref is None:
return 0
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
null_p: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
si: int = 0
for si in range(5):
if si == 4:
mslot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i8_ptr_ty, frame_ref, 4)
if mslot is not None:
llvmlite.build_store(builder, null_p, mslot)
else:
slot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_ref, si)
if slot is not None:
llvmlite.build_store(builder, zero, slot)
# 参数存帧槽(index 5+i)
pj: int = 0
for pj in range(nparams):
pslot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_ref, 5 + pj)
if pslot is not None:
arnb: str = pool.alloc(16)
if arnb is not None:
viperlib.snprintf(arnb, 16, "%%arg%d", pj)
arg_ref: llvmlite.Value* = llvmlite.SSAValue(pool, i32_ty, arnb)
if arg_ref is not None:
llvmlite.build_store(builder, arg_ref, pslot)
llvmlite.build_ret(builder, frame_ref)
return 0
# ============================================================
# M7:每帧类型的全局 free-list 池头(i64,0 = 空)
# ============================================================
def _get_coro_pool(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
name: str) -> llvmlite.GlobalVariable*:
"""取/建 coro_pool_<name> 全局(i64 池头)。池节点 next 存帧首 8 字节。"""
pn_buf: str = pool.alloc(128)
if pn_buf is not None:
viperlib.snprintf(pn_buf, 128, "coro_pool_%s", name)
# 幂等:create/destroy 都会调用,须先查模块全局链表(无 find_global API)
g: llvmlite.GlobalVariable* = mod.GlobalHead
while g is not None:
if g.Name is not None and string.strcmp(g.Name, pn_buf) == 0:
return g
g = g.Next
return llvmlite.create_global_int(pool, mod, pn_buf, 64, 0)
def _register_coro_wake(self, trans: HT.Translator*,
name: str, wake_idx: int):
"""记录 async 名的 wake 槽 index(_coro_wake_names/_coro_wake_idxs 平行表)"""
if trans is None or name is None or trans._coro_wake_names is None:
return
cnt: int = trans._coro_wake_count
if cnt >= HT.MAX_CORO_FUNCS:
return
addr: uint64 = uint64(trans._coro_wake_names) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot[0] = name
trans._coro_wake_idxs[cnt] = wake_idx
trans._coro_wake_count = cnt + 1
def _lookup_coro_wake(self, trans: HT.Translator*,
name: str) -> int:
"""查 async 名的 wake 槽 index,无 wake 槽返回 -1"""
if trans is None or name is None or trans._coro_wake_names is None:
return -1
i: int = 0
for i in range(trans._coro_wake_count):
addr: uint64 = uint64(trans._coro_wake_names) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return trans._coro_wake_idxs[i]
return -1
# ============================================================
# resume_<name>(%Coro_<name>*) -> i32 状态机(静态段切分)
# ============================================================
def _emit_resume(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
name: str,
fd: ast.FunctionDef*,
frame_ty: llvmlite.LLVMType*,
nparams: int, nlocals: int,
nextra: int) -> int:
"""生成 resume_<name>(frame) -> i32 状态机(M2):
entry 读 state → switch → state0 主入口递归翻译整个函数体;
每个 await(顶层或嵌套,DFS 序)分配 state{N} 恢复块(预建 case);
exit 块 load done 返回(0=SUSPEND 1=DONE)。"""
if frame_ty is None:
return 0
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
rname_buf: str = pool.alloc(64)
if rname_buf is not None:
viperlib.snprintf(rname_buf, 64, "resume_%s", name)
mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, rname_buf, 0)
func: llvmlite.Function* = llvmlite.create_function(pool, mod, mangled, i32_ty)
if func is None:
return 0
llvmlite.add_param(pool, func, frame_ptr_ty, "%frame")
funcs_ptr: GenTypes.FuncEntry* = trans._funcs
cur_count: int = trans._func_count
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, cur_count, rname_buf, func, 1024,
None, 0, 1, trans.Pool) == 0:
trans._func_count = cur_count + 1
entry: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "entry")
if entry is None:
return 0
builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, func)
if builder is None:
return 0
llvmlite.position_at_end(builder, entry)
frame_arg: llvmlite.Value* = llvmlite.SSAValue(pool, frame_ptr_ty, "%frame")
if frame_arg is None:
return 0
# GEP 5 头槽(M4 exc / M7 msg)
i8_ptr_ty_r: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
i64_ty_r: llvmlite.LLVMType* = llvmlite.Int64(pool)
state_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg, 0)
done_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg, 1)
ret_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg, 2)
exc_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg, 3)
msg_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i8_ptr_ty_r, frame_arg, 4)
# 参数槽 GEP → 注册到符号表(index 5+i)
pj: int = 0
for pj in range(nparams):
pname: str = self._read_param_name(trans, pj)
if pname is None:
continue
pslot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg, 5 + pj)
if pslot is not None:
self.Gen.VarGen.define_var(trans.SymTab, pname, pslot)
# 局部槽 GEP → 注册到符号表
li: int = 0
for li in range(nlocals):
lname: str = self._read_local_name(trans, li)
if lname is None:
continue
slot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_arg,
trans._coro_local_base + li)
if slot is not None:
self.Gen.VarGen.define_var(trans.SymTab, lname, slot)
# M3-M7:额外槽注册(wake i64 / __f_idx/__f_len/__await i32)。
# 名字反查:wake=uses_sleep 且 ei==0;for=位置数组 _coro_for_slots;
# 其余按 _coro_await_slots 反查 __await_M。
ei: int = 0
for ei in range(nextra):
ety: int = 1
if trans._coro_extra_types is not None:
ety = trans._coro_extra_types[ei]
ety_llvm: llvmlite.LLVMType* = i32_ty
if ety == 2:
ety_llvm = i64_ty_r
eslot: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, ety_llvm, frame_arg,
trans._coro_extra_base + ei)
if eslot is None:
continue
# wake 槽:只存指针,不注册 SymTab(coro_run 轮询用)
if trans._coro_uses_sleep != 0 and ei == 0:
trans._coro_wake_ptr = eslot
continue
ename: str = pool.alloc(16)
# for 槽:_coro_for_slots[N] 是 __f_idx_N 位置,+1 是 __f_len_N
is_for: int = 0
is_len: int = 0
kf: int = 0
for kf in range(trans._coro_scan_for_count):
if trans._coro_for_slots[kf] == ei:
is_for = 1
break
if trans._coro_for_slots[kf] + 1 == ei:
is_for = 1
is_len = 1
break
if is_for != 0:
if ename is not None:
if is_len != 0:
viperlib.snprintf(ename, 16, "__f_len_%d", kf)
else:
viperlib.snprintf(ename, 16, "__f_idx_%d", kf)
else:
# __await_M:反查位置数组
found: int = 0
km: int = 0
for km in range(nextra):
if trans._coro_await_slots[km] == ei:
found = 1
break
if found == 0:
continue
if ename is not None:
viperlib.snprintf(ename, 16, "__await_%d", km)
if ename is not None:
self.Gen.VarGen.define_var(trans.SymTab, ename, eslot)
# state 值 + exit 块
state_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, state_ptr)
exit_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.exit")
if exit_bb is None:
return 0
# 保存 resume 上下文(await 挂起 / 恢复块共享)
trans._coro_state_ptr = state_ptr
trans._coro_done_ptr = done_ptr
trans._coro_ret_ptr = ret_ptr
trans._coro_exc_ptr = exc_ptr
trans._coro_msg_ptr = msg_ptr
trans._coro_wake_ptr = None
trans._coro_exit_bb = exit_bb
trans._coro_frame = frame_arg
trans._coro_await_slot = None
# state0 是入口,await 从状态号 1 开始(与预扫描 DFS 序一致)
trans._coro_next_state = 1
# 翻译期序号(与预扫描同序)
trans._coro_hoist_count = 0
trans._coro_for_counter = 0
trans._coro_try_stack_count = 0
trans._coro_break_bb = None
trans._coro_continue_bb = None
nseg: int = trans._coro_nseg
if nseg <= 0:
nseg = 1
# 预建 state 块 + switch case(一次性生成,await 恢复块 position 填充)
state_bbs: sizet* = pool.alloc(nseg * 8)
if state_bbs is None:
return 0
trans._coro_state_bbs = state_bbs
sw_head: rawptr[llvmlite.SwitchCase] = None
sw_tail: rawptr[llvmlite.SwitchCase] = None
sw_count: int = 0
bb_name: str = pool.alloc(32)
si: int = 0
for si in range(nseg):
if bb_name is not None:
viperlib.snprintf(bb_name, 32, "state%d", si)
sbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_name)
if sbb is None:
continue
state_bbs[si] = sizet(sbb)
sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, llvmlite.const_int32(pool, si), sbb)
if sc is not None:
if sw_head is None:
sw_head = sc
sw_tail = sc
else:
sw_tail.Next = sc
sw_tail = sc
sw_count = sw_count + 1
llvmlite.build_switch(builder, state_val, exit_bb, sw_head, sw_count)
# ---- state0 主入口:递归翻译整个函数体(If/While 内 await 动态恢复)----
# 标准语句翻译(translate_stmt → translate_assign/annassign 等)从
# trans._cur_builder/_cur_func 取当前 IRBuilder/Function——必须在此设置,
# 后续 position_at_end 都作用于同一 builder 对象,_cur_builder 引用不变。
trans._cur_func = func
trans._cur_builder = builder
seg_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](state_bbs[0])
llvmlite.position_at_end(builder, seg_bb)
self._handle_segment(trans, builder, pool, mod, fd.children)
# 函数体自然结束 → 隐式 return(ret=0 + done=1 + br exit)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
zret: llvmlite.Value* = llvmlite.const_int32(pool, 0)
done_one: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, zret, ret_ptr)
llvmlite.build_store(builder, done_one, done_ptr)
llvmlite.build_br(builder, exit_bb)
# exit 块:load done 返回(0=SUSPEND 1=DONE)
llvmlite.position_at_end(builder, exit_bb)
done_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, done_ptr)
llvmlite.build_ret(builder, done_val)
return 0
# ============================================================
# M2:协程体递归翻译(Return/顶层 await/If/While/嵌套 await/普通)
# ============================================================
def _handle_segment(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmts: list[ast.AST*]*):
"""递归翻译协程体语句。builder 当前块 = 活跃执行块(state0 或某恢复块)。"""
if stmts is None:
return
bn: sizet = len(stmts)
i: sizet = 0
for i in range(bn):
stmt: ast.AST* = stmts.get(i)
if stmt is None:
continue
# 当前块已终止(return/挂起后无后续)→ 停止本段
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
return
sk: int = stmt.kind()
if sk == ast.ASTKind.Return:
self._emit_coro_return(builder, pool, mod, trans, stmt)
continue
if sk == ast.ASTKind.If:
self._handle_coro_if(trans, builder, pool, mod, stmt)
continue
if sk == ast.ASTKind.While:
self._handle_coro_while(trans, builder, pool, mod, stmt)
continue
if sk == ast.ASTKind.Raise:
self._handle_coro_raise(builder, pool, mod, trans, stmt)
continue
if sk == ast.ASTKind.Try:
tr_: ast.Try* = ast.Try*(stmt)
has_fin: int = 0
has_exc: int = 0
if tr_.finalbody is not None and len(tr_.finalbody) > 0:
has_fin = 1
if tr_.handlers is not None and len(tr_.handlers) > 0:
has_exc = 1
if has_fin != 0 and has_exc == 0:
self._handle_coro_try_finally(trans, builder, pool, mod, stmt)
else:
self._handle_coro_try(trans, builder, pool, mod, stmt)
continue
if sk == ast.ASTKind.For:
if self._for_deep_await(stmt) != 0:
self._handle_coro_for(trans, builder, pool, mod, stmt)
else:
# 无 await:委托标准 For
self.Gen.StmtGen.translate_stmt(trans, stmt)
continue
if sk == ast.ASTKind.Break:
if trans._coro_break_bb is not None:
llvmlite.build_br(builder, trans._coro_break_bb)
continue
if sk == ast.ASTKind.Continue:
if trans._coro_continue_bb is not None:
llvmlite.build_br(builder, trans._coro_continue_bb)
continue
if sk == ast.ASTKind.Pass:
continue
# 顶层 await:AnnAssign/Assign/Expr 的 value 直接是 Await → 挂起
if sk == ast.ASTKind.AnnAssign or sk == ast.ASTKind.Assign or sk == ast.ASTKind.Expr:
if self._is_await_tail(stmt) != 0:
target_name: str = self._get_assign_target_name(stmt)
if target_name is not None:
trans._coro_await_slot = self.Gen.VarGen.lookup_var(trans.SymTab, target_name)
else:
# Expr(await ...):无目标槽(丢弃返回值),防残留旧槽
trans._coro_await_slot = None
aw_node: rawptr[ast.Await] = self._get_await_value(stmt)
call_name: str = None
if aw_node is not None:
call_name = self._extract_await_call_name(aw_node)
if call_name is not None and self.is_async_func(trans, call_name) != 0:
self._emit_await(builder, pool, mod, trans, aw_node, call_name)
else:
if call_name is None:
call_name = "(unknown)"
err_buf: str = pool.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256, "[coro-M2] await 目标 '%s' 不是 async 函数", call_name)
self.Gen.TypeGenErr.fatal_error(stmt, err_buf, "SyntaxError")
continue
# 语句内嵌套 await → 提升为 __await_N
if self._stmt_has_await(stmt) != 0:
self._handle_nested_await_stmt(trans, builder, pool, mod, stmt)
continue
# 其它语句 → 标准翻译
self.Gen.StmtGen.translate_stmt(trans, stmt)
# ============================================================
# M2:协程版 If(分支内 await 就地挂起/恢复)
# ============================================================
def _handle_coro_if(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
ifn: rawptr[ast.If] = rawptr[ast.If](stmt)
if ifn is None or ifn.test is None:
return
if self._find_expr_await(ifn.test) is not None:
err_b: str = pool.alloc(256)
if err_b is not None:
viperlib.snprintf(err_b, 256, "[coro-M2] if 条件中不支持 await")
self.Gen.TypeGenErr.fatal_error(stmt, err_b, "SyntaxError")
return
cond: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ifn.test, None, 0, trans)
if cond is None:
return
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, cond)
func: llvmlite.Function* = trans._cur_func
then_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.then")
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.end")
has_else: int = 0
if ifn.orelse is not None and len(ifn.orelse) > 0:
has_else = 1
else_bb: rawptr[llvmlite.BasicBlock] = None
if has_else != 0:
else_bb = llvmlite.create_block(pool, func, "coro.else")
if cond1 is None or then_bb is None or merge_bb is None:
return
llvmlite.build_cond_br(builder, cond1, then_bb,
else_bb if else_bb is not None else merge_bb)
# then 分支
llvmlite.position_at_end(builder, then_bb)
self._handle_segment(trans, builder, pool, mod, stmt.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, merge_bb)
# else 分支
if else_bb is not None:
llvmlite.position_at_end(builder, else_bb)
self._handle_segment(trans, builder, pool, mod, ifn.orelse)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, merge_bb)
llvmlite.position_at_end(builder, merge_bb)
# ============================================================
# M2:协程版 While(条件块 + 循环体,body 内 await 就地挂起/恢复)
# ============================================================
def _handle_coro_while(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
whn: rawptr[ast.While] = rawptr[ast.While](stmt)
if whn is None:
return
if whn.test is not None and self._find_expr_await(whn.test) is not None:
err_c: str = pool.alloc(256)
if err_c is not None:
viperlib.snprintf(err_c, 256, "[coro-M2] while 条件中不支持 await")
self.Gen.TypeGenErr.fatal_error(stmt, err_c, "SyntaxError")
return
func: llvmlite.Function* = trans._cur_func
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.wcond")
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.wbody")
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.wend")
if cond_bb is None or body_bb is None or after_bb is None:
return
# break/continue 目标(M2 单层)
prev_break: rawptr[llvmlite.BasicBlock] = trans._coro_break_bb
prev_cont: rawptr[llvmlite.BasicBlock] = trans._coro_continue_bb
trans._coro_break_bb = after_bb
trans._coro_continue_bb = cond_bb
llvmlite.build_br(builder, cond_bb)
# 条件块
llvmlite.position_at_end(builder, cond_bb)
cond: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, whn.test, None, 0, trans)
if cond is None:
cond = llvmlite.const_int32(pool, 0)
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, cond)
llvmlite.build_cond_br(builder, cond1, body_bb, after_bb)
# 循环体
llvmlite.position_at_end(builder, body_bb)
self._handle_segment(trans, builder, pool, mod, stmt.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, cond_bb)
trans._coro_break_bb = prev_break
trans._coro_continue_bb = prev_cont
# 循环结束块
llvmlite.position_at_end(builder, after_bb)
# ============================================================
# M2:嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N
# ============================================================
def _handle_nested_await_stmt(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
"""把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描 DFS 顺序一致)"""
guard: int = 0
while True:
aw_node: rawptr[ast.Await] = self._extract_first_await(stmt)
if aw_node is None:
break
if guard >= HT.MAX_CORO_VARS:
break
guard = guard + 1
temp_name: str = pool.alloc(32)
if temp_name is not None:
viperlib.snprintf(temp_name, 32, "__await_%d", trans._coro_hoist_count)
# 目标槽 = __await_N 帧额外槽(预扫描位置数组,wake/for 槽穿插在前)
slot_idx: int = trans._coro_extra_base + trans._coro_await_slots[trans._coro_hoist_count]
trans._coro_hoist_count = trans._coro_hoist_count + 1
slot: llvmlite.Value* = llvmlite.build_gep_struct(builder, self._lookup_coro_frame_by_trans(trans),
llvmlite.Int32(pool), trans._coro_frame, slot_idx)
trans._coro_await_slot = slot
call_name: str = self._extract_await_call_name(aw_node)
if call_name is None:
break
self._emit_await(builder, pool, mod, trans, aw_node, call_name)
self._replace_await_with_name(pool, stmt, temp_name)
# 提升完成 → 标准翻译(恢复块内继续执行剩余表达式)
self.Gen.StmtGen.translate_stmt(trans, stmt)
# ============================================================
# 嵌套 await 存在性 / 提取 / 替换(DFS 与预扫描同序)
# ============================================================
def _stmt_has_await(self, stmt: ast.AST*) -> int:
aw: rawptr[ast.Await] = self._extract_first_await(stmt)
if aw is not None:
return 1
return 0
def _extract_first_await(self, stmt: ast.AST*) -> rawptr[ast.Await]:
"""取语句中第一个 Await 节点(DFS 字段序),未命中返回 None"""
if stmt is None:
return None
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
return self._find_expr_await(aa.value)
if sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
return self._find_expr_await(as_.value)
if sk == ast.ASTKind.Expr:
e: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
return self._find_expr_await(e.value)
if sk == ast.ASTKind.Return:
rv: rawptr[ast.Return] = rawptr[ast.Return](stmt)
return self._find_expr_await(rv.value)
return None
def _find_expr_await(self, node: ast.AST*) -> rawptr[ast.Await]:
"""表达式树中 DFS 找第一个 Await"""
if node is None:
return None
k: int = node.kind()
if k == ast.ASTKind.Await:
return rawptr[ast.Await](node)
if k == ast.ASTKind.BinOp:
b: ast.BinOp* = ast.BinOp*(node)
r: rawptr[ast.Await] = self._find_expr_await(b.left)
if r is not None:
return r
return self._find_expr_await(b.right)
if k == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(node)
if cl.func is not None:
r2: rawptr[ast.Await] = self._find_expr_await(cl.func)
if r2 is not None:
return r2
if cl.args is not None:
nb: sizet = len(cl.args)
j: sizet = 0
for j in range(nb):
r3: rawptr[ast.Await] = self._find_expr_await(cl.args.get(j))
if r3 is not None:
return r3
return None
if k == ast.ASTKind.UnaryOp:
u: ast.UnaryOp* = ast.UnaryOp*(node)
return self._find_expr_await(u.operand)
if k == ast.ASTKind.Compare:
cm: rawptr[ast.Compare] = rawptr[ast.Compare](node)
r4: rawptr[ast.Await] = self._find_expr_await(cm.left)
if r4 is not None:
return r4
if cm.comparators is not None:
nb2: sizet = len(cm.comparators)
j2: sizet = 0
for j2 in range(nb2):
r5: rawptr[ast.Await] = self._find_expr_await(cm.comparators.get(j2))
if r5 is not None:
return r5
return None
if k == ast.ASTKind.BoolOp:
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
if bo.values is not None:
nb3: sizet = len(bo.values)
j3: sizet = 0
for j3 in range(nb3):
r6: rawptr[ast.Await] = self._find_expr_await(bo.values.get(j3))
if r6 is not None:
return r6
return None
if k == ast.ASTKind.IfExp:
ie: rawptr[ast.IfExp] = rawptr[ast.IfExp](node)
r7: rawptr[ast.Await] = self._find_expr_await(ie.test)
if r7 is not None:
return r7
r8: rawptr[ast.Await] = self._find_expr_await(ie.body)
if r8 is not None:
return r8
return self._find_expr_await(ie.orelse)
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
return self._find_expr_await(at.value)
if k == ast.ASTKind.Subscript:
sb: ast.Subscript* = ast.Subscript*(node)
r9: rawptr[ast.Await] = self._find_expr_await(sb.value)
if r9 is not None:
return r9
return self._find_expr_await(sb.slice)
return None
def _replace_await_with_name(self, pool: memhub.MemBuddy*,
stmt: ast.AST*,
temp_name: str) -> int:
"""把语句树中第一个 Await 替换为 Name(temp_name)(DFS 字段序)"""
if stmt is None or temp_name is None:
return 0
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.value is not None:
return self._replace_expr_await(pool, aa.value, temp_name)
return 0
if sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.value is not None:
return self._replace_expr_await(pool, as_.value, temp_name)
return 0
if sk == ast.ASTKind.Expr:
e: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
if e.value is not None:
return self._replace_expr_await(pool, e.value, temp_name)
return 0
if sk == ast.ASTKind.Return:
rv: rawptr[ast.Return] = rawptr[ast.Return](stmt)
if rv.value is not None:
return self._replace_expr_await(pool, rv.value, temp_name)
return 0
return 0
def _replace_expr_await(self, pool: memhub.MemBuddy*,
node: ast.AST*,
temp_name: str) -> int:
"""在表达式树中把第一个 Await 替换为 Name(temp_name, Load)。
node 本身是 Await 时返回 2(由父字段替换)。返回 1=已替换 0=无 2=node 即 Await。"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Await:
return 2
if k == ast.ASTKind.BinOp:
b: ast.BinOp* = ast.BinOp*(node)
r: int = self._replace_expr_await(pool, b.left, temp_name)
if r == 1:
return 1
if r == 2:
b.left = ast.Name(pool, temp_name, 0)
return 1
r2: int = self._replace_expr_await(pool, b.right, temp_name)
if r2 == 1:
return 1
if r2 == 2:
b.right = ast.Name(pool, temp_name, 0)
return 1
return 0
if k == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(node)
if cl.func is not None:
r3: int = self._replace_expr_await(pool, cl.func, temp_name)
if r3 == 1:
return 1
if r3 == 2:
cl.func = ast.Name(pool, temp_name, 0)
return 1
if cl.args is not None:
nb: sizet = len(cl.args)
j: sizet = 0
for j in range(nb):
r4: int = self._replace_expr_await(pool, cl.args.get(j), temp_name)
if r4 == 1:
return 1
if r4 == 2:
cl.args.set(j, ast.Name(pool, temp_name, 0))
return 1
return 0
if k == ast.ASTKind.UnaryOp:
u: ast.UnaryOp* = ast.UnaryOp*(node)
r5: int = self._replace_expr_await(pool, u.operand, temp_name)
if r5 == 1:
return 1
if r5 == 2:
u.operand = ast.Name(pool, temp_name, 0)
return 1
return 0
if k == ast.ASTKind.Compare:
cm: rawptr[ast.Compare] = rawptr[ast.Compare](node)
r6: int = self._replace_expr_await(pool, cm.left, temp_name)
if r6 == 1:
return 1
if r6 == 2:
cm.left = ast.Name(pool, temp_name, 0)
return 1
if cm.comparators is not None:
nb2: sizet = len(cm.comparators)
j2: sizet = 0
for j2 in range(nb2):
r7: int = self._replace_expr_await(pool, cm.comparators.get(j2), temp_name)
if r7 == 1:
return 1
if r7 == 2:
cm.comparators.set(j2, ast.Name(pool, temp_name, 0))
return 1
return 0
if k == ast.ASTKind.BoolOp:
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
if bo.values is not None:
nb3: sizet = len(bo.values)
j3: sizet = 0
for j3 in range(nb3):
r8: int = self._replace_expr_await(pool, bo.values.get(j3), temp_name)
if r8 == 1:
return 1
if r8 == 2:
bo.values.set(j3, ast.Name(pool, temp_name, 0))
return 1
return 0
if k == ast.ASTKind.IfExp:
ie: rawptr[ast.IfExp] = rawptr[ast.IfExp](node)
r9: int = self._replace_expr_await(pool, ie.test, temp_name)
if r9 == 1:
return 1
if r9 == 2:
ie.test = ast.Name(pool, temp_name, 0)
return 1
r10: int = self._replace_expr_await(pool, ie.body, temp_name)
if r10 == 1:
return 1
if r10 == 2:
ie.body = ast.Name(pool, temp_name, 0)
return 1
r11: int = self._replace_expr_await(pool, ie.orelse, temp_name)
if r11 == 1:
return 1
if r11 == 2:
ie.orelse = ast.Name(pool, temp_name, 0)
return 1
return 0
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
r12: int = self._replace_expr_await(pool, at.value, temp_name)
if r12 == 1:
return 1
if r12 == 2:
at.value = ast.Name(pool, temp_name, 0)
return 1
return 0
if k == ast.ASTKind.Subscript:
sb: ast.Subscript* = ast.Subscript*(node)
r13: int = self._replace_expr_await(pool, sb.value, temp_name)
if r13 == 1:
return 1
if r13 == 2:
sb.value = ast.Name(pool, temp_name, 0)
return 1
r14: int = self._replace_expr_await(pool, sb.slice, temp_name)
if r14 == 1:
return 1
if r14 == 2:
sb.slice = ast.Name(pool, temp_name, 0)
return 1
return 0
return 0
# ============================================================
# 条件归一化(i1 直通;其余 icmp ne 0)
# ============================================================
def _normalize_cond(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
cond: llvmlite.Value*) -> llvmlite.Value*:
if cond is None:
return None
ty: llvmlite.LLVMType* = cond.Ty
is_i1: int = 0
if ty is not None:
match ty:
case LLVMType.Int():
if ty.Bits == 1:
is_i1 = 1
case _:
pass
if is_i1 != 0:
return cond
zero: llvmlite.Value* = llvmlite.ConstZero(pool, ty)
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond, zero)
# ============================================================
# 参数名读取(_coro_params 表)
# ============================================================
def _read_param_name(self, trans: HT.Translator*,
idx: int) -> str:
if trans is None or trans._coro_params is None:
return None
addr: uint64 = uint64(trans._coro_params) + idx * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
return slot[0]
# ============================================================
# 恢复块定位(state{N},预建数组)
# ============================================================
def _get_state_bb(self, trans: HT.Translator*,
state_no: int) -> rawptr[llvmlite.BasicBlock]:
if trans is None or trans._coro_state_bbs is None:
return None
if state_no < 0 or state_no >= trans._coro_nseg:
return None
# 注意:state_bbs 数组存的是块指针(sizet),必须下标取值,
# 不能取元素地址(uint64(数组)+idx*8 是地址,会导致 position
# 到非法块 → IR 指令链损坏 → RenumberSSA/FunctionPrint 崩溃)。
return rawptr[llvmlite.BasicBlock](trans._coro_state_bbs[state_no])
def _lookup_coro_frame_by_trans(self, trans: HT.Translator*) -> llvmlite.LLVMType*:
"""取当前 resume 的帧类型:从 _coro_frames 反查(当前 async 名未知时用帧指针类型不可行,
直接返回当前协程注册的帧类型——_handle_nested_await_stmt 需要帧类型做 GEP。"""
# 简化:恢复块 GEP 需要帧类型;从 _coro_frame 的 Ty(Ptr(帧))取 Pointee
if trans is None or trans._coro_frame is None:
return None
ft: llvmlite.LLVMType* = trans._coro_frame.Ty
if ft is None:
return None
match ft:
case LLVMType.Ptr():
return ft.Pointee
case _:
return None
# ============================================================
# M3:await coro_sleep(ms) —— wake 槽挂起(coro_run 轮询续跑)
# ============================================================
def _emit_await_sleep(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
node: ast.AST*) -> llvmlite.Value*:
"""await coro_sleep(ms):wake = GetTickCount64() + ms 存帧 wake 槽,
父挂起(state 分配 + br exit + position 恢复块);coro_run 轮询续跑。"""
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
if node is None or trans is None or trans._coro_wake_ptr is None:
return llvmlite.const_int32(pool, 0)
ms_val: llvmlite.Value* = llvmlite.const_int64(pool, 0)
aw_s: rawptr[ast.Await] = rawptr[ast.Await](node)
if aw_s.value is not None and aw_s.value.kind() == ast.ASTKind.Call:
cl_s: ast.Call* = ast.Call*(aw_s.value)
if cl_s.args is not None and len(cl_s.args) > 0:
ms_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl_s.args.get(0), None, 0, trans)
if ms_v is not None:
ms_val = ms_v
# GetTickCount64() + ms(i64)
now_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, "GetTickCount64")
if now_fn is None:
now_fn = llvmlite.create_declare(pool, mod, "GetTickCount64", i64_ty)
if now_fn is None:
return llvmlite.const_int32(pool, 0)
now_val: llvmlite.Value* = llvmlite.build_call(builder, "GetTickCount64", None, 0, i64_ty, 0)
if now_val is None:
return llvmlite.const_int32(pool, 0)
wake_val: llvmlite.Value* = llvmlite.build_add(builder, now_val, ms_val)
if wake_val is None:
return llvmlite.const_int32(pool, 0)
llvmlite.build_store(builder, wake_val, trans._coro_wake_ptr)
# 父挂起:新状态号 + br exit + position 恢复块
new_state_s: int = trans._coro_next_state
trans._coro_next_state = new_state_s + 1
st_v_s: llvmlite.Value* = llvmlite.const_int32(pool, new_state_s)
llvmlite.build_store(builder, st_v_s, trans._coro_state_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
resume_bb_s: rawptr[llvmlite.BasicBlock] = self._get_state_bb(trans, new_state_s)
if resume_bb_s is not None:
llvmlite.position_at_end(builder, resume_bb_s)
return llvmlite.const_int32(pool, 0)
# ============================================================
# M4-M6:协程内 raise(异常类型/值 → 帧 exc 槽)
# ============================================================
def _handle_coro_raise(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
stmt: ast.AST*):
"""协程内 raise:解析异常类型/值 → 帧 exc 槽(+msg);
try 栈非空跳 except 处理器,否则 done=1 + br exit 终止。"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
exc_code: llvmlite.Value* = llvmlite.const_int32(pool, 1)
rz: rawptr[ast.Raise] = rawptr[ast.Raise](stmt)
if rz is not None and rz.exc is not None:
code: int = self._resolve_raise_code(pool, rz.exc)
if code != 0:
exc_code = llvmlite.const_int32(pool, code)
# M7:异常消息(Exception("msg") 首参)
msg_v: llvmlite.Value* = self._resolve_raise_msg(builder, pool, mod, trans, rz.exc)
if msg_v is not None and trans._coro_msg_ptr is not None:
llvmlite.build_store(builder, msg_v, trans._coro_msg_ptr)
else:
v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, rz.exc, None, 0, trans)
if v is not None:
exc_code = v
if trans._coro_exc_ptr is not None:
llvmlite.build_store(builder, exc_code, trans._coro_exc_ptr)
# 跳 try except / 终止
if trans._coro_try_stack_count > 0:
tbb_r: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](trans._coro_try_stack[trans._coro_try_stack_count - 1])
llvmlite.build_br(builder, tbb_r)
else:
done_r: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, done_r, trans._coro_done_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
def _resolve_raise_code(self, pool: memhub.MemBuddy*,
exc_node: ast.AST*) -> int:
"""解析 raise 目标的异常码(内置/用户异常类名);非异常类返回 0"""
if exc_node is None:
return 0
name: str = None
if exc_node.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(exc_node)
name = nm.id
elif exc_node.kind() == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(exc_node)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
nm2: ast.Name* = ast.Name*(cl.func)
name = nm2.id
elif exc_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(exc_node)
name = at.attr
if name is None:
return 0
return self.Gen.ClassGenBase.lookup_exception_code(name)
def _resolve_raise_msg(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
exc_node: ast.AST*) -> llvmlite.Value*:
"""取异常消息表达式(Exception("msg") 首参),无则返回 None"""
if exc_node is None or exc_node.kind() != ast.ASTKind.Call:
return None
cl: ast.Call* = ast.Call*(exc_node)
if cl.args is None or len(cl.args) < 1:
return None
return self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
# ============================================================
# M5-M6:协程内 try/except(多 except 链式匹配 + 类型码 + as e 绑定)
# ============================================================
def _handle_coro_try(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
"""协程内 try/except:raise/await 传播异常在 try 栈内改跳 except 处理器;
多 except 按声明序匹配(含子类码集合),Exception/裸 except 捕获所有;
全不匹配重新传播(done=1 + br exit)。"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
tr: ast.Try* = ast.Try*(stmt)
if tr is None:
return
nhandlers: int = 0
if tr.handlers is not None:
nhandlers = len(tr.handlers)
if nhandlers == 0:
err_t: str = pool.alloc(256)
if err_t is not None:
viperlib.snprintf(err_t, 256, "[coro-M6] 协程内 try 需要 except 子句")
self.Gen.TypeGenErr.fatal_error(stmt, err_t, "SyntaxError")
return
func: llvmlite.Function* = trans._cur_func
except_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.try_except")
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.try_merge")
if except_bb is None or merge_bb is None:
return
# try 栈 push
if trans._coro_try_stack_count < HT.MAX_CORO_TRY:
trans._coro_try_stack[trans._coro_try_stack_count] = sizet(except_bb)
trans._coro_try_stack_count = trans._coro_try_stack_count + 1
# try body
self._handle_segment(trans, builder, pool, mod, stmt.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, merge_bb)
if trans._coro_try_stack_count > 0:
trans._coro_try_stack_count = trans._coro_try_stack_count - 1
# ---- 异常分发:exc 码依次匹配各 except ----
llvmlite.position_at_end(builder, except_bb)
exc_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, trans._coro_exc_ptr)
# 预建 check/handler/unmatched 块
check_bbs: sizet* = pool.alloc((nhandlers + 1) * 8)
handler_bbs: sizet* = pool.alloc(nhandlers * 8)
if check_bbs is None or handler_bbs is None:
return
check_bbs[0] = sizet(except_bb)
hi: int = 0
for hi in range(nhandlers):
# [FIX 2026-08-31] 块名用 snprintf 生成(对齐本文件其余块命名):
# 原先 "coro.exc_check_%d" % hi 的 % 是 Python 字符串格式化,本语言
# 未实现 → translate_binop 按整数 srem 编译出 i32 垃圾值 → create_block
# 的 name: str 参数收 i32 → int→ptr 禁令误报(CastError 根因)。
chk_name: str = pool.alloc(64)
exc_name: str = pool.alloc(64)
if chk_name is None or exc_name is None:
return
viperlib.snprintf(chk_name, 64, "coro.exc_check_%d", hi)
viperlib.snprintf(exc_name, 64, "coro.except_%d", hi)
check_bbs[hi + 1] = sizet(llvmlite.create_block(pool, func, chk_name))
handler_bbs[hi] = sizet(llvmlite.create_block(pool, func, exc_name))
unmatched_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.try_reraise")
codes_buf: int | t.CPtr = pool.alloc(256)
# 每个 handler:check 链
for hi in range(nhandlers):
h_node: ast.AST* = tr.handlers.get(hi)
check_bb: rawptr[llvmlite.BasicBlock] = (rawptr[llvmlite.BasicBlock])(check_bbs[hi])
llvmlite.position_at_end(builder, check_bb)
catch_all: int = 0
ncodes: int = 0
if h_node is not None:
hd: ast.ExceptHandler* = ast.ExceptHandler*(h_node)
if hd.type is None:
catch_all = 1
else:
ename: str = self._exception_type_name(pool, hd.type)
if ename is not None and string.strcmp(ename, "Exception") == 0:
catch_all = 1
else:
ncodes = self.Gen.ClassGenBase.collect_descendant_codes(ename, codes_buf, 64)
next_check: rawptr[llvmlite.BasicBlock] = None
if hi + 1 < nhandlers:
next_check = rawptr[llvmlite.BasicBlock](check_bbs[hi + 1])
else:
next_check = unmatched_bb
handler_bb: rawptr[llvmlite.BasicBlock] = (rawptr[llvmlite.BasicBlock])(handler_bbs[hi])
if catch_all != 0:
llvmlite.build_br(builder, handler_bb)
else:
match_cond: llvmlite.Value* = None
ci: int = 0
for ci in range(ncodes):
eq_v: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, exc_val,
llvmlite.const_int32(pool, codes_buf[ci]))
if match_cond is None:
match_cond = eq_v
else:
match_cond = llvmlite.build_or(builder, match_cond, eq_v)
if match_cond is None:
llvmlite.build_br(builder, next_check)
else:
llvmlite.build_cond_br(builder, match_cond, handler_bb, next_check)
# 未匹配:异常继续传播(重新终止协程)
llvmlite.position_at_end(builder, unmatched_bb)
done_u: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, done_u, trans._coro_done_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
# ---- 各 except handler ----
for hi in range(nhandlers):
h_node2: ast.AST* = tr.handlers.get(hi)
handler_bb2: rawptr[llvmlite.BasicBlock] = (rawptr[llvmlite.BasicBlock])(handler_bbs[hi])
llvmlite.position_at_end(builder, handler_bb2)
if h_node2 is not None:
hd2: ast.ExceptHandler* = ast.ExceptHandler*(h_node2)
# as e:异常码绑定 e 槽(e 是局部槽,_collect_local_names 收集)
if hd2.name is not None and trans._coro_exc_ptr is not None:
e_slot: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, hd2.name)
if e_slot is not None:
hv: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, trans._coro_exc_ptr)
llvmlite.build_store(builder, hv, e_slot)
# 捕获后清帧 exc
z_clr: llvmlite.Value* = llvmlite.const_int32(pool, 0)
llvmlite.build_store(builder, z_clr, trans._coro_exc_ptr)
self._handle_segment(trans, builder, pool, mod, h_node2.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, merge_bb)
llvmlite.position_at_end(builder, merge_bb)
def _exception_type_name(self, pool: memhub.MemBuddy*,
type_node: ast.AST*) -> str:
"""取 except 类型名(Name/Attribute),未命中返回 None"""
if type_node is None:
return None
if type_node.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(type_node)
return nm.id
if type_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(type_node)
return at.attr
return None
# ============================================================
# M7:协程内 try/finally(无 except)
# ============================================================
def _handle_coro_try_finally(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
"""协程内 try/finally:正常/异常路径都执行 fbody;
异常时 finally 后重新传播(done=1 + br exit);finally 内不支持 await。"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
tr: ast.Try* = ast.Try*(stmt)
if tr is None:
return
if tr.finalbody is not None and self._stmts_deep_await(tr.finalbody) != 0:
err_f: str = pool.alloc(256)
if err_f is not None:
viperlib.snprintf(err_f, 256, "[coro-M7] finally 内暂不支持 await")
self.Gen.TypeGenErr.fatal_error(stmt, err_f, "SyntaxError")
return
func: llvmlite.Function* = trans._cur_func
fin_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fin")
fin_exc_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fin_exc")
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fin_merge")
if fin_bb is None or fin_exc_bb is None or merge_bb is None:
return
# try 栈 push(异常跳 finally)
if trans._coro_try_stack_count < HT.MAX_CORO_TRY:
trans._coro_try_stack[trans._coro_try_stack_count] = sizet(fin_bb)
trans._coro_try_stack_count = trans._coro_try_stack_count + 1
self._handle_segment(trans, builder, pool, mod, stmt.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, fin_bb)
if trans._coro_try_stack_count > 0:
trans._coro_try_stack_count = trans._coro_try_stack_count - 1
# fin_bb:记录异常标志 + 执行 fbody
llvmlite.position_at_end(builder, fin_bb)
was_exc: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE,
llvmlite.build_load(builder, i32_ty, trans._coro_exc_ptr),
llvmlite.const_int32(pool, 0))
self._handle_segment(trans, builder, pool, mod, tr.finalbody)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_cond_br(builder, was_exc, fin_exc_bb, merge_bb)
# fin_exc:finally 后异常继续传播
llvmlite.position_at_end(builder, fin_exc_bb)
done_f: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, done_f, trans._coro_done_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
llvmlite.position_at_end(builder, merge_bb)
# ============================================================
# M3:协程内 range-For(含 await)变换为 While(__f_idx/__f_len 帧槽)
# ============================================================
def _handle_coro_for(self, trans: HT.Translator*,
builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
stmt: ast.AST*):
"""range-For(含 await):__f_idx_N = start; __f_len_N = end;
while __f_idx_N < __f_len_N: target = __f_idx_N; <body>; __f_idx_N += 1"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
if self._is_range_for(stmt) == 0:
err_g: str = pool.alloc(256)
if err_g is not None:
viperlib.snprintf(err_g, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)")
self.Gen.TypeGenErr.fatal_error(stmt, err_g, "SyntaxError")
return
fn: ast.For* = ast.For*(stmt)
k: int = trans._coro_for_counter
trans._coro_for_counter = k + 1
idx_idx: int = trans._coro_extra_base + trans._coro_for_slots[k]
len_idx: int = idx_idx + 1
idx_slot: llvmlite.Value* = llvmlite.build_gep_struct(builder, self._lookup_coro_frame_by_trans(trans),
i32_ty, trans._coro_frame, idx_idx)
len_slot: llvmlite.Value* = llvmlite.build_gep_struct(builder, self._lookup_coro_frame_by_trans(trans),
i32_ty, trans._coro_frame, len_idx)
if idx_slot is None or len_slot is None:
return
# start/end(range 1/2 参数)
cl: ast.Call* = ast.Call*(fn.iter)
start_val: llvmlite.Value* = None
end_val: llvmlite.Value* = None
nargs: int = len(cl.args)
if nargs == 1:
start_val = llvmlite.const_int32(pool, 0)
end_val = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
else:
start_val = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
end_val = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(1), None, 0, trans)
if start_val is None:
start_val = llvmlite.const_int32(pool, 0)
if end_val is None:
end_val = llvmlite.const_int32(pool, 0)
llvmlite.build_store(builder, start_val, idx_slot)
llvmlite.build_store(builder, end_val, len_slot)
# 循环结构
func: llvmlite.Function* = trans._cur_func
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fcond")
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fbody")
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.fend")
if cond_bb is None or body_bb is None or after_bb is None:
return
prev_break: rawptr[llvmlite.BasicBlock] = trans._coro_break_bb
prev_cont: rawptr[llvmlite.BasicBlock] = trans._coro_continue_bb
trans._coro_break_bb = after_bb
trans._coro_continue_bb = cond_bb
llvmlite.build_br(builder, cond_bb)
# 条件块
llvmlite.position_at_end(builder, cond_bb)
idx_v: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_slot)
len_v: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, len_slot)
cmp_v: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, idx_v, len_v)
llvmlite.build_cond_br(builder, cmp_v, body_bb, after_bb)
# 循环体:target = idx; <body>; idx += 1
llvmlite.position_at_end(builder, body_bb)
if fn.target is not None and fn.target.kind() == ast.ASTKind.Name:
tn: ast.Name* = ast.Name*(fn.target)
tgt_slot: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, tn.id)
if tgt_slot is not None:
idx_v2: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_slot)
llvmlite.build_store(builder, idx_v2, tgt_slot)
self._handle_segment(trans, builder, pool, mod, stmt.children)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
idx_v3: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_slot)
one_v: llvmlite.Value* = llvmlite.const_int32(pool, 1)
nxt_v: llvmlite.Value* = llvmlite.build_add(builder, idx_v3, one_v)
llvmlite.build_store(builder, nxt_v, idx_slot)
llvmlite.build_br(builder, cond_bb)
trans._coro_break_bb = prev_break
trans._coro_continue_bb = prev_cont
llvmlite.position_at_end(builder, after_bb)
# ============================================================
# M3/M4/M7:coro.coro_destroy / coro_exception / coro_exception_msg / coro_gather
# ============================================================
def translate_coro_destroy(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator*) -> llvmlite.Value*:
"""coro.coro_destroy(帧):帧回池(free-list,帧首 8 字节存 next)"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
if cl is None or trans is None or cl.args is None or len(cl.args) < 1:
return llvmlite.const_int32(pool, 0)
async_name: str = self._var_to_async(trans, cl.args.get(0))
if async_name is None:
return llvmlite.const_int32(pool, 0)
frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, async_name)
if frame_ty is None:
return llvmlite.const_int32(pool, 0)
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
frame_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
if frame_val is None:
return llvmlite.const_int32(pool, 0)
frame_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_val, frame_ptr_ty)
if frame_ptr is None:
return llvmlite.const_int32(pool, 0)
# 回池:帧首 8 字节存旧池头;池头 = 本帧(i64)
pool_gv: llvmlite.GlobalVariable* = self._get_coro_pool(pool, mod, trans, async_name)
# GlobalVariable 非 Value 子类:构造 Value 视图(Ty=Ptr(i64), Name="@coro_pool_<name>")
i64_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i64_ty)
pool_ref_name: str = pool.alloc(96)
if pool_ref_name is not None:
viperlib.snprintf(pool_ref_name, 96, "@coro_pool_%s", async_name)
pool_ref: llvmlite.Value* = llvmlite.SSAValue(pool, i64_ptr_ty, pool_ref_name)
pool_head: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, pool_ref)
node_next: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_ptr, i64_ptr_ty)
llvmlite.build_store(builder, pool_head, node_next)
frame_i64: llvmlite.Value* = llvmlite.build_ptrtoint(builder, frame_ptr, i64_ty)
llvmlite.build_store(builder, frame_i64, pool_ref)
return llvmlite.const_int32(pool, 0)
def translate_coro_exception(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator*) -> llvmlite.Value*:
"""coro.coro_exception(帧):返回帧 exc 槽(异常码,0=无异常)"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
if cl is None or trans is None or cl.args is None or len(cl.args) < 1:
return llvmlite.const_int32(pool, 0)
async_name: str = self._var_to_async(trans, cl.args.get(0))
if async_name is None:
return llvmlite.const_int32(pool, 0)
frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, async_name)
if frame_ty is None:
return llvmlite.const_int32(pool, 0)
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
frame_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
if frame_val is None:
return llvmlite.const_int32(pool, 0)
frame_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_val, frame_ptr_ty)
if frame_ptr is None:
return llvmlite.const_int32(pool, 0)
exc_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_ptr, 3)
return llvmlite.build_load(builder, i32_ty, exc_ptr)
def translate_coro_exception_msg(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator*) -> llvmlite.Value*:
"""coro.coro_exception_msg(帧):返回帧 msg 槽(异常消息指针,null=无)"""
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
if cl is None or trans is None or cl.args is None or len(cl.args) < 1:
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
async_name: str = self._var_to_async(trans, cl.args.get(0))
if async_name is None:
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, async_name)
if frame_ty is None:
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
frame_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl.args.get(0), None, 0, trans)
if frame_val is None:
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
frame_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_val, frame_ptr_ty)
if frame_ptr is None:
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
msg_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i8_ptr_ty, frame_ptr, 4)
return llvmlite.build_load(builder, i8_ptr_ty, msg_ptr)
def translate_coro_gather(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator*) -> llvmlite.Value*:
"""coro.coro_gather(帧...):并发推进全部协程到完成,返回完成数(M4 纯 resume 循环)"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
if cl is None or trans is None or cl.args is None:
return llvmlite.const_int32(pool, 0)
nb: sizet = len(cl.args)
j: sizet = 0
for j in range(nb):
arg0: ast.AST* = cl.args.get(j)
async_name: str = self._var_to_async(trans, arg0)
if async_name is None:
continue
frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, async_name)
if frame_ty is None:
continue
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
frame_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg0, None, 0, trans)
if frame_val is None:
continue
frame_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_val, frame_ptr_ty)
if frame_ptr is None:
continue
rn_buf: str = pool.alloc(64)
if rn_buf is not None:
viperlib.snprintf(rn_buf, 64, "resume_%s", async_name)
resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, rn_buf, 0)
if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None:
continue
func: llvmlite.Function* = trans._cur_func
loop_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "gather.loop")
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "gather.after")
if loop_bb is None or after_bb is None:
continue
llvmlite.build_br(builder, loop_bb)
llvmlite.position_at_end(builder, loop_bb)
frame_ptr.Next = None
status: llvmlite.Value* = llvmlite.build_call(builder, resume_mangled, frame_ptr, 1, i32_ty, 0)
done_cond: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, status, llvmlite.const_int32(pool, 0))
llvmlite.build_cond_br(builder, done_cond, after_bb, loop_bb)
llvmlite.position_at_end(builder, after_bb)
return llvmlite.const_int32(pool, 0)
def _var_to_async(self, trans: HT.Translator*,
arg0: ast.AST*) -> str:
"""变量节点 → async 函数名(_coro_var_async 反查),未命中返回 None"""
if trans is None or arg0 is None or arg0.kind() != ast.ASTKind.Name:
return None
nm: ast.Name* = ast.Name*(arg0)
if nm.id is None:
return None
return self._lookup_coro_var(trans, nm.id)
# ============================================================
# await 表达式翻译(顶层段尾 / translate_value Await 分支共用)
# ============================================================
def _emit_await(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
node: ast.AST*,
call_name: str) -> llvmlite.Value*:
"""await async_fn(args...) 内联翻译(M2 带参数):
1. 求值调用参数(表达式逐个翻译,i32)
2. create_<call_name>(args...) 创建子帧
3. resume_<call_name>(child) 推进到 DONE
4. 子帧 ret 槽 GEP [0,2] load → store 到父帧 await 槽(若非 None)
5. 父挂起:store state=新状态号 + br exit;恢复块 state{new_state}
立即 position(预建 case 块),后续语句在恢复块继续翻译
返回子协程 ret 值(i32)。注意 node 是 Await,须先转 ast.Await 再取 value。"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ptr_ty_a: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
if node is None or call_name is None or trans is None:
return llvmlite.const_int32(pool, 0)
# M3:await coro_sleep(ms) —— 挂起到 wake 时刻(帧 wake 槽)
if string.strcmp(call_name, "coro_sleep") == 0:
return self._emit_await_sleep(builder, pool, mod, trans, node)
child_frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, call_name)
if child_frame_ty is None:
return llvmlite.const_int32(pool, 0)
child_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, child_frame_ty)
cc_buf: str = pool.alloc(64)
if cc_buf is not None:
viperlib.snprintf(cc_buf, 64, "create_%s", call_name)
create_mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, cc_buf, 0)
rc_buf: str = pool.alloc(64)
if rc_buf is not None:
viperlib.snprintf(rc_buf, 64, "resume_%s", call_name)
resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, rc_buf, 0)
if self.Gen.CallGenBase.find_func_in_module(mod, create_mangled) is None \
or self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None:
# async 函数必须定义在前(前向引用未支持),静默返回 0
return llvmlite.const_int32(pool, 0)
# M2:子协程调用参数(await fn(a, b) → create_fn(a, b))
args_head: llvmlite.Value* = None
args_tail: llvmlite.Value* = None
args_count: int = 0
aw_n: rawptr[ast.Await] = rawptr[ast.Await](node)
if aw_n.value is not None and aw_n.value.kind() == ast.ASTKind.Call:
cl_a: ast.Call* = ast.Call*(aw_n.value)
if cl_a.args is not None:
nb: sizet = len(cl_a.args)
j: sizet = 0
for j in range(nb):
av: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl_a.args.get(j), None, 0, trans)
if av is None:
av = llvmlite.const_int32(pool, 0)
av.Next = None
if args_head is None:
args_head = av
args_tail = av
else:
args_tail.Next = av
args_tail = av
args_count = args_count + 1
# 子协程 create(M2 带参数)+ resume
child: llvmlite.Value* = llvmlite.build_call(builder, create_mangled, args_head, args_count, child_ptr_ty, 0)
if child is None:
return llvmlite.const_int32(pool, 0)
child.Next = None
llvmlite.build_call(builder, resume_mangled, child, 1, i32_ty, 0)
# 子帧 ret 槽 GEP [0,2] load
child_ret_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, child_frame_ty, i32_ty, child, 2)
child_ret: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, child_ret_ptr)
# M4:子帧异常传播——子帧 exc != 0 → 父 exc/msg 槽 + 跳 try except 或终止
child_exc_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, child_frame_ty, i32_ty, child, 3)
child_exc: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, child_exc_ptr)
zero32_x: llvmlite.Value* = llvmlite.const_int32(pool, 0)
exc_ok_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, "coro.ok")
exc_bad_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, "coro.exc")
if exc_ok_bb is None or exc_bad_bb is None:
return llvmlite.const_int32(pool, 0)
exc_cond: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, child_exc, zero32_x)
llvmlite.build_cond_br(builder, exc_cond, exc_ok_bb, exc_bad_bb)
# exc 路径:父帧 exc/msg 槽 + 跳 try 或终止
llvmlite.position_at_end(builder, exc_bad_bb)
if trans._coro_exc_ptr is not None:
llvmlite.build_store(builder, child_exc, trans._coro_exc_ptr)
if trans._coro_msg_ptr is not None:
child_msg_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, child_frame_ty, i8_ptr_ty_a, child, 4)
child_msg: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_a, child_msg_ptr)
llvmlite.build_store(builder, child_msg, trans._coro_msg_ptr)
if trans._coro_try_stack_count > 0:
tbb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](trans._coro_try_stack[trans._coro_try_stack_count - 1])
llvmlite.build_br(builder, tbb)
else:
done_x: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, done_x, trans._coro_done_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
# 正常路径:存父帧 await 槽(若非 None)+ 挂起
llvmlite.position_at_end(builder, exc_ok_bb)
slot: llvmlite.Value* = trans._coro_await_slot
if slot is not None:
llvmlite.build_store(builder, child_ret, slot)
# 父挂起:新状态号(与预扫描 DFS 序一致)
new_state: int = trans._coro_next_state
trans._coro_next_state = new_state + 1
st_v: llvmlite.Value* = llvmlite.const_int32(pool, new_state)
llvmlite.build_store(builder, st_v, trans._coro_state_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
# 恢复块 state{new_state}:立即 position(预建 case 块,后续翻译在此继续)
resume_bb: rawptr[llvmlite.BasicBlock] = self._get_state_bb(trans, new_state)
if resume_bb is not None:
llvmlite.position_at_end(builder, resume_bb)
return child_ret
# ============================================================
# coro.coro_run(帧) 内联翻译
# ============================================================
def translate_coro_run(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator*) -> llvmlite.Value*:
"""coro.coro_run(frame) 内联翻译:
参数是 Name 变量 → 经 _coro_var_async 反查 async 名 → _coro_frames
取帧类型 → bitcast 变量值到 Ptr(帧) → 循环 resume_<name>(frame) 直到
done != 0 → GEP [0,2] load ret 返回。
M1 无 coro_sleep 轮询(无 wake 槽),纯忙等直到协程完成。
"""
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
if cl is None or trans is None:
return llvmlite.const_int32(pool, 0)
if cl.args is None or len(cl.args) < 1:
return llvmlite.const_int32(pool, 0)
arg0: ast.AST* = cl.args.get(0)
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
return llvmlite.const_int32(pool, 0)
nm: ast.Name* = ast.Name*(arg0)
if nm.id is None:
return llvmlite.const_int32(pool, 0)
async_name: str = self._lookup_coro_var(trans, nm.id)
if async_name is None:
return llvmlite.const_int32(pool, 0)
frame_ty: llvmlite.LLVMType* = self._lookup_coro_frame(trans, async_name)
if frame_ty is None:
return llvmlite.const_int32(pool, 0)
frame_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, frame_ty)
# 帧变量值(i8* / Ptr(帧))→ bitcast 到 Ptr(帧)
frame_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg0, None, 0, trans)
if frame_val is None:
return llvmlite.const_int32(pool, 0)
frame_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, frame_val, frame_ptr_ty)
if frame_ptr is None:
return llvmlite.const_int32(pool, 0)
func: llvmlite.Function* = trans._cur_func
if func is None:
return llvmlite.const_int32(pool, 0)
rn_buf: str = pool.alloc(64)
if rn_buf is not None:
viperlib.snprintf(rn_buf, 64, "resume_%s", async_name)
resume_mangled: str = self.Gen.FuncGenBase._mangle_func_name(trans, rn_buf, 0)
if self.Gen.CallGenBase.find_func_in_module(mod, resume_mangled) is None:
return llvmlite.const_int32(pool, 0)
loop_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.loop")
check_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.check")
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.after")
if loop_bb is None or check_bb is None or after_bb is None:
return llvmlite.const_int32(pool, 0)
llvmlite.build_br(builder, loop_bb)
llvmlite.position_at_end(builder, loop_bb)
frame_ptr.Next = None
status: llvmlite.Value* = llvmlite.build_call(builder, resume_mangled, frame_ptr, 1, i32_ty, 0)
zero_cmp: llvmlite.Value* = llvmlite.const_int32(pool, 0)
done_cond: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, status, zero_cmp)
llvmlite.build_cond_br(builder, done_cond, after_bb, check_bb)
# M3:SUSPEND → wake 轮询(GetTickCount64 >= wake 或 wake==0 继续,否则 Sleep(1))
llvmlite.position_at_end(builder, check_bb)
wake_idx_r: int = self._lookup_coro_wake(trans, async_name)
if wake_idx_r < 0:
llvmlite.build_br(builder, loop_bb)
else:
i64_ty_r2: llvmlite.LLVMType* = llvmlite.Int64(pool)
wake_ptr_r: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i64_ty_r2, frame_ptr, wake_idx_r)
wake_v_r: llvmlite.Value* = llvmlite.build_load(builder, i64_ty_r2, wake_ptr_r)
now_v_r: llvmlite.Value* = llvmlite.build_call(builder, "GetTickCount64", None, 0, i64_ty_r2, 0)
not_wake_r: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, wake_v_r,
llvmlite.const_int64(pool, 0))
due_r: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_UGE, now_v_r, wake_v_r)
cont_r: llvmlite.Value* = llvmlite.build_or(builder, not_wake_r, due_r)
wsleep_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.wsleep")
wdue_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.wdue")
llvmlite.build_cond_br(builder, cont_r, wdue_bb, wsleep_bb)
llvmlite.position_at_end(builder, wsleep_bb)
sleep_one: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_call(builder, "Sleep", sleep_one, 1,
llvmlite.Void(pool), 0)
llvmlite.build_br(builder, loop_bb)
llvmlite.position_at_end(builder, wdue_bb)
llvmlite.build_br(builder, loop_bb)
llvmlite.position_at_end(builder, after_bb)
ret_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, frame_ty, i32_ty, frame_ptr, 2)
ret_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, ret_ptr)
return ret_val
# ============================================================
# 公共查询 / 登记
# ============================================================
def is_async_func(self, trans: HT.Translator*,
name: str) -> int:
"""查询 name 是否已注册为 async 函数(_async_funcs 表),1=是 0=否"""
if trans is None or name is None or trans._async_funcs is None:
return 0
cnt: int = trans._async_func_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._async_funcs) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return 1
return 0
def register_coro_var(self, trans: HT.Translator*,
var_name: str, func_name: str) -> int:
"""记录 变量名→async 函数名 映射(coro.coro_run 反查帧类型用)。
对齐 TPC HandlesAnnAssign.py L319-326。返回 0 成功。"""
if trans is None or var_name is None or func_name is None:
return 1
if trans._coro_var_async is None:
return 1
cnt: int = trans._coro_var_async_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_var_async) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
if pair[0] is not None and string.strcmp(pair[0], var_name) == 0:
return 0
if cnt >= HT.MAX_CORO_VARS:
return 1
pair2_addr: uint64 = uint64(trans._coro_var_async) + cnt * 16
pair2: str | t.CPtr = (str | t.CPtr)(pair2_addr)
pair2[0] = var_name
pair2[1] = func_name
trans._coro_var_async_count = cnt + 1
return 0
def _register_async_func(self, trans: HT.Translator*,
name: str) -> int:
"""注册 async 函数裸名到 _async_funcs 表"""
if trans is None or name is None or trans._async_funcs is None:
return 1
cnt: int = trans._async_func_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._async_funcs) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return 0
if cnt >= HT.MAX_CORO_FUNCS:
return 1
addr2: uint64 = uint64(trans._async_funcs) + cnt * 8
slot2: str | t.CPtr = (str | t.CPtr)(addr2)
slot2[0] = name
trans._async_func_count = cnt + 1
return 0
def _register_coro_frame(self, trans: HT.Translator*,
name: str,
frame_ty: llvmlite.LLVMType*) -> int:
"""注册 async 名→帧类型 到 _coro_frames 表(16 字节/项 = char* + LLVMType*)"""
if trans is None or name is None or frame_ty is None:
return 1
if trans._coro_frames is None:
return 1
cnt: int = trans._coro_frame_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_frames) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
if pair[0] is not None and string.strcmp(pair[0], name) == 0:
pair[1] = str(frame_ty)
return 0
if cnt >= HT.MAX_CORO_FUNCS:
return 1
pair2_addr: uint64 = uint64(trans._coro_frames) + cnt * 16
pair2: str | t.CPtr = (str | t.CPtr)(pair2_addr)
pair2[0] = name
pair2[1] = str(frame_ty)
trans._coro_frame_count = cnt + 1
return 0
def _lookup_coro_frame(self, trans: HT.Translator*,
name: str) -> llvmlite.LLVMType*:
"""按 async 名查帧类型,未命中返回 None"""
if trans is None or name is None or trans._coro_frames is None:
return None
cnt: int = trans._coro_frame_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_frames) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
if pair[0] is not None and string.strcmp(pair[0], name) == 0:
if pair[1] is not None:
ty_addr: sizet = sizet(pair[1])
return (llvmlite.LLVMType*)(ty_addr)
return None
return None
def _lookup_coro_var(self, trans: HT.Translator*,
var_name: str) -> str:
"""按变量名反查 async 函数名(_coro_var_async 表),未命中返回 None"""
if trans is None or var_name is None or trans._coro_var_async is None:
return None
cnt: int = trans._coro_var_async_count
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_var_async) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
if pair[0] is not None and string.strcmp(pair[0], var_name) == 0:
return pair[1]
return None
# ============================================================
# 段翻译辅助
# ============================================================
def _emit_coro_return(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
stmt: ast.AST*) -> None:
"""协程内 Return 特判:store ret 槽 + done=1 + br exit。
M1 不支持 return await(顶层 await 仅限 AnnAssign/Assign)。
注意:stmt 以 ast.AST 基类型传入,AST 基类没有 value 字段
(base.vp 仅 parent/pool/lineno/col/children),直接 stmt.value
读到的是非法偏移(0/垃圾)→ ret 恒 0。必须转回 ast.Return 再取。"""
rv_node: rawptr[ast.Return] = rawptr[ast.Return](stmt)
ret_val: llvmlite.Value* = None
if rv_node is not None and rv_node.value is not None:
if rv_node.value.kind() != ast.ASTKind.Await:
ret_val = self.Gen.ExprGen.translate_value(builder, pool, mod, rv_node.value, None, 0, trans)
if ret_val is None:
ret_val = llvmlite.const_int32(pool, 0)
llvmlite.build_store(builder, ret_val, trans._coro_ret_ptr)
done_one: llvmlite.Value* = llvmlite.const_int32(pool, 1)
llvmlite.build_store(builder, done_one, trans._coro_done_ptr)
llvmlite.build_br(builder, trans._coro_exit_bb)
def _expr_await_is_sleep(self, aw: rawptr[ast.Await]) -> int:
"""Await 目标是否为 coro_sleep(Name 或 coro.coro_sleep)"""
if aw is None or aw.value is None:
return 0
if aw.value.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(aw.value)
if cl.func is None:
return 0
if cl.func.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(cl.func)
if nm.id is not None and string.strcmp(nm.id, "coro_sleep") == 0:
return 1
elif cl.func.kind() == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0:
return 1
return 0
def _is_await_tail(self, stmt: ast.AST*) -> int:
"""判断语句是否为段尾:AnnAssign/Assign/Expr 且 value 直接是 Await"""
if stmt is None:
return 0
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.value is not None and aa.value.kind() == ast.ASTKind.Await:
return 1
elif sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.value is not None and as_.value.kind() == ast.ASTKind.Await:
if as_.targets is not None and len(as_.targets) == 1:
return 1
elif sk == ast.ASTKind.Expr:
e: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
if e.value is not None and e.value.kind() == ast.ASTKind.Await:
return 1
return 0
def _get_assign_target_name(self, stmt: ast.AST*) -> str:
"""取 AnnAssign(target=Name)/Assign(单 target=Name) 的目标名,未命中返回 None"""
if stmt is None:
return None
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
tn: ast.Name* = ast.Name*(aa.target)
return tn.id
elif sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.targets is not None and len(as_.targets) == 1:
t0: ast.AST* = as_.targets.get(0)
if t0 is not None and t0.kind() == ast.ASTKind.Name:
tn2: ast.Name* = ast.Name*(t0)
return tn2.id
return None
def _get_await_value(self, stmt: ast.AST*) -> rawptr[ast.Await]:
"""取段尾语句的 Await value 节点,未命中返回 None"""
if stmt is None:
return None
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.value is not None and aa.value.kind() == ast.ASTKind.Await:
return rawptr[ast.Await](aa.value)
elif sk == ast.ASTKind.Assign:
as_: ast.Assign* = ast.Assign*(stmt)
if as_.value is not None and as_.value.kind() == ast.ASTKind.Await:
return rawptr[ast.Await](as_.value)
elif sk == ast.ASTKind.Expr:
ex: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
if ex.value is not None and ex.value.kind() == ast.ASTKind.Await:
return rawptr[ast.Await](ex.value)
return None
def _extract_await_call_name(self, aw_node: rawptr[ast.Await]) -> str:
"""从 Await(value=Call(func)) 提取 async 函数名或 coro_sleep,未命中返回 None"""
if aw_node is None or aw_node.value is None:
return None
if aw_node.value.kind() == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(aw_node.value)
if cl.func is not None:
if cl.func.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(cl.func)
return nm.id
if cl.func.kind() == ast.ASTKind.Attribute:
# coro.coro_sleep(ms):M3 sleep 挂起
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.attr is not None and string.strcmp(at.attr, "coro_sleep") == 0:
return "coro_sleep"
return None
def _read_local_name(self, trans: HT.Translator*,
idx: int) -> str:
"""读 trans._coro_locals 第 idx 个局部变量名,越界返回 None"""
if trans is None or trans._coro_locals is None:
return None
addr: uint64 = uint64(trans._coro_locals) + idx * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
return slot[0]