authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-02-07 23:14:33+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-07 14:51:37-08:00
log57cec38e6144754fcd15266100974a7cf0059570
tree0e84bb83b0802b7643236cf64585a7c46d7e6543
parent0e38362d244f118565f447f8ee2c6b8a700d05bf

std/zig/ast: fix Tree.lastToken() for blocks

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 },
358358
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 rbrace558 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 statement559 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/rparen567 end_offset += 2; // for the comma/semicolon + rbrace/rparen
567 n = tree.extra_data[datas[n].rhs - 1]; // last member568 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/rparen603 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 {
19841984
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}
657657
658test "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);