Commit d898945786

Andrew Kelley <andrew@ziglang.org>
2021-02-06 04:38:30
zig fmt: builtin call with trailing comma
1 parent 409ca88
Changed files (4)
lib/std/zig/ast.zig
@@ -234,7 +234,9 @@ pub const Tree = struct {
             .StringLiteral,
             .GroupedExpression,
             .BuiltinCallTwo,
+            .BuiltinCallTwoComma,
             .BuiltinCall,
+            .BuiltinCallComma,
             .ErrorSetDecl,
             .AnyType,
             .Comptime,
@@ -474,6 +476,7 @@ pub const Tree = struct {
             .ErrorUnion,
             .IfSimple,
             .WhileSimple,
+            .FnDecl,
             => n = datas[n].rhs,
 
             .FieldAccess,
@@ -497,9 +500,7 @@ pub const Tree = struct {
             .EnumLiteral,
             => return main_tokens[n] + end_offset,
 
-            .Call,
-            .BuiltinCall,
-            => {
+            .Call => {
                 end_offset += 1; // for the rparen
                 const params = tree.extraData(datas[n].rhs, Node.SubRange);
                 if (params.end - params.start == 0) {
@@ -526,6 +527,7 @@ pub const Tree = struct {
             .Block,
             .ContainerDecl,
             .TaggedUnion,
+            .BuiltinCall,
             => {
                 end_offset += 1; // for the rbrace
                 if (datas[n].rhs - datas[n].lhs == 0) {
@@ -533,9 +535,12 @@ pub const Tree = struct {
                 }
                 n = tree.extra_data[datas[n].rhs - 1]; // last statement
             },
-            .ContainerDeclComma, .TaggedUnionComma => {
+            .ContainerDeclComma,
+            .TaggedUnionComma,
+            .BuiltinCallComma,
+            => {
                 assert(datas[n].rhs - datas[n].lhs > 0);
-                end_offset += 2; // for the comma + rbrace
+                end_offset += 2; // for the comma + rbrace/rparen
                 n = tree.extra_data[datas[n].rhs - 1]; // last member
             },
             .CallOne,
@@ -565,11 +570,12 @@ pub const Tree = struct {
                 }
             },
             .ArrayInitDotTwoComma,
+            .BuiltinCallTwoComma,
             .StructInitDotTwoComma,
             .ContainerDeclTwoComma,
             .TaggedUnionTwoComma,
             => {
-                end_offset += 2; // for the comma + rbrace
+                end_offset += 2; // for the comma + rbrace/rparen
                 if (datas[n].rhs != 0) {
                     n = datas[n].rhs;
                 } else if (datas[n].lhs != 0) {
@@ -690,7 +696,6 @@ pub const Tree = struct {
             .Slice => unreachable, // TODO
             .SwitchCaseOne => unreachable, // TODO
             .SwitchRange => unreachable, // TODO
-            .FnDecl => unreachable, // TODO
             .ArrayType => unreachable, // TODO
             .ArrayTypeSentinel => unreachable, // TODO
             .PtrTypeAligned => unreachable, // TODO
@@ -1836,8 +1841,12 @@ pub const Node = struct {
         GroupedExpression,
         /// `@a(lhs, rhs)`. lhs and rhs may be omitted.
         BuiltinCallTwo,
+        /// Same as BuiltinCallTwo but there is known to be a trailing comma before the rparen.
+        BuiltinCallTwoComma,
         /// `@a(b, c)`. `sub_list[lhs..rhs]`.
         BuiltinCall,
+        /// Same as BuiltinCall but there is known to be a trailing comma before the rparen.
+        BuiltinCallComma,
         /// `error{a, b}`.
         /// lhs and rhs both unused.
         ErrorSetDecl,
lib/std/zig/parse.zig
@@ -3676,7 +3676,6 @@ const Parser = struct {
 
     /// FnCallArguments <- LPAREN ExprList RPAREN
     /// ExprList <- (Expr COMMA)* Expr?
-    /// TODO detect when we can emit BuiltinCallTwo instead of BuiltinCall.
     fn parseBuiltinCall(p: *Parser) !Node.Index {
         const builtin_token = p.assertToken(.Builtin);
         _ = (try p.expectTokenRecoverable(.LParen)) orelse {
@@ -3708,7 +3707,7 @@ const Parser = struct {
             .Comma => {
                 if (p.eatToken(.RParen)) |_| {
                     return p.addNode(.{
-                        .tag = .BuiltinCallTwo,
+                        .tag = .BuiltinCallTwoComma,
                         .main_token = builtin_token,
                         .data = .{
                             .lhs = param_one,
@@ -3739,7 +3738,7 @@ const Parser = struct {
             .Comma => {
                 if (p.eatToken(.RParen)) |_| {
                     return p.addNode(.{
-                        .tag = .BuiltinCallTwo,
+                        .tag = .BuiltinCallTwoComma,
                         .main_token = builtin_token,
                         .data = .{
                             .lhs = param_one,
@@ -3776,10 +3775,30 @@ const Parser = struct {
             try list.append(param);
             switch (p.token_tags[p.nextToken()]) {
                 .Comma => {
-                    if (p.eatToken(.RParen)) |_| break;
+                    if (p.eatToken(.RParen)) |_| {
+                        const params = try p.listToSpan(list.items);
+                        return p.addNode(.{
+                            .tag = .BuiltinCallComma,
+                            .main_token = builtin_token,
+                            .data = .{
+                                .lhs = params.start,
+                                .rhs = params.end,
+                            },
+                        });
+                    }
                     continue;
                 },
-                .RParen => break,
+                .RParen => {
+                    const params = try p.listToSpan(list.items);
+                    return p.addNode(.{
+                        .tag = .BuiltinCall,
+                        .main_token = builtin_token,
+                        .data = .{
+                            .lhs = params.start,
+                            .rhs = params.end,
+                        },
+                    });
+                },
                 else => {
                     // This is likely just a missing comma;
                     // give an error but continue parsing this list.
@@ -3790,15 +3809,6 @@ const Parser = struct {
                 },
             }
         }
-        const params = try p.listToSpan(list.items);
-        return p.addNode(.{
-            .tag = .BuiltinCall,
-            .main_token = builtin_token,
-            .data = .{
-                .lhs = params.start,
-                .rhs = params.end,
-            },
-        });
     }
 
     // string literal or multiline string literal
lib/std/zig/parser_test.zig
@@ -263,38 +263,38 @@ test "zig fmt: trailing comma in fn parameter list" {
     );
 }
 
-//test "zig fmt: comptime struct field" {
-//    try testCanonical(
-//        \\const Foo = struct {
-//        \\    a: i32,
-//        \\    comptime b: i32 = 1234,
-//        \\};
-//        \\
-//    );
-//}
-//
+test "zig fmt: comptime struct field" {
+    try testCanonical(
+        \\const Foo = struct {
+        \\    a: i32,
+        \\    comptime b: i32 = 1234,
+        \\};
+        \\
+    );
+}
+
 //test "zig fmt: c pointer type" {
 //    try testCanonical(
 //        \\pub extern fn repro() [*c]const u8;
 //        \\
 //    );
 //}
-//
-//test "zig fmt: builtin call with trailing comma" {
-//    try testCanonical(
-//        \\pub fn main() void {
-//        \\    @breakpoint();
-//        \\    _ = @boolToInt(a);
-//        \\    _ = @call(
-//        \\        a,
-//        \\        b,
-//        \\        c,
-//        \\    );
-//        \\}
-//        \\
-//    );
-//}
-//
+
+test "zig fmt: builtin call with trailing comma" {
+    try testCanonical(
+        \\pub fn main() void {
+        \\    @breakpoint();
+        \\    _ = @boolToInt(a);
+        \\    _ = @call(
+        \\        a,
+        \\        b,
+        \\        c,
+        \\    );
+        \\}
+        \\
+    );
+}
+
 //test "zig fmt: asm expression with comptime content" {
 //    try testCanonical(
 //        \\comptime {
@@ -3988,14 +3988,9 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
         return error.ParseError;
     }
 
-    var buffer = std.ArrayList(u8).init(allocator);
-    errdefer buffer.deinit();
-
-    const writer = buffer.writer();
-    try std.zig.render(allocator, writer, tree);
-    const result = buffer.toOwnedSlice();
-    anything_changed.* = !mem.eql(u8, result, source);
-    return result;
+    const formatted = try std.zig.render(allocator, tree);
+    anything_changed.* = !mem.eql(u8, formatted, source);
+    return formatted;
 }
 fn testTransform(source: []const u8, expected_source: []const u8) !void {
     const needed_alloc_count = x: {
lib/std/zig/render.zig
@@ -22,13 +22,19 @@ pub const Error = error{
 const Writer = std.ArrayList(u8).Writer;
 const Ais = std.io.AutoIndentingStream(Writer);
 
-/// Returns whether anything changed.
-/// `gpa` is used for allocating extra stack memory if needed, because
-/// this function utilizes recursion.
-pub fn render(gpa: *mem.Allocator, writer: Writer, tree: ast.Tree) Error!void {
-    assert(tree.errors.len == 0); // cannot render an invalid tree
-    var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, writer);
-    return renderRoot(&auto_indenting_stream, tree);
+/// `gpa` is used both for allocating the resulting formatted source code, but also
+/// for allocating extra stack memory if needed, because this function utilizes recursion.
+/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006.
+/// Caller owns the returned slice of bytes, allocated with `gpa`.
+pub fn render(gpa: *mem.Allocator, tree: ast.Tree) Error![]u8 {
+    assert(tree.errors.len == 0); // Cannot render an invalid tree.
+
+    var buffer = std.ArrayList(u8).init(gpa);
+    defer buffer.deinit();
+
+    var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, buffer.writer());
+    try renderRoot(&auto_indenting_stream, tree);
+    return buffer.toOwnedSlice();
 }
 
 /// Assumes there are no tokens in between start and end.
@@ -770,7 +776,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
         //    }
         //},
 
-        .BuiltinCallTwo => {
+        .BuiltinCallTwo, .BuiltinCallTwoComma => {
             if (datas[node].lhs == 0) {
                 const params = [_]ast.Node.Index{};
                 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
@@ -782,7 +788,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
                 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
             }
         },
-        .BuiltinCall => {
+        .BuiltinCall, .BuiltinCallComma => {
             const params = tree.extra_data[datas[node].lhs..datas[node].rhs];
             return renderBuiltinCall(ais, tree, main_tokens[node], params, space);
         },