From 3d58d7232ab6d1fd54523182beb99c31512bc4b9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 20 Feb 2018 00:05:38 -0500 Subject: parse async fn calls and cancel expressions --- src/ast_render.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/ast_render.cpp') diff --git a/src/ast_render.cpp b/src/ast_render.cpp index aed4b3e6db..eec4b996a0 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -244,6 +244,8 @@ static const char *node_type_str(NodeType node_type) { return "TestExpr"; case NodeTypeErrorSetDecl: return "ErrorSetDecl"; + case NodeTypeCancel: + return "Cancel"; } zig_unreachable(); } @@ -1037,6 +1039,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "}"); break; } + case NodeTypeCancel: + { + fprintf(ar->f, "cancel "); + render_node_grouped(ar, node->data.cancel_expr.expr); + break; + } case NodeTypeFnDecl: case NodeTypeParamDecl: case NodeTypeTestDecl: -- cgit v1.2.3 From c60496a297a0d4c53ad0e22850ad62b0b4a2d841 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Feb 2018 00:04:11 -0500 Subject: parse await and suspend syntax See #727 --- doc/langref.html.in | 10 +++++-- src/all_types.hpp | 13 +++++++++ src/analyze.cpp | 2 ++ src/ast_render.cpp | 21 ++++++++++++++ src/ir.cpp | 20 ++++++++++++++ src/parser.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 139 insertions(+), 6 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 9c33f9e607..2d4bead65e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5687,7 +5687,7 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "*%=" | "+%=" | "-%=" -BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) +BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body) CompTimeExpression(body) = "comptime" body @@ -5705,6 +5705,8 @@ ReturnExpression = "return" option(Expression) TryExpression = "try" Expression +AwaitExpression = "await" Expression + BreakExpression = "break" option(":" Symbol) option(Expression) CancelExpression = "cancel" Expression; @@ -5713,6 +5715,8 @@ Defer(body) = ("defer" | "deferror") body IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body)) +SuspendExpression(body) = "suspend" option(("|" Symbol "|" body)) + IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body) TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body)) @@ -5763,7 +5767,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") StructLiteralField = "." Symbol "=" Expression -PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" +PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl @@ -5771,7 +5775,7 @@ ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" GroupedExpression = "(" Expression ")" -KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" +KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" ErrorSetDecl = "error" "{" list(Symbol, ",") "}" diff --git a/src/all_types.hpp b/src/all_types.hpp index 3cf5676dfe..d2705d8ec6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -401,6 +401,8 @@ enum NodeType { NodeTypeTestExpr, NodeTypeErrorSetDecl, NodeTypeCancel, + NodeTypeAwaitExpr, + NodeTypeSuspend, }; struct AstNodeRoot { @@ -859,6 +861,15 @@ struct AstNodeErrorType { struct AstNodeVarLiteral { }; +struct AstNodeAwaitExpr { + AstNode *expr; +}; + +struct AstNodeSuspend { + AstNode *block; + AstNode *promise_symbol; +}; + struct AstNode { enum NodeType type; size_t line; @@ -917,6 +928,8 @@ struct AstNode { AstNodeVarLiteral var_literal; AstNodeErrorSetDecl err_set_decl; AstNodeCancelExpr cancel_expr; + AstNodeAwaitExpr await_expr; + AstNodeSuspend suspend; } data; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 69b6fe4790..ce9e99f8fa 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3214,6 +3214,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeTestExpr: case NodeTypeErrorSetDecl: case NodeTypeCancel: + case NodeTypeAwaitExpr: + case NodeTypeSuspend: zig_unreachable(); } } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index eec4b996a0..5f3e1998fd 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -246,6 +246,10 @@ static const char *node_type_str(NodeType node_type) { return "ErrorSetDecl"; case NodeTypeCancel: return "Cancel"; + case NodeTypeAwaitExpr: + return "AwaitExpr"; + case NodeTypeSuspend: + return "Suspend"; } zig_unreachable(); } @@ -1045,6 +1049,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { render_node_grouped(ar, node->data.cancel_expr.expr); break; } + case NodeTypeAwaitExpr: + { + fprintf(ar->f, "await "); + render_node_grouped(ar, node->data.await_expr.expr); + break; + } + case NodeTypeSuspend: + { + fprintf(ar->f, "suspend"); + if (node->data.suspend.block != nullptr) { + fprintf(ar->f, " |"); + render_node_grouped(ar, node->data.suspend.promise_symbol); + fprintf(ar->f, "| "); + render_node_grouped(ar, node->data.suspend.block); + } + break; + } case NodeTypeFnDecl: case NodeTypeParamDecl: case NodeTypeTestDecl: diff --git a/src/ir.cpp b/src/ir.cpp index 70a099f7c4..7ed66b92bd 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5834,6 +5834,22 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode return ir_build_cancel(irb, parent_scope, node, target_inst); } +static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeAwaitExpr); + + IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, parent_scope); + if (target_inst == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + zig_panic("TODO: generate await expr"); +} + +static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeSuspend); + + zig_panic("TODO: generate suspend"); +} + static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) { @@ -5932,6 +5948,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); case NodeTypeCancel: return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); + case NodeTypeAwaitExpr: + return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); + case NodeTypeSuspend: + return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval); } zig_unreachable(); } diff --git a/src/parser.cpp b/src/parser.cpp index e64c569e2f..763273fd0a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory); static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index); +static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index); static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index); static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { @@ -650,6 +651,41 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m return node; } +/* +SuspendExpression(body) = "suspend" "|" Symbol "|" body +*/ +static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) { + size_t orig_token_index = *token_index; + + Token *suspend_token = &pc->tokens->at(*token_index); + if (suspend_token->id == TokenIdKeywordSuspend) { + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, suspend_token, TokenIdKeywordSuspend); + zig_unreachable(); + } else { + return nullptr; + } + + Token *bar_token = &pc->tokens->at(*token_index); + if (bar_token->id == TokenIdBinOr) { + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, suspend_token, TokenIdBinOr); + zig_unreachable(); + } else { + *token_index = orig_token_index; + return nullptr; + } + + AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token); + node->data.suspend.promise_symbol = ast_parse_symbol(pc, token_index); + ast_eat_token(pc, token_index, TokenIdBinOr); + node->data.suspend.block = ast_parse_block(pc, token_index, true); + + return node; +} + /* CompTimeExpression(body) = "comptime" body */ @@ -674,7 +710,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b /* PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl -KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" +KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" ErrorSetDecl = "error" "{" list(Symbol, ",") "}" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -738,6 +774,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); *token_index += 1; return node; + } else if (token->id == TokenIdKeywordSuspend) { + AstNode *node = ast_create_node(pc, NodeTypeSuspend, token); + *token_index += 1; + return node; } else if (token->id == TokenIdKeywordError) { Token *next_token = &pc->tokens->at(*token_index + 1); if (next_token->id == TokenIdLBrace) { @@ -1067,7 +1107,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) { /* PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression -PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" +PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" */ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -1077,6 +1117,9 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, if (token->id == TokenIdKeywordTry) { return ast_parse_try_expr(pc, token_index); } + if (token->id == TokenIdKeywordAwait) { + return ast_parse_await_expr(pc, token_index); + } PrefixOp prefix_op = tok_to_prefix_op(token); if (prefix_op == PrefixOpInvalid) { return ast_parse_suffix_op_expr(pc, token_index, mandatory); @@ -1535,6 +1578,23 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index) { return node; } +/* +AwaitExpression : "await" Expression +*/ +static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index) { + Token *token = &pc->tokens->at(*token_index); + + if (token->id != TokenIdKeywordAwait) { + return nullptr; + } + *token_index += 1; + + AstNode *node = ast_create_node(pc, NodeTypeAwaitExpr, token); + node->data.await_expr.expr = ast_parse_expression(pc, token_index, true); + + return node; +} + /* BreakExpression = "break" option(":" Symbol) option(Expression) */ @@ -2044,7 +2104,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo } /* -BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) +BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body) */ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -2073,6 +2133,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool if (comptime_node) return comptime_node; + AstNode *suspend_node = ast_parse_suspend_block(pc, token_index, false); + if (suspend_node) + return suspend_node; + if (mandatory) ast_invalid_token_error(pc, token); @@ -2255,6 +2319,8 @@ static bool statement_terminates_without_semicolon(AstNode *node) { return node->data.comptime_expr.expr->type == NodeTypeBlock; case NodeTypeDefer: return node->data.defer.expr->type == NodeTypeBlock; + case NodeTypeSuspend: + return node->data.suspend.block != nullptr && node->data.suspend.block->type == NodeTypeBlock; case NodeTypeSwitchExpr: case NodeTypeBlock: return true; @@ -2994,5 +3060,12 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeCancel: visit_field(&node->data.cancel_expr.expr, visit, context); break; + case NodeTypeAwaitExpr: + visit_field(&node->data.await_expr.expr, visit, context); + break; + case NodeTypeSuspend: + visit_field(&node->data.suspend.promise_symbol, visit, context); + visit_field(&node->data.suspend.block, visit, context); + break; } } -- cgit v1.2.3 From 8429d4ceac4eb99fbe8aeca2ebe864dfd5b40470 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 28 Feb 2018 22:18:48 -0500 Subject: implement coroutine resume --- doc/langref.html.in | 4 +++- src/all_types.hpp | 6 ++++++ src/analyze.cpp | 1 + src/ast_render.cpp | 8 ++++++++ src/codegen.cpp | 2 +- src/ir.cpp | 18 +++++++++++++++++- src/parser.cpp | 27 ++++++++++++++++++++++++++- test/cases/coroutines.zig | 27 +++++++++++++++++++++++++++ 8 files changed, 89 insertions(+), 4 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 25a90e3361..83d5e65bba 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5682,7 +5682,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression BlockOrExpression = Block | Expression -Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression +Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")" @@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression) CancelExpression = "cancel" Expression; +ResumeExpression = "resume" Expression; + Defer(body) = ("defer" | "deferror") body IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body)) diff --git a/src/all_types.hpp b/src/all_types.hpp index d727f4a862..d2c7875943 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -403,6 +403,7 @@ enum NodeType { NodeTypeTestExpr, NodeTypeErrorSetDecl, NodeTypeCancel, + NodeTypeResume, NodeTypeAwaitExpr, NodeTypeSuspend, }; @@ -849,6 +850,10 @@ struct AstNodeCancelExpr { AstNode *expr; }; +struct AstNodeResumeExpr { + AstNode *expr; +}; + struct AstNodeContinueExpr { Buf *name; }; @@ -930,6 +935,7 @@ struct AstNode { AstNodeVarLiteral var_literal; AstNodeErrorSetDecl err_set_decl; AstNodeCancelExpr cancel_expr; + AstNodeResumeExpr resume_expr; AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; } data; diff --git a/src/analyze.cpp b/src/analyze.cpp index be01f6b5f8..8842b4967e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeTestExpr: case NodeTypeErrorSetDecl: case NodeTypeCancel: + case NodeTypeResume: case NodeTypeAwaitExpr: case NodeTypeSuspend: zig_unreachable(); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 5f3e1998fd..6318ba3cff 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) { return "ErrorSetDecl"; case NodeTypeCancel: return "Cancel"; + case NodeTypeResume: + return "Resume"; case NodeTypeAwaitExpr: return "AwaitExpr"; case NodeTypeSuspend: @@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { render_node_grouped(ar, node->data.cancel_expr.expr); break; } + case NodeTypeResume: + { + fprintf(ar->f, "resume "); + render_node_grouped(ar, node->data.resume_expr.expr); + break; + } case NodeTypeAwaitExpr: { fprintf(ar->f, "await "); diff --git a/src/codegen.cpp b/src/codegen.cpp index 315699b826..59956c9279 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) { if (g->coro_alloc_helper_fn_val != nullptr) - return g->coro_alloc_fn_val; + return g->coro_alloc_helper_fn_val; assert(fn_type->id == TypeTableEntryIdFn); diff --git a/src/ir.cpp b/src/ir.cpp index dc845bdaf7..4222196f37 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5927,6 +5927,16 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode return ir_build_cancel(irb, parent_scope, node, target_inst); } +static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeResume); + + IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope); + if (target_inst == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + return ir_build_coro_resume(irb, parent_scope, node, target_inst); +} + static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeAwaitExpr); @@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); case NodeTypeCancel: return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); + case NodeTypeResume: + return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval); case NodeTypeAwaitExpr: return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); case NodeTypeSuspend: @@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst if (type_is_invalid(awaiter_handle->value.type)) return ira->codegen->builtin_types.entry_invalid; + IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise); + if (type_is_invalid(casted_target->value.type)) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, awaiter_handle); + instruction->base.source_node, casted_target); ir_link_new_instruction(result, &instruction->base); result->value.type = ira->codegen->builtin_types.entry_void; return result->value.type; diff --git a/src/parser.cpp b/src/parser.cpp index 763273fd0a..38994c79fc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1638,6 +1638,24 @@ static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) { return node; } +/* +ResumeExpression = "resume" Expression; +*/ +static AstNode *ast_parse_resume_expr(ParseContext *pc, size_t *token_index) { + Token *token = &pc->tokens->at(*token_index); + + if (token->id != TokenIdKeywordResume) { + return nullptr; + } + *token_index += 1; + + AstNode *node = ast_create_node(pc, NodeTypeResume, token); + + node->data.resume_expr.expr = ast_parse_expression(pc, token_index, false); + + return node; +} + /* Defer(body) = ("defer" | "errdefer") body */ @@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in } /* -Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression +Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression */ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool if (cancel_expr) return cancel_expr; + AstNode *resume_expr = ast_parse_resume_expr(pc, token_index); + if (resume_expr) + return resume_expr; + AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false); if (ass_expr) return ass_expr; @@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeCancel: visit_field(&node->data.cancel_expr.expr, visit, context); break; + case NodeTypeResume: + visit_field(&node->data.resume_expr.expr, visit, context); + break; case NodeTypeAwaitExpr: visit_field(&node->data.await_expr.expr, visit, context); break; diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig index f5e70774fa..2a5505360c 100644 --- a/test/cases/coroutines.zig +++ b/test/cases/coroutines.zig @@ -14,3 +14,30 @@ async fn simpleAsyncFn() void { suspend; x += 1; } + +test "coroutine suspend, resume, cancel" { + seq('a'); + const p = (async(std.debug.global_allocator) testAsyncSeq()) catch unreachable; + seq('c'); + resume p; + seq('f'); + cancel p; + seq('g'); + + assert(std.mem.eql(u8, points, "abcdefg")); +} + +async fn testAsyncSeq() void { + defer seq('e'); + + seq('b'); + suspend; + seq('d'); +} +var points = []u8{0} ** "abcdefg".len; +var index: usize = 0; + +fn seq(c: u8) void { + points[index] = c; + index += 1; +} -- cgit v1.2.3