| 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,7 +357,9 @@ pub const Tree = struct { |
| 357 | }, | 357 | }, |
| 358 | 358 | ||
| 359 | .Block, | 359 | .Block, |
| 360 | .BlockSemicolon, | ||
| 360 | .BlockTwo, | 361 | .BlockTwo, |
| 362 | .BlockTwoSemicolon, | ||
| 361 | => { | 363 | => { |
| 362 | // Look for a label. | 364 | // Look for a label. |
| 363 | const lbrace = main_tokens[n]; | 365 | const lbrace = main_tokens[n]; |
| ... | @@ -552,18 +554,17 @@ pub const Tree = struct { | ... | @@ -552,18 +554,17 @@ pub const Tree = struct { |
| 552 | .TaggedUnion, | 554 | .TaggedUnion, |
| 553 | .BuiltinCall, | 555 | .BuiltinCall, |
| 554 | => { | 556 | => { |
| 557 | assert(datas[n].rhs - datas[n].lhs > 0); | ||
| 555 | end_offset += 1; // for the rbrace | 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 | n = tree.extra_data[datas[n].rhs - 1]; // last statement | 559 | n = tree.extra_data[datas[n].rhs - 1]; // last statement |
| 560 | }, | 560 | }, |
| 561 | .BlockSemicolon, | ||
| 561 | .ContainerDeclComma, | 562 | .ContainerDeclComma, |
| 562 | .TaggedUnionComma, | 563 | .TaggedUnionComma, |
| 563 | .BuiltinCallComma, | 564 | .BuiltinCallComma, |
| 564 | => { | 565 | => { |
| 565 | assert(datas[n].rhs - datas[n].lhs > 0); | 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 | n = tree.extra_data[datas[n].rhs - 1]; // last member | 568 | n = tree.extra_data[datas[n].rhs - 1]; // last member |
| 568 | }, | 569 | }, |
| 569 | .CallOne, | 570 | .CallOne, |
| ... | @@ -594,11 +595,12 @@ pub const Tree = struct { | ... | @@ -594,11 +595,12 @@ pub const Tree = struct { |
| 594 | }, | 595 | }, |
| 595 | .ArrayInitDotTwoComma, | 596 | .ArrayInitDotTwoComma, |
| 596 | .BuiltinCallTwoComma, | 597 | .BuiltinCallTwoComma, |
| 598 | .BlockTwoSemicolon, | ||
| 597 | .StructInitDotTwoComma, | 599 | .StructInitDotTwoComma, |
| 598 | .ContainerDeclTwoComma, | 600 | .ContainerDeclTwoComma, |
| 599 | .TaggedUnionTwoComma, | 601 | .TaggedUnionTwoComma, |
| 600 | => { | 602 | => { |
| 601 | end_offset += 2; // for the comma + rbrace/rparen | 603 | end_offset += 2; // for the comma/semicolon + rbrace/rparen |
| 602 | if (datas[n].rhs != 0) { | 604 | if (datas[n].rhs != 0) { |
| 603 | n = datas[n].rhs; | 605 | n = datas[n].rhs; |
| 604 | } else if (datas[n].lhs != 0) { | 606 | } else if (datas[n].lhs != 0) { |
| ... | @@ -2137,12 +2139,16 @@ pub const Node = struct { | ... | @@ -2137,12 +2139,16 @@ pub const Node = struct { |
| 2137 | Comptime, | 2139 | Comptime, |
| 2138 | /// `nosuspend lhs`. rhs unused. | 2140 | /// `nosuspend lhs`. rhs unused. |
| 2139 | Nosuspend, | 2141 | Nosuspend, |
| 2140 | /// `{lhs; rhs;}`. rhs or lhs can be omitted. | 2142 | /// `{lhs rhs}`. rhs or lhs can be omitted. |
| 2141 | /// main_token points at the lbrace. | 2143 | /// main_token points at the lbrace. |
| 2142 | BlockTwo, | 2144 | BlockTwo, |
| 2145 | /// Same as BlockTwo but there is known to be a semicolon before the rbrace. | ||
| 2146 | BlockTwoSemicolon, | ||
| 2143 | /// `{}`. `sub_list[lhs..rhs]`. | 2147 | /// `{}`. `sub_list[lhs..rhs]`. |
| 2144 | /// main_token points at the lbrace. | 2148 | /// main_token points at the lbrace. |
| 2145 | Block, | 2149 | Block, |
| 2150 | /// Same as BlockTwo but there is known to be a semicolon before the rbrace. | ||
| 2151 | BlockSemicolon, | ||
| 2146 | /// `asm(lhs)`. rhs unused. | 2152 | /// `asm(lhs)`. rhs unused. |
| 2147 | AsmSimple, | 2153 | AsmSimple, |
| 2148 | /// `asm(lhs, a)`. `sub_range_list[rhs]`. | 2154 | /// `asm(lhs, a)`. `sub_range_list[rhs]`. |
lib/std/zig/parse.zig+6-3| ... | @@ -1984,8 +1984,9 @@ const Parser = struct { | ... | @@ -1984,8 +1984,9 @@ const Parser = struct { |
| 1984 | 1984 | ||
| 1985 | const stmt_one = try p.expectStatementRecoverable(); | 1985 | const stmt_one = try p.expectStatementRecoverable(); |
| 1986 | if (p.eatToken(.RBrace)) |_| { | 1986 | if (p.eatToken(.RBrace)) |_| { |
| 1987 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | ||
| 1987 | return p.addNode(.{ | 1988 | return p.addNode(.{ |
| 1988 | .tag = .BlockTwo, | 1989 | .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo, |
| 1989 | .main_token = lbrace, | 1990 | .main_token = lbrace, |
| 1990 | .data = .{ | 1991 | .data = .{ |
| 1991 | .lhs = stmt_one, | 1992 | .lhs = stmt_one, |
| ... | @@ -1995,8 +1996,9 @@ const Parser = struct { | ... | @@ -1995,8 +1996,9 @@ const Parser = struct { |
| 1995 | } | 1996 | } |
| 1996 | const stmt_two = try p.expectStatementRecoverable(); | 1997 | const stmt_two = try p.expectStatementRecoverable(); |
| 1997 | if (p.eatToken(.RBrace)) |_| { | 1998 | if (p.eatToken(.RBrace)) |_| { |
| 1999 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | ||
| 1998 | return p.addNode(.{ | 2000 | return p.addNode(.{ |
| 1999 | .tag = .BlockTwo, | 2001 | .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo, |
| 2000 | .main_token = lbrace, | 2002 | .main_token = lbrace, |
| 2001 | .data = .{ | 2003 | .data = .{ |
| 2002 | .lhs = stmt_one, | 2004 | .lhs = stmt_one, |
| ... | @@ -2017,9 +2019,10 @@ const Parser = struct { | ... | @@ -2017,9 +2019,10 @@ const Parser = struct { |
| 2017 | if (p.token_tags[p.tok_i] == .RBrace) break; | 2019 | if (p.token_tags[p.tok_i] == .RBrace) break; |
| 2018 | } | 2020 | } |
| 2019 | _ = try p.expectToken(.RBrace); | 2021 | _ = try p.expectToken(.RBrace); |
| 2022 | const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon; | ||
| 2020 | const statements_span = try p.listToSpan(statements.items); | 2023 | const statements_span = try p.listToSpan(statements.items); |
| 2021 | return p.addNode(.{ | 2024 | return p.addNode(.{ |
| 2022 | .tag = .Block, | 2025 | .tag = if (semicolon) .BlockSemicolon else .Block, |
| 2023 | .main_token = lbrace, | 2026 | .main_token = lbrace, |
| 2024 | .data = .{ | 2027 | .data = .{ |
| 2025 | .lhs = statements_span.start, | 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,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 | //test "zig fmt: async function" { | 676 | //test "zig fmt: async function" { |
| 659 | // try testCanonical( | 677 | // try testCanonical( |
| 660 | // \\pub const Server = struct { | 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,7 +202,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac |
| 202 | // } | 202 | // } |
| 203 | // return renderToken(ais, tree, any_type.token, space); | 203 | // return renderToken(ais, tree, any_type.token, space); |
| 204 | //}, | 204 | //}, |
| 205 | .BlockTwo => { | 205 | .BlockTwo, |
| 206 | .BlockTwoSemicolon, | ||
| 207 | => { | ||
| 206 | const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; | 208 | const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; |
| 207 | if (datas[node].lhs == 0) { | 209 | if (datas[node].lhs == 0) { |
| 208 | return renderBlock(ais, tree, main_tokens[node], statements[0..0], space); | 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,7 +214,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac |
| 212 | return renderBlock(ais, tree, main_tokens[node], statements[0..2], space); | 214 | return renderBlock(ais, tree, main_tokens[node], statements[0..2], space); |
| 213 | } | 215 | } |
| 214 | }, | 216 | }, |
| 215 | .Block => { | 217 | .Block, |
| 218 | .BlockSemicolon, | ||
| 219 | => { | ||
| 216 | const lbrace = main_tokens[node]; | 220 | const lbrace = main_tokens[node]; |
| 217 | const statements = tree.extra_data[datas[node].lhs..datas[node].rhs]; | 221 | const statements = tree.extra_data[datas[node].lhs..datas[node].rhs]; |
| 218 | return renderBlock(ais, tree, main_tokens[node], statements, space); | 222 | return renderBlock(ais, tree, main_tokens[node], statements, space); |