Commit 725adf8332

Andrew Kelley <andrew@ziglang.org>
2021-02-04 06:12:11
zig fmt: builtin calls and array access
1 parent f5279cb
Changed files (4)
lib/std/zig/ast.zig
@@ -319,35 +319,54 @@ pub const Tree = struct {
                 }
             },
 
-            .GlobalVarDecl => unreachable,
-            .LocalVarDecl => unreachable,
-            .SimpleVarDecl => unreachable,
-            .AlignedVarDecl => unreachable,
-            .ArrayType => unreachable,
-            .ArrayTypeSentinel => unreachable,
-            .PtrTypeAligned => unreachable,
-            .PtrTypeSentinel => unreachable,
-            .PtrType => unreachable,
-            .SliceType => unreachable,
-            .StructInit => unreachable,
-            .SwitchCaseMulti => unreachable,
-            .WhileSimple => unreachable,
-            .WhileCont => unreachable,
-            .While => unreachable,
-            .ForSimple => unreachable,
-            .For => unreachable,
-            .FnProtoSimple => unreachable,
-            .FnProtoSimpleMulti => unreachable,
-            .FnProtoOne => unreachable,
-            .FnProto => unreachable,
-            .ContainerDecl => unreachable,
-            .ContainerDeclArg => unreachable,
-            .TaggedUnion => unreachable,
-            .TaggedUnionEnumTag => unreachable,
-            .AsmOutput => unreachable,
-            .AsmInput => unreachable,
-            .ErrorValue => unreachable,
-            .ErrorUnion => unreachable,
+            .GlobalVarDecl,
+            .LocalVarDecl,
+            .SimpleVarDecl,
+            .AlignedVarDecl,
+            => {
+                var i = main_tokens[n]; // mut token
+                while (i > 0) {
+                    i -= 1;
+                    switch (token_tags[i]) {
+                        .Keyword_extern,
+                        .Keyword_export,
+                        .Keyword_comptime,
+                        .Keyword_pub,
+                        .Keyword_threadlocal,
+                        .StringLiteral,
+                        => continue,
+
+                        else => return i + 1,
+                    }
+                }
+                return i;
+            },
+
+            .ArrayType => unreachable, // TODO
+            .ArrayTypeSentinel => unreachable, // TODO
+            .PtrTypeAligned => unreachable, // TODO
+            .PtrTypeSentinel => unreachable, // TODO
+            .PtrType => unreachable, // TODO
+            .SliceType => unreachable, // TODO
+            .StructInit => unreachable, // TODO
+            .SwitchCaseMulti => unreachable, // TODO
+            .WhileSimple => unreachable, // TODO
+            .WhileCont => unreachable, // TODO
+            .While => unreachable, // TODO
+            .ForSimple => unreachable, // TODO
+            .For => unreachable, // TODO
+            .FnProtoSimple => unreachable, // TODO
+            .FnProtoSimpleMulti => unreachable, // TODO
+            .FnProtoOne => unreachable, // TODO
+            .FnProto => unreachable, // TODO
+            .ContainerDecl => unreachable, // TODO
+            .ContainerDeclArg => unreachable, // TODO
+            .TaggedUnion => unreachable, // TODO
+            .TaggedUnionEnumTag => unreachable, // TODO
+            .AsmOutput => unreachable, // TODO
+            .AsmInput => unreachable, // TODO
+            .ErrorValue => unreachable, // TODO
+            .ErrorUnion => unreachable, // TODO
         };
     }
 
