authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-02 14:15:31-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-02 14:15:31-04:00
log895f262a55b9951647efef4528c17cf64d6b7c07
tree14ec51f41d29214e550317f283aa8dcdbf223b9d
parent44fd3045ce85abb3e10dc0ad70d195b7d8044c43

pull request fixups

* clean up parser code * fix stage2 parse and render code * remove redundant test * make stage1 compile tests leaner

7 files changed, 53 insertions(+), 117 deletions(-)

src/parser.cpp+14-22
...@@ -651,37 +651,29 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m...@@ -651,37 +651,29 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
651SuspendExpression(body) = "suspend" option( body )651SuspendExpression(body) = "suspend" option( body )
652*/652*/
653static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {653static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {
654 size_t orig_token_index = *token_index;654 Token *suspend_token = &pc->tokens->at(*token_index);
655 Token *token = &pc->tokens->at(*token_index);
656 Token *suspend_token = nullptr;
657655
658 if (token->id == TokenIdKeywordSuspend) {656 if (suspend_token->id == TokenIdKeywordSuspend) {
659 *token_index += 1;657 *token_index += 1;
660 suspend_token = token;
661 token = &pc->tokens->at(*token_index);
662 } else if (mandatory) {658 } else if (mandatory) {
663 ast_expect_token(pc, token, TokenIdKeywordSuspend);659 ast_expect_token(pc, suspend_token, TokenIdKeywordSuspend);
664 zig_unreachable();660 zig_unreachable();
665 } else {661 } else {
666 return nullptr;662 return nullptr;
667 }663 }
668664
669 //guessing that semicolon is checked elsewhere?665 Token *lbrace = &pc->tokens->at(*token_index);
670 if (token->id != TokenIdLBrace) {666 if (lbrace->id == TokenIdLBrace) {
671 if (mandatory) {667 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
672 ast_expect_token(pc, token, TokenIdLBrace);668 node->data.suspend.block = ast_parse_block(pc, token_index, true);
673 zig_unreachable();669 return node;
674 } else {670 } else if (mandatory) {
675 *token_index = orig_token_index;671 ast_expect_token(pc, lbrace, TokenIdLBrace);
676 return nullptr;672 zig_unreachable();
677 }673 } else {
674 *token_index -= 1;
675 return nullptr;
678 }676 }
679
680 //Expect that we have a block;
681 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
682 node->data.suspend.block = ast_parse_block(pc, token_index, true);
683
684 return node;
685}677}
686678
687/*679/*
std/zig/ast.zig-12
...@@ -1778,19 +1778,12 @@ pub const Node = struct {...@@ -1778,19 +1778,12 @@ pub const Node = struct {
17781778
1779 pub const Suspend = struct {1779 pub const Suspend = struct {
1780 base: Node,1780 base: Node,
1781 label: ?TokenIndex,
1782 suspend_token: TokenIndex,1781 suspend_token: TokenIndex,
1783 payload: ?*Node,
1784 body: ?*Node,1782 body: ?*Node,
17851783
1786 pub fn iterate(self: *Suspend, index: usize) ?*Node {1784 pub fn iterate(self: *Suspend, index: usize) ?*Node {
1787 var i = index;1785 var i = index;
17881786
1789 if (self.payload) |payload| {
1790 if (i < 1) return payload;
1791 i -= 1;
1792 }
1793
1794 if (self.body) |body| {1787 if (self.body) |body| {
1795 if (i < 1) return body;1788 if (i < 1) return body;
1796 i -= 1;1789 i -= 1;
...@@ -1800,7 +1793,6 @@ pub const Node = struct {...@@ -1800,7 +1793,6 @@ pub const Node = struct {
1800 }1793 }
18011794
1802 pub fn firstToken(self: *Suspend) TokenIndex {1795 pub fn firstToken(self: *Suspend) TokenIndex {
1803 if (self.label) |label| return label;
1804 return self.suspend_token;1796 return self.suspend_token;
1805 }1797 }
18061798
...@@ -1809,10 +1801,6 @@ pub const Node = struct {...@@ -1809,10 +1801,6 @@ pub const Node = struct {
1809 return body.lastToken();1801 return body.lastToken();
1810 }1802 }
18111803
1812 if (self.payload) |payload| {
1813 return payload.lastToken();
1814 }
1815
1816 return self.suspend_token;1804 return self.suspend_token;
1817 }1805 }
1818 };1806 };
std/zig/parse.zig+14-19
...@@ -852,19 +852,6 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -852,19 +852,6 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
852 }) catch unreachable;852 }) catch unreachable;
853 continue;853 continue;
854 },854 },
855 Token.Id.Keyword_suspend => {
856 const node = try arena.create(ast.Node.Suspend{
857 .base = ast.Node{ .id = ast.Node.Id.Suspend },
858 .label = ctx.label,
859 .suspend_token = token_index,
860 .payload = null,
861 .body = null,
862 });
863 ctx.opt_ctx.store(&node.base);
864 stack.append(State{ .SuspendBody = node }) catch unreachable;
865 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
866 continue;
867 },
868 Token.Id.Keyword_inline => {855 Token.Id.Keyword_inline => {
869 stack.append(State{856 stack.append(State{
870 .Inline = InlineCtx{857 .Inline = InlineCtx{
...@@ -1415,10 +1402,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1415,10 +1402,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1415 },1402 },
14161403
1417 State.SuspendBody => |suspend_node| {1404 State.SuspendBody => |suspend_node| {
1418 if (suspend_node.payload != null) {1405 const token = nextToken(&tok_it, &tree);
1419 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });1406 switch (token.ptr.id) {
1407 Token.Id.Semicolon => {
1408 prevToken(&tok_it, &tree);
1409 continue;
1410 },
1411 Token.Id.LBrace => {
1412 prevToken(&tok_it, &tree);
1413 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
1414 continue;
1415 },
1416 else => {
1417 ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = token.index } };
1418 },
1420 }1419 }
1421 continue;
1422 },1420 },
1423 State.AsyncAllocator => |async_node| {1421 State.AsyncAllocator => |async_node| {
1424 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {1422 if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
...@@ -3086,15 +3084,12 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con...@@ -3086,15 +3084,12 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
3086 Token.Id.Keyword_suspend => {3084 Token.Id.Keyword_suspend => {
3087 const node = try arena.create(ast.Node.Suspend{3085 const node = try arena.create(ast.Node.Suspend{
3088 .base = ast.Node{ .id = ast.Node.Id.Suspend },3086 .base = ast.Node{ .id = ast.Node.Id.Suspend },
3089 .label = null,
3090 .suspend_token = token_index,3087 .suspend_token = token_index,
3091 .payload = null,
3092 .body = null,3088 .body = null,
3093 });3089 });
3094 ctx.store(&node.base);3090 ctx.store(&node.base);
30953091
3096 stack.append(State{ .SuspendBody = node }) catch unreachable;3092 stack.append(State{ .SuspendBody = node }) catch unreachable;
3097 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
3098 return true;3093 return true;
3099 },3094 },
3100 Token.Id.Keyword_if => {3095 Token.Id.Keyword_if => {
std/zig/parser_test.zig+3-3
...@@ -898,11 +898,11 @@ test "zig fmt: union(enum(u32)) with assigned enum values" {...@@ -898,11 +898,11 @@ test "zig fmt: union(enum(u32)) with assigned enum values" {
898 );898 );
899}899}
900900
901test "zig fmt: labeled suspend" {901test "zig fmt: resume from suspend block" {
902 try testCanonical(902 try testCanonical(
903 \\fn foo() void {903 \\fn foo() void {
904 \\ s: suspend |p| {904 \\ suspend {
905 \\ break :s;905 \\ resume @handle();
906 \\ }906 \\ }
907 \\}907 \\}
908 \\908 \\
std/zig/render.zig+1-15
...@@ -323,21 +323,7 @@ fn renderExpression(...@@ -323,21 +323,7 @@ fn renderExpression(
323 ast.Node.Id.Suspend => {323 ast.Node.Id.Suspend => {
324 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);324 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
325325
326 if (suspend_node.label) |label| {326 if (suspend_node.body) |body| {
327 try renderToken(tree, stream, label, indent, start_col, Space.None);
328 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
329 }
330
331 if (suspend_node.payload) |payload| {
332 if (suspend_node.body) |body| {
333 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
334 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
335 return renderExpression(allocator, stream, tree, indent, start_col, body, space);
336 } else {
337 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
338 return renderExpression(allocator, stream, tree, indent, start_col, payload, space);
339 }
340 } else if (suspend_node.body) |body| {
341 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);327 try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
342 return renderExpression(allocator, stream, tree, indent, start_col, body, space);328 return renderExpression(allocator, stream, tree, indent, start_col, body, space);
343 } else {329 } else {
test/cases/coroutines.zig-16
...@@ -256,19 +256,3 @@ async fn testBreakFromSuspend(my_result: *i32) void {...@@ -256,19 +256,3 @@ async fn testBreakFromSuspend(my_result: *i32) void {
256 suspend;256 suspend;
257 my_result.* += 1;257 my_result.* += 1;
258}258}
259
260test "suspend resume @handle()" {
261 var buf: [500]u8 = undefined;
262 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
263 var my_result: i32 = 1;
264 const p = try async<a> testBreakFromSuspend(&my_result);
265 std.debug.assert(my_result == 2);
266}
267async fn testSuspendResumeAtHandle() void {
268 suspend {
269 resume @handle();
270 }
271 my_result.* += 1;
272 suspend;
273 my_result.* += 1;
274}
\ No newline at end of file
test/compile_errors.zig+21-30
...@@ -1,6 +1,27 @@...@@ -1,6 +1,27 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "@handle() called outside of function definition",
6 \\var handle_undef: promise = undefined;
7 \\var handle_dummy: promise = @handle();
8 \\export fn entry() bool {
9 \\ return handle_undef == handle_dummy;
10 \\}
11 ,
12 ".tmp_source.zig:2:29: error: @handle() called outside of function definition",
13 );
14
15 cases.add(
16 "@handle() in non-async function",
17 \\export fn entry() bool {
18 \\ var handle_undef: promise = undefined;
19 \\ return handle_undef == @handle();
20 \\}
21 ,
22 ".tmp_source.zig:3:28: error: @handle() in non-async function",
23 );
24
4 cases.add(25 cases.add(
5 "while loop body expression ignored",26 "while loop body expression ignored",
6 \\fn returns() usize {27 \\fn returns() usize {
...@@ -4738,34 +4759,4 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4738,34 +4759,4 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4738 ,4759 ,
4739 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",4760 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
4740 );4761 );
4741
4742 cases.add(
4743 "@handle() called outside of function definition",
4744 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
4745 \\ @import("std").os.exit(126);
4746 \\}
4747 \\
4748 \\var handle_undef: promise = undefined;
4749 \\var handle_dummy: promise = @handle();
4750 \\
4751 \\pub fn main() void {
4752 \\ if (handle_undef == handle_dummy) return 0;
4753 \\}
4754 ,
4755 ".tmp_source.zig:6:29: error: @handle() called outside of function definition",
4756 );
4757
4758 cases.add(
4759 "@handle() in non-async function",
4760 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
4761 \\ @import("std").os.exit(126);
4762 \\}
4763 \\
4764 \\pub fn main() void {
4765 \\ var handle_undef: promise = undefined;
4766 \\ if (handle_undef == @handle()) return 0;
4767 \\}
4768 ,
4769 ".tmp_source.zig:7:25: error: @handle() in non-async function",
4770 );
4771}4762}