feature. See also
. The project being documented here (as the example) is the Zig library itself.
Parse.parseWhileStatement
fn parseWhileStatement(p: *Parse) !?Node.Index
File
Code
fn parseWhileStatement(p: *Parse) !?Node.Index {
const while_token = p.eatToken(.keyword_while) orelse return null;
_ = try p.expectToken(.l_paren);
const condition = try p.expectExpr();
_ = try p.expectToken(.r_paren);
_ = try p.parsePtrPayload();
const cont_expr = try p.parseWhileContinueExpr();
// inside while statements, even if there is an `else`.
var else_required = false;
const then_expr = blk: {
const block_expr = try p.parseBlockExpr();
if (block_expr) |block| break :blk block;
const assign_expr = try p.parseAssignExpr() orelse {
return p.fail(.expected_block_or_assignment);
};
if (p.eatToken(.semicolon)) |_| {
if (cont_expr == null) {
return try p.addNode(.{
.tag = .while_simple,
.main_token = while_token,
.data = .{ .node_and_node = .{
condition,
assign_expr,
} },
});
} else {
return try p.addNode(.{
.tag = .while_cont,
.main_token = while_token,
.data = .{ .node_and_extra = .{
condition,
try p.addExtra(Node.WhileCont{
.cont_expr = cont_expr.?,
.then_expr = assign_expr,
}),
} },
});
}
}
else_required = true;
break :blk assign_expr;
};
_ = p.eatToken(.keyword_else) orelse {
if (else_required) {
try p.warn(.expected_semi_or_else);
}
if (cont_expr == null) {
return try p.addNode(.{
.tag = .while_simple,
.main_token = while_token,
.data = .{ .node_and_node = .{
condition,
then_expr,
} },
});
} else {
return try p.addNode(.{
.tag = .while_cont,
.main_token = while_token,
.data = .{ .node_and_extra = .{
condition,
try p.addExtra(Node.WhileCont{
.cont_expr = cont_expr.?,
.then_expr = then_expr,
}),
} },
});
}
};
_ = try p.parsePayload();
const else_expr = try p.expectStatement(false);
return try p.addNode(.{
.tag = .@"while",
.main_token = while_token,
.data = .{ .node_and_extra = .{
condition,
try p.addExtra(Node.While{
.cont_expr = .fromOptional(cont_expr),
.then_expr = then_expr,
.else_expr = else_expr,
}),
} },
});
}