| author | |
| committer | |
| log | 895f262a55b9951647efef4528c17cf64d6b7c07 |
| tree | 14ec51f41d29214e550317f283aa8dcdbf223b9d |
| parent | 44fd3045ce85abb3e10dc0ad70d195b7d8044c43 |
* clean up parser code
* fix stage2 parse and render code
* remove redundant test
* make stage1 compile tests leaner7 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 |
| 651 | SuspendExpression(body) = "suspend" option( body ) | 651 | SuspendExpression(body) = "suspend" option( body ) |
| 652 | */ | 652 | */ |
| 653 | static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) { | 653 | static 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; | ||
| 657 | 655 | ||
| 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 | } |
| 668 | 664 | ||
| 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 | } |
| 686 | 678 | ||
| 687 | /* | 679 | /* |
std/zig/ast.zig-12| ... | @@ -1778,19 +1778,12 @@ pub const Node = struct { | ... | @@ -1778,19 +1778,12 @@ pub const Node = struct { |
| 1778 | 1778 | ||
| 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, |
| 1785 | 1783 | ||
| 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; |
| 1788 | 1786 | ||
| 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 | } |
| 1801 | 1794 | ||
| 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 | } |
| 1806 | 1798 | ||
| ... | @@ -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 | } |
| 1811 | 1803 | ||
| 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 | }, |
| 1416 | 1403 | ||
| 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); |
| 3095 | 3091 | ||
| 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 | } |
| 900 | 900 | ||
| 901 | test "zig fmt: labeled suspend" { | 901 | test "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); |
| 325 | 325 | ||
| 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 | |||
| 260 | test "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 | } | ||
| 267 | async 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 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub 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 | } |