authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-09 18:35:12+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
log056ba8e57c9c2f4cfc6e72303af19a6476205a6f
tree65aeddc040bcf9dc9a543ff1c87720cbadd9a80c
parent3eb90a110f2c4b6eea82b0fcd7c8cab386594437

autodoc: add support for `@This` and improve call support in decl paths


2 files changed, 89 insertions(+), 44 deletions(-)

lib/docs/main.js+23-18
......@@ -661,9 +661,9 @@
661661 if (typeValue.hasCte) {
662662 // TODO: find the cte, print it nicely
663663 if (wantLink) {
664 return '<a href=""># CTE TODO #</a>';
664 return '<a href="">[ComptimeExpr]</a>';
665665 } else {
666 return "# CTE TODO #";
666 return "[ComptimeExpr]";
667667 }
668668 }
669669 var declIndex = typeValue.declPath[0];
......@@ -735,7 +735,7 @@
735735 function getValueText(typeRef, value, wantHtml, wantLink) {
736736 var resolvedTypeRef = resolveValue(typeRef);
737737 if ("comptimeExpr" in resolvedTypeRef) {
738 return "# CTE TODO #";
738 return "[ComptimeExpr]";
739739 }
740740 console.assert("type" in resolvedTypeRef);
741741 var typeObj = zigAnalysis.types[typeRef.type];
......@@ -773,9 +773,10 @@
773773 return "?" + typeValueName(typeObj.child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl);
774774 case typeKinds.Pointer:
775775 var name = "";
776 switch (typeObj.len) {
777 case pointerSizeEnum.One:
776 switch (typeObj.size) {
778777 default:
778 console.log("TODO: implement unhandled pointer size case");
779 case pointerSizeEnum.One:
779780 name += "*";
780781 break;
781782 case pointerSizeEnum.Many:
......@@ -976,23 +977,27 @@
976977 }
977978 }
978979
979 if (isVarArgs && i === typeObj.args.length - 1) {
980 if (isVarArgs && i === typeObj.params.length - 1) {
980981 payloadHtml += '...';
981 } else if ("declRef" in value) {
982 var decl = zigAnalysis.decls[value.declRef];
983 var val = resolveValue(decl.value);
984 var valType = zigAnalysis.types[argTypeIndex];
985
986 var valTypeName = typeShorthandName(valType);
987
988 payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';
989 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
990 payloadHtml += '</a>';
982 } else if ("declPath" in value) {
983 if (value.hasCte) {
984 var cte = findCteInDeclPath(value.declPath);
985 payloadHtml += "[ComptimeExpr]";
986 } else {
987 var decl = zigAnalysis.decls[value.declPath[0]];
988 var val = resolveValue(decl.value);
989 var valType = zigAnalysis.types[argTypeIndex];
990
991 var valTypeName = typeShorthandName(valType);
992 payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';
993 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
994 payloadHtml += '</a>';
995 }
991996 } else if ("type" in value) {
992997 var name = typeValueName(value, false);
993998 payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
994999 } else if ("comptimeExpr" in value) {
995 payloadHtml += '<span class="tok-kw"> # CTE TODO #</span>';
1000 payloadHtml += '<span class="tok-kw">[ComptimeExpr]</span>';
9961001 } else if (wantHtml) {
9971002 payloadHtml += '<span class="tok-kw">var</span>';
9981003 } else {
......@@ -1350,7 +1355,7 @@
13501355
13511356 // TODO: handle nested decl paths properly!
13521357 if (field.hasCte) {
1353 html += "<a href=\"\"># CTE TODO #</a>";
1358 html += "<a href=\"\">[ComptimeExpr]</a>";
13541359 break;
13551360 }
13561361
src/Autodoc.zig+66-26
......@@ -144,10 +144,11 @@ pub fn generateZirData(self: *Autodoc) !void {
144144 }
145145 }
146146
147 var root_scope = Scope{ .parent = null };
147 const main_type_index = self.types.items.len;
148 var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
148149 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
149 try self.files.put(self.arena, file, self.types.items.len);
150 const main_type_index = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst);
150 try self.files.put(self.arena, file, main_type_index);
151 _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst);
151152
152153 if (self.decl_paths_pending_on_decls.count() > 0) {
153154 @panic("some decl paths were never fully analized (pending on decls)");
......@@ -170,7 +171,7 @@ pub fn generateZirData(self: *Autodoc) !void {
170171 .comptimeExprs = self.comptime_exprs.items,
171172 };
172173
173 data.packages[0].main = main_type_index.type;
174 data.packages[0].main = main_type_index;
174175
175176 if (self.doc_location.directory) |d| {
176177 d.handle.makeDir(
......@@ -215,6 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void {
215216const Scope = struct {
216217 parent: ?*Scope,
217218 map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls`
219 enclosing_type: usize, // index into `types`
218220
219221 /// Assumes all decls in present scope and upper scopes have already
220222 /// been either fully resolved or at least reserved.
......@@ -475,6 +477,7 @@ const DocData = struct {
475477 const DeclPath = struct {
476478 path: []usize, // indexes in `decls`
477479 hasCte: bool = false, // a prefix of this path could not be resolved
480 // TODO: make hasCte return the actual index where the cte is!
478481 };
479482
480483 const TypeRef = union(enum) {
......@@ -482,14 +485,10 @@ const DocData = struct {
482485 declPath: DeclPath,
483486 type: usize, // index in `types`
484487 comptimeExpr: usize, // index in `comptimeExprs`
485
486 pub fn fromWalkResult(wr: WalkResult) TypeRef {
487 return switch (wr) {
488 .declPath => |v| .{ .declPath = v },
489 .type => |v| .{ .type = v },
490 else => @panic("Found non-type WalkResult"),
491 };
492 }
488 // TODO: maybe we should not consider calls to be typerefs and instread
489 // directly refer to their return value. The problem at the moment
490 // is that we can't analyze function calls at all.
491 call: usize, // index in `call`
493492
494493 pub fn jsonStringify(
495494 self: TypeRef,
......@@ -503,7 +502,7 @@ const DocData = struct {
503502 , .{});
504503 },
505504
506 .type, .comptimeExpr => |v| {
505 .type, .comptimeExpr, .call => |v| {
507506 try w.print(
508507 \\{{ "{s}":{} }}
509508 , .{ @tagName(self), v });
......@@ -647,7 +646,7 @@ fn walkInstruction(
647646 switch (tags[inst_index]) {
648647 else => {
649648 std.debug.panic(
650 "TODO: implement `walkInstruction` for {s}\n\n",
649 "TODO: implement `{s}` for walkInstruction\n\n",
651650 .{@tagName(tags[inst_index])},
652651 );
653652 },
......@@ -674,7 +673,10 @@ fn walkInstruction(
674673
675674 result.value_ptr.* = self.types.items.len;
676675
677 var new_scope = Scope{ .parent = null };
676 var new_scope = Scope{
677 .parent = null,
678 .enclosing_type = self.types.items.len,
679 };
678680 const new_file_walk_result = self.walkInstruction(
679681 new_file.file,
680682 &new_scope,
......@@ -849,7 +851,7 @@ fn walkInstruction(
849851 });
850852 break :idx idx;
851853 };
852 const str_tok = data[inst_index].str_tok;
854 const str_tok = data[lhs].str_tok;
853855 const file_path = str_tok.get(file.zir);
854856
855857 const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});
......@@ -906,7 +908,7 @@ fn walkInstruction(
906908 const pl_node = data[inst_index].pl_node;
907909 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
908910
909 const callee = DocData.TypeRef.fromWalkResult(
911 const callee = walkResultToTypeRef(
910912 try self.walkRef(file, parent_scope, extra.data.callee),
911913 );
912914
......@@ -917,11 +919,21 @@ fn walkInstruction(
917919 args[idx] = try self.walkRef(file, parent_scope, ref);
918920 }
919921
922 // TODO: see if we can ever do something better than just always
923 // resolve function calls to a comptimeExpr.
924 const cte_slot_index = self.comptime_exprs.items.len;
925 try self.comptime_exprs.append(self.arena, .{
926 .code = "func call",
927 .typeRef = .{
928 .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr),
929 }, // TODO: extract return type from callee when available
930 });
931
920932 const call_slot_index = self.calls.items.len;
921933 try self.calls.append(self.arena, .{
922934 .func = callee,
923935 .args = args,
924 .ret = .{ .void = {} }, // TODO: handle returns!
936 .ret = .{ .comptimeExpr = cte_slot_index },
925937 });
926938
927939 return DocData.WalkResult{ .call = call_slot_index };
......@@ -967,7 +979,7 @@ fn walkInstruction(
967979 const param_type_ref = try self.walkRef(file, parent_scope, break_operand);
968980
969981 param_type_refs.appendAssumeCapacity(
970 DocData.TypeRef.fromWalkResult(param_type_ref),
982 walkResultToTypeRef(param_type_ref),
971983 );
972984 },
973985 }
......@@ -978,7 +990,7 @@ fn walkInstruction(
978990 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
979991 const break_operand = data[last_instr_index].@"break".operand;
980992 const wr = try self.walkRef(file, parent_scope, break_operand);
981 break :blk DocData.TypeRef.fromWalkResult(wr);
993 break :blk walkResultToTypeRef(wr);
982994 };
983995
984996 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
......@@ -1025,7 +1037,10 @@ fn walkInstruction(
10251037 );
10261038 },
10271039 .union_decl => {
1028 var scope: Scope = .{ .parent = parent_scope };
1040 var scope: Scope = .{
1041 .parent = parent_scope,
1042 .enclosing_type = type_slot_index,
1043 };
10291044
10301045 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
10311046 var extra_index: usize = extended.operand;
......@@ -1128,7 +1143,10 @@ fn walkInstruction(
11281143 return DocData.WalkResult{ .type = type_slot_index };
11291144 },
11301145 .enum_decl => {
1131 var scope: Scope = .{ .parent = parent_scope };
1146 var scope: Scope = .{
1147 .parent = parent_scope,
1148 .enclosing_type = type_slot_index,
1149 };
11321150
11331151 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
11341152 var extra_index: usize = extended.operand;
......@@ -1256,7 +1274,10 @@ fn walkInstruction(
12561274 return DocData.WalkResult{ .type = type_slot_index };
12571275 },
12581276 .struct_decl => {
1259 var scope: Scope = .{ .parent = parent_scope };
1277 var scope: Scope = .{
1278 .parent = parent_scope,
1279 .enclosing_type = type_slot_index,
1280 };
12601281
12611282 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
12621283 var extra_index: usize = extended.operand;
......@@ -1345,6 +1366,24 @@ fn walkInstruction(
13451366
13461367 return DocData.WalkResult{ .type = type_slot_index };
13471368 },
1369 .this => {
1370 // TODO: consider if we should reuse an existing decl
1371 // that points to this type (if present).
1372 const decl_slot_index = self.decls.items.len;
1373 try self.decls.append(self.arena, .{
1374 .name = "@This()",
1375 .value = .{ .type = parent_scope.enclosing_type },
1376 .src = 0,
1377 .kind = "const",
1378 ._analyzed = false,
1379 });
1380 const dpath = try self.arena.alloc(usize, 1);
1381 dpath[0] = decl_slot_index;
1382 return DocData.WalkResult{ .declPath = .{
1383 .hasCte = false,
1384 .path = dpath,
1385 } };
1386 },
13481387 }
13491388 },
13501389 }
......@@ -1625,11 +1664,11 @@ fn tryResolveDeclPath(
16251664 switch (parent.value) {
16261665 else => {
16271666 std.debug.panic(
1628 "TODO: handle `{s}`in tryResolveDecl.field_val\n \"{s}\":{}",
1667 "TODO: handle `{s}`in tryResolveDecl\n \"{s}\":{}",
16291668 .{ @tagName(parent.value), parent.name, parent.value },
16301669 );
16311670 },
1632 .comptimeExpr => {
1671 .comptimeExpr, .call => {
16331672 // Since we hit a cte, we leave the remaining strings unresolved
16341673 // and completely give up on resolving this decl path.
16351674 decl_path.hasCte = true;
......@@ -1968,12 +2007,13 @@ fn walkRef(
19682007fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef {
19692008 return switch (wr) {
19702009 else => std.debug.panic(
1971 "TODO: handle `{s}` in `walkResultToTypeRef.as_node.dest_type`\n",
2010 "TODO: handle `{s}` in `walkResultToTypeRef`\n",
19722011 .{@tagName(wr)},
19732012 ),
19742013
19752014 .declPath => |v| .{ .declPath = v },
19762015 .type => |v| .{ .type = v },
2016 .call => |v| .{ .call = v },
19772017 };
19782018}
19792019