同 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)与本迁移无关,保持不动。
2660 lines
131 KiB
Plaintext
2660 lines
131 KiB
Plaintext
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]
|