authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-11 18:26:21+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
logec7f4d1faab8aa9b797f96d233d2ca12c99d2179
tree5b942af287986be24b342f30fce1c1cbbbb996c6
parentd745dde54f00ee882010e681d364283f0c6f045a

autodoc: add support for anytype and improve semantics for array length


2 files changed, 188 insertions(+), 78 deletions(-)

lib/docs/main.js+112-69
......@@ -187,7 +187,7 @@
187187 i += 1;
188188 console.assert(isDecl(decl));
189189 if ("type" in decl.value) {
190 return typeTypeId;
190 return { type: typeTypeId };
191191 }
192192
193193 if ("declPath" in decl.value) {
......@@ -232,6 +232,10 @@
232232 return fn_type.ret;
233233 }
234234
235 if ("void" in decl.value) {
236 return { type: typeTypeId };
237 }
238
235239 console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
236240 console.assert(false);
237241 throw {};
......@@ -472,22 +476,9 @@
472476 var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
473477 if (isVarArgs && i === typeObj.params.length - 1) {
474478 html += '...';
475 } else if ("declRef" in value) {
476 var decl = zigAnalysis.decls[value.declRef];
477 var val = resolveValue(decl.value);
478 var valType = zigAnalysis.types[argTypeIndex];
479
480 var valTypeName = typeShorthandName(valType);
481
482 html += '<a href="'+navLinkDecl(decl.name)+'">';
483 html += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
484 html += '</a>';
485 html += ' ('+ valTypeName +')';
486 } else if ("type" in value) {
487 var name = zigAnalysis.types[value.type].name;
488 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
489479 } else {
490 html += '<span class="tok-kw">var</span>';
480 var name = typeValueName(value);
481 html += '<span class="tok-kw">' + name + '</span>';
491482 }
492483
493484 html += ',</pre>';
......@@ -657,24 +648,52 @@
657648 }
658649
659650 function typeValueName(typeValue, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
660 if ("declPath" in typeValue) {
661 if (typeValue.hasCte) {
662 // TODO: find the cte, print it nicely
663 if (wantLink) {
664 return '<a href="">[ComptimeExpr]</a>';
665 } else {
666 return "[ComptimeExpr]";
667 }
668 }
669 var declIndex = typeValue.declPath[0];
670 var name = zigAnalysis.decls[declIndex].name;
671 var declPath = getCanonDeclPath(declIndex);
672 if (wantLink) {
673 var nl = navLink(declPath.pkgNames, declPath.declNames);
674 return '<a href="' + nl + '">' + name + '</a>';
675 } else {
676 return name;
651
652 if ("int" in typeValue) {
653 return typeValue.int.value;
654 }
655 if ("call" in typeValue) {
656 var result = "";
657 var call = zigAnalysis.calls[typeValue.call];
658 var functionName = typeValueName(call.func);
659 result += functionName + "(";
660 for (var j = 0; j < call.args.length; j += 1) {
661 result += typeValueName(call.args[j]);
662 if (j != call.args.length -1) result += ",";
677663 }
664
665 return result + ")";
666 }
667 if ("comptimeExpr" in typeValue) {
668 return "[ComptimeExpr]";
669 }
670 if ("declPath" in typeValue) {
671 var result = "";
672 for (var j = typeValue.declPath.length - 1; j >= 0; j--) {
673 var decl = zigAnalysis.decls[typeValue.declPath[j]];
674
675 // TODO: handle nested decl paths properly!
676 if (typeValue.hasCte) {
677 if (wantHtml)
678 result += "<a href=\"\">[ComptimeExpr]</a>";
679 else
680 result += "[ComptimeExpr]";
681 break;
682 }
683 var name = escapeHtml(decl.name);
684 if (wantHtml) {
685 result += '<a href="'+navLinkDecl(decl.name)+'">';
686 result += '<span class="tok-kw" style="color:lightblue;">' +
687 name + '</span>';
688 result += '</a>';
689 } else {
690 result += name;
691 }
692
693 if (j != 0) result += ".";
694 }
695
696 return result;
678697 }
679698
680699 console.assert("type" in typeValue)
......@@ -760,10 +779,11 @@
760779 switch (typeObj.kind) {
761780 case typeKinds.Array:
762781 var name = "[";
782 var lenName = typeValueName(typeObj.len, wantHtml);
763783 if (wantHtml) {
764 name += '<span class="tok-number">' + typeObj.len + '</span>';
784 name += '<span class="tok-number">' + lenName + '</span>';
765785 } else {
766 name += typeObj.len;
786 name += lenName;
767787 }
768788 name += "]";
769789 name += typeValueName(typeObj.child, wantHtml, wantSubLink, null);
......@@ -986,12 +1006,16 @@
9861006 } else {
9871007 var decl = zigAnalysis.decls[value.declPath[0]];
9881008 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>';
1009 if ("comptimeExpr" in val) {
1010 payloadHtml += "[ComptimeExpr]";
1011 } else {
1012 console.assert("type" in val);
1013 var valType = zigAnalysis.types[val.type];
1014 var valTypeName = typeShorthandName(valType);
1015 payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';
1016 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
1017 payloadHtml += '</a>';
1018 }
9951019 }
9961020 } else if ("type" in value) {
9971021 var name = typeValueName(value, false);
......@@ -1258,6 +1282,43 @@
12581282 }
12591283 }
12601284 }
1285
1286 declLen = container.privDecls ? container.privDecls.length : 0;
1287 for (var i = 0; i < declLen; i += 1) {
1288 var decl = zigAnalysis.decls[container.privDecls[i]];
1289 var declValue = resolveValue(decl.value);
1290
1291 if (decl.kind === 'var') {
1292 varsList.push(decl);
1293 continue;
1294 }
1295
1296 if (decl.kind === 'const') {
1297 if (!("type" in declValue)){
1298 valsList.push(decl);
1299 } else {
1300 var value = zigAnalysis.types[declValue.type];
1301 var kind = value.kind;
1302 if (kind === typeKinds.Fn) {
1303 // TODO: handle CTE return types when we know their type.
1304 const resVal = resolveValue(value.ret);
1305 if ("type" in resVal && resVal.type == typeTypeId) {
1306 typesList.push(decl);
1307 } else {
1308 fnsList.push(decl);
1309 }
1310
1311 } else if (typeIsErrSet(declValue.type)) {
1312 errSetsList.push(decl);
1313 } else if (typeIsStructWithNoFields(declValue.type)) {
1314 namespacesList.push(decl);
1315 } else {
1316 typesList.push(decl);
1317 }
1318 }
1319 }
1320 }
1321
12611322 typesList.sort(byNameProperty);
12621323 namespacesList.sort(byNameProperty);
12631324 errSetsList.sort(byNameProperty);
......@@ -1349,35 +1410,9 @@
13491410 html += ": ";
13501411 if (field.failure === true) {
13511412 html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';
1352 } else if ("declPath" in field) {
1353 for (var j = field.declPath.length - 1; j >= 0; j--) {
1354 var decl = zigAnalysis.decls[field.declPath[j]];
1355
1356 // TODO: handle nested decl paths properly!
1357 if (field.hasCte) {
1358 html += "<a href=\"\">[ComptimeExpr]</a>";
1359 break;
1360 }
1361
1362 html += '<a href="'+navLinkDecl(decl.name)+'">';
1363 html += '<span class="tok-kw" style="color:lightblue;">' +
1364 escapeHtml(decl.name) + '</span>';
1365 html += '</a>';
1366 if (j != 0) html += ".";
1367 }
1368 // at the end of the for loop this is the value of `decl`
1369 //decl = zigAnalysis.decls[field.declPath[0]];
1370
1371 var val = resolveValue(decl.value);
1372 console.assert("type" in val);
1373 var valType = zigAnalysis.types[val.type];
1374 var valTypeName = typeShorthandName(valType);
1375 html += ' ('+ valTypeName +')';
1376 } else if ("type" in field) {
1377 var name = zigAnalysis.types[field.type].name;
1378 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
13791413 } else {
1380 html += '<span class="tok-kw">var</span>';
1414 var name = typeValueName(field);
1415 html += '<span class="tok-kw">'+ name +'</span>';
13811416 }
13821417 }
13831418
......@@ -1544,6 +1579,14 @@
15441579 return childDecl;
15451580 }
15461581 }
1582 if (!parentType.privDecls) return null;
1583 for (var i = 0; i < parentType.privDecls.length; i += 1) {
1584 var declIndex = parentType.privDecls[i];
1585 var childDecl = zigAnalysis.decls[declIndex];
1586 if (childDecl.name === childName) {
1587 return childDecl;
1588 }
1589 }
15471590 return null;
15481591 }
15491592
src/Autodoc.zig+76-9
......@@ -92,7 +92,15 @@ pub fn generateZirData(self: *Autodoc) !void {
9292 // instead of just assinging "array" to them.
9393 break :blk .{
9494 .Array = .{
95 .len = 1,
95 .len = .{
96 .int = .{
97 .typeRef = .{
98 .type = @enumToInt(Ref.usize_type),
99 },
100 .value = 1,
101 .negated = false,
102 },
103 },
96104 .child = .{ .type = 0 },
97105 },
98106 };
......@@ -374,7 +382,7 @@ const DocData = struct {
374382 child: TypeRef,
375383 },
376384 Array: struct {
377 len: usize,
385 len: WalkResult,
378386 child: TypeRef,
379387 },
380388 Struct: struct {
......@@ -516,6 +524,7 @@ const DocData = struct {
516524 /// An example of indidirectness is `const bar = foo;`.
517525 const TypeRef = union(enum) {
518526 unspecified,
527 @"anytype",
519528 declPath: DeclPath,
520529 type: usize, // index in `types`
521530 comptimeExpr: usize, // index in `comptimeExprs`
......@@ -530,10 +539,10 @@ const DocData = struct {
530539 w: anytype,
531540 ) !void {
532541 switch (self) {
533 .unspecified => {
542 .unspecified, .@"anytype" => {
534543 try w.print(
535 \\{{ "unspecified":{{}} }}
536 , .{});
544 \\{{ "{s}":{{}} }}
545 , .{@tagName(self)});
537546 },
538547
539548 .type, .comptimeExpr, .call => |v| {
......@@ -566,6 +575,7 @@ const DocData = struct {
566575 @"undefined": TypeRef,
567576 @"struct": Struct,
568577 bool: bool,
578 @"anytype",
569579 type: usize, // index in `types`
570580 declPath: DeclPath,
571581 int: struct {
......@@ -600,7 +610,7 @@ const DocData = struct {
600610 w: anytype,
601611 ) !void {
602612 switch (self) {
603 .void, .@"unreachable" => {
613 .void, .@"unreachable", .@"anytype" => {
604614 try w.print(
605615 \\{{ "{s}":{{}} }}
606616 , .{@tagName(self)});
......@@ -755,6 +765,13 @@ fn walkInstruction(
755765 },
756766 };
757767 },
768 .error_union_type => {
769 const pl_node = data[inst_index].pl_node;
770 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
771
772 // TODO: return the actual error union instread of cheating
773 return self.walkRef(file, parent_scope, extra.data.rhs);
774 },
758775 .ptr_type_simple => {
759776 const ptr = data[inst_index].ptr_type_simple;
760777 const type_slot_index = self.types.items.len;
......@@ -768,6 +785,20 @@ fn walkInstruction(
768785
769786 return DocData.WalkResult{ .type = type_slot_index };
770787 },
788 .array_type => {
789 const bin = data[inst_index].bin;
790 const len = try self.walkRef(file, parent_scope, bin.lhs);
791 const child = walkResultToTypeRef(try self.walkRef(file, parent_scope, bin.rhs));
792
793 const type_slot_index = self.types.items.len;
794 try self.types.append(self.arena, .{
795 .Array = .{
796 .len = len,
797 .child = child,
798 },
799 });
800 return DocData.WalkResult{ .type = type_slot_index };
801 },
771802 .array_init => {
772803 const pl_node = data[inst_index].pl_node;
773804 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
......@@ -780,7 +811,13 @@ fn walkInstruction(
780811 const type_slot_index = self.types.items.len;
781812 try self.types.append(self.arena, .{
782813 .Array = .{
783 .len = operands.len,
814 .len = .{
815 .int = .{
816 .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
817 .value = operands.len,
818 .negated = false,
819 },
820 },
784821 .child = typeOfWalkResult(array_data[0]),
785822 },
786823 });
......@@ -1017,6 +1054,23 @@ fn walkInstruction(
10171054 .{@tagName(tags[param_index])},
10181055 );
10191056 },
1057 .param_anytype => {
1058 // TODO: where are the doc comments?
1059 const str_tok = data[param_index].str_tok;
1060
1061 const name = str_tok.get(file.zir);
1062
1063 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
1064 self.ast_nodes.appendAssumeCapacity(.{
1065 .name = name,
1066 .docs = "",
1067 .@"comptime" = true,
1068 });
1069
1070 param_type_refs.appendAssumeCapacity(
1071 DocData.TypeRef{ .@"anytype" = {} },
1072 );
1073 },
10201074 .param, .param_comptime => {
10211075 const pl_tok = data[param_index].pl_tok;
10221076 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
......@@ -1024,10 +1078,11 @@ fn walkInstruction(
10241078 file.zir.nullTerminatedString(extra.data.doc_comment)
10251079 else
10261080 "";
1081 const name = file.zir.nullTerminatedString(extra.data.name);
10271082
10281083 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
10291084 self.ast_nodes.appendAssumeCapacity(.{
1030 .name = file.zir.nullTerminatedString(extra.data.name),
1085 .name = name,
10311086 .docs = doc_comment,
10321087 .@"comptime" = tags[param_index] == .param_comptime,
10331088 });
......@@ -1094,6 +1149,18 @@ fn walkInstruction(
10941149 .{@tagName(extended.opcode)},
10951150 );
10961151 },
1152 .variable => {
1153 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
1154 var extra_index: usize = extended.operand;
1155 if (small.has_lib_name) extra_index += 1;
1156 if (small.has_align) extra_index += 1;
1157
1158 const value: DocData.WalkResult =
1159 if (small.has_init)
1160 .{ .void = {} } else .{ .void = {} };
1161
1162 return value;
1163 },
10971164 .union_decl => {
10981165 var scope: Scope = .{
10991166 .parent = parent_scope,
......@@ -1887,7 +1954,7 @@ fn collectUnionFieldInfo(
18871954 @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index])
18881955 else
18891956 .void_type;
1890 extra_index += 1;
1957 if (has_type) extra_index += 1;
18911958
18921959 if (has_align) extra_index += 1;
18931960 if (has_tag) extra_index += 1;