Commit 15603f403c

Andrew Kelley <andrew@ziglang.org>
2021-02-22 00:01:22
AST: use fn_proto not fn_decl for extern decls
saves a few bytes per extern function declaration
1 parent 88d0e77
Changed files (3)
lib/std/zig/ast.zig
@@ -2642,20 +2642,29 @@ pub const Node = struct {
         @"return",
         /// `fn(a: lhs) rhs`. lhs can be omitted.
         /// anytype and ... parameters are omitted from the AST tree.
+        /// main_token is the `fn` keyword.
+        /// extern function declarations use this tag.
         fn_proto_simple,
         /// `fn(a: b, c: d) rhs`. `sub_range_list[lhs]`.
         /// anytype and ... parameters are omitted from the AST tree.
+        /// main_token is the `fn` keyword.
+        /// extern function declarations use this tag.
         fn_proto_multi,
         /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`.
         /// zero or one parameters.
         /// anytype and ... parameters are omitted from the AST tree.
+        /// main_token is the `fn` keyword.
+        /// extern function declarations use this tag.
         fn_proto_one,
         /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`.
         /// anytype and ... parameters are omitted from the AST tree.
+        /// main_token is the `fn` keyword.
+        /// extern function declarations use this tag.
         fn_proto,
         /// lhs is the fn_proto.
-        /// rhs is the function body block if non-zero.
-        /// if rhs is zero, the function decl has no body (e.g. an extern function)
+        /// rhs is the function body block.
+        /// Note that extern function declarations use the fn_proto tags rather
+        /// than this one.
         fn_decl,
         /// `anyframe->rhs`. main_token is `anyframe`. `lhs` is arrow token index.
         anyframe_type,
lib/std/zig/parse.zig
@@ -542,15 +542,8 @@ const Parser = struct {
         if (fn_proto != 0) {
             switch (p.token_tags[p.tok_i]) {
                 .semicolon => {
-                    const semicolon_token = p.nextToken();
-                    return p.addNode(.{
-                        .tag = .fn_decl,
-                        .main_token = p.nodes.items(.main_token)[fn_proto],
-                        .data = .{
-                            .lhs = fn_proto,
-                            .rhs = 0,
-                        },
-                    });
+                    p.tok_i += 1;
+                    return fn_proto;
                 },
                 .l_brace => {
                     const body_block = try p.parseBlock();
lib/std/zig/render.zig
@@ -81,19 +81,39 @@ 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);
             }
-            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
-            }
+            assert(datas[decl].rhs != 0);
+            try renderExpression(ais, tree, fn_proto, .space);
+            return renderExpression(ais, tree, datas[decl].rhs, space);
         },
         .fn_proto_simple,
         .fn_proto_multi,
         .fn_proto_one,
         .fn_proto,
         => {
+            // Extern function prototypes are parsed as these tags.
+            // Go back to the first token we should render here.
+            const fn_token = main_tokens[decl];
+            var i = fn_token;
+            while (i > 0) {
+                i -= 1;
+                switch (token_tags[i]) {
+                    .keyword_extern,
+                    .keyword_export,
+                    .keyword_pub,
+                    .string_literal,
+                    .keyword_inline,
+                    .keyword_noinline,
+                    => continue,
+
+                    else => {
+                        i += 1;
+                        break;
+                    },
+                }
+            }
+            while (i < fn_token) : (i += 1) {
+                try renderToken(ais, tree, i, .space);
+            }
             try renderExpression(ais, tree, decl, .none);
             return renderToken(ais, tree, tree.lastToken(decl) + 1, space); // semicolon
         },