Commit 8cf0ef2779

Andrew Kelley <andrew@ziglang.org>
2021-04-17 07:21:26
AstGen: implement simple enums and decls for enums
1 parent 0409d43
Changed files (2)
src/AstGen.zig
@@ -2438,12 +2438,11 @@ fn structDeclInner(
 
     const decl_inst = try gz.addBlock(tag, node);
     try gz.instructions.append(gpa, decl_inst);
-    if (field_index != 0) {
+    if (block_scope.instructions.items.len != 0) {
         _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
     }
 
-    try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
-        @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
+    try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
         bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len +
         block_scope.instructions.items.len +
         wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
@@ -2483,6 +2482,7 @@ fn containerDecl(
     const tree = &astgen.file.tree;
     const token_tags = tree.tokens.items(.tag);
     const node_tags = tree.nodes.items(.tag);
+    const node_datas = tree.nodes.items(.data);
 
     // We must not create any types until Sema. Here the goal is only to generate
     // ZIR for all the field types, alignments, and default value expressions.
@@ -2594,22 +2594,12 @@ fn containerDecl(
                     },
                 );
             }
-            if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
-                return astgen.failNode(node, "TODO AstGen simple enums", .{});
-            }
             // In this case we must generate ZIR code for the tag values, similar to
             // how structs are handled above.
             const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
                 .enum_decl
             else
                 .enum_decl_nonexhaustive;
-            if (counts.total_fields == 0) {
-                return gz.addPlNode(tag, node, Zir.Inst.EnumDecl{
-                    .tag_type = arg_inst,
-                    .fields_len = 0,
-                    .body_len = 0,
-                });
-            }
 
             // The enum_decl instruction introduces a scope in which the decls of the enum
             // are in scope, so that tag values can refer to decls within the enum itself.
@@ -2621,6 +2611,9 @@ fn containerDecl(
             };
             defer block_scope.instructions.deinit(gpa);
 
+            var wip_decls: WipDecls = .{};
+            defer wip_decls.deinit(gpa);
+
             var fields_data = ArrayListUnmanaged(u32){};
             defer fields_data.deinit(gpa);
 
@@ -2639,7 +2632,81 @@ fn containerDecl(
                     .container_field_init => tree.containerFieldInit(member_node),
                     .container_field_align => tree.containerFieldAlign(member_node),
                     .container_field => tree.containerField(member_node),
-                    else => continue,
+
+                    .fn_decl => {
+                        const fn_proto = node_datas[member_node].lhs;
+                        const body = node_datas[member_node].rhs;
+                        switch (node_tags[fn_proto]) {
+                            .fn_proto_simple => {
+                                var params: [1]ast.Node.Index = undefined;
+                                try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(&params, fn_proto));
+                                continue;
+                            },
+                            .fn_proto_multi => {
+                                try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto));
+                                continue;
+                            },
+                            .fn_proto_one => {
+                                var params: [1]ast.Node.Index = undefined;
+                                try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(&params, fn_proto));
+                                continue;
+                            },
+                            .fn_proto => {
+                                try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto));
+                                continue;
+                            },
+                            else => unreachable,
+                        }
+                    },
+                    .fn_proto_simple => {
+                        var params: [1]ast.Node.Index = undefined;
+                        try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(&params, member_node));
+                        continue;
+                    },
+                    .fn_proto_multi => {
+                        try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node));
+                        continue;
+                    },
+                    .fn_proto_one => {
+                        var params: [1]ast.Node.Index = undefined;
+                        try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(&params, member_node));
+                        continue;
+                    },
+                    .fn_proto => {
+                        try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node));
+                        continue;
+                    },
+
+                    .global_var_decl => {
+                        try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node));
+                        continue;
+                    },
+                    .local_var_decl => {
+                        try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node));
+                        continue;
+                    },
+                    .simple_var_decl => {
+                        try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node));
+                        continue;
+                    },
+                    .aligned_var_decl => {
+                        try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node));
+                        continue;
+                    },
+
+                    .@"comptime" => {
+                        try astgen.comptimeDecl(gz, scope, member_node);
+                        continue;
+                    },
+                    .@"usingnamespace" => {
+                        try astgen.usingnamespaceDecl(gz, scope, member_node);
+                        continue;
+                    },
+                    .test_decl => {
+                        try astgen.testDecl(gz, scope, member_node);
+                        continue;
+                    },
+                    else => unreachable,
                 };
                 if (field_index % 32 == 0 and field_index != 0) {
                     try bit_bag.append(gpa, cur_bit_bag);
@@ -2663,27 +2730,45 @@ fn containerDecl(
 
                 field_index += 1;
             }
-            const empty_slot_count = 32 - (field_index % 32);
-            cur_bit_bag >>= @intCast(u5, empty_slot_count);
+            {
+                const empty_slot_count = 32 - (field_index % 32);
+                cur_bit_bag >>= @intCast(u5, empty_slot_count);
+            }
+
+            if (wip_decls.decl_index != 0) {
+                const empty_slot_count = 16 - (wip_decls.decl_index % 16);
+                wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
+            }
 
             const decl_inst = try gz.addBlock(tag, node);
             try gz.instructions.append(gpa, decl_inst);
-            _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
+            if (block_scope.instructions.items.len != 0) {
+                _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
+            }
 
-            try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
-                @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
+            try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
                 bit_bag.items.len + 1 + fields_data.items.len +
-                block_scope.instructions.items.len);
+                block_scope.instructions.items.len +
+                wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
+                wip_decls.name_and_value.items.len);
             const zir_datas = astgen.instructions.items(.data);
             zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
                 .tag_type = arg_inst,
                 .body_len = @intCast(u32, block_scope.instructions.items.len),
                 .fields_len = @intCast(u32, field_index),
