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 {
357357 },
358358
359359 .Block,
360 .BlockSemicolon,
360361 .BlockTwo,
362 .BlockTwoSemicolon,
361363 => {
362364 // Look for a label.
363365 const lbrace = main_tokens[n];
......@@ -552,18 +554,17 @@ pub const Tree = struct {
552554 .TaggedUnion,
553555 .BuiltinCall,
554556 => {
557 assert(datas[n].rhs - datas[n].lhs > 0);
555558 end_offset += 1; // for the rbrace
556 if (datas[n].rhs - datas[n].lhs == 0) {
557 return main_tokens[n] + end_offset;
558 }
559559 n = tree.extra_data[datas[n].rhs - 1]; // last statement
560560 },
561 .BlockSemicolon,
561562 .ContainerDeclComma,
562563 .TaggedUnionComma,
563564 .BuiltinCallComma,
564565 => {
565566 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
567568 n = tree.extra_data[datas[n].rhs - 1]; // last member
568569 },
569570 .CallOne,
......@@ -594,11 +595,12 @@ pub const Tree = struct {
594595 },
595596 .ArrayInitDotTwoComma,
596597 .BuiltinCallTwoComma,
598 .BlockTwoSemicolon,
597599 .StructInitDotTwoComma,
598600 .ContainerDeclTwoComma,
599601 .TaggedUnionTwoComma,
600602 => {
601 end_offset += 2; // for the comma + rbrace/rparen
603 end_offset += 2; // for the comma/semicolon + rbrace/rparen
602604 if (datas[n].rhs != 0) {
603605 n = datas[n].rhs;
604606 } else if (datas[n].lhs != 0) {
......@@ -2137,12 +2139,16 @@ pub const Node = struct {
21372139 Comptime,
21382140 /// `nosuspend lhs`. rhs unused.
21392141 Nosuspend,
2140 /// `{lhs; rhs;}`. rhs or lhs can be omitted.
2142 /// `{lhs rhs}`. rhs or lhs can be omitted.
21412143 /// main_token points at the lbrace.
21422144 BlockTwo,
2145 /// Same as BlockTwo but there is known to be a semicolon before the rbrace.
2146 BlockTwoSemicolon,
21432147 /// `{}`. `sub_list[lhs..rhs]`.
21442148 /// main_token points at the lbrace.
21452149 Block,
2150 /// Same as BlockTwo but there is known to be a semicolon before the rbrace.
2151 BlockSemicolon,
21462152 /// `asm(lhs)`. rhs unused.
21472153 AsmSimple,
21482154 /// `asm(lhs, a)`. `sub_range_list[rhs]`.
lib/std/zig/parse.zig+6-3
......@@ -1984,8 +1984,9 @@ const Parser = struct {
19841984
19851985 const stmt_one = try p.expectStatementRecoverable();
19861986 if (p.eatToken(.RBrace)) |_| {
1987 const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon;
19871988 return p.addNode(.{
1988 .tag = .BlockTwo,
1989 .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo,
19891990 .main_token = lbrace,
19901991 .data = .{
19911992 .lhs = stmt_one,
......@@ -1995,8 +1996,9 @@ const Parser = struct {
19951996 }
19961997 const stmt_two = try p.expectStatementRecoverable();
19971998 if (p.eatToken(.RBrace)) |_| {
1999 const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon;
19982000 return p.addNode(.{
1999 .tag = .BlockTwo,
2001 .tag = if (semicolon) .BlockTwoSemicolon else .BlockTwo,
20002002 .main_token = lbrace,
20012003 .data = .{
20022004 .lhs = stmt_one,
......@@ -2017,9 +2019,10 @@ const Parser = struct {
20172019 if (p.token_tags[p.tok_i] == .RBrace) break;
20182020 }
20192021 _ = try p.expectToken(.RBrace);
2022 const semicolon = p.token_tags[p.tok_i - 2] == .Semicolon;
20202023 const statements_span = try p.listToSpan(statements.items);
20212024 return p.addNode(.{
2022 .tag = .Block,
2025 .tag = if (semicolon) .BlockSemicolon else .Block,
20232026 .main_token = lbrace,
20242027 .data = .{
20252028 .lhs = statements_span.start,
lib/std/zig/parser_test.zig+18
......@@ -655,6 +655,24 @@ test "zig fmt: slices with spaces in bounds" {
655655 );
656656}
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
658676//test "zig fmt: async function" {
659677// try testCanonical(
660678// \\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
202202 // }
203203 // return renderToken(ais, tree, any_type.token, space);
204204 //},
205 .BlockTwo => {
205 .BlockTwo,
206 .BlockTwoSemicolon,
207 => {
206208 const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
207209 if (datas[node].lhs == 0) {
208210 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
212214 return renderBlock(ais, tree, main_tokens[node], statements[0..2], space);
213215 }
214216 },
215 .Block => {
217 .Block,
218 .BlockSemicolon,
219 => {
216220 const lbrace = main_tokens[node];
217221 const statements = tree.extra_data[datas[node].lhs..datas[node].rhs];
218222 return renderBlock(ais, tree, main_tokens[node], statements, space);