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
signaturelock-open 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 {...@@ -1890,11 +1890,20 @@ pub fn taggedUnionEnumTag(tree: Ast, node: Node.Index) full.ContainerDecl {
18901890
1891pub fn switchFull(tree: Ast, node: Node.Index) full.Switch {1891pub fn switchFull(tree: Ast, node: Node.Index) full.Switch {
1892 const data = &tree.nodes.items(.data)[node];1892 const data = &tree.nodes.items(.data)[node];
1893 return tree.fullSwitchComponents(.{1893 const main_token = tree.nodes.items(.main_token)[node];
1894 .switch_token = tree.nodes.items(.main_token)[node],1894 const switch_token: TokenIndex, const label_token: ?TokenIndex = switch (tree.tokens.items(.tag)[main_token]) {
1895 .condition = data.lhs,1895 .identifier => .{ main_token + 2, main_token },
1896 .sub_range = data.rhs,1896 .keyword_switch => .{ main_token, null },
1897 });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 };
1898}1907}
18991908
1900pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase {1909pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase {
...@@ -3278,6 +3287,7 @@ pub const Node = struct {...@@ -3278,6 +3287,7 @@ pub const Node = struct {
3278 /// main_token is the `(`.3287 /// main_token is the `(`.
3279 async_call_comma,3288 async_call_comma,
3280 /// `switch(lhs) {}`. `SubRange[rhs]`.3289 /// `switch(lhs) {}`. `SubRange[rhs]`.
3290 /// `main_token` is the identifier of a preceding label, if any; otherwise `switch`.
3281 @"switch",3291 @"switch",
3282 /// Same as switch except there is known to be a trailing comma3292 /// Same as switch except there is known to be a trailing comma
3283 /// before the final rbrace3293 /// before the final rbrace
lib/std/zig/Parse.zig+9-9
...@@ -1245,7 +1245,7 @@ fn parseLabeledStatement(p: *Parse) !Node.Index {...@@ -1245,7 +1245,7 @@ fn parseLabeledStatement(p: *Parse) !Node.Index {
1245 const loop_stmt = try p.parseLoopStatement();1245 const loop_stmt = try p.parseLoopStatement();
1246 if (loop_stmt != 0) return loop_stmt;1246 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);
1249 if (switch_expr != 0) return switch_expr;1249 if (switch_expr != 0) return switch_expr;
12501250
1251 if (label_token != 0) {1251 if (label_token != 0) {
...@@ -2699,7 +2699,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {...@@ -2699,7 +2699,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
2699 .builtin => return p.parseBuiltinCall(),2699 .builtin => return p.parseBuiltinCall(),
2700 .keyword_fn => return p.parseFnProto(),2700 .keyword_fn => return p.parseFnProto(),
2701 .keyword_if => return p.parseIf(expectTypeExpr),2701 .keyword_if => return p.parseIf(expectTypeExpr),
2702 .keyword_switch => return p.expectSwitchExpr(),2702 .keyword_switch => return p.expectSwitchExpr(false),
27032703
2704 .keyword_extern,2704 .keyword_extern,
2705 .keyword_packed,2705 .keyword_packed,
...@@ -2756,7 +2756,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {...@@ -2756,7 +2756,7 @@ fn parsePrimaryTypeExpr(p: *Parse) !Node.Index {
2756 },2756 },
2757 .keyword_switch => {2757 .keyword_switch => {
2758 p.tok_i += 2;2758 p.tok_i += 2;
2759 return p.expectSwitchExpr();2759 return p.expectSwitchExpr(true);
2760 },2760 },
2761 .l_brace => {2761 .l_brace => {
2762 p.tok_i += 2;2762 p.tok_i += 2;
...@@ -3034,17 +3034,17 @@ fn parseWhileTypeExpr(p: *Parse) !Node.Index {...@@ -3034,17 +3034,17 @@ fn parseWhileTypeExpr(p: *Parse) !Node.Index {
3034}3034}
30353035
3036/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE3036/// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
3037fn parseSwitchExpr(p: *Parse) !Node.Index {3037fn parseSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
3038 const switch_token = p.eatToken(.keyword_switch) orelse return null_node;3038 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);
3040}3040}
30413041
3042fn expectSwitchExpr(p: *Parse) !Node.Index {3042fn expectSwitchExpr(p: *Parse, is_labeled: bool) !Node.Index {
3043 const switch_token = p.assertToken(.keyword_switch);3043 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);
3045}3045}
30463046
3047fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {3047fn expectSwitchSuffix(p: *Parse, main_token: TokenIndex) !Node.Index {
3048 _ = try p.expectToken(.l_paren);3048 _ = try p.expectToken(.l_paren);
3049 const expr_node = try p.expectExpr();3049 const expr_node = try p.expectExpr();
3050 _ = try p.expectToken(.r_paren);3050 _ = try p.expectToken(.r_paren);
...@@ -3055,7 +3055,7 @@ fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {...@@ -3055,7 +3055,7 @@ fn expectSwitchSuffix(p: *Parse, switch_token: TokenIndex) !Node.Index {
30553055
3056 return p.addNode(.{3056 return p.addNode(.{
3057 .tag = if (trailing_comma) .switch_comma else .@"switch",3057 .tag = if (trailing_comma) .switch_comma else .@"switch",
3058 .main_token = switch_token,3058 .main_token = main_token,
3059 .data = .{3059 .data = .{
3060 .lhs = expr_node,3060 .lhs = expr_node,
3061 .rhs = try p.addExtra(Node.SubRange{3061 .rhs = try p.addExtra(Node.SubRange{