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
56825682
56835683BlockOrExpression = Block | Expression
56845684
5685Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression
5685Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
56865686
56875687AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
56885688
......@@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression)
57305730
57315731CancelExpression = "cancel" Expression;
57325732
5733ResumeExpression = "resume" Expression;
5734
57335735Defer(body) = ("defer" | "deferror") body
57345736
57355737IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
src/all_types.hpp+6
......@@ -403,6 +403,7 @@ enum NodeType {
403403 NodeTypeTestExpr,
404404 NodeTypeErrorSetDecl,
405405 NodeTypeCancel,
406 NodeTypeResume,
406407 NodeTypeAwaitExpr,
407408 NodeTypeSuspend,
408409};
......@@ -849,6 +850,10 @@ struct AstNodeCancelExpr {
849850 AstNode *expr;
850851};
851852
853struct AstNodeResumeExpr {
854 AstNode *expr;
855};
856
852857struct AstNodeContinueExpr {
853858 Buf *name;
854859};
......@@ -930,6 +935,7 @@ struct AstNode {
930935 AstNodeVarLiteral var_literal;
931936 AstNodeErrorSetDecl err_set_decl;
932937 AstNodeCancelExpr cancel_expr;
938 AstNodeResumeExpr resume_expr;
933939 AstNodeAwaitExpr await_expr;
934940 AstNodeSuspend suspend;
935941 } data;
src/analyze.cpp+1
......@@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
32123212 case NodeTypeTestExpr:
32133213 case NodeTypeErrorSetDecl:
32143214 case NodeTypeCancel:
3215 case NodeTypeResume:
32153216 case NodeTypeAwaitExpr:
32163217 case NodeTypeSuspend:
32173218 zig_unreachable();
src/ast_render.cpp+8
......@@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) {
246246 return "ErrorSetDecl";
247247 case NodeTypeCancel:
248248 return "Cancel";
249 case NodeTypeResume:
250 return "Resume";
249251 case NodeTypeAwaitExpr:
250252 return "AwaitExpr";
251253 case NodeTypeSuspend:
......@@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10491051 render_node_grouped(ar, node->data.cancel_expr.expr);
10501052 break;
10511053 }
1054 case NodeTypeResume:
1055 {
1056 fprintf(ar->f, "resume ");
1057 render_node_grouped(ar, node->data.resume_expr.expr);
1058 break;
1059 }
10521060 case NodeTypeAwaitExpr:
10531061 {
10541062 fprintf(ar->f, "await ");
src/codegen.cpp+1-1
......@@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir
40044004
40054005static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
40064006 if (g->coro_alloc_helper_fn_val != nullptr)
4007 return g->coro_alloc_fn_val;
4007 return g->coro_alloc_helper_fn_val;
40084008
40094009 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
59275927 return ir_build_cancel(irb, parent_scope, node, target_inst);
59285928}
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
59305940static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
59315941 assert(node->type == NodeTypeAwaitExpr);
59325942
......@@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
61016111 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
61026112 case NodeTypeCancel:
61036113 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);
61046116 case NodeTypeAwaitExpr:
61056117 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);
61066118 case NodeTypeSuspend:
......@@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst
1736417376 if (type_is_invalid(awaiter_handle->value.type))
1736517377 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
1736717383 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);
1736917385 ir_link_new_instruction(result, &instruction->base);
1737017386 result->value.type = ira->codegen->builtin_types.entry_void;
1737117387 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) {
16381638 return node;
16391639}
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
16411659/*
16421660Defer(body) = ("defer" | "errdefer") body
16431661*/
......@@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
22662284}
22672285
22682286/*
2269Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression
2287Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
22702288*/
22712289static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
22722290 Token *token = &pc->tokens->at(*token_index);
......@@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
22872305 if (cancel_expr)
22882306 return cancel_expr;
22892307
2308 AstNode *resume_expr = ast_parse_resume_expr(pc, token_index);
2309 if (resume_expr)
2310 return resume_expr;
2311
22902312 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
22912313 if (ass_expr)
22922314 return ass_expr;
......@@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30603082 case NodeTypeCancel:
30613083 visit_field(&node->data.cancel_expr.expr, visit, context);
30623084 break;
3085 case NodeTypeResume:
3086 visit_field(&node->data.resume_expr.expr, visit, context);
3087 break;
30633088 case NodeTypeAwaitExpr:
30643089 visit_field(&node->data.await_expr.expr, visit, context);
30653090 break;
test/cases/coroutines.zig+27
......@@ -14,3 +14,30 @@ async fn simpleAsyncFn() void {
1414 suspend;
1515 x += 1;
1616}
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}