Commit 928f6f48a6

Isaac Freund <ifreund@ifreund.xyz>
2021-02-10 18:17:50
zig fmt: implement Tree.lastToken() for array init
1 parent 3110a73
Changed files (4)
lib/std/zig/ast.zig
@@ -255,6 +255,7 @@ pub const Tree = struct {
             => return main_tokens[n] - end_offset,
 
             .ArrayInitDot,
+            .ArrayInitDotComma,
             .ArrayInitDotTwo,
             .ArrayInitDotTwoComma,
             .StructInitDot,
@@ -311,7 +312,9 @@ pub const Tree = struct {
             .Deref,
             .ArrayAccess,
             .ArrayInitOne,
+            .ArrayInitOneComma,
             .ArrayInit,
+            .ArrayInitComma,
             .StructInitOne,
             .StructInit,
             .CallOne,
@@ -604,6 +607,13 @@ pub const Tree = struct {
                 const extra = tree.extraData(datas[n].rhs, Node.Asm);
                 return extra.rparen + end_offset;
             },
+            .ArrayInit => {
+                const elements = tree.extraData(datas[n].rhs, Node.SubRange);
+                assert(elements.end - elements.start > 0);
+                end_offset += 1; // for the rbrace
+                n = tree.extra_data[elements.end - 1]; // last element
+            },
+            .ArrayInitComma,
             .ContainerDeclArgComma,
             .SwitchComma,
             => {
@@ -612,6 +622,7 @@ pub const Tree = struct {
                 end_offset += 2; // for the comma + rbrace
                 n = tree.extra_data[members.end - 1]; // last parameter
             },
+            .ArrayInitDot,
             .Block,
             .ContainerDecl,
             .TaggedUnion,
@@ -621,6 +632,7 @@ pub const Tree = struct {
                 end_offset += 1; // for the rbrace
                 n = tree.extra_data[datas[n].rhs - 1]; // last statement
             },
+            .ArrayInitDotComma,
             .BlockSemicolon,
             .ContainerDeclComma,
             .TaggedUnionComma,
@@ -772,7 +784,16 @@ pub const Tree = struct {
                 }
             },
 
-            .SliceOpen, .CallOneComma, .AsyncCallOneComma => {
+            .ArrayInitOne => {
+                end_offset += 1; // rbrace
+                n = datas[n].rhs;
+                assert(n != 0);
+            },
+            .SliceOpen,
+            .CallOneComma,
+            .AsyncCallOneComma,
+            .ArrayInitOneComma,
+            => {
                 end_offset += 2; // ellipsis2 + rbracket, or comma + rparen
                 n = datas[n].rhs;
                 assert(n != 0);
@@ -912,9 +933,6 @@ pub const Tree = struct {
             // require recursion due to the optional comma followed by rbrace.
             // TODO follow the pattern set by StructInitDotTwoComma which will allow
             // lastToken to work for all of these.
-            .ArrayInit => unreachable, // TODO
-            .ArrayInitOne => unreachable, // TODO
-            .ArrayInitDot => unreachable, // TODO
             .StructInit => unreachable, // TODO
             .StructInitOne => unreachable, // TODO
             .StructInitDot => unreachable, // TODO
@@ -1151,7 +1169,8 @@ pub const Tree = struct {
     }
 
     pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit {
-        assert(tree.nodes.items(.tag)[node] == .ArrayInitOne);
+        assert(tree.nodes.items(.tag)[node] == .ArrayInitOne or
+            tree.nodes.items(.tag)[node] == .ArrayInitOneComma);
         const data = tree.nodes.items(.data)[node];
         buffer[0] = data.rhs;
         const elements = if (data.rhs == 0) buffer[0..0] else buffer[0..1];
@@ -1185,7 +1204,8 @@ pub const Tree = struct {
     }
 
     pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit {
-        assert(tree.nodes.items(.tag)[node] == .ArrayInitDot);
+        assert(tree.nodes.items(.tag)[node] == .ArrayInitDot or
+            tree.nodes.items(.tag)[node] == .ArrayInitDotComma);
         const data = tree.nodes.items(.data)[node];
         return .{
             .ast = .{
@@ -1197,7 +1217,8 @@ pub const Tree = struct {
     }
 
     pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit {
-        assert(tree.nodes.items(.tag)[node] == .ArrayInit);
+        assert(tree.nodes.items(.tag)[node] == .ArrayInit or
+            tree.nodes.items(.tag)[node] == .ArrayInitComma);
         const data = tree.nodes.items(.data)[node];
         const elem_range = tree.extraData(data.rhs, Node.SubRange);
         return .{
@@ -2436,6 +2457,8 @@ pub const Node = struct {
         ArrayAccess,
         /// `lhs{rhs}`. rhs can be omitted.
         ArrayInitOne,
+        /// `lhs{rhs,}`. rhs can *not* be omitted
+        ArrayInitOneComma,
         /// `.{lhs, rhs}`. lhs and rhs can be omitted.
         ArrayInitDotTwo,
         /// Same as `ArrayInitDotTwo` except there is known to be a trailing comma
@@ -2443,8 +2466,14 @@ pub const Node = struct {
         ArrayInitDotTwoComma,
         /// `.{a, b}`. `sub_list[lhs..rhs]`.
         ArrayInitDot,
+        /// Same as `ArrayInitDot` except there is known to be a trailing comma
+        /// before the final rbrace.
+        ArrayInitDotComma,
         /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`.
         ArrayInit,
+        /// Same as `ArrayInit` except there is known to be a trailing comma
+        /// before the final rbrace.
+        ArrayInitComma,
         /// `lhs{.a = rhs}`. rhs can be omitted making it empty.
         /// main_token is the lbrace.
         StructInitOne,
lib/std/zig/parse.zig
@@ -2205,9 +2205,10 @@ const Parser = struct {
         }
 
         const elem_init = try p.expectExpr();
+        const comma_one = p.eatToken(.Comma);
         if (p.eatToken(.RBrace)) |_| {
             return p.addNode(.{
-                .tag = .ArrayInitOne,
+                .tag = if (comma_one != null) .ArrayInitOneComma else .ArrayInitOne,
                 .main_token = lbrace,
                 .data = .{
                     .lhs = lhs,
@@ -2215,21 +2216,30 @@ const Parser = struct {
                 },
             });
         }
+        if (comma_one == null) {
+            try p.warn(.{
+                .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
+            });
+        }
 
         var init_list = std.ArrayList(Node.Index).init(p.gpa);
         defer init_list.deinit();
 
         try init_list.append(elem_init);
 
-        while (p.eatToken(.Comma)) |_| {
-            const next = try p.parseExpr();
-            if (next == 0) break;
+        var trailing_comma = true;
+        var next = try p.parseExpr();
+        while (next != 0) : (next = try p.parseExpr()) {
             try init_list.append(next);
+            if (p.eatToken(.Comma) == null) {
+                trailing_comma = false;
+                break;
+            }
         }
         _ = try p.expectToken(.RBrace);
         const span = try p.listToSpan(init_list.items);
         return p.addNode(.{
-            .tag = .ArrayInit,
+            .tag = if (trailing_comma) .ArrayInitComma else .ArrayInit,
             .main_token = lbrace,
             .data = .{
                 .lhs = lhs,
@@ -2805,7 +2815,7 @@ const Parser = struct {
                     const comma_two = p.eatToken(.Comma);
                     if (p.eatToken(.RBrace)) |_| {
                         return p.addNode(.{
-                            .tag = if (comma_one != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo,
+                            .tag = if (comma_two != null) .ArrayInitDotTwoComma else .ArrayInitDotTwo,
                             .main_token = lbrace,
                             .data = .{
                                 .lhs = elem_init_one,
@@ -2855,7 +2865,7 @@ const Parser = struct {
                     }
                     const span = try p.listToSpan(init_list.items);
                     return p.addNode(.{
-                        .tag = .ArrayInitDot,
+                        .tag = if (p.token_tags[p.tok_i - 2] == .Comma) .ArrayInitDotComma else .ArrayInitDot,
                         .main_token = lbrace,
                         .data = .{
                             .lhs = span.start,
lib/std/zig/parser_test.zig
@@ -568,109 +568,135 @@ test "zig fmt: struct literal 3 element comma" {
 
 test "zig fmt: anon list literal 1 element" {
     try testCanonical(
-        \\const x = .{a};
+        \\test {
+        \\    const x = .{a};
+        \\}
         \\
     );
 }
 
 test "zig fmt: anon list literal 1 element comma" {
     try testCanonical(
-        \\const x = .{
-        \\    a,
-        \\};
+        \\test {
+        \\    const x = .{
+        \\        a,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: anon list literal 2 element" {
     try testCanonical(
-        \\const x = .{ a, b };
+        \\test {
+        \\    const x = .{ a, b };
+        \\}
         \\
     );
 }
 
 test "zig fmt: anon list literal 2 element comma" {
     try testCanonical(
-        \\const x = .{
-        \\    a,
-        \\    b,
-        \\};
+        \\test {
+        \\    const x = .{
+        \\        a,
+        \\        b,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: anon list literal 3 element" {
     try testCanonical(
-        \\const x = .{ a, b, c };
+        \\test {
+        \\    const x = .{ a, b, c };
+        \\}
         \\
     );
 }
 
 test "zig fmt: anon list literal 3 element comma" {
     try testCanonical(
-        \\const x = .{
-        \\    a,
-        \\    b,
-        \\    c,
-        \\};
+        \\test {
+        \\    const x = .{
+        \\        a,
+        \\        b,
+        \\        c,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 1 element" {
     try testCanonical(
-        \\const x = [_]u32{a};
+        \\test {
+        \\    const x = [_]u32{a};
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 1 element comma" {
     try testCanonical(
-        \\const x = [1]u32{
-        \\    a,
-        \\};
+        \\test {
+        \\    const x = [1]u32{
+        \\        a,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 2 element" {
     try testCanonical(
-        \\const x = [_]u32{ a, b };
+        \\test {
+        \\    const x = [_]u32{ a, b };
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 2 element comma" {
     try testCanonical(
-        \\const x = [2]u32{
-        \\    a,
-        \\    b,
-        \\};
+        \\test {
+        \\    const x = [2]u32{
+        \\        a,
+        \\        b,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 3 element" {
     try testCanonical(
-        \\const x = [_]u32{ a, b, c };
+        \\test {
+        \\    const x = [_]u32{ a, b, c };
+        \\}
         \\
     );
 }
 
 test "zig fmt: array literal 3 element comma" {
     try testCanonical(
-        \\const x = [3]u32{
-        \\    a,
-        \\    b,
-        \\    c,
-        \\};
+        \\test {
+        \\    const x = [3]u32{
+        \\        a,
+        \\        b,
+        \\        c,
+        \\    };
+        \\}
         \\
     );
 }
 
 test "zig fmt: sentinel array literal 1 element" {
     try testCanonical(
-        \\const x = [_:9000]u32{a};
+        \\test {
+        \\    const x = [_:9000]u32{a};
+        \\}
         \\
     );
 }
lib/std/zig/render.zig
@@ -390,7 +390,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
         .PtrType => return renderPtrType(ais, tree, tree.ptrType(node), space),
         .PtrTypeBitRange => return renderPtrType(ais, tree, tree.ptrTypeBitRange(node), space),
 
-        .ArrayInitOne => {
+        .ArrayInitOne, .ArrayInitOneComma => {
             var elements: [1]ast.Node.Index = undefined;
             return renderArrayInit(ais, tree, tree.arrayInitOne(&elements, node), space);
         },
@@ -398,8 +398,12 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
             var elements: [2]ast.Node.Index = undefined;
             return renderArrayInit(ais, tree, tree.arrayInitDotTwo(&elements, node), space);
         },
-        .ArrayInitDot => return renderArrayInit(ais, tree, tree.arrayInitDot(node), space),
-        .ArrayInit => return renderArrayInit(ais, tree, tree.arrayInit(node), space),
+        .ArrayInitDot,
+        .ArrayInitDotComma,
+        => return renderArrayInit(ais, tree, tree.arrayInitDot(node), space),
+        .ArrayInit,
+        .ArrayInitComma,
+        => return renderArrayInit(ais, tree, tree.arrayInit(node), space),
 
         .StructInitOne => {
             var fields: [1]ast.Node.Index = undefined;