diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2024-04-29 02:25:54 +0100 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2024-09-01 18:30:31 +0100 |
| commit | 0cc8435a830d9d3850add163be4f12e5bd4f2f5c (patch) | |
| tree | f2b11a2c14628ed80865e6336ef2237504a107a7 /lib/std | |
| parent | 5e12ca9fe3c77ce1d2a3ea1c22c4bcb6d9b2bb0c (diff) | |
| download | zig-0cc8435a830d9d3850add163be4f12e5bd4f2f5c.tar.gz zig-0cc8435a830d9d3850add163be4f12e5bd4f2f5c.zip | |
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.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/zig/Ast.zig | 20 | ||||
| -rw-r--r-- | lib/std/zig/Parse.zig | 18 |
2 files changed, 24 insertions, 14 deletions
diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index b6f4ad68ee..d9080175c3 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -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 diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 20e69845cb..677911d14b 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -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{ |
