parser: disallow defer and variable declaration as else branch

Closes #13658
This commit is contained in:
Veikka Tuominen 2022-11-26 22:40:43 +02:00
parent 1829b6eab8
commit 34be5784a3
2 changed files with 39 additions and 13 deletions

View File

@ -950,13 +950,15 @@ const Parser = struct {
/// / LabeledStatement
/// / SwitchExpr
/// / AssignExpr SEMICOLON
fn parseStatement(p: *Parser) Error!Node.Index {
fn parseStatement(p: *Parser, allow_defer_var: bool) Error!Node.Index {
const comptime_token = p.eatToken(.keyword_comptime);
const var_decl = try p.parseVarDecl();
if (var_decl != 0) {
try p.expectSemicolon(.expected_semi_after_decl, true);
return var_decl;
if (allow_defer_var) {
const var_decl = try p.parseVarDecl();
if (var_decl != 0) {
try p.expectSemicolon(.expected_semi_after_decl, true);
return var_decl;
}
}
if (comptime_token) |token| {
@ -993,7 +995,7 @@ const Parser = struct {
},
});
},
.keyword_defer => return p.addNode(.{
.keyword_defer => if (allow_defer_var) return p.addNode(.{
.tag = .@"defer",
.main_token = p.nextToken(),
.data = .{
@ -1001,7 +1003,7 @@ const Parser = struct {
.rhs = try p.expectBlockExprStatement(),
},
}),
.keyword_errdefer => return p.addNode(.{
.keyword_errdefer => if (allow_defer_var) return p.addNode(.{
.tag = .@"errdefer",
.main_token = p.nextToken(),
.data = .{
@ -1040,8 +1042,8 @@ const Parser = struct {
return null_node;
}
fn expectStatement(p: *Parser) !Node.Index {
const statement = try p.parseStatement();
fn expectStatement(p: *Parser, allow_defer_var: bool) !Node.Index {
const statement = try p.parseStatement(allow_defer_var);
if (statement == 0) {
return p.fail(.expected_statement);
}
@ -1053,7 +1055,7 @@ const Parser = struct {
/// statement, returns 0.
fn expectStatementRecoverable(p: *Parser) Error!Node.Index {
while (true) {
return p.expectStatement() catch |err| switch (err) {
return p.expectStatement(true) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextStmt(); // Try to skip to the next statement.
@ -1114,7 +1116,7 @@ const Parser = struct {
});
};
_ = try p.parsePayload();
const else_expr = try p.expectStatement();
const else_expr = try p.expectStatement(false);
return p.addNode(.{
.tag = .@"if",
.main_token = if_token,
@ -1226,7 +1228,7 @@ const Parser = struct {
.lhs = array_expr,
.rhs = try p.addExtra(Node.If{
.then_expr = then_expr,
.else_expr = try p.expectStatement(),
.else_expr = try p.expectStatement(false),
}),
},
});
@ -1309,7 +1311,7 @@ const Parser = struct {
}
};
_ = try p.parsePayload();
const else_expr = try p.expectStatement();
const else_expr = try p.expectStatement(false);
return p.addNode(.{
.tag = .@"while",
.main_token = while_token,

View File

@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {
);
}
test "zig fmt: invalid else branch statement" {
try testError(
\\comptime {
\\ if (true) {} else var a = 0;
\\ if (true) {} else defer {}
\\}
\\comptime {
\\ while (true) {} else var a = 0;
\\ while (true) {} else defer {}
\\}
\\comptime {
\\ for ("") |_| {} else var a = 0;
\\ for ("") |_| {} else defer {}
\\}
, &[_]Error{
.expected_statement,
.expected_statement,
.expected_statement,
.expected_statement,
.expected_statement,
.expected_statement,
});
}
test "zig fmt: anytype struct field" {
try testError(
\\pub const Pointer = struct {