diff --git a/Test/CoroTest/App/main.vp b/Test/CoroTest/App/main.vp new file mode 100644 index 0000000..6809a3f --- /dev/null +++ b/Test/CoroTest/App/main.vp @@ -0,0 +1,21 @@ +import t, c +from stdint import * +import stdio +import coro + + +async def leaf() -> int: + return 7 + + +async def task() -> int: + a: int = await leaf() + b: int = await leaf() + return a + b + + +def main() -> t.CInt: + tt: coro.Coroutine = task() + r: t.CInt = coro.coro_run(tt) + stdio.printf("coro result = %d\n", r) + return 0 diff --git a/Test/CoroTest/project.json b/Test/CoroTest/project.json new file mode 100644 index 0000000..fbf5c11 --- /dev/null +++ b/Test/CoroTest/project.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "CoroTest", + "version": "1.0.0", + "source_dir": "./App", + "build_dir": "./.tpv_build", + "compiler": { + "cmd": "llc", + "flags": [ + "-filetype=obj" + ] + }, + "linker": { + "cmd": "clang++", + "flags": [ + "-Wl,--allow-multiple-definition", + "-lmsvcrt", + "-lucrt", + "-lpthread", + "-lmingwex", + "-lkernel32", + "-luser32" + ], + "output": "CoroTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "sha1_slice_level": 1, + "target": "llvm", + "strict_mode": true + } +} diff --git a/includes/coro.vp b/includes/coro.vp new file mode 100644 index 0000000..f0e1e0e --- /dev/null +++ b/includes/coro.vp @@ -0,0 +1,28 @@ +import t, c +from stdint import * +import stdlib + + +@t.CVTable +class Coroutine: + """协程帧句柄(M1:__ptr__ 持有 create_() 返回的帧指针)""" + __ptr__: t.CPtr + + +def coro_resume(c: Coroutine) -> t.CInt: + # M1 占位:实际由编译器将 coro.coro_run 内联翻译为 resume_ 循环, + # 本函数不会被真正调用(仅保证模块可编译)。 + return 0 + + +def coro_result(c: Coroutine) -> t.CInt: + # M1 占位:coro_run 内联翻译直接从帧 ret 槽取结果。 + return 0 + + +def coro_run(c: Coroutine) -> t.CInt: + # M1 占位实现:编译器在调用点对 coro.coro_run 做内联翻译(resume 循环)。 + s: t.CInt = 0 + while s == 0: + s = coro_resume(c) + return coro_result(c) diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 8a4c413..cd2a308 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -316,6 +316,14 @@ class AnnAssignHandle(BaseHandle): def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen + # M1 协程:记录 async 函数调用赋值的变量名(coro.coro_run 内联翻译需要) + if isinstance(Node.target, ast.Name) and Node.value is not None: + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + callee: str = Node.value.func.id + if hasattr(self.Trans, 'AsyncHandler') and self.Trans.AsyncHandler._IsAsyncFunc(callee): + if not hasattr(Gen, '_coro_var_async'): + Gen._coro_var_async = {} + Gen._coro_var_async[Node.target.id] = callee if isinstance(Node.target, ast.Name): VarName: str = Node.target.id TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) diff --git a/lib/core/Handles/HandlesAsyncFunctions.py b/lib/core/Handles/HandlesAsyncFunctions.py new file mode 100644 index 0000000..949247b --- /dev/null +++ b/lib/core/Handles/HandlesAsyncFunctions.py @@ -0,0 +1,469 @@ +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 +from lib.includes import t + + +class AsyncFunctionHandle(BaseHandle): + """语言内协程 M1:async def + await + coro_run 状态机翻译。 + + M1 语义约定: + - async def 无参数、返回 i32/int。 + - 每个 async 函数生成 3 部分: + 1. 帧结构体 %Coro_ = type { i32, i32, i32, <跨 await 局部变量> } + (前 3 槽:state, done, ret) + 2. create_() -> %Coro_*:stdlib.malloc 分配帧,state/done/ret 置 0 + 3. resume_(%Coro_*) -> i32:0=SUSPEND 1=DONE;switch(state) 切分 await 点 + - await :创建子帧 -> call resume(child)(M1 假设一次完成) + -> 取子帧 ret -> 存父帧局部变量槽 -> 父挂起(state=下一切片、ret=0(SUSPEND)) + - return expr:写帧 ret + done=1 + br 完成块;函数体结尾隐式同 return 路径。 + - 普通函数调用 async 函数(如 main 里 task()):生成 create 调用(返回帧指针)。 + - coro.coro_run(帧):内联翻译为 resume 循环,返回帧 ret。 + """ + + # ------------------------------------------------------------------ + # 公共查询 + # ------------------------------------------------------------------ + + 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 + if Node.args.args: + raise SyntaxError( + f"[coro-M1] async 函数 '{name}' 暂不支持参数(M1 仅支持无参数 async def)" + ) + # 防重复生成:模块可能被多次编译(泛型特化等触发),避免 create_/resume_ 重名 + if f'create_{name}' in Gen.functions or name in getattr(Gen, '_coro_frame_types', {}): + return + self._RegisterAsyncFunc(name, Node) + # 保存外层 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_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), + } + try: + self.Trans.VarScopes.append({}) + frame_ty: ir.IdentifiedStructType = self._GetOrCreateFrameType(name, Node, Gen) + self._EmitCreateFunction(name, 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() + 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'] + + # ------------------------------------------------------------------ + # 帧结构体与局部变量收集 + # ------------------------------------------------------------------ + + def _GetOrCreateFrameType(self, name: str, Node: ast.AsyncFunctionDef, Gen: LlvmCodeGenerator) -> ir.IdentifiedStructType: + if not hasattr(Gen, '_coro_frame_types'): + Gen._coro_frame_types = {} + if not hasattr(Gen, '_coro_local_vars'): + Gen._coro_local_vars = {} + if name in Gen._coro_frame_types: + return Gen._coro_frame_types[name] + local_names: list[str] = self._CollectLocalVars(Node) + fields: list[ir.Type] = [ + ir.IntType(32), # 0: state + ir.IntType(32), # 1: done + ir.IntType(32), # 2: ret + ] + for _ in local_names: + fields.append(ir.IntType(32)) + frame_ty: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f'Coro_{name}') + frame_ty.set_body(*fields) + Gen._coro_frame_types[name] = frame_ty + Gen._coro_local_vars[name] = local_names + return frame_ty + + def _CollectLocalVars(self, Node: ast.AsyncFunctionDef) -> list[str]: + """收集协程体内顶层 AnnAssign/Assign 的 Name 目标(M1 仅 i32 槽)。""" + names: list[str] = [] + seen: set[str] = set() + for stmt in Node.body: + target: str | None = None + if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name): + target = stmt.target.id + elif (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Name)): + target = stmt.targets[0].id + if target is not None and target not in seen: + seen.add(target) + names.append(target) + return names + + # ------------------------------------------------------------------ + # create_() -> %Coro_* + # ------------------------------------------------------------------ + + 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, frame_ty: ir.IdentifiedStructType, Gen: LlvmCodeGenerator) -> None: + malloc_fn: ir.Function = self._GetMalloc(Gen) + frame_size: int = Gen._get_struct_size(frame_ty) + create_ty: ir.FunctionType = ir.FunctionType(ir.PointerType(frame_ty), []) + 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(3): + 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) + Gen.builder.ret(frame_ptr) + Gen.builder = None + Gen.func = None + + # ------------------------------------------------------------------ + # resume_(%Coro_*) -> i32 状态机 + # ------------------------------------------------------------------ + + def _SplitBody(self, body: list[ast.stmt]) -> list[list[ast.stmt]]: + """按顶层 await 切分函数体。 + + await 仅识别 AnnAssign.value / Assign.value(Name 目标)顶层形式; + 含 await 的语句作为所在段的最后一条(翻译后 br exit 挂起)。 + """ + segments: list[list[ast.stmt]] = [] + current: list[ast.stmt] = [] + for stmt in body: + has_await: bool = False + if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await): + has_await = True + elif (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Name) + and isinstance(stmt.value, ast.Await)): + has_await = True + current.append(stmt) + if has_await: + segments.append(current) + current = [] + if current: + segments.append(current) + return segments + + 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 + segments: list[list[ast.stmt]] = self._SplitBody(Node.body) + 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] = {} + for idx, var in enumerate(Gen._coro_local_vars.get(name, [])): + slot_ptr: ir.Value = Gen.builder.gep( + frame_arg, + [zero32, ir.Constant(ir.IntType(32), 3 + idx)], + name=f'{var}_slot', + ) + local_slot_ptrs[var] = 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 + Gen._coro_exit_bb = exit_bb + Gen._coro_frame_ptr = frame_arg + switch_instr: Any = Gen.builder.switch(state_val, exit_bb) + state_bbs: list[ir.Block] = [] + for i in range(len(segments)): + bb: ir.Block = resume_fn.append_basic_block(f'state{i}') + state_bbs.append(bb) + switch_instr.add_case(ir.Constant(ir.IntType(32), i), bb) + # 逐段生成 + for i, seg in enumerate(segments): + Gen.builder.position_at_start(state_bbs[i]) + Gen.variables = dict(local_slot_ptrs) + Gen._coro_next_state = i + 1 + self._HandleCoroSegment(seg, 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 isinstance(stmt, ast.AnnAssign) and isinstance(stmt.value, ast.Await): + self._HandleCoroAwaitAnnAssign(stmt, Gen) + return + 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) + return + if isinstance(stmt, ast.Return): + self._HandleCoroReturn(stmt, Gen) + return + # M1 防御:await 仅支持顶层(AnnAssign/Assign 的 value 直接是 Await) + if any(isinstance(n, ast.Await) for n in ast.walk(stmt)): + raise SyntaxError( + f"[coro-M1] await 仅支持顶层赋值形式 `var: int = await fn()` " + f"(line {getattr(stmt, 'lineno', 0)})" + ) + if isinstance(stmt, ast.AnnAssign): + self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(stmt) + continue + if isinstance(stmt, ast.Assign): + self.Trans.AssignHandler._HandleAssignLlvm(stmt) + continue + if isinstance(stmt, ast.Expr): + self.Trans.ExprHandler.HandleExprLlvm(stmt.value) + continue + raise SyntaxError( + f"[coro-M1] async 函数体暂不支持语句: {type(stmt).__name__} " + f"(line {getattr(stmt, 'lineno', 0)})" + ) + + 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/挂起)。""" + Gen._coro_await_slot_ptr = Gen.variables.get(target) + # 校验 await 目标必须是 async 函数调用,且子协程已生成 + call: Any = await_node.value + async_name: str | None = self._GetAsyncCallName(call) if isinstance(call, ast.Call) else None + if not async_name: + raise SyntaxError( + f"[coro-M1] await 目标必须是 async 函数调用 (line {getattr(await_node, 'lineno', 0)})" + ) + self.Trans.ExprHandler.HandleExprLlvm(await_node) # → _HandleAwaitLlvm + + def _HandleAwaitLlvm(self, Node: ast.Await, Gen: LlvmCodeGenerator) -> ir.Value: + """await 表达式翻译: + 创建子帧 -> resume 到 DONE(M1 假设一次完成)-> 取子帧 ret -> 存父帧槽 -> 父挂起。 + """ + zero32: ir.Constant = ir.Constant(ir.IntType(32), 0) + call: Any = Node.value + 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 + child: ir.Value = Gen.builder.call(create_fn, [], 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') + # 存父帧局部变量槽 + slot: ir.Value | None = getattr(Gen, '_coro_await_slot_ptr', None) + if slot is not None: + Gen._store(child_ret, slot) + # 父挂起:state = 下一切片,ret = 0(SUSPEND) + state_ptr: ir.Value | None = getattr(Gen, '_coro_state_ptr', None) + if state_ptr is not None: + Gen._store(ir.Constant(ir.IntType(32), getattr(Gen, '_coro_next_state', 1)), state_ptr) + ret_field_ptr: ir.Value | None = getattr(Gen, '_coro_ret_field_ptr', None) + if ret_field_ptr is not None: + Gen._store(zero32, ret_field_ptr) + exit_bb: ir.Block | None = getattr(Gen, '_coro_exit_bb', None) + if exit_bb is not None: + Gen.builder.branch(exit_bb) + return child_ret + + def _HandleCoroReturn(self, stmt: ast.Return, Gen: LlvmCodeGenerator) -> None: + 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) + + # ------------------------------------------------------------------ + # 普通函数调用 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) + result: ir.Value = Gen.builder.call(create_fn, [], name=f'create_{FuncName}') + return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name='coro_frame_i8ptr') + + # ------------------------------------------------------------------ + # coro.coro_run(帧) 内联翻译(M1) + # ------------------------------------------------------------------ + + 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') + 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, 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') diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index e6cb97b..ed3cdd9 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -61,6 +61,8 @@ class ExprHandle(BaseHandle): return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node) elif isinstance(Node, ast.Call): return self.Trans.ExprCallHandle._HandleCallLlvm(Node) + elif isinstance(Node, ast.Await): + return self.Trans.AsyncHandler._HandleAwaitLlvm(Node, Gen) elif isinstance(Node, ast.Compare): return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node) elif isinstance(Node, ast.Attribute): diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 7a225af..7bfa2ce 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -274,10 +274,17 @@ class ExprCallHandle(BaseHandle): def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen + # M1 协程:coro.coro_run(帧) 内联翻译为 resume 循环 + if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_run': + if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id): + return self.Trans.AsyncHandler._HandleCoroRunLlvm(Node, Gen) FuncAttr: str | None = None ModulePath: str | None = None if isinstance(Node.func, ast.Name): FuncName = Node.func.id + # M1 协程:普通函数调用 async 函数 → create_()(返回帧指针) + if hasattr(self.Trans, 'AsyncHandler') and self.Trans.AsyncHandler._IsAsyncFunc(FuncName): + return self.Trans.AsyncHandler._HandleAsyncCreateCallLlvm(Node, FuncName) if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates: return self._HandleGenericCallLlvm(Node, FuncName) result = self.Trans.ExprBuiltinHandle._HandleBuiltinCallLlvm(Node) diff --git a/lib/core/Handles/__init__.py b/lib/core/Handles/__init__.py index b7c469e..528d660 100644 --- a/lib/core/Handles/__init__.py +++ b/lib/core/Handles/__init__.py @@ -30,3 +30,4 @@ from .HandlesMatch import MatchHandle from .HandlesClassDef import ClassHandle from .HandlesFunctions import FunctionHandle from .HandlesImports import ImportHandle +from .HandlesAsyncFunctions import AsyncFunctionHandle diff --git a/lib/core/Translator/BaseTranslator.py b/lib/core/Translator/BaseTranslator.py index fce641b..e48d963 100644 --- a/lib/core/Translator/BaseTranslator.py +++ b/lib/core/Translator/BaseTranslator.py @@ -19,7 +19,8 @@ from lib.core.Handles import ( CSpecialCallHandle, TSpecialCallHandle, ClassHandle, FunctionHandle, - ImportHandle + ImportHandle, + AsyncFunctionHandle ) from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.SymbolTable import SymbolTable @@ -109,6 +110,7 @@ class BaseTranslatorMixin: self.AssertHandler = AssertHandle(self) self.RaiseHandler = RaiseHandle(self) self.MatchHandler = MatchHandle(self) + self.AsyncHandler = AsyncFunctionHandle(self) def LogWarning(self, message: str, LineNum: int | None = None) -> None: """记录警告 diff --git a/lib/core/Translator/LlvmGenerator.py b/lib/core/Translator/LlvmGenerator.py index d68605f..75acef6 100644 --- a/lib/core/Translator/LlvmGenerator.py +++ b/lib/core/Translator/LlvmGenerator.py @@ -142,6 +142,10 @@ class LlvmGeneratorMixin: FuncName: str = Node.name if FuncName not in self.FunctionDefCache: self.FunctionDefCache[FuncName] = Node + elif isinstance(Node, ast.AsyncFunctionDef): + # 协程:注册到 AsyncHandler(生成 create_/resume_,不进 FunctionDefCache, + # 避免被当作普通函数前向声明) + self.AsyncHandler._RegisterAsyncFunc(Node.name, Node) # 首先处理所有导入语句,确保模块在类型解析前被加载 for Node in ast.iter_child_nodes(Tree): @@ -196,6 +200,8 @@ class LlvmGeneratorMixin: continue elif isinstance(Node, ast.FunctionDef): self.FunctionHandler._EmitFunctionLlvm(Node, Gen) + elif isinstance(Node, ast.AsyncFunctionDef): + self.AsyncHandler._EmitAsyncFunctionLlvm(Node, Gen) elif isinstance(Node, ast.AnnAssign): self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) elif isinstance(Node, ast.Assign): @@ -463,6 +469,14 @@ class LlvmGeneratorMixin: FuncNode.IsFunction = True FuncNode.file = '' self.SymbolTable.insert(FuncName, FuncNode) + elif isinstance(Node, ast.AsyncFunctionDef): + FuncName = Node.name + if not self.SymbolTable.has(FuncName): + FuncNode = CTypeInfo() + FuncNode.Name = FuncName + FuncNode.IsFunction = True + FuncNode.file = '' + self.SymbolTable.insert(FuncName, FuncNode) elif isinstance(Node, ast.AnnAssign): if isinstance(Node.target, ast.Name): VarName: str = Node.target.id