mirror of
https://github.com/ziglang/zig.git
synced 2026-01-03 03:53:20 +00:00
std.zig: resolve syntactic ambiguity
The parse of `fn foo(a: switch (...) { ... })` was previously handled
incorrectly; `a` was treated as both the parameter name and a label.
The same issue exists for `for` and `while` expressions -- they should
be fixed too, and the grammar amended appropriately. This commit does
not do this: it only aims to avoid introducing regressions from labeled
switch syntax.
This commit is contained in:
parent
5e12ca9fe3
commit
0cc8435a83
@ -1890,11 +1890,20 @@ pub fn taggedUnionEnumTag(tree: Ast, node: Node.Index) full.ContainerDecl {
|
||||
|
||||
pub fn switchFull(tree: Ast, node: Node.Index) full.Switch {
|
||||
const data = &tree.nodes.items(.data)[node];
|
||||
return tree.fullSwitchComponents(.{
|
||||
.switch_token = tree.nodes.items(.main_token)[node],
|
||||
.condition = data.lhs,
|
||||
.sub_range = data.rhs,
|
||||
});
|
||||
const main_token = tree.nodes.items(.main_token)[node];
|
||||
const switch_token: TokenIndex, const label_token: ?TokenIndex = switch (tree.tokens.items(.tag)[main_token]) {
|
||||
.identifier => .{ main_token + 2, main_token },
|
||||
.keyword_switch => .{ main_token, null },
|
||||
else => unreachable,
|
||||
};
|
||||
return .{
|
||||
.ast = .{
|
||||
.switch_token = switch_token,
|
||||
.condition = data.lhs,
|
||||
.sub_range = data.rhs,
|
||||
},
|
||||
.label_token = label_token,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase {
|
||||
@ -3278,6 +3287,7 @@ pub const Node = struct {
|
||||
/// main_token is the `(`.
|
||||
async_call_comma,
|
||||
/// `switch(lhs) {}`. `SubRange[rhs]`.
|
||||
/// `main_token` is the identifier of a preceding label, if any; otherwise `switch`.
|
||||
@"switch",
|
||||
/// Same as switch except there is known to be a trailing comma
|
||||
/// before the final rbrace
|
||||
|
||||
@ -1245,7 +1245,7 @@ fn parseLabeledStatement(p: *Parse) !Node.Index {
|
||||
const loop_stmt = try p.parseLoopStatement();
|
||||
if (loop_stmt != 0) return loop_stmt;
|
||||
|
||||
const switch_expr = try p.parseSwitchExpr();
|
||||
const switch_expr = try p.parseSwitchExpr(label_token != 0);
|
||||
if (switch_expr != 0) return switch_expr;
|
||||
|
||||
if (label_token != 0) {
|
||||
@ -2699,7 +2699,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
|
||||
.builtin => return p.parseBuiltinCall(),
|
||||
.keyword_fn => return p.parseFnProto(),
|
||||
.keyword_if => return p.parseIf(expectTypeExpr),
|
||||
.keyword_switch => return p.expectSwitchExpr(),
|
||||
.keyword_switch => return p.expectSwitchExpr(false),
|
||||
|
||||
.keyword_extern,
|
||||
.keyword_packed,
|
||||
@ -2756,7 +2756,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
|
||||
},
|
||||
.keyword_switch => {
|
||||
p.tok_i += 2;
|
||||
return p.expectSwitchExpr();
|
||||
return p.expectSwitchExpr(true);
|
||||
},
|
||||
.l_brace => {
|
||||
p.tok_i += 2;
|
||||
@ -3034,17 +3034,17 @@ fn parseWhileTypeExpr(p: *Parse) !Node.Index {
|
||||
}
|
||||
|
||||
/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
|
||||
fn parseSwitchExpr(p: *Parse) !Node.Index {
|
||||
fn parseSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
|
||||
const switch_token = p.eatToken(.keyword_switch) orelse return null_node;
|
||||
return p.expectSwitchSuffix(switch_token);
|
||||
return p.expectSwitchSuffix(if (is_labeled) switch_token - 2 else switch_token);
|
||||
}
|
||||
|
||||
fn expectSwitchExpr(p: *Parse) !Node.Index {
|
||||
fn expectSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
|
||||
const switch_token = p.assertToken(.keyword_switch);
|
||||
return p.expectSwitchSuffix(switch_token);
|
||||
return p.expectSwitchSuffix(if (is_labeled) switch_token - 2 else switch_token);
|
||||
}
|
||||
|
||||
fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {
|
||||
fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {
|
||||
_ = try p.expectToken(.l_paren);
|
||||
const expr_node = try p.expectExpr();
|
||||
_ = try p.expectToken(.r_paren);
|
||||
@ -3055,7 +3055,7 @@ fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {
|
||||
|
||||
return p.addNode(.{
|
||||
.tag = if (trailing_comma) .switch_comma else .@"switch",
|
||||
.main_token = switch_token,
|
||||
.main_token = main_token,
|
||||
.data = .{
|
||||
.lhs = expr_node,
|
||||
.rhs = try p.addExtra(Node.SubRange{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user