authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-04-29 02:25:54+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-01 18:30:31+01:00
log0cc8435a830d9d3850add163be4f12e5bd4f2f5c
treef2b11a2c14628ed80865e6336ef2237504a107a7
parent5e12ca9fe3c77ce1d2a3ea1c22c4bcb6d9b2bb0c
signature Commit is signed but in an unrecognized format.

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.

2 files changed, 24 insertions(+), 14 deletions(-)

lib/std/zig/Ast.zig+15-5
......@@ -1890,11 +1890,20 @@ pub fn taggedUnionEnumTag(tree: Ast, node: Node.Index) full.ContainerDecl {
18901890
18911891pub fn switchFull(tree: Ast, node: Node.Index) full.Switch {
18921892 const data = &tree.nodes.items(.data)[node];
1893 return tree.fullSwitchComponents(.{
1894 .switch_token = tree.nodes.items(.main_token)[node],
1895 .condition = data.lhs,
1896 .sub_range = data.rhs,
1897 });
1893 const main_token = tree.nodes.items(.main_token)[node];
1894 const switch_token: TokenIndex, const label_token: ?TokenIndex = switch (tree.tokens.items(.tag)[main_token]) {
1895 .identifier => .{ main_token + 2, main_token },
1896 .keyword_switch => .{ main_token, null },
1897 else => unreachable,
1898 };
1899 return .{
1900 .ast = .{
1901 .switch_token = switch_token,
1902 .condition = data.lhs,
1903 .sub_range = data.rhs,
1904 },
1905 .label_token = label_token,
1906 };
18981907}
18991908
19001909pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase {
......@@ -3278,6 +3287,7 @@ pub const Node = struct {
32783287 /// main_token is the `(`.
32793288 async_call_comma,
32803289 /// `switch(lhs) {}`. `SubRange[rhs]`.
3290 /// `main_token` is the identifier of a preceding label, if any; otherwise `switch`.
32813291 @"switch",
32823292 /// Same as switch except there is known to be a trailing comma
32833293 /// before the final rbrace
lib/std/zig/Parse.zig+9-9
......@@ -1245,7 +1245,7 @@ fn parseLabeledStatement(p: *Parse) !Node.Index {
12451245 const loop_stmt = try p.parseLoopStatement();
12461246 if (loop_stmt != 0) return loop_stmt;
12471247
1248 const switch_expr = try p.parseSwitchExpr();
1248 const switch_expr = try p.parseSwitchExpr(label_token != 0);
12491249 if (switch_expr != 0) return switch_expr;
12501250
12511251 if (label_token != 0) {
......@@ -2699,7 +2699,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
26992699 .builtin => return p.parseBuiltinCall(),
27002700 .keyword_fn => return p.parseFnProto(),
27012701 .keyword_if => return p.parseIf(expectTypeExpr),
2702 .keyword_switch => return p.expectSwitchExpr(),
2702 .keyword_switch => return p.expectSwitchExpr(false),
27032703
27042704 .keyword_extern,
27052705 .keyword_packed,
......@@ -2756,7 +2756,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
27562756 },
27572757 .keyword_switch => {
27582758 p.tok_i += 2;
2759 return p.expectSwitchExpr();
2759 return p.expectSwitchExpr(true);
27602760 },
27612761 .l_brace => {
27622762 p.tok_i += 2;
......@@ -3034,17 +3034,17 @@ fn parseWhileTypeExpr(p: *Parse) !Node.Index {
30343034}
30353035
30363036/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
3037fn parseSwitchExpr(p: *Parse) !Node.Index {
3037fn parseSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
30383038 const switch_token = p.eatToken(.keyword_switch) orelse return null_node;
3039 return p.expectSwitchSuffix(switch_token);
3039 return p.expectSwitchSuffix(if (is_labeled) switch_token - 2 else switch_token);
30403040}
30413041
3042fn expectSwitchExpr(p: *Parse) !Node.Index {
3042fn expectSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
30433043 const switch_token = p.assertToken(.keyword_switch);
3044 return p.expectSwitchSuffix(switch_token);
3044 return p.expectSwitchSuffix(if (is_labeled) switch_token - 2 else switch_token);
30453045}
30463046
3047fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {
3047fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {
30483048 _ = try p.expectToken(.l_paren);
30493049 const expr_node = try p.expectExpr();
30503050 _ = try p.expectToken(.r_paren);
......@@ -3055,7 +3055,7 @@ fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {
30553055
30563056 return p.addNode(.{
30573057 .tag = if (trailing_comma) .switch_comma else .@"switch",
3058 .main_token = switch_token,
3058 .main_token = main_token,
30593059 .data = .{
30603060 .lhs = expr_node,
30613061 .rhs = try p.addExtra(Node.SubRange{