Commit a524e57090

Isaac Freund <ifreund@ifreund.xyz>
2021-02-10 15:19:30
zig fmt: support bodyless function decls
extern function declarations do not have a body, so allow setting the rhs for FnDecl to 0 to indicate this is the case.
1 parent 80b719d
Changed files (4)
lib/std/zig/ast.zig
@@ -521,7 +521,8 @@ pub const Tree = struct {
             .IfSimple,
             .WhileSimple,
             .ForSimple,
-            .FnDecl,
+            .FnProtoSimple,
+            .FnProtoMulti,
             .PtrTypeAligned,
             .PtrTypeSentinel,
             .PtrType,
@@ -538,8 +539,6 @@ pub const Tree = struct {
             .AsmSimple,
             .AsmOutput,
             .AsmInput,
-            .FnProtoSimple,
-            .FnProtoMulti,
             .ErrorValue,
             => return datas[n].rhs + end_offset,
 
@@ -804,6 +803,13 @@ pub const Tree = struct {
                     return main_tokens[n] + end_offset;
                 }
             },
+            .FnDecl => {
+                if (datas[n].rhs != 0) {
+                    n = datas[n].rhs;
+                } else {
+                    n = datas[n].lhs;
+                }
+            },
             .FnProtoOne => {
                 const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
                 // linksection, callconv, align can appear in any order, so we
@@ -2520,7 +2526,9 @@ pub const Node = struct {
         /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`.
         /// anytype and ... parameters are omitted from the AST tree.
         FnProto,
-        /// lhs is the FnProto, rhs is the function body block.
+        /// lhs is the FnProto.
+        /// rhs is the function body block if non-zero.
+        /// if rhs is zero, the funtion decl has no body (e.g. an extern function)
         FnDecl,
         /// `anyframe->rhs`. main_token is `anyframe`. `lhs` is arrow token index.
         AnyFrameType,
lib/std/zig/parse.zig
@@ -516,7 +516,14 @@ const Parser = struct {
                 .Semicolon => {
                     const semicolon_token = p.nextToken();
                     try p.parseAppendedDocComment(semicolon_token);
-                    return fn_proto;
+                    return p.addNode(.{
+                        .tag = .FnDecl,
+                        .main_token = p.nodes.items(.main_token)[fn_proto],
+                        .data = .{
+                            .lhs = fn_proto,
+                            .rhs = 0,
+                        },
+                    });
                 },
                 .LBrace => {
                     const body_block = try p.parseBlock();
lib/std/zig/parser_test.zig
@@ -298,12 +298,12 @@ test "zig fmt: grouped expressions (parentheses)" {
     );
 }
 
-//test "zig fmt: c pointer type" {
-//    try testCanonical(
-//        \\pub extern fn repro() [*c]const u8;
-//        \\
-//    );
-//}
+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(
@@ -2339,7 +2339,23 @@ test "zig fmt: alignment" {
 //        \\
 //    );
 //}
-//
+
+test "zig fmt: function attributes" {
+    try testCanonical(
+        \\export fn foo() void {}
+        \\pub export fn foo() void {}
+        \\extern fn foo() void;
+        \\pub extern fn foo() void;
+        \\extern "c" fn foo() void;
+        \\pub extern "c" fn foo() void;
+        \\inline fn foo() void {}
+        \\pub inline fn foo() void {}
+        \\noinline fn foo() void {}
+        \\pub noinline fn foo() void {}
+        \\
+    );
+}
+
 //test "zig fmt: pointer attributes" {
 //    try testCanonical(
 //        \\extern fn f1(s: *align(*u8) u8) c_int;
lib/std/zig/render.zig
@@ -121,6 +121,8 @@ fn renderMember(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index, space: Space) E
                     .Keyword_export,
                     .Keyword_pub,
                     .StringLiteral,
+                    .Keyword_inline,
+                    .Keyword_noinline,
                     => continue,
 
                     else => {
@@ -132,8 +134,13 @@ fn renderMember(ais: *Ais, tree: ast.Tree, decl: ast.Node.Index, space: Space) E
             while (i < fn_token) : (i += 1) {
                 try renderToken(ais, tree, i, .Space);
             }
-            try renderExpression(ais, tree, fn_proto, .Space);
-            return renderExpression(ais, tree, datas[decl].rhs, space);
+            if (datas[decl].rhs != 0) {
+                try renderExpression(ais, tree, fn_proto, .Space);
+                return renderExpression(ais, tree, datas[decl].rhs, space);
+            } else {
+                try renderExpression(ais, tree, fn_proto, .None);
+                return renderToken(ais, tree, tree.lastToken(fn_proto) + 1, space); // semicolon
+            }
         },
         .FnProtoSimple,
         .FnProtoMulti,