pull request fixups

* clean up parser code
 * fix stage2 parse and render code
 * remove redundant test
 * make stage1 compile tests leaner
This commit is contained in:
Andrew Kelley 2018-08-02 14:15:31 -04:00
parent 44fd3045ce
commit 895f262a55
7 changed files with 53 additions and 117 deletions

View File

@ -651,37 +651,29 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
SuspendExpression(body) = "suspend" option( body )
*/
static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {
size_t orig_token_index = *token_index;
Token *token = &pc->tokens->at(*token_index);
Token *suspend_token = nullptr;
Token *suspend_token = &pc->tokens->at(*token_index);
if (token->id == TokenIdKeywordSuspend) {
if (suspend_token->id == TokenIdKeywordSuspend) {
*token_index += 1;
suspend_token = token;
token = &pc->tokens->at(*token_index);
} else if (mandatory) {
ast_expect_token(pc, token, TokenIdKeywordSuspend);
ast_expect_token(pc, suspend_token, TokenIdKeywordSuspend);
zig_unreachable();
} else {
return nullptr;
}
//guessing that semicolon is checked elsewhere?
if (token->id != TokenIdLBrace) {
if (mandatory) {
ast_expect_token(pc, token, TokenIdLBrace);
zig_unreachable();
} else {
*token_index = orig_token_index;
return nullptr;
}
Token *lbrace = &pc->tokens->at(*token_index);
if (lbrace->id == TokenIdLBrace) {
AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
node->data.suspend.block = ast_parse_block(pc, token_index, true);
return node;
} else if (mandatory) {
ast_expect_token(pc, lbrace, TokenIdLBrace);
zig_unreachable();
} else {
*token_index -= 1;
return nullptr;
}
//Expect that we have a block;
AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
node->data.suspend.block = ast_parse_block(pc, token_index, true);
return node;
}
/*

View File

@ -1778,19 +1778,12 @@ pub const Node = struct {
pub const Suspend = struct {
base: Node,
label: ?TokenIndex,
suspend_token: TokenIndex,
payload: ?*Node,
body: ?*Node,
pub fn iterate(self: *Suspend, index: usize) ?*Node {
var i = index;
if (self.payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
if (self.body) |body| {
if (i < 1) return body;
i -= 1;
@ -1800,7 +1793,6 @@ pub const Node = struct {
}
pub fn firstToken(self: *Suspend) TokenIndex {
if (self.label) |label| return label;
return self.suspend_token;
}
@ -1809,10 +1801,6 @@ pub const Node = struct {
return body.lastToken();
}
if (self.payload) |payload| {
return payload.lastToken();
}
return self.suspend_token;
}
};

View File

@ -852,19 +852,6 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
}) catch unreachable;
continue;
},
Token.Id.Keyword_suspend => {
const node = try arena.create(ast.Node.Suspend{
.base = ast.Node{ .id = ast.Node.Id.Suspend },
.label = ctx.label,
.suspend_token = token_index,
.payload = null,
.body = null,
});
ctx.opt_ctx.store(&node.base);
stack.append(State{ .SuspendBody = node }) catch unreachable;
try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
continue;
},
Token.Id.Keyword_inline => {
stack.append(State{
.Inline = InlineCtx{
@ -1415,10 +1402,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
},
State.SuspendBody => |suspend_node| {
if (suspend_node.payload != null) {
try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
const token = nextToken(&tok_it, &tree);
switch (token.ptr.id) {
Token.Id.Semicolon => {
prevToken(&tok_it, &tree);
continue;
},
Token.Id.LBrace => {
prevToken(&tok_it, &tree);
try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .RequiredNull = &suspend_node.body } });
continue;
},
else => {
((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = token.index } };
},
}
continue;
},
State.AsyncAllocator => |async_node| {
if (eatToken(&tok_it, &tree, Token.Id.AngleBracketLeft) == null) {
@ -3086,15 +3084,12 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
Token.Id.Keyword_suspend => {
const node = try arena.create(ast.Node.Suspend{
.base = ast.Node{ .id = ast.Node.Id.Suspend },
.label = null,
.suspend_token = token_index,
.payload = null,
.body = null,
});
ctx.store(&node.base);
stack.append(State{ .SuspendBody = node }) catch unreachable;
try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
return true;
},
Token.Id.Keyword_if => {

View File

@ -898,11 +898,11 @@ test "zig fmt: union(enum(u32)) with assigned enum values" {
);
}
test "zig fmt: labeled suspend" {
test "zig fmt: resume from suspend block" {
try testCanonical(
\\fn foo() void {
\\ s: suspend |p| {
\\ break :s;
\\ suspend {
\\ resume @handle();
\\ }
\\}
\\

View File

@ -323,21 +323,7 @@ fn renderExpression(
ast.Node.Id.Suspend => {
const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
if (suspend_node.label) |label| {
try renderToken(tree, stream, label, indent, start_col, Space.None);
try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
}
if (suspend_node.payload) |payload| {
if (suspend_node.body) |body| {
try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, body, space);
} else {
try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, payload, space);
}
} else if (suspend_node.body) |body| {
if (suspend_node.body) |body| {
try renderToken(tree, stream, suspend_node.suspend_token, indent, start_col, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, body, space);
} else {

View File

@ -256,19 +256,3 @@ async fn testBreakFromSuspend(my_result: *i32) void {
suspend;
my_result.* += 1;
}
test "suspend resume @handle()" {
var buf: [500]u8 = undefined;
var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
var my_result: i32 = 1;
const p = try async<a> testBreakFromSuspend(&my_result);
std.debug.assert(my_result == 2);
}
async fn testSuspendResumeAtHandle() void {
suspend {
resume @handle();
}
my_result.* += 1;
suspend;
my_result.* += 1;
}

View File

@ -1,6 +1,27 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"@handle() called outside of function definition",
\\var handle_undef: promise = undefined;
\\var handle_dummy: promise = @handle();
\\export fn entry() bool {
\\ return handle_undef == handle_dummy;
\\}
,
".tmp_source.zig:2:29: error: @handle() called outside of function definition",
);
cases.add(
"@handle() in non-async function",
\\export fn entry() bool {
\\ var handle_undef: promise = undefined;
\\ return handle_undef == @handle();
\\}
,
".tmp_source.zig:3:28: error: @handle() in non-async function",
);
cases.add(
"while loop body expression ignored",
\\fn returns() usize {
@ -4738,34 +4759,4 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
,
".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
);
cases.add(
"@handle() called outside of function definition",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
\\}
\\
\\var handle_undef: promise = undefined;
\\var handle_dummy: promise = @handle();
\\
\\pub fn main() void {
\\ if (handle_undef == handle_dummy) return 0;
\\}
,
".tmp_source.zig:6:29: error: @handle() called outside of function definition",
);
cases.add(
"@handle() in non-async function",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
\\}
\\
\\pub fn main() void {
\\ var handle_undef: promise = undefined;
\\ if (handle_undef == @handle()) return 0;
\\}
,
".tmp_source.zig:7:25: error: @handle() in non-async function",
);
}