Commit 0482e8ba9d

Loris Cro <kappaloris@gmail.com>
2022-08-21 18:53:00
autodoc: initial support for struct_init_anon
1 parent 583175d
Changed files (2)
lib
docs
src
lib/docs/main.js
@@ -1430,20 +1430,25 @@ var zigAnalysis;
         return lhs + "!" + rhs;
       }
       case "struct": {
-        const struct_name =
-          zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
+        // const struct_name =
+        //   zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
+        const struct_name = ".";
         let struct_body = "";
         struct_body += struct_name + "{ ";
         for (let i = 0; i < expr.struct.length; i++) {
-          const val = expr.struct[i].name;
-          const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
-          let value_field = exprArg[Object.keys(exprArg)[0]];
-          if (value_field instanceof Object) {
-            value_field =
-              zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
-                .name;
-          }
-          struct_body += "." + val + " = " + value_field;
+          const fv = expr.struct[i];
+          const field_name = fv.name;
+          const exprArg = zigAnalysis.exprs[fv.val.expr.as.exprArg];
+          let field_value = exprName(exprArg, opts);
+          // TODO: commented out because it seems not needed. if it deals
+          //       with a corner case, please add a comment when re-enabling it.
+          // let field_value = exprArg[Object.keys(exprArg)[0]];
+          // if (field_value instanceof Object) {
+          //   value_field = exprName(value_field)
+          //     zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
+          //       .name;
+          // }
+          struct_body += "." + field_name + " = " + field_value;
           if (i !== expr.struct.length - 1) {
             struct_body += ", ";
           } else {
src/Autodoc.zig
@@ -69,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
         }
     }
 
+    log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
+
     const root_src_dir = self.module.main_pkg.root_src_directory;
     const root_src_path = self.module.main_pkg.root_src_path;
     const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
@@ -159,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
                     .void_type => .{
                         .Void = .{ .name = tmpbuf.toOwnedSlice() },
                     },
+                    .type_info_type => .{
+                        .Unanalyzed = .{},
+                    },
                     .type_type => .{
                         .Type = .{ .name = tmpbuf.toOwnedSlice() },
                     },
@@ -608,6 +613,7 @@ const DocData = struct {
         type: usize, // index in `types`
         this: usize, // index in `types`
         declRef: usize, // index in `decls`
+        builtinField: enum { len, ptr },
         fieldRef: FieldRef,
         refPath: []Expr,
         int: struct {
@@ -697,20 +703,26 @@ const DocData = struct {
             var jsw = std.json.writeStream(w, 15);
             try jsw.beginObject();
             try jsw.objectField(@tagName(active_tag));
-            inline for (comptime std.meta.fields(Expr)) |case| {
-                if (@field(Expr, case.name) == active_tag) {
-                    switch (active_tag) {
-                        .int => {
-                            if (self.int.negated) try w.writeAll("-");
-                            try jsw.emitNumber(self.int.value);
-                        },
-                        .int_big => {
+            switch (self) {
+                .int => {
+                    if (self.int.negated) try w.writeAll("-");
+                    try jsw.emitNumber(self.int.value);
+                },
+                .int_big => {
 
-                            //@panic("TODO: json serialization of big ints!");
-                            //if (v.negated) try w.writeAll("-");
-                            //try jsw.emitNumber(v.value);
-                        },
-                        else => {
+                    //@panic("TODO: json serialization of big ints!");
+                    //if (v.negated) try w.writeAll("-");
+                    //try jsw.emitNumber(v.value);
+                },
+                .builtinField => {
+                    try jsw.emitString(@tagName(self.builtinField));
+                },
+                else => {
+                    inline for (comptime std.meta.fields(Expr)) |case| {
+                        // TODO: this is super ugly, fix once `inline else` is a thing
+                        if (comptime std.mem.eql(u8, case.name, "builtinField"))
+                            continue;
+                        if (@field(Expr, case.name) == active_tag) {
                             try std.json.stringify(@field(self, case.name), opt, w);
                             jsw.state_index -= 1;
                             // TODO: we should not reach into the state of the
@@ -719,9 +731,9 @@ const DocData = struct {
                             //       would be nice to have a proper integration
                             //       between the json writer and the generic
                             //       std.json.stringify implementation
-                        },
+                        }
                     }
-                }
+                },
             }
             try jsw.endObject();
         }
@@ -1905,31 +1917,38 @@ fn walkInstruction(
             const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
 
             var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
-            var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
-
             try path.append(self.arena, .{
                 .string = file.zir.nullTerminatedString(extra.data.field_name_start),
             });
+
             // Put inside path the starting index of each decl name that
-            // we encounter as we navigate through all the field_vals
-            while (tags[lhs] == .field_val or
-                tags[lhs] == .field_call_bind or
-                tags[lhs] == .field_ptr or
-                tags[lhs] == .field_type)
-            {
-                const lhs_extra = file.zir.extraData(
-                    Zir.Inst.Field,
-                    data[lhs].pl_node.payload_index,
-                );
+            // we encounter as we navigate through all the field_*s
+            const lhs_ref = blk: {
+                var lhs_extra = extra;
+                while (true) {
+                    if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
+                        break :blk lhs_extra.data.lhs;
+                    }
 
-                try path.append(self.arena, .{
-                    .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
-                });
-                lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
-            }
+                    const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
+                    if (tags[lhs] != .field_val and
+                        tags[lhs] != .field_call_bind and
+                        tags[lhs] != .field_ptr and
+                        tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
+
+                    lhs_extra = file.zir.extraData(
+                        Zir.Inst.Field,
+                        data[lhs].pl_node.payload_index,
+                    );
+
+                    try path.append(self.arena, .{
+                        .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
+                    });
+                }
+            };
 
             // TODO: double check that we really don't need type info here
-            const wr = try self.walkInstruction(file, parent_scope, lhs, false);
+            const wr = try self.walkRef(file, parent_scope, lhs_ref, false);
             try path.append(self.arena, wr.expr);
 
             // This way the data in `path` has the same ordering that the ref
@@ -1948,7 +1967,7 @@ fn walkInstruction(
             // - (2) Paths can sometimes never resolve fully. This means that
             //       any value that depends on that will have to become a
             //       comptimeExpr.
-            try self.tryResolveRefPath(file, lhs, path.items);
+            try self.tryResolveRefPath(file, inst_index, path.items);
             return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
         },
         .int_type => {
@@ -2053,6 +2072,46 @@ fn walkInstruction(
             );
             return self.cteTodo(@tagName(tags[inst_index]));
         },
+        .struct_init_anon => {
+            const pl_node = data[inst_index].pl_node;
+            const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
+
+            const field_vals = try self.arena.alloc(
+                DocData.Expr.FieldVal,
+                extra.data.fields_len,
+            );
+
+            log.debug("number of fields: {}", .{extra.data.fields_len});
+            var idx = extra.end;
+            for (field_vals) |*fv| {
+                const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
+                const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
+                fv.* = .{
+                    .name = field_name,
+                    .val = DocData.WalkResult{
+                        .expr = .{ .comptimeExpr = 0 },
+                    },
+                };
+                // printWithContext(
+                //     file,
+                //     inst_index,
+                //     "analyzing field [{}] %{} `{s}`",
+                //     .{ i, init_extra.data.init, field_name },
+                // );
+                // const value = try self.walkRef(
+                //     file,
+                //     parent_scope,
+                //     init_extra.data.init,
+                //     need_type,
+                // );
+                // fv.* = .{ .name = field_name, .val = value };
+                // idx = init_extra.end;
+            }
+
+            return DocData.WalkResult{
+                .expr = .{ .@"struct" = field_vals },
+            };
+        },
         .error_set_decl => {
             const pl_node = data[inst_index].pl_node;
             const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
@@ -3094,6 +3153,20 @@ fn tryResolveRefPath(
 
                     return;
                 },
+                .Array => {
+                    if (std.mem.eql(u8, child_string, "len")) {
+                        path[i + 1] = .{
+                            .builtinField = .len,
+                        };
+                    } else {
+                        panicWithContext(
+                            file,
+                            inst_index,
+                            "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
+                            .{ child_string, resolved_parent },
+                        );
+                    }
+                },
                 .Enum => |t_enum| {
                     for (t_enum.pubDecls) |d| {
                         // TODO: this could be improved a lot
@@ -3820,9 +3893,12 @@ fn walkRef(
     } else if (enum_value < Ref.typed_value_map.len) {
         switch (ref) {
             else => {
-                std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
-                    @tagName(ref),
-                });
+                panicWithContext(
+                    file,
+                    0,
+                    "TODO: handle {s} in walkRef",
+                    .{@tagName(ref)},
+                );
             },
             .undef => {
                 return DocData.WalkResult{ .expr = .@"undefined" };