| author | |
| committer | |
| log | 57cec38e6144754fcd15266100974a7cf0059570 |
| tree | 0e84bb83b0802b7643236cf64585a7c46d7e6543 |
| parent | 0e38362d244f118565f447f8ee2c6b8a700d05bf |
The fact that blocks may end in a semicolon but this semicolon is not
counted by recursive lastToken() evaluation on the sub expression causes
off-by-one errors for lastToken() on blocks currently.
To fix this, introduce BlockSemicolon and BlockTwoSemicolon following
the pattern used for trailing commas in e.g. builtin function arguments.4 files changed, 42 insertions(+), 11 deletions(-)
lib/std/zig/ast.zig+12-6| ... | ... | @@ -357,7 +357,9 @@ pub const Tree = struct { |
| 357 | 357 | }, |
| 358 | 358 | |
| 359 | 359 | .Block, |
| 360 | .BlockSemicolon, | |
| 360 | 361 | .BlockTwo, |
| 362 | .BlockTwoSemicolon, | |
| 361 | 363 | => { |
| 362 | 364 | // Look for a label. |
| 363 | 365 | const lbrace = main_tokens[n]; |
| ... | ... | @@ -552,18 +554,17 @@ pub const Tree = struct { |
| 552 | 554 | .TaggedUnion, |
| 553 | 555 | .BuiltinCall, |
| 554 | 556 | => { |
| 557 | assert(datas[n].rhs - datas[n].lhs > 0); | |
| 555 | 558 | end_offset += 1; // for the rbrace |
| 556 | if (datas[n].rhs - datas[n].lhs == 0) { | |
| 557 | return main_tokens[n] + end_offset; | |
| 558 | } | |
| 559 | 559 | n = tree.extra_data[datas[n].rhs - 1]; // last statement |
| 560 | 560 | }, |
| 561 | .BlockSemicolon, | |
| 561 | 562 | .ContainerDeclComma, |
| 562 | 563 | .TaggedUnionComma, |
| 563 | 564 | .BuiltinCallComma, |
| 564 | 565 | => { |
| 565 | 566 | assert(datas[n].rhs - datas[n].lhs > 0); |
| 566 | end_offset += 2; // for the comma + rbrace/rparen | |
| 567 | end_offset += 2; // for the comma/semicolon + rbrace/rparen | |
| 567 | 568 | n = tree.extra_data[datas[n].rhs - 1]; // last member |
| 568 | 569 | }, |
| 569 | 570 | .CallOne, |
| ... | ... | @@ -594,11 +595,12 @@ pub const Tree = struct { |
| 594 | 595 | }, |
| 595 | 596 | .ArrayInitDotTwoComma, |
| 596 | 597 | .BuiltinCallTwoComma, |
| 598 | .BlockTwoSemicolon, | |
| 597 | 599 | .StructInitDotTwoComma, |
| 598 | 600 | .ContainerDeclTwoComma, |
| 599 | 601 | .TaggedUnionTwoComma, |
| 600 | 602 | => { |
| 601 | end_offset += 2; // for the comma + rbrace/rparen | |
| 603 | end_offset += 2; // for the comma/semicolon + rbrace/rparen | |
| 602 | 604 | if (datas[n].rhs != 0) { |
| 603 | 605 | n = datas[n].rhs; |
| 604 | 606 | } else if (datas[n].lhs != 0) { |
| ... | ... | @@ -2137,12 +2139,16 @@ pub const Node = struct { |
| 2137 | 2139 | Comptime, |
| 2138 | 2140 | /// `nosuspend lhs`. rhs unused. |
| 2139 | 2141 | Nosuspend, |
| 2140 | /// `{lhs; rhs;}`. rhs or lhs can be omitted. | |
| 2142 | /// `{lhs rhs}`. rhs or lhs can be omitted. | |
| 2141 | 2143 | /// main_token points at the lbrace. |
| 2142 | 2144 | BlockTwo, |
| 2145 | /// Same as BlockTwo but there is known to be a semicolon before the rbrace. | |
| 2146 | BlockTwoSemicolon, | |
| 2143 | 2147 | /// `{}`. `sub_list[lhs..rhs]`. |
| 2144 | 2148 | /// main_token points at the lbrace. |
| 2145 | 2149 | Block, |
| 2150 | /// Same as BlockTwo but there is known to be a semicolon before the rbrace. | |
| 2151 | BlockSemicolon, | |
| 2146 | 2152 | /// `asm(lhs)`. rhs unused. |
| 2147 | 2153 | AsmSimple, |
| 2148 | 2154 | /// `asm(lhs, a)`. `sub_range_list[rhs]`. |
lib/std/zig/parse.zig+6-3| ... | ... | @@ -1984,8 +1984,9 @@ const Parser = struct { |
| 1984 | 1984 | |
| 1985 | 1985 | const stmt_one = try p.expectStatementRecoverable(); |
| 1986 | 1986 | if (p.eatToken(.RBrace)) |_| { |
| 1987 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | |
| 1987 | 1988 | return p.addNode(.{ |
| 1988 | .tag = .BlockTwo, | |
| 1989 | .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo, | |
| 1989 | 1990 | .main_token = lbrace, |
| 1990 | 1991 | .data = .{ |
| 1991 | 1992 | .lhs = stmt_one, |
| ... | ... | @@ -1995,8 +1996,9 @@ const Parser = struct { |
| 1995 | 1996 | } |
| 1996 | 1997 | const stmt_two = try p.expectStatementRecoverable(); |
| 1997 | 1998 | if (p.eatToken(.RBrace)) |_| { |
| 1999 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | |
| 1998 | 2000 | return p.addNode(.{ |
| 1999 | .tag = .BlockTwo, | |
| 2001 | .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo, | |
| 2000 | 2002 | .main_token = lbrace, |
| 2001 | 2003 | .data = .{ |
| 2002 | 2004 | .lhs = stmt_one, |
| ... | ... | @@ -2017,9 +2019,10 @@ const Parser = struct { |
| 2017 | 2019 | if (p.token_tags[p.tok_i] == .RBrace) break; |
| 2018 | 2020 | } |
| 2019 | 2021 | _ = try p.expectToken(.RBrace); |
| 2022 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | |
| 2020 | 2023 | const statements_span = try p.listToSpan(statements.items); |
| 2021 | 2024 | return p.addNode(.{ |
| 2022 | .tag = .Block, | |
| 2025 | .tag = if (semicolon) .BlockSemicolon else .Block, | |
| 2023 | 2026 | .main_token = lbrace, |
| 2024 | 2027 | .data = .{ |
| 2025 | 2028 | .lhs = statements_span.start, |
lib/std/zig/parser_test.zig+18| ... | ... | @@ -655,6 +655,24 @@ test "zig fmt: slices with spaces in bounds" { |
| 655 | 655 | ); |
| 656 | 656 | } |
| 657 | 657 | |
| 658 | test "zig fmt: block in slice expression" { | |
| 659 | try testCanonical( | |
| 660 | \\const a = b[{ | |
| 661 | \\ _ = x; | |
| 662 | \\}..]; | |
| 663 | \\const c = d[0..{ | |
| 664 | \\ _ = x; | |
| 665 | \\ _ = y; | |
| 666 | \\}]; | |
| 667 | \\const e = f[0..1 :{ | |
| 668 | \\ _ = x; | |
| 669 | \\ _ = y; | |
| 670 | \\ _ = z; | |
| 671 | \\}]; | |
| 672 | \\ | |
| 673 | ); | |
| 674 | } | |
| 675 | ||
| 658 | 676 | //test "zig fmt: async function" { |
| 659 | 677 | // try testCanonical( |
| 660 | 678 | // \\pub const Server = struct { |
lib/std/zig/render.zig+6-2| ... | ... | @@ -202,7 +202,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac |
| 202 | 202 | // } |
| 203 | 203 | // return renderToken(ais, tree, any_type.token, space); |
| 204 | 204 | //}, |
| 205 | .BlockTwo => { | |
| 205 | .BlockTwo, | |
| 206 | .BlockTwoSemicolon, | |
| 207 | => { | |
| 206 | 208 | const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; |
| 207 | 209 | if (datas[node].lhs == 0) { |
| 208 | 210 | return renderBlock(ais, tree, main_tokens[node], statements[0..0], space); |
| ... | ... | @@ -212,7 +214,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac |
| 212 | 214 | return renderBlock(ais, tree, main_tokens[node], statements[0..2], space); |
| 213 | 215 | } |
| 214 | 216 | }, |
| 215 | .Block => { | |
| 217 | .Block, | |
| 218 | .BlockSemicolon, | |
| 219 | => { | |
| 216 | 220 | const lbrace = main_tokens[node]; |
| 217 | 221 | const statements = tree.extra_data[datas[node].lhs..datas[node].rhs]; |
| 218 | 222 | return renderBlock(ais, tree, main_tokens[node], statements, space); |