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 @@...@@ -661,9 +661,9 @@
661 if (typeValue.hasCte) {661 if (typeValue.hasCte) {
662 // TODO: find the cte, print it nicely662 // TODO: find the cte, print it nicely
663 if (wantLink) {663 if (wantLink) {
664 return '<a href=""># CTE TODO #</a>';664 return '<a href="">[ComptimeExpr]</a>';
665 } else {665 } else {
666 return "# CTE TODO #";666 return "[ComptimeExpr]";
667 }667 }
668 }668 }
669 var declIndex = typeValue.declPath[0];669 var declIndex = typeValue.declPath[0];
...@@ -735,7 +735,7 @@...@@ -735,7 +735,7 @@
735 function getValueText(typeRef, value, wantHtml, wantLink) {735 function getValueText(typeRef, value, wantHtml, wantLink) {
736 var resolvedTypeRef = resolveValue(typeRef);736 var resolvedTypeRef = resolveValue(typeRef);
737 if ("comptimeExpr" in resolvedTypeRef) {737 if ("comptimeExpr" in resolvedTypeRef) {
738 return "# CTE TODO #";738 return "[ComptimeExpr]";
739 }739 }
740 console.assert("type" in resolvedTypeRef);740 console.assert("type" in resolvedTypeRef);
741 var typeObj = zigAnalysis.types[typeRef.type];741 var typeObj = zigAnalysis.types[typeRef.type];
...@@ -773,9 +773,10 @@...@@ -773,9 +773,10 @@
773 return "?" + typeValueName(typeObj.child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl);773 return "?" + typeValueName(typeObj.child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl);
774 case typeKinds.Pointer:774 case typeKinds.Pointer:
775 var name = "";775 var name = "";
776 switch (typeObj.len) {776 switch (typeObj.size) {
777 case pointerSizeEnum.One:
778 default:777 default:
778 console.log("TODO: implement unhandled pointer size case");
779 case pointerSizeEnum.One:
779 name += "*";780 name += "*";
780 break;781 break;
781 case pointerSizeEnum.Many:782 case pointerSizeEnum.Many:
...@@ -976,23 +977,27 @@...@@ -976,23 +977,27 @@
976 }977 }
977 }978 }
978979
979 if (isVarArgs && i === typeObj.args.length - 1) {980 if (isVarArgs && i === typeObj.params.length - 1) {
980 payloadHtml += '...';981 payloadHtml += '...';
981 } else if ("declRef" in value) {982 } else if ("declPath" in value) {
982 var decl = zigAnalysis.decls[value.declRef];983 if (value.hasCte) {
983 var val = resolveValue(decl.value);984 var cte = findCteInDeclPath(value.declPath);
984 var valType = zigAnalysis.types[argTypeIndex];985 payloadHtml += "[ComptimeExpr]";
985986 } else {
986 var valTypeName = typeShorthandName(valType);987 var decl = zigAnalysis.decls[value.declPath[0]];
987988 var val = resolveValue(decl.value);
988 payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';989 var valType = zigAnalysis.types[argTypeIndex];
989 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';990
990 payloadHtml += '</a>';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 }
991 } else if ("type" in value) {996 } else if ("type" in value) {
992 var name = typeValueName(value, false);997 var name = typeValueName(value, false);
993 payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';998 payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
994 } else if ("comptimeExpr" in value) {999 } else if ("comptimeExpr" in value) {
995 payloadHtml += '<span class="tok-kw"> # CTE TODO #</span>';1000 payloadHtml += '<span class="tok-kw">[ComptimeExpr]</span>';
996 } else if (wantHtml) {1001 } else if (wantHtml) {
997 payloadHtml += '<span class="tok-kw">var</span>';1002 payloadHtml += '<span class="tok-kw">var</span>';
998 } else {1003 } else {
...@@ -1350,7 +1355,7 @@...@@ -1350,7 +1355,7 @@
13501355
1351 // TODO: handle nested decl paths properly!1356 // TODO: handle nested decl paths properly!
1352 if (field.hasCte) {1357 if (field.hasCte) {
1353 html += "<a href=\"\"># CTE TODO #</a>";1358 html += "<a href=\"\">[ComptimeExpr]</a>";
1354 break;1359 break;
1355 }1360 }
13561361
src/Autodoc.zig+66-26
...@@ -144,10 +144,11 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -144,10 +144,11 @@ pub fn generateZirData(self: *Autodoc) !void {
144 }144 }
145 }145 }
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 };
148 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });149 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
149 try self.files.put(self.arena, file, self.types.items.len);150 try self.files.put(self.arena, file, main_type_index);
150 const main_type_index = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst);151 _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst);
151152
152 if (self.decl_paths_pending_on_decls.count() > 0) {153 if (self.decl_paths_pending_on_decls.count() > 0) {
153 @panic("some decl paths were never fully analized (pending on decls)");154 @panic("some decl paths were never fully analized (pending on decls)");
...@@ -170,7 +171,7 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -170,7 +171,7 @@ pub fn generateZirData(self: *Autodoc) !void {
170 .comptimeExprs = self.comptime_exprs.items,171 .comptimeExprs = self.comptime_exprs.items,
171 };172 };
172173
173 data.packages[0].main = main_type_index.type;174 data.packages[0].main = main_type_index;
174175
175 if (self.doc_location.directory) |d| {176 if (self.doc_location.directory) |d| {
176 d.handle.makeDir(177 d.handle.makeDir(
...@@ -215,6 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -215,6 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void {
215const Scope = struct {216const Scope = struct {
216 parent: ?*Scope,217 parent: ?*Scope,
217 map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls`218 map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls`
219 enclosing_type: usize, // index into `types`
218220
219 /// Assumes all decls in present scope and upper scopes have already221 /// Assumes all decls in present scope and upper scopes have already
220 /// been either fully resolved or at least reserved.222 /// been either fully resolved or at least reserved.
...@@ -475,6 +477,7 @@ const DocData = struct {...@@ -475,6 +477,7 @@ const DocData = struct {
475 const DeclPath = struct {477 const DeclPath = struct {
476 path: []usize, // indexes in `decls`478 path: []usize, // indexes in `decls`
477 hasCte: bool = false, // a prefix of this path could not be resolved479 hasCte: bool = false, // a prefix of this path could not be resolved
480 // TODO: make hasCte return the actual index where the cte is!
478 };481 };
479482
480 const TypeRef = union(enum) {483 const TypeRef = union(enum) {
...@@ -482,14 +485,10 @@ const DocData = struct {...@@ -482,14 +485,10 @@ const DocData = struct {
482 declPath: DeclPath,485 declPath: DeclPath,
483 type: usize, // index in `types`486 type: usize, // index in `types`
484 comptimeExpr: usize, // index in `comptimeExprs`487 comptimeExpr: usize, // index in `comptimeExprs`
485488 // TODO: maybe we should not consider calls to be typerefs and instread
486 pub fn fromWalkResult(wr: WalkResult) TypeRef {489 // directly refer to their return value. The problem at the moment
487 return switch (wr) {490 // is that we can't analyze function calls at all.
488 .declPath => |v| .{ .declPath = v },491 call: usize, // index in `call`
489 .type => |v| .{ .type = v },
490 else => @panic("Found non-type WalkResult"),
491 };
492 }
493492
494 pub fn jsonStringify(493 pub fn jsonStringify(
495 self: TypeRef,494 self: TypeRef,
...@@ -503,7 +502,7 @@ const DocData = struct {...@@ -503,7 +502,7 @@ const DocData = struct {
503 , .{});502 , .{});
504 },503 },
505504
506 .type, .comptimeExpr => |v| {505 .type, .comptimeExpr, .call => |v| {
507 try w.print(506 try w.print(
508 \\{{ "{s}":{} }}507 \\{{ "{s}":{} }}
509 , .{ @tagName(self), v });508 , .{ @tagName(self), v });
...@@ -647,7 +646,7 @@ fn walkInstruction(...@@ -647,7 +646,7 @@ fn walkInstruction(
647 switch (tags[inst_index]) {646 switch (tags[inst_index]) {
648 else => {647 else => {
649 std.debug.panic(648 std.debug.panic(
650 "TODO: implement `walkInstruction` for {s}\n\n",649 "TODO: implement `{s}` for walkInstruction\n\n",
651 .{@tagName(tags[inst_index])},650 .{@tagName(tags[inst_index])},
652 );651 );
653 },652 },
...@@ -674,7 +673,10 @@ fn walkInstruction(...@@ -674,7 +673,10 @@ fn walkInstruction(
674673
675 result.value_ptr.* = self.types.items.len;674 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 };
678 const new_file_walk_result = self.walkInstruction(680 const new_file_walk_result = self.walkInstruction(
679 new_file.file,681 new_file.file,
680 &new_scope,682 &new_scope,
...@@ -849,7 +851,7 @@ fn walkInstruction(...@@ -849,7 +851,7 @@ fn walkInstruction(
849 });851 });
850 break :idx idx;852 break :idx idx;
851 };853 };
852 const str_tok = data[inst_index].str_tok;854 const str_tok = data[lhs].str_tok;
853 const file_path = str_tok.get(file.zir);855 const file_path = str_tok.get(file.zir);
854856
855 const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});857 const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});
...@@ -906,7 +908,7 @@ fn walkInstruction(...@@ -906,7 +908,7 @@ fn walkInstruction(
906 const pl_node = data[inst_index].pl_node;908 const pl_node = data[inst_index].pl_node;
907 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);909 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
908910
909 const callee = DocData.TypeRef.fromWalkResult(911 const callee = walkResultToTypeRef(
910 try self.walkRef(file, parent_scope, extra.data.callee),912 try self.walkRef(file, parent_scope, extra.data.callee),
911 );913 );
912914
...@@ -917,11 +919,21 @@ fn walkInstruction(...@@ -917,11 +919,21 @@ fn walkInstruction(
917 args[idx] = try self.walkRef(file, parent_scope, ref);919 args[idx] = try self.walkRef(file, parent_scope, ref);
918 }920 }
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
920 const call_slot_index = self.calls.items.len;932 const call_slot_index = self.calls.items.len;
921 try self.calls.append(self.arena, .{933 try self.calls.append(self.arena, .{
922 .func = callee,934 .func = callee,
923 .args = args,935 .args = args,
924 .ret = .{ .void = {} }, // TODO: handle returns!936 .ret = .{ .comptimeExpr = cte_slot_index },
925 });937 });
926938
927 return DocData.WalkResult{ .call = call_slot_index };939 return DocData.WalkResult{ .call = call_slot_index };
...@@ -967,7 +979,7 @@ fn walkInstruction(...@@ -967,7 +979,7 @@ fn walkInstruction(
967 const param_type_ref = try self.walkRef(file, parent_scope, break_operand);979 const param_type_ref = try self.walkRef(file, parent_scope, break_operand);
968980
969 param_type_refs.appendAssumeCapacity(981 param_type_refs.appendAssumeCapacity(
970 DocData.TypeRef.fromWalkResult(param_type_ref),982 walkResultToTypeRef(param_type_ref),
971 );983 );
972 },984 },
973 }985 }
...@@ -978,7 +990,7 @@ fn walkInstruction(...@@ -978,7 +990,7 @@ fn walkInstruction(
978 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];990 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
979 const break_operand = data[last_instr_index].@"break".operand;991 const break_operand = data[last_instr_index].@"break".operand;
980 const wr = try self.walkRef(file, parent_scope, break_operand);992 const wr = try self.walkRef(file, parent_scope, break_operand);
981 break :blk DocData.TypeRef.fromWalkResult(wr);993 break :blk walkResultToTypeRef(wr);
982 };994 };
983995
984 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;996 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
...@@ -1025,7 +1037,10 @@ fn walkInstruction(...@@ -1025,7 +1037,10 @@ fn walkInstruction(
1025 );1037 );
1026 },1038 },
1027 .union_decl => {1039 .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
1030 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);1045 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
1031 var extra_index: usize = extended.operand;1046 var extra_index: usize = extended.operand;
...@@ -1128,7 +1143,10 @@ fn walkInstruction(...@@ -1128,7 +1143,10 @@ fn walkInstruction(
1128 return DocData.WalkResult{ .type = type_slot_index };1143 return DocData.WalkResult{ .type = type_slot_index };
1129 },1144 },
1130 .enum_decl => {1145 .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
1133 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);1151 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
1134 var extra_index: usize = extended.operand;1152 var extra_index: usize = extended.operand;
...@@ -1256,7 +1274,10 @@ fn walkInstruction(...@@ -1256,7 +1274,10 @@ fn walkInstruction(
1256 return DocData.WalkResult{ .type = type_slot_index };1274 return DocData.WalkResult{ .type = type_slot_index };
1257 },1275 },
1258 .struct_decl => {1276 .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
1261 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);1282 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
1262 var extra_index: usize = extended.operand;1283 var extra_index: usize = extended.operand;
...@@ -1345,6 +1366,24 @@ fn walkInstruction(...@@ -1345,6 +1366,24 @@ fn walkInstruction(
13451366
1346 return DocData.WalkResult{ .type = type_slot_index };1367 return DocData.WalkResult{ .type = type_slot_index };
1347 },1368 },
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 },
1348 }1387 }
1349 },1388 },
1350 }1389 }
...@@ -1625,11 +1664,11 @@ fn tryResolveDeclPath(...@@ -1625,11 +1664,11 @@ fn tryResolveDeclPath(
1625 switch (parent.value) {1664 switch (parent.value) {
1626 else => {1665 else => {
1627 std.debug.panic(1666 std.debug.panic(
1628 "TODO: handle `{s}`in tryResolveDecl.field_val\n \"{s}\":{}",1667 "TODO: handle `{s}`in tryResolveDecl\n \"{s}\":{}",
1629 .{ @tagName(parent.value), parent.name, parent.value },1668 .{ @tagName(parent.value), parent.name, parent.value },
1630 );1669 );
1631 },1670 },
1632 .comptimeExpr => {1671 .comptimeExpr, .call => {
1633 // Since we hit a cte, we leave the remaining strings unresolved1672 // Since we hit a cte, we leave the remaining strings unresolved
1634 // and completely give up on resolving this decl path.1673 // and completely give up on resolving this decl path.
1635 decl_path.hasCte = true;1674 decl_path.hasCte = true;
...@@ -1968,12 +2007,13 @@ fn walkRef(...@@ -1968,12 +2007,13 @@ fn walkRef(
1968fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef {2007fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef {
1969 return switch (wr) {2008 return switch (wr) {
1970 else => std.debug.panic(2009 else => std.debug.panic(
1971 "TODO: handle `{s}` in `walkResultToTypeRef.as_node.dest_type`\n",2010 "TODO: handle `{s}` in `walkResultToTypeRef`\n",
1972 .{@tagName(wr)},2011 .{@tagName(wr)},
1973 ),2012 ),
19742013
1975 .declPath => |v| .{ .declPath = v },2014 .declPath => |v| .{ .declPath = v },
1976 .type => |v| .{ .type = v },2015 .type => |v| .{ .type = v },
2016 .call => |v| .{ .call = v },
1977 };2017 };
1978}2018}
19792019