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_ = type { i32 state, i32 done, i32 ret, i32 exc, i8* msg, <参数槽>, <局部槽>, <额外槽(wake/for/await)> } 状态机:create_(args...) 分配帧 + 存参数;resume_(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), 'msg_ptr': getattr(Gen, '_coro_msg_ptr', 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 = '' 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'] Gen._coro_msg_ptr = saved_coro_state['msg_ptr'] # ------------------------------------------------------------------ # 帧结构体与局部变量收集 # ------------------------------------------------------------------ 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=无异常) ir.PointerType(ir.IntType(8)), # 4: msg(异常消息,null=无) ] 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_(args...) -> %Coro_* # ------------------------------------------------------------------ def _GetCoroPool(self, name: str, Gen: LlvmCodeGenerator) -> ir.GlobalVariable: """每帧类型的全局 free-list 池头(i8*),跨 create/destroy 复用帧内存。""" pool_name: str = f'coro_pool_{Gen._mangle_func_name(name)}' for gv in Gen.module.global_values: if getattr(gv, 'name', None) == pool_name: return gv gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.PointerType(ir.IntType(8)), pool_name) gv.initializer = ir.Constant(ir.PointerType(ir.IntType(8)), None) gv.linkage = 'internal' return gv 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 zero32: ir.Constant = ir.Constant(ir.IntType(32), 0) null_i8p: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) # 帧池:pop(非空则复用,空则 malloc) pool_gv: ir.GlobalVariable = self._GetCoroPool(name, Gen) pool_head: ir.Value = Gen.builder.load(pool_gv, name='pool_head') pool_hit_bb: ir.Block = create_fn.append_basic_block('pool_hit') pool_miss_bb: ir.Block = create_fn.append_basic_block('pool_miss') join_bb: ir.Block = create_fn.append_basic_block('pool_join') head_is_null: ir.Value = Gen.builder.icmp_signed('==', pool_head, null_i8p, name='pool_empty') Gen.builder.cbranch(head_is_null, pool_miss_bb, pool_hit_bb) # pool_hit:弹出一个池节点(帧头部存 next) Gen.builder.position_at_start(pool_hit_bb) next_head: ir.Value = Gen.builder.load( Gen.builder.bitcast(pool_head, ir.PointerType(ir.PointerType(ir.IntType(8))), name='pool_node_next_ptr'), name='pool_next') Gen.builder.store(next_head, pool_gv) hit_frame: ir.Value = Gen.builder.bitcast(pool_head, ir.PointerType(frame_ty), name='frame') Gen.builder.branch(join_bb) # pool_miss:malloc + 状态清零 Gen.builder.position_at_start(pool_miss_bb) raw: ir.Value = Gen.builder.call(malloc_fn, [ir.Constant(ir.IntType(64), frame_size)], name='frame_raw') miss_frame: ir.Value = Gen.builder.bitcast(raw, ir.PointerType(frame_ty), name='frame') for i in range(4): slot_ptr: ir.Value = Gen.builder.gep(miss_frame, [zero32, ir.Constant(ir.IntType(32), i)], name=f'init_slot{i}') Gen._store(zero32, slot_ptr) msg_slot: ir.Value = Gen.builder.gep(miss_frame, [zero32, ir.Constant(ir.IntType(32), 4)], name='init_msg_slot') Gen._store(null_i8p, msg_slot) Gen.builder.branch(join_bb) # join:phi 选择帧 + 参数存入(池取/新建都要写参数槽) Gen.builder.position_at_start(join_bb) frame_phi: Any = Gen.builder.phi(ir.PointerType(frame_ty), name='frame') frame_phi.add_incoming(hit_frame, pool_hit_bb) frame_phi.add_incoming(miss_frame, pool_miss_bb) for i in range(len(params)): slot_ptr = Gen.builder.gep(frame_phi, [zero32, ir.Constant(ir.IntType(32), 5 + 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_phi) Gen.builder = None Gen.func = None # ------------------------------------------------------------------ # resume_(%Coro_*) -> 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), 5 + 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 msg_ptr: ir.Value = Gen.builder.gep(frame_arg, [zero32, ir.Constant(ir.IntType(32), 4)], name='msg_ptr') Gen._coro_msg_ptr = msg_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): if stmt.finalbody and not stmt.handlers: self._HandleCoroTryFinally(stmt, Gen) else: 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-list):帧头部存当前池头,池头指向本帧 pool_gv: ir.GlobalVariable = self._GetCoroPool(async_name, Gen) pool_head: ir.Value = Gen.builder.load(pool_gv, name='pool_head') node_next_ptr: ir.Value = Gen.builder.bitcast( frame_ptr, ir.PointerType(ir.PointerType(ir.IntType(8))), name='pool_node_next') Gen.builder.store(pool_head, node_next_ptr) Gen.builder.store( Gen.builder.bitcast(frame_ptr, ir.IntType(8).as_pointer(), name='pool_node'), pool_gv) return ir.Constant(ir.IntType(32), 0) def _ResolveRaiseInfo(self, exc_node: ast.expr) -> tuple[int, ast.expr | None] | None: """解析 raise 目标的异常类型(返回 (异常码, 消息表达式));普通表达式返回 None 走值路径。""" name: str | None = None msg_node: ast.expr | 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 if exc_node.args: msg_node = exc_node.args[0] 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), msg_node) 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: tuple[int, ast.expr | None] | None = self._ResolveRaiseInfo(stmt.exc) if resolved is not None: exc_code = ir.Constant(ir.IntType(32), resolved[0]) msg_node: ast.expr | None = resolved[1] if msg_node is not None: msg_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(msg_node) msg_ptr_r: ir.Value | None = getattr(Gen, '_coro_msg_ptr', None) if msg_val is not None and isinstance(msg_val.type, ir.PointerType) and msg_ptr_r is not None: Gen._store(msg_val, msg_ptr_r) 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 _HandleCoroExceptionMsgLlvm(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> ir.Value: """coro.coro_exception_msg(帧):返回帧 msg 槽(异常消息指针,null=无)。""" if not Node.args: return ir.Constant(ir.PointerType(ir.IntType(8)), None) 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.PointerType(ir.IntType(8)), None) frame_ty: ir.IdentifiedStructType | None = getattr(Gen, '_coro_frame_types', {}).get(async_name) if not frame_ty: return ir.Constant(ir.PointerType(ir.IntType(8)), None) frame_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(arg) if frame_val is None: return ir.Constant(ir.PointerType(ir.IntType(8)), None) 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.PointerType(ir.IntType(8)), None) msg_ptr: ir.Value = Gen.builder.gep( frame_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 4)], name='coro_msg_ptr', ) return Gen._load(msg_ptr, name='coro_msg') 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) child_msg_ptr: ir.Value = Gen.builder.gep( child, [zero32, ir.Constant(ir.IntType(32), 4)], name='child_msg_ptr', ) child_msg: ir.Value = Gen._load(child_msg_ptr, name='child_msg') parent_msg_ptr: ir.Value | None = getattr(Gen, '_coro_msg_ptr', None) if parent_msg_ptr is not None: Gen._store(child_msg, parent_msg_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 _HandleCoroTryFinally(self, Node: ast.Try, Gen: LlvmCodeGenerator) -> None: """协程内 try/finally(无 except):正常/异常路径都执行 fbody; 异常时 finally 后重新传播(done=1 + br exit);finally 内暂不支持 await。""" if any(isinstance(n, ast.Await) for s in Node.finalbody for n in ast.walk(s)): raise SyntaxError( f"[coro-M7] finally 内暂不支持 await (line {getattr(Node, 'lineno', 0)})" ) fin_bb: ir.Block = Gen.func.append_basic_block('coro_fin') fin_exc_bb: ir.Block = Gen.func.append_basic_block('coro_fin_exc') merge_bb: ir.Block = Gen.func.append_basic_block('coro_fin_merge') if not getattr(Gen, '_coro_try_stack', None): Gen._coro_try_stack = [] Gen._coro_try_stack.append(fin_bb) self._HandleCoroSegment(Node.body, Gen) if Gen.builder is not None and not Gen.builder.block.is_terminated: Gen.builder.branch(fin_bb) Gen._coro_try_stack.pop() # fin_bb:记录异常标志,执行 fbody Gen.builder.position_at_start(fin_bb) exc_ptr_f: ir.Value | None = getattr(Gen, '_coro_exc_ptr', None) if exc_ptr_f is not None: was_exc: ir.Value = Gen.builder.icmp_signed( '!=', Gen._load(exc_ptr_f, name='coro_fin_exc'), ir.Constant(ir.IntType(32), 0), name='coro_fin_was_exc') else: was_exc = ir.Constant(ir.IntType(1), 0) self._HandleCoroSegment(Node.finalbody, Gen) if Gen.builder is not None and not Gen.builder.block.is_terminated: Gen.builder.cbranch(was_exc, fin_exc_bb, merge_bb) # fin_exc_bb:finally 后异常继续传播 Gen.builder.position_at_start(fin_exc_bb) if not fin_exc_bb.is_terminated: done_ptr_f: ir.Value | None = getattr(Gen, '_coro_done_ptr', None) if done_ptr_f is not None: Gen._store(ir.Constant(ir.IntType(32), 1), done_ptr_f) exit_bb_f: ir.Block | None = getattr(Gen, '_coro_exit_bb', None) if exit_bb_f is not None: Gen.builder.branch(exit_bb_f) 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 st in Node.body for n in ast.walk(st)): 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; ; __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 = 5 + 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 = 5 + 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')