authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-28 22:18:48-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-28 22:18:48-05:00
log8429d4ceac4eb99fbe8aeca2ebe864dfd5b40470
tree693a05c4e44a5a1148505df8bf599ab5dda99fca
parentc6227661568a9e8cad9d28bd7a11cb76c4f9c1c1

implement coroutine resume


8 files changed, 89 insertions(+), 4 deletions(-)

doc/langref.html.in+3-1
...@@ -5682,7 +5682,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression...@@ -5682,7 +5682,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
56825682
5683BlockOrExpression = Block | Expression5683BlockOrExpression = Block | Expression
56845684
5685Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression5685Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
56865686
5687AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"5687AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
56885688
...@@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression)...@@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression)
57305730
5731CancelExpression = "cancel" Expression;5731CancelExpression = "cancel" Expression;
57325732
5733ResumeExpression = "resume" Expression;
5734
5733Defer(body) = ("defer" | "deferror") body5735Defer(body) = ("defer" | "deferror") body
57345736
5735IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))5737IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
src/all_types.hpp+6
...@@ -403,6 +403,7 @@ enum NodeType {...@@ -403,6 +403,7 @@ enum NodeType {
403 NodeTypeTestExpr,403 NodeTypeTestExpr,
404 NodeTypeErrorSetDecl,404 NodeTypeErrorSetDecl,
405 NodeTypeCancel,405 NodeTypeCancel,
406 NodeTypeResume,
406 NodeTypeAwaitExpr,407 NodeTypeAwaitExpr,
407 NodeTypeSuspend,408 NodeTypeSuspend,
408};409};
...@@ -849,6 +850,10 @@ struct AstNodeCancelExpr {...@@ -849,6 +850,10 @@ struct AstNodeCancelExpr {
849 AstNode *expr;850 AstNode *expr;
850};851};
851852
853struct AstNodeResumeExpr {
854 AstNode *expr;
855};
856
852struct AstNodeContinueExpr {857struct AstNodeContinueExpr {
853 Buf *name;858 Buf *name;
854};859};
...@@ -930,6 +935,7 @@ struct AstNode {...@@ -930,6 +935,7 @@ struct AstNode {
930 AstNodeVarLiteral var_literal;935 AstNodeVarLiteral var_literal;
931 AstNodeErrorSetDecl err_set_decl;936 AstNodeErrorSetDecl err_set_decl;
932 AstNodeCancelExpr cancel_expr;937 AstNodeCancelExpr cancel_expr;
938 AstNodeResumeExpr resume_expr;
933 AstNodeAwaitExpr await_expr;939 AstNodeAwaitExpr await_expr;
934 AstNodeSuspend suspend;940 AstNodeSuspend suspend;
935 } data;941 } data;
src/analyze.cpp+1
...@@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3212 case NodeTypeTestExpr:3212 case NodeTypeTestExpr:
3213 case NodeTypeErrorSetDecl:3213 case NodeTypeErrorSetDecl:
3214 case NodeTypeCancel:3214 case NodeTypeCancel:
3215 case NodeTypeResume:
3215 case NodeTypeAwaitExpr:3216 case NodeTypeAwaitExpr:
3216 case NodeTypeSuspend:3217 case NodeTypeSuspend:
3217 zig_unreachable();3218 zig_unreachable();
src/ast_render.cpp+8
...@@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) {...@@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) {
246 return "ErrorSetDecl";246 return "ErrorSetDecl";
247 case NodeTypeCancel:247 case NodeTypeCancel:
248 return "Cancel";248 return "Cancel";
249 case NodeTypeResume:
250 return "Resume";
249 case NodeTypeAwaitExpr:251 case NodeTypeAwaitExpr:
250 return "AwaitExpr";252 return "AwaitExpr";
251 case NodeTypeSuspend:253 case NodeTypeSuspend:
...@@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1049 render_node_grouped(ar, node->data.cancel_expr.expr);1051 render_node_grouped(ar, node->data.cancel_expr.expr);
1050 break;1052 break;
1051 }1053 }
1054 case NodeTypeResume:
1055 {
1056 fprintf(ar->f, "resume ");
1057 render_node_grouped(ar, node->data.resume_expr.expr);
1058 break;
1059 }
1052 case NodeTypeAwaitExpr:1060 case NodeTypeAwaitExpr:
1053 {1061 {
1054 fprintf(ar->f, "await ");1062 fprintf(ar->f, "await ");
src/codegen.cpp+1-1
...@@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir...@@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir
40044004
4005static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {4005static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
4006 if (g->coro_alloc_helper_fn_val != nullptr)4006 if (g->coro_alloc_helper_fn_val != nullptr)
4007 return g->coro_alloc_fn_val;4007 return g->coro_alloc_helper_fn_val;
40084008
4009 assert(fn_type->id == TypeTableEntryIdFn);4009 assert(fn_type->id == TypeTableEntryIdFn);
40104010
src/ir.cpp+17-1
...@@ -5927,6 +5927,16 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -5927,6 +5927,16 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode
5927 return ir_build_cancel(irb, parent_scope, node, target_inst);5927 return ir_build_cancel(irb, parent_scope, node, target_inst);
5928}5928}
59295929
5930static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5931 assert(node->type == NodeTypeResume);
5932
5933 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope);
5934 if (target_inst == irb->codegen->invalid_instruction)
5935 return irb->codegen->invalid_instruction;
5936
5937 return ir_build_coro_resume(irb, parent_scope, node, target_inst);
5938}
5939
5930static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {5940static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5931 assert(node->type == NodeTypeAwaitExpr);5941 assert(node->type == NodeTypeAwaitExpr);
59325942
...@@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6101 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);6111 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
6102 case NodeTypeCancel:6112 case NodeTypeCancel:
6103 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);6113 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
6114 case NodeTypeResume:
6115 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval);
6104 case NodeTypeAwaitExpr:6116 case NodeTypeAwaitExpr:
6105 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);6117 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);
6106 case NodeTypeSuspend:6118 case NodeTypeSuspend:
...@@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst...@@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst
17364 if (type_is_invalid(awaiter_handle->value.type))17376 if (type_is_invalid(awaiter_handle->value.type))
17365 return ira->codegen->builtin_types.entry_invalid;17377 return ira->codegen->builtin_types.entry_invalid;
1736617378
17379 IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise);
17380 if (type_is_invalid(casted_target->value.type))
17381 return ira->codegen->builtin_types.entry_invalid;
17382
17367 IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope,17383 IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope,
17368 instruction->base.source_node, awaiter_handle);17384 instruction->base.source_node, casted_target);
17369 ir_link_new_instruction(result, &instruction->base);17385 ir_link_new_instruction(result, &instruction->base);
17370 result->value.type = ira->codegen->builtin_types.entry_void;17386 result->value.type = ira->codegen->builtin_types.entry_void;
17371 return result->value.type;17387 return result->value.type;
src/parser.cpp+26-1
...@@ -1638,6 +1638,24 @@ static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) {...@@ -1638,6 +1638,24 @@ static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) {
1638 return node;1638 return node;
1639}1639}
16401640
1641/*
1642ResumeExpression = "resume" Expression;
1643*/
1644static AstNode *ast_parse_resume_expr(ParseContext *pc, size_t *token_index) {
1645 Token *token = &pc->tokens->at(*token_index);
1646
1647 if (token->id != TokenIdKeywordResume) {
1648 return nullptr;
1649 }
1650 *token_index += 1;
1651
1652 AstNode *node = ast_create_node(pc, NodeTypeResume, token);
1653
1654 node->data.resume_expr.expr = ast_parse_expression(pc, token_index, false);
1655
1656 return node;
1657}
1658
1641/*1659/*
1642Defer(body) = ("defer" | "errdefer") body1660Defer(body) = ("defer" | "errdefer") body
1643*/1661*/
...@@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in...@@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
2266}2284}
22672285
2268/*2286/*
2269Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression2287Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
2270*/2288*/
2271static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {2289static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
2272 Token *token = &pc->tokens->at(*token_index);2290 Token *token = &pc->tokens->at(*token_index);
...@@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool...@@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
2287 if (cancel_expr)2305 if (cancel_expr)
2288 return cancel_expr;2306 return cancel_expr;
22892307
2308 AstNode *resume_expr = ast_parse_resume_expr(pc, token_index);
2309 if (resume_expr)
2310 return resume_expr;
2311
2290 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);2312 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
2291 if (ass_expr)2313 if (ass_expr)
2292 return ass_expr;2314 return ass_expr;
...@@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3060 case NodeTypeCancel:3082 case NodeTypeCancel:
3061 visit_field(&node->data.cancel_expr.expr, visit, context);3083 visit_field(&node->data.cancel_expr.expr, visit, context);
3062 break;3084 break;
3085 case NodeTypeResume:
3086 visit_field(&node->data.resume_expr.expr, visit, context);
3087 break;
3063 case NodeTypeAwaitExpr:3088 case NodeTypeAwaitExpr:
3064 visit_field(&node->data.await_expr.expr, visit, context);3089 visit_field(&node->data.await_expr.expr, visit, context);
3065 break;3090 break;
test/cases/coroutines.zig+27
...@@ -14,3 +14,30 @@ async fn simpleAsyncFn() void {...@@ -14,3 +14,30 @@ async fn simpleAsyncFn() void {
14 suspend;14 suspend;
15 x += 1;15 x += 1;
16}16}
17
18test "coroutine suspend, resume, cancel" {
19 seq('a');
20 const p = (async(std.debug.global_allocator) testAsyncSeq()) catch unreachable;
21 seq('c');
22 resume p;
23 seq('f');
24 cancel p;
25 seq('g');
26
27 assert(std.mem.eql(u8, points, "abcdefg"));
28}
29
30async fn testAsyncSeq() void {
31 defer seq('e');
32
33 seq('b');
34 suspend;
35 seq('d');
36}
37var points = []u8{0} ** "abcdefg".len;
38var index: usize = 0;
39
40fn seq(c: u8) void {
41 points[index] = c;
42 index += 1;
43}