Files
TransPyC/lib/core/Handles/HandlesAsyncFunctions.py
T
TermiNexus 8b9e88287a feat(coro): M6——raise 异常类型 + 多 except 类型匹配
- raise 支持异常类型名/调用(EXCEPTION_CODE_MAP/exception_registry → 异常码),
  普通表达式仍走值路径
- _HandleCoroTry 多 except dispatch:独立 check_bbs 链式匹配 exc 码(含子类码
  集合),命中进入对应 handler,全不匹配重新终止传播;Exception/裸 except 捕获所有
- CoroTest 验证:raise ValueError 匹配 except ValueError → 1;
  raise KeyError 匹配 except KeyError → 2(gather 并发)
2026-08-21 14:32:52 +08:00

1282 lines
67 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, EXCEPTION_CODE_MAP
from lib.includes import t
class AsyncFunctionHandle(BaseHandle):
"""语言内协程 M3:async def + await + coro_run 状态机翻译。
M3 在 M2 基础上扩展:
- For 内 await:range 迭代变换为 While(__f_idx_N/__f_len_N 帧槽),复用协程版 While。
- coro_sleep(ms):帧加 wake 槽(i64),挂起后 coro_run 轮询 GetTickCount64 到点续跑。
- coro_destroy(帧):释放帧内存(free)。
M2 能力:async 参数、嵌套 await 提升(__await_N 槽)、If/While 控制流、动态状态号恢复块。
帧布局:%Coro_<name> = type { i32 state, i32 done, i32 ret, i32 exc, <参数槽>, <局部槽>, <额外槽(wake/for/await)> }
状态机:create_<name>(args...) 分配帧 + 存参数;resume_<name>(frame) -> i32
(0=SUSPEND 1=DONE)按 state 分发到主入口 state0 与各恢复块。
"""
# ------------------------------------------------------------------
# 公共查询
# ------------------------------------------------------------------
def _IsAsyncFunc(self, name: str) -> bool:
Gen: LlvmCodeGenerator | None = getattr(self.Trans, 'LlvmGen', None)
if Gen is None:
return False
return name in getattr(Gen, '_async_funcs', {})
def _RegisterAsyncFunc(self, name: str, Node: ast.AsyncFunctionDef) -> None:
Gen: LlvmCodeGenerator | None = getattr(self.Trans, 'LlvmGen', None)
if Gen is None:
return
if not hasattr(Gen, '_async_funcs'):
Gen._async_funcs = {}
Gen._async_funcs[name] = {'node': Node}
def _GetAsyncCallName(self, call: ast.Call) -> str | None:
if isinstance(call.func, ast.Name):
name: str = call.func.id
if self._IsAsyncFunc(name):
return name
return None
def _IsCoroModule(self, name: str) -> bool:
if name == 'coro':
return True
aliases: Any = getattr(self.Trans.SymbolTable, 'import_aliases', {})
return aliases.get(name) == 'coro'
# ------------------------------------------------------------------
# 入口:async 函数定义
# ------------------------------------------------------------------
def _EmitAsyncFunctionLlvm(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> None:
name: str = Node.name
# 防重复生成:模块可能被多次编译(泛型特化等触发),避免 create_/resume_ 重名
if f'create_{name}' in Gen.functions or name in getattr(Gen, '_coro_frame_types', {}):
return
self._RegisterAsyncFunc(name, Node)
# 预扫描额外槽(嵌套 await 临时变量 + For 索引/上限 + coro_sleep 唤醒槽)
extra_slots: list[str] = self._PreScanExtraSlots(Node, Gen)
if not hasattr(Gen, '_coro_extra_slots'):
Gen._coro_extra_slots = {}
Gen._coro_extra_slots[name] = extra_slots
# 保存外层 Gen 状态(create/resume 生成期间会切换 builder/func/variables)
saved_builder: ir.IRBuilder | None = Gen.builder
saved_func: Any = Gen.func
saved_variables: Any = Gen.variables
saved_reg_values: Any = Gen._reg_values
saved_direct_values: Any = Gen._direct_values
saved_var_signedness: Any = Gen.var_signedness
saved_var_struct_class: Any = Gen.var_struct_class
saved_var_type_info: Any = Gen.var_type_info
saved_var_type_assignments: Any = Gen.var_type_assignments
saved_var_scope_len: int = len(self.Trans.VarScopes)
saved_loop_len: int = len(Gen.loop_break_targets)
saved_cont_len: int = len(Gen.loop_continue_targets)
saved_coro_state = {
'state_ptr': getattr(Gen, '_coro_state_ptr', None),
'done_ptr': getattr(Gen, '_coro_done_ptr', None),
'ret_ptr': getattr(Gen, '_coro_ret_field_ptr', None),
'exit_bb': getattr(Gen, '_coro_exit_bb', None),
'next_state': getattr(Gen, '_coro_next_state', None),
'await_slot': getattr(Gen, '_coro_await_slot_ptr', None),
'frame_ptr': getattr(Gen, '_coro_frame_ptr', None),
'switch': getattr(Gen, '_coro_switch_instr', None),
'state_counter': getattr(Gen, '_coro_state_counter', None),
'hoist_counter': getattr(Gen, '_coro_hoist_counter', None),
'for_counter': getattr(Gen, '_coro_for_counter', None),
'wake_ptr': getattr(Gen, '_coro_wake_ptr', None),
'exc_ptr': getattr(Gen, '_coro_exc_ptr', None),
'try_stack': getattr(Gen, '_coro_try_stack', None),
}
try:
self.Trans.VarScopes.append({})
frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen, extra_slots)
Gen._coro_hoist_counter = 0
Gen._coro_for_counter = 0
self._EmitCreateFunction(name, Node, frame_ty, Gen)
self._EmitResumeFunction(name, Node, frame_ty, Gen)
# 符号表注册(普通名称),供 _HandleCallLlvm 的类型解析
if not self.Trans.SymbolTable.has(name):
FuncInfo: CTypeInfo = CTypeInfo()
FuncInfo.Name = name
FuncInfo.IsFunction = True
FuncInfo.file = '<stdin>'
self.Trans.SymbolTable.insert(name, FuncInfo)
self.Trans.FunctionReturnTypes[name] = CTypeInfo.FromTypeName('int')
finally:
while len(self.Trans.VarScopes) > saved_var_scope_len:
self.Trans.VarScopes.pop()
del Gen.loop_break_targets[saved_loop_len:]
del Gen.loop_continue_targets[saved_cont_len:]
Gen.builder = saved_builder
Gen.func = saved_func
Gen.variables = saved_variables
Gen._reg_values = saved_reg_values
Gen._direct_values = saved_direct_values
Gen.var_signedness = saved_var_signedness
Gen.var_struct_class = saved_var_struct_class
Gen.var_type_info = saved_var_type_info
Gen.var_type_assignments = saved_var_type_assignments
Gen._coro_state_ptr = saved_coro_state['state_ptr']
Gen._coro_done_ptr = saved_coro_state['done_ptr']
Gen._coro_ret_field_ptr = saved_coro_state['ret_ptr']
Gen._coro_exit_bb = saved_coro_state['exit_bb']
Gen._coro_next_state = saved_coro_state['next_state']
Gen._coro_await_slot_ptr = saved_coro_state['await_slot']
Gen._coro_frame_ptr = saved_coro_state['frame_ptr']
Gen._coro_switch_instr = saved_coro_state['switch']
Gen._coro_state_counter = saved_coro_state['state_counter']
Gen._coro_hoist_counter = saved_coro_state['hoist_counter']
Gen._coro_for_counter = saved_coro_state['for_counter']
Gen._coro_wake_ptr = saved_coro_state['wake_ptr']
Gen._coro_exc_ptr = saved_coro_state['exc_ptr']
Gen._coro_try_stack = saved_coro_state['try_stack']
# ------------------------------------------------------------------
# 帧结构体与局部变量收集
# ------------------------------------------------------------------
def _ResolveSlotType(self, annotation: ast.expr | None, Gen: LlvmCodeGenerator) -> ir.Type:
"""从注解推断帧槽 LLVM 类型;失败/void/结构体值一律按安全标量处理。"""
if annotation is None:
return ir.IntType(32)
try:
TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
except Exception:
TypeInfo = None
if TypeInfo is None:
return ir.IntType(32)
try:
llvm_ty: ir.Type | None = TypeInfo.ToLLVM(Gen)
except Exception:
return ir.IntType(32)
if llvm_ty is None or isinstance(llvm_ty, ir.VoidType):
return ir.IntType(32)
if isinstance(llvm_ty, ir.IdentifiedStructType):
llvm_ty = ir.PointerType(llvm_ty)
return llvm_ty
def _CollectFrameVars(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> list[tuple[str, ir.Type]]:
"""递归收集协程体内所有 AnnAssign/Assign 的 Name 目标及其槽类型(含控制流内部)。"""
vars_: list[tuple[str, ir.Type]] = []
seen: set[str] = set()
def _walk(stmts: list[ast.stmt]) -> None:
for stmt in stmts:
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
target: str = stmt.target.id
slot_ty: ir.Type = self._ResolveSlotType(stmt.annotation, Gen)
elif (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)):
target = stmt.targets[0].id
slot_ty = ir.IntType(32)
elif isinstance(stmt, ast.For):
# For 迭代目标进帧槽(协程版 For 变换后跨挂起存活)
if isinstance(stmt.target, ast.Name):
_tname: str = stmt.target.id
if _tname not in seen:
seen.add(_tname)
vars_.append((_tname, ir.IntType(32)))
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
elif isinstance(stmt, (ast.If, ast.While)):
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
elif isinstance(stmt, ast.Try):
# except X as e:e 进帧槽(异常码)
for _h in stmt.handlers:
if _h.name and _h.name not in seen:
seen.add(_h.name)
vars_.append((_h.name, ir.IntType(32)))
_walk(stmt.body)
for _h in stmt.handlers:
_walk(_h.body)
if stmt.orelse:
_walk(stmt.orelse)
if stmt.finalbody:
_walk(stmt.finalbody)
continue
else:
continue
if target not in seen:
seen.add(target)
vars_.append((target, slot_ty))
_walk(Node.body)
return vars_
def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator, extra_slots: list[str]) -> ir.IdentifiedStructType:
if not hasattr(Gen, '_coro_frame_types'):
Gen._coro_frame_types = {}
if not hasattr(Gen, '_coro_slot_vars'):
Gen._coro_slot_vars = {}
if not hasattr(Gen, '_coro_param_vars'):
Gen._coro_param_vars = {}
if name in Gen._coro_frame_types:
return Gen._coro_frame_types[name]
# 参数:名字 + LLVM 类型
params: list[tuple[str, ir.Type]] = []
for a in Node.args.args:
pname: str = a.arg
pty: ir.Type = self._ResolveSlotType(a.annotation, Gen)
params.append((pname, pty))
locals_: list[tuple[str, ir.Type]] = self._CollectFrameVars(Node, Gen)
param_names: set[str] = {p for p, _ in params}
# 额外槽:__coro_wake_us(i64) / __f_idx_N/__f_len_N / __await_N(i32)
fields: list[ir.Type] = [
ir.IntType(32), # 0: state
ir.IntType(32), # 1: done
ir.IntType(32), # 2: ret
ir.IntType(32), # 3: exc(异常码,0=无异常)
]
slot_vars: list[str] = []
for pname, pty in params:
fields.append(pty)
slot_vars.append(pname)
for lname, lty in locals_:
if lname in param_names or lname in slot_vars:
continue
fields.append(lty)
slot_vars.append(lname)
for sname in extra_slots:
fields.append(ir.IntType(64) if sname == '__coro_wake_us' else ir.IntType(32))
slot_vars.append(sname)
frame_ty: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f'Coro_{name}')
frame_ty.set_body(*fields)
Gen._coro_frame_types[name] = frame_ty
Gen.structs[f'Coro_{name}'] = frame_ty
Gen._coro_slot_vars[name] = slot_vars
Gen._coro_param_vars[name] = params
return frame_ty
# ------------------------------------------------------------------
# 预扫描:嵌套 await 提升(分配 __await_N 临时槽)
# ------------------------------------------------------------------
def _PreScanExtraSlots(self, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> list[str]:
"""按 DFS 顺序收集额外帧槽名(与翻译端分配顺序一致):
- __coro_wake_us:函数体使用 coro_sleep 时置首位(i64 槽)
- __f_idx_N / __f_len_N:range-For(body 含 await)的迭代索引/上限
- __await_N:嵌套 await 提升临时变量
"""
slots: list[str] = []
await_counter: int = 0
for_counter: int = 0
uses_sleep: list[bool] = [False]
def _walk(stmts: list[ast.stmt]) -> None:
nonlocal await_counter, for_counter
for stmt in stmts:
if isinstance(stmt, (ast.If, ast.While)):
_walk(stmt.body)
if stmt.orelse:
_walk(stmt.orelse)
continue
if isinstance(stmt, ast.Try):
_walk(stmt.body)
for _h in stmt.handlers:
_walk(_h.body)
if stmt.orelse:
_walk(stmt.orelse)
if stmt.finalbody:
_walk(stmt.finalbody)
continue
if isinstance(stmt, ast.For):
if not any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
continue # 无 await:委托 ForHandler,不需额外槽
if not self._IsRangeFor(stmt):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(stmt, 'lineno', 0)})"
)
slots.append(f'__f_idx_{for_counter}')
slots.append(f'__f_len_{for_counter}')
for_counter += 1
_walk(stmt.body)
continue
# 顶层 await(value 直接是 Await)不提升,但仍检测 coro_sleep
if (isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)) or (
isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Await)):
for _n in ast.walk(stmt):
if isinstance(_n, ast.Call) and self._IsCoroSleepCall(_n):
uses_sleep[0] = True
continue
for n in ast.walk(stmt):
if isinstance(n, ast.Await):
slots.append(f'__await_{await_counter}')
await_counter += 1
if isinstance(n, ast.Call) and self._IsCoroSleepCall(n):
uses_sleep[0] = True
_walk(Node.body)
if uses_sleep[0]:
slots.insert(0, '__coro_wake_us')
return slots
# ------------------------------------------------------------------
# create_<name>(args...) -> %Coro_<name>*
# ------------------------------------------------------------------
def _GetMalloc(self, Gen: LlvmCodeGenerator) -> ir.Function:
for fn in Gen.module.global_values:
if getattr(fn, 'name', None) == 'malloc':
return fn
malloc_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
fn: ir.Function = ir.Function(Gen.module, malloc_ty, name='malloc')
Gen.functions['malloc'] = fn
return fn
def _RegisterCoroFunction(self, Gen: LlvmCodeGenerator, raw_name: str, fn: ir.Function) -> None:
"""按 _EmitFunctionForwardDeclLlvm 惯例注册 create_/resume_ 函数。"""
mangled: str = Gen._mangle_func_name(raw_name)
Gen.functions[mangled] = fn
if mangled == raw_name or raw_name not in Gen._export_extern_funcs:
Gen.functions[raw_name] = fn
def _EmitCreateFunction(self, name: str, Node: ast.AsyncFunctionDef, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
malloc_fn: ir.Function = self._GetMalloc(Gen)
frame_size: int = Gen._get_struct_size(frame_ty)
params: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(name, [])
param_tys: list[ir.Type] = [ty for _, ty in params]
create_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(frame_ty), param_tys)
create_fn: ir.Function = ir.Function(Gen.module, create_ty, name=Gen._mangle_func_name(f'create_{name}'))
self._RegisterCoroFunction(Gen, f'create_{name}', create_fn)
create_fn.attributes.add('noredzone')
entry: ir.Block = create_fn.append_basic_block('entry')
Gen.builder = ir.IRBuilder(entry)
Gen.func = create_fn
raw: ir.Value = Gen.builder.call(malloc_fn, [ir.Constant(ir.IntType(64), frame_size)], name='frame_raw')
frame_ptr: ir.Value = Gen.builder.bitcast(raw, ir.PointerType(frame_ty), name='frame')
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
for i in range(4):
slot_ptr: ir.Value = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), i)], name=f'init_slot{i}')
Gen._store(zero32, slot_ptr)
# 参数存入帧槽(4 + i)
for i in range(len(params)):
slot_ptr = Gen.builder.gep(frame_ptr, [zero32, ir.Constant(ir.IntType(32), 4 + i)], name=f'param{i}_slot')
arg_val: ir.Argument = create_fn.args[i]
arg_val.name = f'arg{i}'
Gen._store(arg_val, slot_ptr)
Gen.builder.ret(frame_ptr)
Gen.builder = None
Gen.func = None
# ------------------------------------------------------------------
# resume_<name>(%Coro_<name>*) -> i32 状态机(动态状态号)
# ------------------------------------------------------------------
def _EmitResumeFunction(self, name: str, Node: ast.AsyncFunctionDef, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None:
resume_ty: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ir.PointerType(frame_ty)])
resume_fn: ir.Function = ir.Function(Gen.module, resume_ty, name=Gen._mangle_func_name(f'resume_{name}'))
self._RegisterCoroFunction(Gen, f'resume_{name}', resume_fn)
resume_fn.attributes.add('noredzone')
Gen.func = resume_fn
entry: ir.Block = resume_fn.append_basic_block('entry')
Gen.builder = ir.IRBuilder(entry)
frame_arg: ir.Argument = resume_fn.args[0]
frame_arg.name = 'frame'
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
one32: ir.Constant = ir.Constant(ir.IntType(32), 1)
two32: ir.Constant = ir.Constant(ir.IntType(32), 2)
state_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, zero32], name='state_ptr')
done_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, one32], name='done_ptr')
ret_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, two32], name='ret_ptr')
# 槽指针 → Gen.variables(读取/写入自动走帧字段 GEP)
local_slot_ptrs: dict[str, ir.Value] = {}
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(name, [])
for idx, var in enumerate(slot_vars):
slot_ptr: ir.Value = Gen.builder.gep(
frame_arg,
[zero32, ir.Constant(ir.IntType(32), 4 + idx)],
name=f'{var}_slot',
)
local_slot_ptrs[var] = slot_ptr
if var == '__coro_wake_us':
Gen._coro_wake_ptr = slot_ptr
state_val: ir.Value = Gen._load(state_ptr, name='state')
exit_bb: ir.Block = resume_fn.append_basic_block('coro_exit')
Gen._coro_state_ptr = state_ptr
Gen._coro_done_ptr = done_ptr
Gen._coro_ret_field_ptr = ret_ptr
exc_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, ir.Constant(ir.IntType(32), 3)], name='exc_ptr')
Gen._coro_exc_ptr = exc_ptr
Gen._coro_exit_bb = exit_bb
Gen._coro_frame_ptr = frame_arg
switch_instr: Any = Gen.builder.switch(state_val, exit_bb)
Gen._coro_switch_instr = switch_instr
Gen._coro_state_counter = 1
state0: ir.Block = resume_fn.append_basic_block('state0')
switch_instr.add_case(ir.Constant(ir.IntType(32), 0), state0)
# 主入口:翻译整个函数体(If/While 内 await 会动态分配恢复块)
Gen.builder.position_at_start(state0)
Gen.variables = dict(local_slot_ptrs)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
self._EmitCoroImplicitReturn(Gen)
# 完成块:返回 done(0=SUSPEND 1=DONE)
Gen.builder.position_at_start(exit_bb)
done_val: ir.Value = Gen._load(done_ptr, name='done')
Gen.builder.ret(done_val)
Gen.builder = None
Gen.func = None
# ------------------------------------------------------------------
# 协程体段翻译
# ------------------------------------------------------------------
def _HandleCoroSegment(self, stmts: list[ast.stmt], Gen: LlvmCodeGenerator) -> None:
for stmt in stmts:
if Gen.builder is None or Gen.builder.block.is_terminated:
return
Gen._set_node_info(stmt)
if isinstance(stmt, ast.Return):
self._HandleCoroReturn(stmt, Gen)
continue
if isinstance(stmt, ast.Raise):
self._HandleCoroRaiseLlvm(stmt, Gen)
continue
if (isinstance(stmt, ast.AnnAssign)
and isinstance(stmt.target, ast.Name)
and isinstance(stmt.value, ast.Await)):
self._HandleCoroAwaitAnnAssign(stmt, Gen)
continue
if (isinstance(stmt, ast.Assign)
and len(stmt.targets) == 1
and isinstance(stmt.targets[0], ast.Name)
and isinstance(stmt.value, ast.Await)):
self._HandleCoroAwaitAssign(stmt, Gen)
continue
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Await):
self._HandleCoroAwaitCommon('__discard__', stmt.value, Gen)
continue
if isinstance(stmt, ast.If):
self._HandleCoroIf(stmt, Gen)
continue
if isinstance(stmt, ast.While):
self._HandleCoroWhile(stmt, Gen)
continue
if isinstance(stmt, ast.Try):
self._HandleCoroTry(stmt, Gen)
continue
if isinstance(stmt, ast.For):
self._HandleCoroFor(stmt, Gen)
continue
if isinstance(stmt, ast.Break):
if Gen.loop_break_targets:
Gen.builder.branch(Gen.loop_break_targets[-1])
continue
if isinstance(stmt, ast.Continue):
if Gen.loop_continue_targets:
Gen.builder.branch(Gen.loop_continue_targets[-1])
continue
if isinstance(stmt, ast.Pass):
continue
# 语句内嵌套 await(非顶层)→ 提升
if any(isinstance(n, ast.Await) for n in ast.walk(stmt)):
self._HandleNestedAwaitStmt(stmt, Gen)
continue
self._TranslateOrdinaryStmt(stmt, Gen)
def _TranslateOrdinaryStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
if isinstance(stmt, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt)
return
if isinstance(stmt, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(stmt)
return
if isinstance(stmt, ast.Expr):
self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
return
raise SyntaxError(
f"[coro-M2] async 函数体暂不支持语句: {type(stmt).__name__} "
f"(line {getattr(stmt, 'lineno', 0)})"
)
# ------------------------------------------------------------------
# 嵌套 await 提升:a = b + await f() → __await_N = await f(); a = b + __await_N
# ------------------------------------------------------------------
def _FindFirstAwait(self, node: ast.AST) -> ast.Await | None:
for n in ast.walk(node):
if isinstance(n, ast.Await):
return n
return None
def _ReplaceAwaitWithName(self, node: ast.AST, temp_name: str) -> bool:
"""把语句树中第一个 Await 替换为 Name(temp_name, Load)(DFS 顺序)。"""
for field in node._fields:
val: Any = getattr(node, field, None)
if isinstance(val, ast.Await):
setattr(node, field, ast.Name(temp_name, ast.Load()))
return True
if isinstance(val, list):
for i, item in enumerate(val):
if isinstance(item, ast.Await):
val[i] = ast.Name(temp_name, ast.Load())
return True
if isinstance(item, ast.AST):
if self._ReplaceAwaitWithName(item, temp_name):
return True
elif isinstance(val, ast.AST):
if self._ReplaceAwaitWithName(val, temp_name):
return True
return False
def _HandleNestedAwaitStmt(self, stmt: ast.stmt, Gen: LlvmCodeGenerator) -> None:
"""把语句中所有嵌套 await 提升为顶层临时赋值(与预扫描顺序一致)。"""
counter: int = getattr(Gen, '_coro_hoist_counter', 0)
while True:
await_node: ast.Await | None = self._FindFirstAwait(stmt)
if await_node is None:
break
temp_name: str = f'__await_{counter}'
counter += 1
hoisted: ast.Assign = ast.Assign(
targets=[ast.Name(temp_name, ast.Store())],
value=await_node,
type_comment=None,
)
# 提升赋值挂起 + position 到恢复块
self._HandleCoroAwaitAssign(hoisted, Gen)
self._ReplaceAwaitWithName(stmt, temp_name)
Gen._coro_hoist_counter = counter
self._TranslateOrdinaryStmt(stmt, Gen)
# ------------------------------------------------------------------
# await 表达式翻译
# ------------------------------------------------------------------
def _HandleCoroAwaitAnnAssign(self, stmt: ast.AnnAssign, Gen: LlvmCodeGenerator) -> None:
target: str = stmt.target.id
self._HandleCoroAwaitCommon(target, stmt.value, Gen)
# 注册作用域信息(模拟 AnnAssignHandler 的局部变量路径)
TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(stmt.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
if self.Trans.VarScopes:
self.Trans.VarScopes[-1][target] = TypeInfo
Gen._record_var_signedness(target, False)
def _HandleCoroAwaitAssign(self, stmt: ast.Assign, Gen: LlvmCodeGenerator) -> None:
target: str = stmt.targets[0].id
self._HandleCoroAwaitCommon(target, stmt.value, Gen)
Gen._record_var_signedness(target, False)
def _HandleCoroAwaitCommon(self, target: str, await_node: ast.Await, Gen: LlvmCodeGenerator) -> None:
"""await 顶层翻译:设置目标槽后调用 _HandleAwaitLlvm(生成子帧/resume/挂起)。"""
if target == '__ret__':
Gen._coro_await_slot_ptr = getattr(Gen, '_coro_ret_field_ptr', None)
else:
Gen._coro_await_slot_ptr = Gen.variables.get(target)
# 校验 await 目标:async 函数调用 或 coro_sleep(ms)
call: Any = await_node.value
if isinstance(call, ast.Call) and self._IsCoroSleepCall(call):
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm(sleep)
return
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
raise SyntaxError(
f"[coro-M3] await 目标必须是 async 函数调用或 coro_sleep(ms) "
f"(line {getattr(await_node, 'lineno', 0)})"
)
self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm
def _IsCoroSleepCall(self, call: ast.Call) -> bool:
return (isinstance(call.func, ast.Name) and call.func.id == 'coro_sleep') or (
isinstance(call.func, ast.Attribute)
and call.func.attr == 'coro_sleep'
and isinstance(call.func.value, ast.Name)
and self._IsCoroModule(call.func.value.id)
)
def _GetWinFunc(self, name: str, Gen: LlvmCodeGenerator, ret_ty: ir.Type,
args: list[ir.Type] | None = None) -> ir.Function:
fn: ir.Function | None = Gen._get_function(name)
if fn is not None:
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ret_ty, args or []), name=name)
Gen.functions[name] = fn
return fn
def _GetFree(self, Gen: LlvmCodeGenerator) -> ir.Function:
for fn in Gen.module.global_values:
if getattr(fn, 'name', None) == 'free':
return fn
fn = ir.Function(Gen.module, ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]), name='free')
Gen.functions['free'] = fn
return fn
def _HandleAwaitSleepLlvm(self, call: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""await coro_sleep(ms):wake = GetTickCount64() + ms 存帧,挂起(coro_run 轮询续跑)。"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
ms_val: ir.Value = ir.Constant(ir.IntType(64), 0)
if call.args:
ms_v: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(call.args[0])
if ms_v is not None and isinstance(ms_v.type, ir.IntType):
if ms_v.type.width < 64:
ms_val = Gen.builder.zext(ms_v, ir.IntType(64), name='zext_sleep_ms')
elif ms_v.type.width > 64:
ms_val = Gen.builder.trunc(ms_v, ir.IntType(64), name='trunc_sleep_ms')
else:
ms_val = ms_v
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
wake_val: ir.Value = Gen.builder.add(now_val, ms_val, name='coro_wake_us')
wake_ptr: ir.Value | None = getattr(Gen, '_coro_wake_ptr', None)
if wake_ptr is not None:
Gen._store(wake_val, wake_ptr)
# 挂起:分配恢复块 + state + ret=0 + br exit + position 恢复块
state_no: int = getattr(Gen, '_coro_state_counter', 1)
Gen._coro_state_counter = state_no + 1
resume_bb: ir.Block = Gen.func.append_basic_block(f'state{state_no}')
switch_instr: Any = getattr(Gen, '_coro_switch_instr', None)
if switch_instr is not None:
switch_instr.add_case(ir.Constant(ir.IntType(32), state_no), resume_bb)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), state_no), state_ptr)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
Gen.builder.position_at_start(resume_bb)
return zero32
def _HandleCoroDestroyLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_destroy(帧):释放帧内存(free)。"""
if not Node.args:
return ir.Constant(ir.IntType(32), 0)
arg: ast.expr = Node.args[0]
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
return ir.Constant(ir.IntType(32), 0)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
if not frame_ty:
return ir.Constant(ir.IntType(32), 0)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='coro_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='coro_frame')
else:
return ir.Constant(ir.IntType(32), 0)
free_fn: ir.Function = self._GetFree(Gen)
raw: ir.Value = Gen.builder.bitcast(frame_ptr, ir.IntType(8).as_pointer(), name='coro_free_ptr')
Gen.builder.call(free_fn, [raw])
return ir.Constant(ir.IntType(32), 0)
def _ResolveRaiseCode(self, exc_node: ast.expr) -> int | None:
"""解析 raise 目标的异常类型码(注册类/内置异常);普通表达式返回 None 走值路径。"""
name: str | None = None
if isinstance(exc_node, ast.Name):
name = exc_node.id
elif isinstance(exc_node, ast.Call) and isinstance(exc_node.func, ast.Name):
name = exc_node.func.id
elif isinstance(exc_node, ast.Attribute):
name = exc_node.attr
if name:
if name in EXCEPTION_CODE_MAP or name in getattr(self.Trans, 'exception_registry', {}):
try:
return self.Trans.RaiseHandler._get_exception_code(name)
except Exception:
return None
return None
def _HandleCoroRaiseLlvm(self, stmt: ast.Raise, Gen: LlvmCodeGenerator) -> None:
"""协程内 raise:异常类型/值 → 帧 exc 槽;try 内跳 except,否则终止协程。"""
exc_code: ir.Value = ir.Constant(ir.IntType(32), 1)
if stmt.exc is not None:
v: ir.Value | None = None
resolved: int | None = self._ResolveRaiseCode(stmt.exc)
if resolved is not None:
exc_code = ir.Constant(ir.IntType(32), resolved)
else:
v = self.Trans.ExprHandler.HandleExprLlvm(stmt.exc)
if v is not None:
if isinstance(v.type, ir.IntType):
if v.type.width < 32:
exc_code = Gen.builder.zext(v, ir.IntType(32), name='zext_exc')
elif v.type.width > 32:
exc_code = Gen.builder.trunc(v, ir.IntType(32), name='trunc_exc')
else:
exc_code = v
elif isinstance(v.type, ir.PointerType):
exc_code = Gen.builder.ptrtoint(v, ir.IntType(32), name='exc_ptr2int')
exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if exc_ptr is not None:
Gen._store(exc_code, exc_ptr)
coro_try_stack: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None)
if coro_try_stack:
Gen.builder.branch(coro_try_stack[-1])
return
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
def _HandleCoroExceptionLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_exception(帧):返回帧 exc 槽(异常码,0=无异常)。"""
if not Node.args:
return ir.Constant(ir.IntType(32), 0)
arg: ast.expr = Node.args[0]
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
return ir.Constant(ir.IntType(32), 0)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
if not frame_ty:
return ir.Constant(ir.IntType(32), 0)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='coro_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='coro_frame')
else:
return ir.Constant(ir.IntType(32), 0)
exc_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 3)],
name='coro_exc_ptr',
)
return Gen._load(exc_ptr, name='coro_exc')
def _CoerceArg(self, v: ir.Value | None, target_ty: ir.Type, Gen: LlvmCodeGenerator, name: str = 'arg') -> ir.Value:
"""实参转换到 create 形参类型(int 宽转换 / 指针 bitcast)。"""
if v is None:
if isinstance(target_ty, ir.IntType):
return ir.Constant(target_ty, 0)
return ir.Constant(target_ty, None)
src_ty: ir.Type = v.type
if src_ty == target_ty:
return v
if isinstance(src_ty, ir.IntType) and isinstance(target_ty, ir.IntType):
if src_ty.width < target_ty.width:
return Gen.builder.zext(v, target_ty, name=f'zext_{name}')
if src_ty.width > target_ty.width:
return Gen.builder.trunc(v, target_ty, name=f'trunc_{name}')
return v
if isinstance(src_ty, ir.PointerType) and isinstance(target_ty, ir.PointerType):
return Gen.builder.bitcast(v, target_ty, name=f'bitcast_{name}')
return v
def _HandleAwaitLlvm(self, Node: ast.Await, Gen: LlvmCodeGenerator) -> ir.Value:
"""await 表达式翻译:
创建子帧(含参数)-> resume 到 DONE -> 取子帧 ret -> 存父帧槽
-> 父挂起(state=新恢复块编号、ret=0)-> position 到恢复块继续。
"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
call: Any = Node.value
# M3: await coro_sleep(ms) —— 挂起到指定时刻(帧 wake 槽)
if isinstance(call, ast.Call) and self._IsCoroSleepCall(call):
return self._HandleAwaitSleepLlvm(call, Gen)
async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None
if not async_name:
return zero32
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
create_fn: ir.Function | None = Gen._get_function(f'create_{async_name}')
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
if not frame_ty or not create_fn or not resume_fn:
return zero32
# 子协程参数
call_args: list[ir.Value] = []
if call.args:
param_info: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(async_name, [])
for i, arg_node in enumerate(call.args):
arg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg_node)
if i < len(param_info):
arg_val = self._CoerceArg(arg_val, param_info[i][1], Gen, name=f'arg{i}')
call_args.append(arg_val)
child: ir.Value = Gen.builder.call(create_fn, call_args, name=f'create_{async_name}')
Gen.builder.call(resume_fn, [child], name=f'resume_{async_name}')
child_ret_ptr: ir.Value = Gen.builder.gep(
child,
[zero32, ir.Constant(ir.IntType(32), 2)],
name='child_ret_ptr',
)
child_ret: ir.Value = Gen._load(child_ret_ptr, name='child_ret')
# M4: 子协程异常传播——子帧 exc != 0 时父协程带异常终止
child_exc_ptr: ir.Value = Gen.builder.gep(
child,
[zero32, ir.Constant(ir.IntType(32), 3)],
name='child_exc_ptr',
)
child_exc: ir.Value = Gen._load(child_exc_ptr, name='child_exc')
normal_bb: ir.Block = Gen.func.append_basic_block('coro_ok')
exc_bb: ir.Block = Gen.func.append_basic_block('coro_exc')
exc_cond: ir.Value = Gen.builder.icmp_signed('==', child_exc, zero32, name='child_exc_ok')
Gen.builder.cbranch(exc_cond, normal_bb, exc_bb)
Gen.builder.position_at_start(exc_bb)
parent_exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if parent_exc_ptr is not None:
Gen._store(child_exc, parent_exc_ptr)
coro_try: list[ir.Block] | None = getattr(Gen, '_coro_try_stack', None)
if coro_try:
Gen.builder.branch(coro_try[-1])
else:
parent_done_ptr: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if parent_done_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), parent_done_ptr)
exit_bb_ref: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_ref is not None:
Gen.builder.branch(exit_bb_ref)
# 正常路径:存父帧局部变量槽 + 挂起
Gen.builder.position_at_start(normal_bb)
slot: ir.Value | None = getattr(Gen, '_coro_await_slot_ptr', None)
if slot is not None:
Gen._store(child_ret, slot)
# 父挂起:分配新恢复块(switch case),state=新块编号,ret=0(SUSPEND)
state_no: int = getattr(Gen, '_coro_state_counter', 1)
Gen._coro_state_counter = state_no + 1
resume_bb: ir.Block = Gen.func.append_basic_block(f'state{state_no}')
switch_instr: Any = getattr(Gen, '_coro_switch_instr', None)
if switch_instr is not None:
switch_instr.add_case(ir.Constant(ir.IntType(32), state_no), resume_bb)
state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None)
if state_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), state_no), state_ptr)
exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb is not None:
Gen.builder.branch(exit_bb)
Gen.builder.position_at_start(resume_bb)
return child_ret
def _HandleCoroReturn(self, stmt: ast.Return, Gen: LlvmCodeGenerator) -> None:
# return await x:await 直接存父帧 ret 槽(挂起前),恢复块仅完成协程
if stmt.value is not None and isinstance(stmt.value, ast.Await):
self._HandleCoroAwaitCommon('__ret__', stmt.value, Gen)
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb_r: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_r is not None:
Gen.builder.branch(exit_bb_r)
return
val: ir.Value | None = None
if stmt.value:
val = self.Trans.ExprHandler.HandleExprLlvm(stmt.value)
if val is None:
val = ir.Constant(ir.IntType(32), 0)
if isinstance(val.type, ir.IntType) and val.type.width != 32:
if val.type.width < 32:
val = Gen.builder.zext(val, ir.IntType(32), name='zext_coro_ret')
else:
val = Gen.builder.trunc(val, ir.IntType(32), name='trunc_coro_ret')
Gen._store(val, Gen._coro_ret_field_ptr)
Gen._store(ir.Constant(ir.IntType(32), 1), Gen._coro_done_ptr)
Gen.builder.branch(Gen._coro_exit_bb)
def _EmitCoroImplicitReturn(self, Gen: LlvmCodeGenerator) -> None:
"""函数体自然结束:同 return 路径(ret=0 + done=1)。"""
Gen._store(ir.Constant(ir.IntType(32), 0), Gen._coro_ret_field_ptr)
Gen._store(ir.Constant(ir.IntType(32), 1), Gen._coro_done_ptr)
Gen.builder.branch(Gen._coro_exit_bb)
# ------------------------------------------------------------------
# 控制流(协程版:body 内 await 就地挂起/恢复)
# ------------------------------------------------------------------
def _HandleCoroIf(self, Node: ast.If, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
raise SyntaxError(
f"[coro-M2] if 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
)
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_ifcond')
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_ifcond')
ThenBB: ir.Block = Gen.func.append_basic_block(name='coro_then')
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_else') if Node.orelse else None
MergeBB: ir.Block = Gen.func.append_basic_block(name='coro_endif')
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
Gen.builder.position_at_start(ThenBB)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self._HandleCoroSegment(Node.orelse, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if not MergeBB.is_terminated:
Gen.builder.position_at_start(MergeBB)
else:
Gen.builder.position_at_end(MergeBB)
def _HandleCoroWhile(self, Node: ast.While, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node.test)):
raise SyntaxError(
f"[coro-M2] while 条件中不支持 await (line {getattr(Node, 'lineno', 0)})"
)
CondBB: ir.Block = Gen.func.append_basic_block(name='coro_wcond')
BodyBB: ir.Block = Gen.func.append_basic_block(name='coro_wbody')
ElseBB: ir.Block | None = Gen.func.append_basic_block(name='coro_welse') if Node.orelse else None
AfterBB: ir.Block = Gen.func.append_basic_block(name='coro_wend')
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(CondBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if Cond:
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name='coro_wcond')
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name='coro_wcond')
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self._HandleCoroSegment(Node.orelse, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
if not AfterBB.is_terminated:
Gen.builder.position_at_start(AfterBB)
else:
Gen.builder.position_at_end(AfterBB)
def _HandleCoroTry(self, Node: ast.Try, Gen: LlvmCodeGenerator) -> None:
"""协程内 try/except:捕获 raise 与 await 传播异常(M6:多 except 类型匹配;Exception/裸 except 捕获所有)。"""
if not Node.handlers:
raise SyntaxError(
f"[coro-M6] 协程内 try 需要 except 子句 (line {getattr(Node, 'lineno', 0)})"
)
if Node.finalbody:
raise SyntaxError(
f"[coro-M6] 协程内暂不支持 try/finally (line {getattr(Node, 'lineno', 0)})"
)
except_bb: ir.Block = Gen.func.append_basic_block('coro_try_except')
merge_bb: ir.Block = Gen.func.append_basic_block('coro_try_merge')
if not getattr(Gen, '_coro_try_stack', None):
Gen._coro_try_stack = []
Gen._coro_try_stack.append(except_bb)
# try body
self._HandleCoroSegment(Node.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(merge_bb)
Gen._coro_try_stack.pop()
# ---- 异常分发:exc 码依次匹配各 except ----
Gen.builder.position_at_start(except_bb)
exc_ptr: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None)
if exc_ptr is not None:
exc_val: ir.Value = Gen._load(exc_ptr, name='coro_exc_val')
else:
exc_val = ir.Constant(ir.IntType(32), 0)
check_bbs: list[ir.Block] = [except_bb] + [Gen.func.append_basic_block(f'coro_exc_check_{i}')
for i in range(len(Node.handlers) - 1)]
handler_bbs: list[ir.Block] = [Gen.func.append_basic_block(f'coro_except_{i}')
for i in range(len(Node.handlers))]
unmatched_bb: ir.Block = Gen.func.append_basic_block('coro_try_reraise')
try_handler: Any = self.Trans.TryHandler
for i, handler in enumerate(Node.handlers):
catch_all: bool = handler.type is None
codes: list[int] = [1]
if handler.type is not None:
ename: str | None = try_handler._get_exception_name(handler.type)
if ename == 'Exception':
catch_all = True
else:
codes = try_handler._get_all_match_codes(handler.type)
Gen.builder.position_at_end(check_bbs[i])
if check_bbs[i].is_terminated:
break
if catch_all:
Gen.builder.branch(handler_bbs[i])
break
next_check: ir.Block = check_bbs[i + 1] if i + 1 < len(Node.handlers) else unmatched_bb
match_cond: ir.Value | None = None
for c in codes:
eq: ir.Value = Gen.builder.icmp_signed('==', exc_val, ir.Constant(ir.IntType(32), c), name=f'coro_exc_match_{i}')
match_cond = eq if match_cond is None else Gen.builder.or_(match_cond, eq, name=f'coro_exc_or_{i}')
Gen.builder.cbranch(match_cond, handler_bbs[i], next_check)
# 未匹配:异常继续传播(重新终止协程)
Gen.builder.position_at_start(unmatched_bb)
if not unmatched_bb.is_terminated:
done_ptr_r: ir.Value | None = getattr(Gen, '_coro_done_ptr', None)
if done_ptr_r is not None:
Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_r)
exit_bb_r: ir.Block | None = getattr(Gen, '_coro_exit_bb', None)
if exit_bb_r is not None:
Gen.builder.branch(exit_bb_r)
# ---- 各 except handler ----
for i, handler in enumerate(Node.handlers):
Gen.builder.position_at_start(handler_bbs[i])
if handler.name:
e_slot: ir.Value | None = Gen.variables.get(handler.name)
if e_slot is not None and exc_ptr is not None:
h_exc_val: ir.Value = Gen._load(exc_ptr, name='coro_exc_val')
Gen._store(h_exc_val, e_slot)
Gen._record_var_signedness(handler.name, False)
if exc_ptr is not None:
Gen._store(ir.Constant(ir.IntType(32), 0), exc_ptr)
self._HandleCoroSegment(handler.body, Gen)
if Gen.builder is not None and not Gen.builder.block.is_terminated:
Gen.builder.branch(merge_bb)
if not merge_bb.is_terminated:
Gen.builder.position_at_start(merge_bb)
else:
Gen.builder.position_at_end(merge_bb)
def _HandleCoroFor(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None:
if any(isinstance(n, ast.Await) for n in ast.walk(Node)):
if not self._IsRangeFor(Node):
raise SyntaxError(
f"[coro-M3] 协程内 For 仅支持 range 迭代(含 await)"
f"(line {getattr(Node, 'lineno', 0)})"
)
self._HandleCoroForRange(Node, Gen)
return
if any(isinstance(n, ast.Return) for n in ast.walk(Node.body)):
raise SyntaxError(
f"[coro-M2] For 循环体内暂不支持 return(M3 实现)(line {getattr(Node, 'lineno', 0)})"
)
# 无 await/return:委托现有 ForHandler(迭代索引等 alloca 不跨挂起,安全)
self.Trans.ForHandler._HandleForLlvm(Node)
def _IsRangeFor(self, Node: ast.For) -> bool:
"""判断是否为可协程化 range-For:单 Name 目标 + range 1/2 参数(step=1)。"""
if not (isinstance(Node.iter, ast.Call)
and isinstance(Node.iter.func, ast.Name)
and Node.iter.func.id == 'range'):
return False
if not isinstance(Node.target, ast.Name):
return False
if len(Node.iter.args) not in (1, 2):
return False
for a in Node.iter.args:
if any(isinstance(n, ast.Await) for n in ast.walk(a)):
return False
return True
def _HandleCoroForRange(self, Node: ast.For, Gen: LlvmCodeGenerator) -> None:
"""协程版 range-For:变换为 While 复用协程路径
__f_idx_N = start; __f_len_N = end;
while __f_idx_N < __f_len_N: target = __f_idx_N; <body>; __f_idx_N += 1
"""
k: int = getattr(Gen, '_coro_for_counter', 0)
Gen._coro_for_counter = k + 1
idx_name: str = f'__f_idx_{k}'
len_name: str = f'__f_len_{k}'
args: list[ast.expr] = Node.iter.args
if len(args) == 1:
start_node: ast.expr = ast.Constant(0)
end_node: ast.expr = args[0]
else:
start_node = args[0]
end_node = args[1]
target: str = Node.target.id
idx_load: ast.expr = ast.Name(idx_name, ast.Load())
init_stmts: list[ast.stmt] = [
ast.Assign(targets=[ast.Name(idx_name, ast.Store())], value=start_node, type_comment=None),
ast.Assign(targets=[ast.Name(len_name, ast.Store())], value=end_node, type_comment=None),
]
while_node: ast.While = ast.While(
test=ast.Compare(left=idx_load, ops=[ast.Lt()],
comparators=[ast.Name(len_name, ast.Load())]),
body=[
ast.Assign(targets=[ast.Name(target, ast.Store())], value=idx_load, type_comment=None),
] + list(Node.body) + [
ast.Assign(targets=[ast.Name(idx_name, ast.Store())],
value=ast.BinOp(left=idx_load, op=ast.Add(), right=ast.Constant(1)),
type_comment=None),
],
orelse=[],
)
self._HandleCoroSegment(init_stmts + [while_node], Gen)
# ------------------------------------------------------------------
# 普通函数调用 async 函数:task(...) -> create_task(...)(返回帧指针)
# ------------------------------------------------------------------
def _HandleAsyncCreateCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
create_fn: ir.Function | None = Gen._get_function(f'create_{FuncName}')
if not create_fn:
return ir.Constant(ir.IntType(32), 0)
call_args: list[ir.Value] = []
if Node.args:
param_info: list[tuple[str, ir.Type]] = getattr(Gen, '_coro_param_vars', {}).get(FuncName, [])
for i, arg_node in enumerate(Node.args):
arg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg_node)
if i < len(param_info):
arg_val = self._CoerceArg(arg_val, param_info[i][1], Gen, name=f'arg{i}')
call_args.append(arg_val)
result: ir.Value = Gen.builder.call(create_fn, call_args, name=f'create_{FuncName}')
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name='coro_frame_i8ptr')
# ------------------------------------------------------------------
# coro.coro_run(帧) 内联翻译
# ------------------------------------------------------------------
def _HandleCoroGatherLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
"""coro.coro_gather(帧...):并发推进全部协程到完成(含 coro_sleep 轮询),返回完成数。"""
zero32: ir.Constant = ir.Constant(ir.IntType(32), 0)
count: int = 0
for arg in Node.args:
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
continue
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
if not frame_ty or not resume_fn:
continue
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
continue
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='gather_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='gather_frame')
else:
continue
loop_bb: ir.Block = Gen.func.append_basic_block('gather_loop')
check_bb: ir.Block = Gen.func.append_basic_block('gather_wcheck')
after_bb: ir.Block = Gen.func.append_basic_block('gather_after')
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(loop_bb)
status: ir.Value = Gen.builder.call(resume_fn, [frame_ptr], name=f'gather_resume_{async_name}')
done_cond: ir.Value = Gen.builder.icmp_signed('!=', status, zero32, name='gather_done_cond')
Gen.builder.cbranch(done_cond, after_bb, check_bb)
# SUSPEND:coro_sleep 唤醒轮询
Gen.builder.position_at_start(check_bb)
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(async_name, [])
wake_idx: int | None = None
if '__coro_wake_us' in slot_vars:
wake_idx = 4 + slot_vars.index('__coro_wake_us')
if wake_idx is not None:
wsleep_bb: ir.Block = Gen.func.append_basic_block('gather_wsleep')
wdue_bb: ir.Block = Gen.func.append_basic_block('gather_wdue')
wake_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), wake_idx)],
name='gather_wake_ptr',
)
wake_val: ir.Value = Gen._load(wake_ptr, name='gather_wake')
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='gather_tick_now')
not_wake: ir.Value = Gen.builder.icmp_signed('==', wake_val, ir.Constant(ir.IntType(64), 0), name='gather_wake_zero')
due: ir.Value = Gen.builder.icmp_unsigned('>=', now_val, wake_val, name='gather_wake_due')
sleep_cond: ir.Value = Gen.builder.or_(not_wake, due, name='gather_continue_cond')
Gen.builder.cbranch(sleep_cond, wdue_bb, wsleep_bb)
Gen.builder.position_at_start(wsleep_bb)
sleep_fn: ir.Function = self._GetWinFunc('Sleep', Gen, ir.VoidType(), [ir.IntType(32)])
Gen.builder.call(sleep_fn, [ir.Constant(ir.IntType(32), 1)])
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(wdue_bb)
Gen.builder.branch(loop_bb)
else:
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(after_bb)
count += 1
return ir.Constant(ir.IntType(32), count)
def _HandleCoroRunLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value:
if not Node.args:
return ir.Constant(ir.IntType(32), 0)
arg: ast.expr = Node.args[0]
async_name: str | None = None
if isinstance(arg, ast.Name):
async_name = getattr(Gen, '_coro_var_async', {}).get(arg.id)
if not async_name:
return ir.Constant(ir.IntType(32), 0)
frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name)
resume_fn: ir.Function | None = Gen._get_function(f'resume_{async_name}')
if not frame_ty or not resume_fn:
return ir.Constant(ir.IntType(32), 0)
frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg)
if frame_val is None:
return ir.Constant(ir.IntType(32), 0)
if isinstance(frame_val.type, ir.PointerType):
frame_ptr: ir.Value = Gen.builder.bitcast(frame_val, ir.PointerType(frame_ty), name='coro_frame')
elif isinstance(frame_val.type, ir.IntType):
frame_ptr = Gen.builder.inttoptr(frame_val, ir.PointerType(frame_ty), name='coro_frame')
else:
return ir.Constant(ir.IntType(32), 0)
loop_bb: ir.Block = Gen.func.append_basic_block('coro_loop')
after_bb: ir.Block = Gen.func.append_basic_block('coro_after')
check_bb: ir.Block = Gen.func.append_basic_block('coro_wcheck')
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(loop_bb)
status: ir.Value = Gen.builder.call(resume_fn, [frame_ptr], name=f'resume_{async_name}')
done_cond: ir.Value = Gen.builder.icmp_signed('!=', status, ir.Constant(ir.IntType(32), 0), name='coro_done_cond')
Gen.builder.cbranch(done_cond, after_bb, check_bb)
# SUSPEND:若 coro_sleep 唤醒槽存在且未到点,Sleep(1) 后继续轮询
Gen.builder.position_at_start(check_bb)
wake_idx: int | None = None
slot_vars: list[str] = getattr(Gen, '_coro_slot_vars', {}).get(async_name, [])
if '__coro_wake_us' in slot_vars:
wake_idx = 4 + slot_vars.index('__coro_wake_us')
if wake_idx is not None:
wake_wait_bb: ir.Block = Gen.func.append_basic_block('coro_wsleep')
wake_due_bb: ir.Block = Gen.func.append_basic_block('coro_wdue')
wake_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), wake_idx)],
name='coro_wake_ptr',
)
wake_val: ir.Value = Gen._load(wake_ptr, name='coro_wake')
now_fn: ir.Function = self._GetWinFunc('GetTickCount64', Gen, ir.IntType(64))
now_val: ir.Value = Gen.builder.call(now_fn, [], name='tick_now')
not_wake: ir.Value = Gen.builder.icmp_signed('==', wake_val, ir.Constant(ir.IntType(64), 0), name='coro_wake_zero')
due: ir.Value = Gen.builder.icmp_unsigned('>=', now_val, wake_val, name='coro_wake_due')
sleep_cond: ir.Value = Gen.builder.or_(not_wake, due, name='coro_continue_cond')
Gen.builder.cbranch(sleep_cond, wake_due_bb, wake_wait_bb)
Gen.builder.position_at_start(wake_wait_bb)
sleep_fn: ir.Function = self._GetWinFunc('Sleep', Gen, ir.VoidType(), [ir.IntType(32)])
Gen.builder.call(sleep_fn, [ir.Constant(ir.IntType(32), 1)])
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(wake_due_bb)
Gen.builder.branch(loop_bb)
else:
Gen.builder.branch(loop_bb)
Gen.builder.position_at_start(after_bb)
ret_ptr: ir.Value = Gen.builder.gep(
frame_ptr,
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 2)],
name='coro_ret_ptr',
)
return Gen._load(ret_ptr, name='coro_result')