mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
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:
parent
44fd3045ce
commit
895f262a55
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -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 => {
|
||||
|
||||
@ -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();
|
||||
\\ }
|
||||
\\}
|
||||
\\
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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",
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user