+                .decls_len = @intCast(u32, wip_decls.decl_index),
             });
             astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
             astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
             astgen.extra.appendAssumeCapacity(cur_bit_bag);
             astgen.extra.appendSliceAssumeCapacity(fields_data.items);
+
+            astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
+            if (wip_decls.decl_index != 0) {
+                astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
+            }
+            astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
+
             return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node);
         },
         .keyword_opaque => {
src/Zir.zig
@@ -1591,11 +1591,20 @@ pub const Inst = struct {
     ///        field_name: u32,
     ///        value: Ref, // if corresponding bit is set
     ///    }
+    /// 3. decl_bits: u32 // for every 16 decls
+    ///    - sets of 2 bits:
+    ///      0b0X: whether corresponding decl is pub
+    ///      0bX0: whether corresponding decl is exported
+    /// 4. decl: { // for every decls_len
+    ///        name: u32, // null terminated string index
+    ///        value: Index,
+    ///    }
     pub const EnumDecl = struct {
         /// Can be `Ref.none`.
         tag_type: Ref,
         body_len: u32,
         fields_len: u32,
+        decls_len: u32,
     };
 
     /// Trailing:
@@ -2231,6 +2240,7 @@ const Writer = struct {
         const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index);
         const body = self.code.extra[extra.end..][0..extra.data.body_len];
         const fields_len = extra.data.fields_len;
+        const decls_len = extra.data.decls_len;
         const tag_ty_ref = extra.data.tag_type;
 
         if (tag_ty_ref != .none) {
@@ -2238,53 +2248,63 @@ const Writer = struct {
             try stream.writeAll(", ");
         }
 
+        var extra_index: usize = undefined;
+
         if (fields_len == 0) {
             assert(body.len == 0);
-            try stream.writeAll("{}, {}) ");
-            try self.writeSrc(stream, inst_data.src());
-            return;
-        }
-
-        try stream.writeAll("{\n");
-        self.indent += 2;
-        try self.writeBody(stream, body);
+            try stream.writeAll("{}, {}, {");
+            extra_index = extra.end;
+        } else {
+            try stream.writeAll("{\n");
+            self.indent += 2;
+            try self.writeBody(stream, body);
 
-        try stream.writeByteNTimes(' ', self.indent - 2);
-        try stream.writeAll("}, {\n");
+            try stream.writeByteNTimes(' ', self.indent - 2);
+            try stream.writeAll("}, {\n");
 
-        const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
-        const body_end = extra.end + body.len;
-        var extra_index: usize = body_end + bit_bags_count;
-        var bit_bag_index: usize = body_end;
-        var cur_bit_bag: u32 = undefined;
-        var field_i: u32 = 0;
-        while (field_i < fields_len) : (field_i += 1) {
-            if (field_i % 32 == 0) {
-                cur_bit_bag = self.code.extra[bit_bag_index];
-                bit_bag_index += 1;
-            }
-            const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
-            cur_bit_bag >>= 1;
+            const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
+            const body_end = extra.end + body.len;
+            extra_index = body_end + bit_bags_count;
+            var bit_bag_index: usize = body_end;
+            var cur_bit_bag: u32 = undefined;
+            var field_i: u32 = 0;
+            while (field_i < fields_len) : (field_i += 1) {
+                if (field_i % 32 == 0) {
+                    cur_bit_bag = self.code.extra[bit_bag_index];
+                    bit_bag_index += 1;
+                }
+                const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
+                cur_bit_bag >>= 1;
 
-            const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
-            extra_index += 1;
+                const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
+                extra_index += 1;
 
-            try stream.writeByteNTimes(' ', self.indent);
-            try stream.print("{}", .{std.zig.fmtId(field_name)});
+                try stream.writeByteNTimes(' ', self.indent);
+                try stream.print("{}", .{std.zig.fmtId(field_name)});
 
-            if (has_tag_value) {
-                const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
-                extra_index += 1;
+                if (has_tag_value) {
+                    const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
+                    extra_index += 1;
 
-                try stream.writeAll(" = ");
-                try self.writeInstRef(stream, tag_value_ref);
+                    try stream.writeAll(" = ");
+                    try self.writeInstRef(stream, tag_value_ref);
+                }
+                try stream.writeAll(",\n");
             }
-            try stream.writeAll(",\n");
+            self.indent -= 2;
+            try stream.writeByteNTimes(' ', self.indent);
+            try stream.writeAll("}, {");
+        }
+        if (decls_len == 0) {
+            try stream.writeAll("}) ");
+        } else {
+            try stream.writeAll("\n");
+            self.indent += 2;
+            try self.writeDecls(stream, decls_len, extra_index);
+            self.indent -= 2;
+            try stream.writeByteNTimes(' ', self.indent);
+            try stream.writeAll("}) ");
         }
-
-        self.indent -= 2;
-        try stream.writeByteNTimes(' ', self.indent);
-        try stream.writeAll("}) ");
         try self.writeSrc(stream, inst_data.src());
     }