authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-21 19:56:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-21 19:56:41-04:00
logf885a1ab61a664378c3f3062a3de1150b6a4ee07
tree87e29d3ebcd6d7d7b859cc9ef9c33b83c8a3433c
parent66fec3a3d726733b162761211dee58e896370e95

change async function call syntax

* instead of `async(allocator) call()`, now it is `async<allocator> call()`. * Fixes syntax ambiguity when leaving off the allocator * Fixes parse failure when call is a field access This sets a precedent for using `<` to pass arguments to a keyword. This will affect `enum`, `union`, and `fn` (see #661)

4 files changed, 31 insertions(+), 17 deletions(-)

doc/langref.html.in+1-1
......@@ -5845,7 +5845,7 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
58455845
58465846PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
58475847
5848SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
5848SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
58495849
58505850FieldAccessExpression = "." Symbol
58515851
src/parser.cpp+10-9
......@@ -956,7 +956,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
956956}
957957
958958/*
959SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
959SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
960960FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
961961ArrayAccessExpression : token(LBracket) Expression token(RBracket)
962962SliceExpression = "[" Expression ".." option(Expression) "]"
......@@ -972,19 +972,20 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
972972
973973 AstNode *allocator_expr_node = nullptr;
974974 Token *async_lparen_tok = &pc->tokens->at(*token_index);
975 if (async_lparen_tok->id == TokenIdLParen) {
975 if (async_lparen_tok->id == TokenIdCmpLessThan) {
976976 *token_index += 1;
977 allocator_expr_node = ast_parse_expression(pc, token_index, true);
978 ast_eat_token(pc, token_index, TokenIdRParen);
977 allocator_expr_node = ast_parse_prefix_op_expr(pc, token_index, true);
978 ast_eat_token(pc, token_index, TokenIdCmpGreaterThan);
979979 }
980980
981 AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true);
982 Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen);
983 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok);
981 Token *fncall_token = &pc->tokens->at(*token_index);
982 AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);
983 if (node->type != NodeTypeFnCallExpr) {
984 ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id));
985 }
984986 node->data.fn_call_expr.is_async = true;
985987 node->data.fn_call_expr.async_allocator = allocator_expr_node;
986 node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node;
987 ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
988 assert(node->data.fn_call_expr.fn_ref_expr != nullptr);
988989
989990 primary_expr = node;
990991 } else {
test/cases/coroutines.zig+19-6
......@@ -4,7 +4,7 @@ const assert = std.debug.assert;
44var x: i32 = 1;
55
66test "create a coroutine and cancel it" {
7 const p = try async(std.debug.global_allocator) simpleAsyncFn();
7 const p = try async<std.debug.global_allocator> simpleAsyncFn();
88 cancel p;
99 assert(x == 2);
1010}
......@@ -17,7 +17,7 @@ async fn simpleAsyncFn() void {
1717
1818test "coroutine suspend, resume, cancel" {
1919 seq('a');
20 const p = try async(std.debug.global_allocator) testAsyncSeq();
20 const p = try async<std.debug.global_allocator> testAsyncSeq();
2121 seq('c');
2222 resume p;
2323 seq('f');
......@@ -43,7 +43,7 @@ fn seq(c: u8) void {
4343}
4444
4545test "coroutine suspend with block" {
46 const p = try async(std.debug.global_allocator) testSuspendBlock();
46 const p = try async<std.debug.global_allocator> testSuspendBlock();
4747 std.debug.assert(!result);
4848 resume a_promise;
4949 std.debug.assert(result);
......@@ -65,7 +65,7 @@ var await_final_result: i32 = 0;
6565
6666test "coroutine await" {
6767 await_seq('a');
68 const p = async(std.debug.global_allocator) await_amain() catch unreachable;
68 const p = async<std.debug.global_allocator> await_amain() catch unreachable;
6969 await_seq('f');
7070 resume await_a_promise;
7171 await_seq('i');
......@@ -104,7 +104,7 @@ var early_final_result: i32 = 0;
104104
105105test "coroutine await early return" {
106106 early_seq('a');
107 const p = async(std.debug.global_allocator) early_amain() catch unreachable;
107 const p = async<std.debug.global_allocator> early_amain() catch unreachable;
108108 early_seq('f');
109109 assert(early_final_result == 1234);
110110 assert(std.mem.eql(u8, early_points, "abcdef"));
......@@ -133,7 +133,7 @@ fn early_seq(c: u8) void {
133133
134134test "coro allocation failure" {
135135 var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
136 if (async(&failing_allocator.allocator) asyncFuncThatNeverGetsRun()) {
136 if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
137137 @panic("expected allocation failure");
138138 } else |err| switch (err) {
139139 error.OutOfMemory => {},
......@@ -143,3 +143,16 @@ test "coro allocation failure" {
143143async fn asyncFuncThatNeverGetsRun() void {
144144 @panic("coro frame allocation should fail");
145145}
146
147test "async function with dot syntax" {
148 const S = struct {
149 var y: i32 = 1;
150 async fn foo() void {
151 y += 1;
152 suspend;
153 }
154 };
155 const p = try async<std.debug.global_allocator> S.foo();
156 cancel p;
157 assert(S.y == 2);
158}
test/compile_errors.zig+1-1
......@@ -17,7 +17,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1717 cases.add("returning error from void async function",
1818 \\const std = @import("std");
1919 \\export fn entry() void {
20 \\ const p = async(std.debug.global_allocator) amain() catch unreachable;
20 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;
2121 \\}
2222 \\async fn amain() void {
2323 \\ return error.ShouldBeCompileError;