feat(coro): 语言内协程 M1——async def + await + coro_run 状态机
TPC 新增协程生成器 AsyncFunctionHandle(lib/core/Handles/HandlesAsyncFunctions.py):
async def 编译为帧结构体 {state, done, ret, 局部变量槽} + create_<name>()(malloc
分配)+ resume_<name>()(switch 状态机,0=SUSPEND/1=DONE)。await 按顶层赋值
切分函数体:创建子帧 -> resume -> 取子帧 ret -> 存父帧槽 -> 父挂起(state 前进);
普通调用 async 函数生成 create(返回帧指针);coro.coro_run 在调用点内联翻译为
resume 循环。vast parser 已支持语法;新增 includes/coro.vp(Coroutine + 占位
运行时)与 Test/CoroTest(期望输出 coro result = 14)。
M1 限制:async 无参数、返回 i32/int;协程体仅顶层 AnnAssign/Assign/Expr/Return;
await 仅顶层赋值形式、子协程假设一次完成(无嵌套挂起);coro_run 依赖本模块
先赋值的协程变量。M2 将支持参数/嵌套 await/控制流。
This commit is contained in:
1 parent
12207e91d8
commit
13a8f6c1b6
10 files changed
+592
-1
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Coroutine:
|
||||
"""协程帧句柄(M1:__ptr__ 持有 create_<name>() 返回的帧指针)"""
|
||||
__ptr__: t.CPtr
|
||||
|
||||
|
||||
def coro_resume(c: Coroutine) -> t.CInt:
|
||||
# M1 占位:实际由编译器将 coro.coro_run 内联翻译为 resume_<name> 循环,
|
||||
# 本函数不会被真正调用(仅保证模块可编译)。
|
||||
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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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_<name> = type { i32, i32, i32, <跨 await 局部变量> }
|
||||
(前 3 槽:state, done, ret)
|
||||
2. create_<name>() -> %Coro_<name>*:stdlib.malloc 分配帧,state/done/ret 置 0
|
||||
3. resume_<name>(%Coro_<name>*) -> i32:0=SUSPEND 1=DONE;switch(state) 切分 await 点
|
||||
- await <async调用>:创建子帧 -> 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 = '<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()
|
||||
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_<name>() -> %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, 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_<name>(%Coro_<name>*) -> 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')
|
||||
@@ -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):
|
||||
|
||||
@@ -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_<name>()(返回帧指针)
|
||||
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)
|
||||
|
||||
@@ -30,3 +30,4 @@ from .HandlesMatch import MatchHandle
|
||||
from .HandlesClassDef import ClassHandle
|
||||
from .HandlesFunctions import FunctionHandle
|
||||
from .HandlesImports import ImportHandle
|
||||
from .HandlesAsyncFunctions import AsyncFunctionHandle
|
||||
@@ -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:
|
||||
"""记录警告
|
||||
|
||||
@@ -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 = '<stdin>'
|
||||
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 = '<stdin>'
|
||||
self.SymbolTable.insert(FuncName, FuncNode)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
|
||||
Reference in new issue
Block a user