@@ -445,7 +464,9 @@ pub const Tree = struct {
             .Identifier,
             => return main_tokens[n] + end_offset,
 
-            .Call => {
+            .Call,
+            .BuiltinCall,
+            => {
                 end_offset += 1; // for the `)`
                 const params = tree.extraData(datas[n].rhs, Node.SubRange);
                 if (params.end - params.start == 0) {
@@ -453,69 +474,81 @@ pub const Tree = struct {
                 }
                 n = tree.extra_data[params.end - 1]; // last parameter
             },
-            .CallOne => {
-                end_offset += 1; // for the `)`
+            .CallOne,
+            .ArrayAccess,
+            => {
+                end_offset += 1; // for the rparen/rbracket
                 if (datas[n].rhs == 0) {
                     return main_tokens[n] + end_offset;
                 }
                 n = datas[n].rhs;
             },
 
+            .BuiltinCallTwo => {
+                end_offset += 1; // for the rparen
+                if (datas[n].rhs == 0) {
+                    if (datas[n].lhs == 0) {
+                        return main_tokens[n] + end_offset;
+                    } else {
+                        n = datas[n].lhs;
+                    }
+                } else {
+                    n = datas[n].rhs;
+                }
+            },
+
             .ContainerFieldInit => unreachable,
             .ContainerFieldAlign => unreachable,
             .ContainerField => unreachable,
 
-            .ArrayInitDotTwo => unreachable,
-            .ArrayInitDot => unreachable,
-            .StructInitDotTwo => unreachable,
-            .StructInitDot => unreachable,
-            .Switch => unreachable,
-            .If => unreachable,
-            .Continue => unreachable,
-            .EnumLiteral => unreachable,
-            .BuiltinCallTwo => unreachable,
-            .BuiltinCall => unreachable,
-            .ErrorSetDecl => unreachable,
-            .Block => unreachable,
-            .AsmSimple => unreachable,
-            .Asm => unreachable,
-            .SliceOpen => unreachable,
-            .Slice => unreachable,
-            .Deref => unreachable,
-            .ArrayAccess => unreachable,
-            .ArrayInitOne => unreachable,
-            .ArrayInit => unreachable,
-            .StructInitOne => unreachable,
-            .SwitchCaseOne => unreachable,
-            .SwitchRange => unreachable,
-            .FnDecl => unreachable,
-            .GlobalVarDecl => unreachable,
-            .LocalVarDecl => unreachable,
-            .SimpleVarDecl => unreachable,
-            .AlignedVarDecl => unreachable,
-            .ArrayType => unreachable,
-            .ArrayTypeSentinel => unreachable,
-            .PtrTypeAligned => unreachable,
-            .PtrTypeSentinel => unreachable,
-            .PtrType => unreachable,
-            .SliceType => unreachable,
-            .StructInit => unreachable,
-            .SwitchCaseMulti => unreachable,
-            .WhileCont => unreachable,
-            .While => unreachable,
-            .ForSimple => unreachable,
-            .For => unreachable,
-            .FnProtoSimple => unreachable,
-            .FnProtoSimpleMulti => unreachable,
-            .FnProtoOne => unreachable,
-            .FnProto => unreachable,
-            .ContainerDecl => unreachable,
-            .ContainerDeclArg => unreachable,
-            .TaggedUnion => unreachable,
-            .TaggedUnionEnumTag => unreachable,
-            .AsmOutput => unreachable,
-            .AsmInput => unreachable,
-            .ErrorValue => unreachable,
+            .ArrayInitDotTwo => unreachable, // TODO
+            .ArrayInitDot => unreachable, // TODO
+            .StructInitDotTwo => unreachable, // TODO
+            .StructInitDot => unreachable, // TODO
+            .Switch => unreachable, // TODO
+            .If => unreachable, // TODO
+            .Continue => unreachable, // TODO
+            .EnumLiteral => unreachable, // TODO
+            .ErrorSetDecl => unreachable, // TODO
+            .Block => unreachable, // TODO
+            .AsmSimple => unreachable, // TODO
+            .Asm => unreachable, // TODO
+            .SliceOpen => unreachable, // TODO
+            .Slice => unreachable, // TODO
+            .Deref => unreachable, // TODO
+            .ArrayInitOne => unreachable, // TODO
+            .ArrayInit => unreachable, // TODO
+            .StructInitOne => unreachable, // TODO
+            .SwitchCaseOne => unreachable, // TODO
+            .SwitchRange => unreachable, // TODO
+            .FnDecl => unreachable, // TODO
+            .GlobalVarDecl => unreachable, // TODO
+            .LocalVarDecl => unreachable, // TODO
+            .SimpleVarDecl => unreachable, // TODO
+            .AlignedVarDecl => unreachable, // TODO
+            .ArrayType => unreachable, // TODO
+            .ArrayTypeSentinel => unreachable, // TODO
+            .PtrTypeAligned => unreachable, // TODO
+            .PtrTypeSentinel => unreachable, // TODO
+            .PtrType => unreachable, // TODO
+            .SliceType => unreachable, // TODO
+            .StructInit => unreachable, // TODO
+            .SwitchCaseMulti => unreachable, // TODO
+            .WhileCont => unreachable, // TODO
+            .While => unreachable, // TODO
+            .ForSimple => unreachable, // TODO
+            .For => unreachable, // TODO
+            .FnProtoSimple => unreachable, // TODO
+            .FnProtoSimpleMulti => unreachable, // TODO
+            .FnProtoOne => unreachable, // TODO
+            .FnProto => unreachable, // TODO
+            .ContainerDecl => unreachable, // TODO
+            .ContainerDeclArg => unreachable, // TODO
+            .TaggedUnion => unreachable, // TODO
+            .TaggedUnionEnumTag => unreachable, // TODO
+            .AsmOutput => unreachable, // TODO
+            .AsmInput => unreachable, // TODO
+            .ErrorValue => unreachable, // TODO
         };
     }
 
lib/std/zig/parse.zig
@@ -3483,9 +3483,8 @@ const Parser = struct {
     /// ExprList <- (Expr COMMA)* Expr?
     /// TODO detect when we can emit BuiltinCallTwo instead of BuiltinCall.
     fn parseBuiltinCall(p: *Parser) !Node.Index {
-        const builtin_token = p.eatToken(.Builtin) orelse return null_node;
-
-        const lparen = (try p.expectTokenRecoverable(.LParen)) orelse {
+        const builtin_token = p.assertToken(.Builtin);
+        _ = (try p.expectTokenRecoverable(.LParen)) orelse {
             try p.warn(.{
                 .ExpectedParamList = .{ .token = p.tok_i },
             });
@@ -3499,8 +3498,104 @@ const Parser = struct {
                 },
             });
         };
-        const params = try ListParseFn(parseExpr)(p);
-        _ = try p.expectToken(.RParen);
+        if (p.eatToken(.RParen)) |_| {
+            return p.addNode(.{
+                .tag = .BuiltinCallTwo,
+                .main_token = builtin_token,
+                .data = .{
+                    .lhs = 0,
+                    .rhs = 0,
+                },
+            });
+        }
+        const param_one = try p.expectExpr();
+        switch (p.token_tags[p.nextToken()]) {
+            .Comma => {
+                if (p.eatToken(.RParen)) |_| {
+                    return p.addNode(.{
+                        .tag = .BuiltinCallTwo,
+                        .main_token = builtin_token,
+                        .data = .{
+                            .lhs = param_one,
+                            .rhs = 0,
+                        },
+                    });
+                }
+            },
+            .RParen => return p.addNode(.{
+                .tag = .BuiltinCallTwo,
+                .main_token = builtin_token,
+                .data = .{
+                    .lhs = param_one,
+                    .rhs = 0,
+                },
+            }),
+            else => {
+                // This is likely just a missing comma;
+                // give an error but continue parsing this list.
+                p.tok_i -= 1;
+                try p.warn(.{
+                    .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
+                });
+            },
+        }
+        const param_two = try p.expectExpr();
+        switch (p.token_tags[p.nextToken()]) {
+            .Comma => {
+                if (p.eatToken(.RParen)) |_| {
+                    return p.addNode(.{
+                        .tag = .BuiltinCallTwo,
+                        .main_token = builtin_token,
+                        .data = .{
+                            .lhs = param_one,
+                            .rhs = param_two,
+                        },
+                    });
+                }
+            },
+            .RParen => return p.addNode(.{
+                .tag = .BuiltinCallTwo,
+                .main_token = builtin_token,
+                .data = .{
+                    .lhs = param_one,
+                    .rhs = param_two,
+                },
+            }),
+            else => {
+                // This is likely just a missing comma;
+                // give an error but continue parsing this list.
+                p.tok_i -= 1;
+                try p.warn(.{
+                    .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
+                });
+            },
+        }
+
+        var list = std.ArrayList(Node.Index).init(p.gpa);
+        defer list.deinit();
+
+        try list.appendSlice(&[_]Node.Index{ param_one, param_two });
+
+        while (true) {
+            const param = try p.expectExpr();
+            try list.append(param);
+            switch (p.token_tags[p.nextToken()]) {
+                .Comma => {
+                    if (p.eatToken(.RParen)) |_| break;
+                    continue;
+                },
+                .RParen => break,
+                else => {
+                    // This is likely just a missing comma;
+                    // give an error but continue parsing this list.
+                    p.tok_i -= 1;
+                    try p.warn(.{
+                        .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
+                    });
+                },
+            }
+        }
+        const params = try p.listToSpan(list.items);
         return p.addNode(.{
             .tag = .BuiltinCall,
             .main_token = builtin_token,
lib/std/zig/parser_test.zig
@@ -21,21 +21,21 @@ test "zig fmt: two spaced line comments before decl" {
     );
 }
 
-//test "zig fmt: respect line breaks after var declarations" {
-//    try testCanonical(
-//        \\const crc =
-//        \\    lookup_tables[0][p[7]] ^
-//        \\    lookup_tables[1][p[6]] ^
-//        \\    lookup_tables[2][p[5]] ^
-//        \\    lookup_tables[3][p[4]] ^
-//        \\    lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
-//        \\    lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
-//        \\    lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
-//        \\    lookup_tables[7][@truncate(u8, self.crc >> 0)];
-//        \\
-//    );
-//}
-//
+test "zig fmt: respect line breaks after var declarations" {
+    try testCanonical(
+        \\const crc =
+        \\    lookup_tables[0][p[7]] ^
+        \\    lookup_tables[1][p[6]] ^
+        \\    lookup_tables[2][p[5]] ^
+        \\    lookup_tables[3][p[4]] ^
+        \\    lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
+        \\    lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
+        \\    lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
+        \\    lookup_tables[7][@truncate(u8, self.crc >> 0)];
+        \\
+    );
+}
+
 //test "zig fmt: multiline string mixed with comments" {
 //    try testCanonical(
 //        \\const s1 =
lib/std/zig/render.zig
@@ -308,7 +308,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
             const field_access = datas[node];
             try renderExpression(ais, tree, field_access.lhs, .None);
             try renderToken(ais, tree, main_tokens[node], .None);
-            return renderToken(ais, tree, field_access.rhs, .None);
+            return renderToken(ais, tree, field_access.rhs, space);
         },
 
         .ErrorUnion,
@@ -362,18 +362,15 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
         => {
             const infix = datas[node];
             try renderExpression(ais, tree, infix.lhs, .Space);
-
             const op_token = main_tokens[node];
-            const after_op_space: Space = if (tree.tokensOnSameLine(op_token, op_token + 1))
-                .Space
-            else
-                .Newline;
-            {
+            if (tree.tokensOnSameLine(op_token, op_token + 1)) {
+                try renderToken(ais, tree, op_token, .Space);
+            } else {
                 ais.pushIndent();
-                try renderToken(ais, tree, op_token, after_op_space);
+                try renderToken(ais, tree, op_token, .Newline);
                 ais.popIndent();
+                ais.pushIndentOneShot();
             }
-            ais.pushIndentOneShot();
             return renderExpression(ais, tree, infix.rhs, space);
         },
 
@@ -955,28 +952,15 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
             return renderToken(ais, tree, after_last_param_tok, space); // )
         },
 
-        .ArrayAccess => unreachable, // TODO
-        //.ArrayAccess => {
-        //    const suffix_op = base.castTag(.ArrayAccess).?;
-
-        //    const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
-        //    const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
-
-        //    try renderExpression(ais, tree, suffix_op.lhs, Space.None);
-        //    try renderToken(ais, tree, lbracket, Space.None); // [
-
-        //    const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment;
-        //    const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment;
-        //    {
-        //        const new_space = if (ends_with_comment) Space.Newline else Space.None;
-
-        //        ais.pushIndent();
-        //        defer ais.popIndent();
-        //        try renderExpression(ais, tree, suffix_op.index_expr, new_space);
-        //    }
-        //    if (starts_with_comment) try ais.maybeInsertNewline();
-        //    return renderToken(ais, tree, rbracket, space); // ]
-        //},
+        .ArrayAccess => {
+            const suffix = datas[node];
+            const lbracket = tree.firstToken(suffix.rhs) - 1;
+            const rbracket = tree.lastToken(suffix.rhs) + 1;
+            try renderExpression(ais, tree, suffix.lhs, .None);
+            try renderToken(ais, tree, lbracket, .None); // [
+            try renderExpression(ais, tree, suffix.rhs, .None);
+            return renderToken(ais, tree, rbracket, space); // ]
+        },
 
         .Slice => unreachable, // TODO
         .SliceOpen => unreachable, // TODO
@@ -1278,68 +1262,22 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
         //    }
         //},
 
-        .BuiltinCall => unreachable, // TODO
-        .BuiltinCallTwo => unreachable, // TODO
-        //.BuiltinCall => {
-        //    const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
-
-        //    // TODO remove after 0.7.0 release
-        //    if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
-        //        return ais.writer().writeAll("opaque {}");
-
-        //    // TODO remove after 0.7.0 release
-        //    {
-        //        const params = builtin_call.paramsConst();
-        //        if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
-        //            params.len == 1)
-        //        {
-        //            if (params[0].castTag(.EnumLiteral)) |enum_literal|
-        //                if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
-        //                    return ais.writer().writeAll("opaque {}");
-        //        }
-        //    }
-
-        //    try renderToken(ais, tree, builtin_call.builtin_token, Space.None); // @name
-
-        //    const src_params_trailing_comma = blk: {
-        //        if (builtin_call.params_len == 0) break :blk false;
-        //        const last_node = builtin_call.params()[builtin_call.params_len - 1];
-        //        const maybe_comma = tree.nextToken(last_node.lastToken());
-        //        break :blk tree.token_tags[maybe_comma] == .Comma;
-        //    };
-
-        //    const lparen = tree.nextToken(builtin_call.builtin_token);
-
-        //    if (!src_params_trailing_comma) {
-        //        try renderToken(ais, tree, lparen, Space.None); // (
-
-        //        // render all on one line, no trailing comma
-        //        const params = builtin_call.params();
-        //        for (params) |param_node, i| {
-        //            const maybe_comment = param_node.firstToken() - 1;
-        //            if (param_node.*.tag == .MultilineStringLiteral or tree.token_tags[maybe_comment] == .LineComment) {
-        //                ais.pushIndentOneShot();
-        //            }
-        //            try renderExpression(ais, tree, param_node, Space.None);
-
-        //            if (i + 1 < params.len) {
-        //                const comma_token = tree.nextToken(param_node.lastToken());
-        //                try renderToken(ais, tree, comma_token, Space.Space); // ,
-        //            }
-        //        }
-        //    } else {
-        //        // one param per line
-        //        ais.pushIndent();
-        //        defer ais.popIndent();
-        //        try renderToken(ais, tree, lparen, Space.Newline); // (
-
-        //        for (builtin_call.params()) |param_node| {
-        //            try renderExpression(ais, tree, param_node, Space.Comma);
-        //        }
-        //    }
-
-        //    return renderToken(ais, tree, builtin_call.rparen_token, space); // )
-        //},
+        .BuiltinCallTwo => {
+            if (datas[node].lhs == 0) {
+                const params = [_]ast.Node.Index{};
+                return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
+            } else if (datas[node].rhs == 0) {
+                const params = [_]ast.Node.Index{datas[node].lhs};
+                return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
+            } else {
+                const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
+                return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
+            }
+        },
+        .BuiltinCall => {
+            const params = tree.extra_data[datas[node].lhs..datas[node].rhs];
+            return renderBuiltinCall(ais, tree, main_tokens[node], params, space);
+        },
 
         .FnProtoSimple => unreachable, // TODO
         .FnProtoSimpleMulti => unreachable, // TODO
@@ -2221,6 +2159,52 @@ fn renderParamDecl(
     }
 }
 
+fn renderBuiltinCall(
+    ais: *Ais,
+    tree: ast.Tree,
+    builtin_token: ast.TokenIndex,
+    params: []const ast.Node.Index,
+    space: Space,
+) Error!void {
+    const token_tags = tree.tokens.items(.tag);
+
+    try renderToken(ais, tree, builtin_token, .None); // @name
+
+    if (params.len == 0) {
+        try renderToken(ais, tree, builtin_token + 1, .None); // (
+        return renderToken(ais, tree, builtin_token + 2, space); // )
+    }
+
+    const last_param = params[params.len - 1];
+    const after_last_param_token = tree.lastToken(last_param) + 1;
+
+    if (token_tags[after_last_param_token] != .Comma) {
+        // Render all on one line, no trailing comma.
+        try renderToken(ais, tree, builtin_token + 1, .None); // (
+
+        for (params) |param_node, i| {
+            try renderExpression(ais, tree, param_node, .None);
+
+            if (i + 1 < params.len) {
+                const comma_token = tree.lastToken(param_node) + 1;
+                try renderToken(ais, tree, comma_token, .Space); // ,
+            }
+        }
+        return renderToken(ais, tree, after_last_param_token, space); // )
+    } else {
+        // Render one param per line.
+        ais.pushIndent();
+        try renderToken(ais, tree, builtin_token + 1, Space.Newline); // (
+
+        for (params) |param_node| {
+            try renderExpression(ais, tree, param_node, .Comma);
+        }
+        ais.popIndent();
+
+        return renderToken(ais, tree, after_last_param_token + 1, space); // )
+    }
+}
+
 /// Render an expression, and the comma that follows it, if it is present in the source.
 fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
     const token_tags = tree.tokens.items(.tag);