authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-02-02 20:33:58+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:10-07:00
logce40f34cbca3b013e5db766487833a1e5ced6658
treecf697d427b86f73898704a89cdd76a321ebb87a2
parent29771440b23f5a05ee522d444704131f1f6ab173

autodocs: added support for some non-type values


2 files changed, 231 insertions(+), 51 deletions(-)

lib/docs/main.js+32-17
......@@ -177,8 +177,8 @@
177177 return renderUnknownDecl(lastDeclOrType);
178178 } else if (lastDeclOrType.kind === 'var') {
179179 return renderVar(lastDeclOrType);
180 } else if (lastDeclOrType.kind === 'const' && lastDeclOrType.type != null) {
181 var typeObj = zigAnalysis.types[lastDeclOrType.type];
180 } else if (lastDeclOrType.kind === 'const' && "value" in lastDeclOrType && !("type" in lastDeclOrType.value)) {
181 var typeObj = zigAnalysis.types[getDeclValTypeId(lastDeclOrType)];
182182 if (typeObj.kind === typeKinds.Fn) {
183183 return renderFn(lastDeclOrType);
184184 } else {
......@@ -960,6 +960,7 @@
960960
961961 function renderValue(decl) {
962962
963 var declTypeId = getDeclValTypeId(decl);
963964 var declValueText = "";
964965 switch(Object.keys(decl.value)[0]) {
965966 case "int":
......@@ -971,7 +972,7 @@
971972 }
972973
973974 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
974 escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true) +
975 escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true) +
975976 " = " + declValueText;
976977
977978 var docs = zigAnalysis.astNodes[decl.src].docs;
......@@ -984,8 +985,9 @@
984985 }
985986
986987 function renderVar(decl) {
988 var declTypeId = getDeclValTypeId(decl);
987989 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
988 escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
990 escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true);
989991
990992 var docs = zigAnalysis.astNodes[decl.src].docs;
991993 if (docs != null) {
......@@ -1011,10 +1013,8 @@
10111013 if (decl.kind === 'var') {
10121014 varsList.push(decl);
10131015 continue;
1014 } else if (decl.kind === 'const' && decl.type != null) {
1015 if (decl.type === typeTypeId) {
1016 // todo: this actually makes sense for decl_vals too
1017 // the problem is, how should we get to the final type though?
1016 } else if (decl.kind === 'const' && "value" in decl) {
1017 if (declValTypeId === typeTypeId) {
10181018 if (typeIsErrSet(declValTypeId)) {
10191019 errSetsList.push(decl);
10201020 } else if (typeIsStructWithNoFields(declValTypeId)) {
......@@ -1023,8 +1023,9 @@
10231023 typesList.push(decl);
10241024 }
10251025 } else {
1026 var typeKind = zigAnalysis.types[decl.type].kind;
1026 var typeKind = zigAnalysis.types[declValTypeId].kind;
10271027 if (typeKind === typeKinds.Fn) {
1028 // TODO: this is broken but I don't understand functions yet
10281029 if (allCompTimeFnCallsHaveTypeResult(decl.type, declValTypeId)) {
10291030 typesList.push(decl);
10301031 } else {
......@@ -1125,8 +1126,8 @@
11251126 if (typeof(field) === 'object') {
11261127 if (field.failure === true) {
11271128 html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';
1128 } else if ("decl_ref" in field) {
1129 var decl = zigAnalysis.decls[field.decl_ref];
1129 } else if ("declRef" in field) {
1130 var decl = zigAnalysis.decls[field.declRef];
11301131 var valType = zigAnalysis.types[getDeclValTypeId(decl)];
11311132 var valTypeName = valType.name;
11321133 if (valType.kind === typeKinds.Struct) {
......@@ -1174,7 +1175,7 @@
11741175 tdNameA.setAttribute('href', navLinkDecl(decl.name));
11751176 tdNameA.textContent = decl.name;
11761177
1177 tdType.innerHTML = typeIndexName(decl.type, true, true);
1178 tdType.innerHTML = typeIndexName(getDeclValTypeId(decl), true, true);
11781179
11791180 var docs = zigAnalysis.astNodes[decl.src].docs;
11801181 if (docs != null) {
......@@ -1201,7 +1202,7 @@
12011202 tdNameA.setAttribute('href', navLinkDecl(decl.name));
12021203 tdNameA.textContent = decl.name;
12031204
1204 tdType.innerHTML = typeIndexName(decl.type, true, true);
1205 tdType.innerHTML = typeIndexName(getDeclValTypeId(decl), true, true);
12051206
12061207 var docs = zigAnalysis.astNodes[decl.src].docs;
12071208 if (docs != null) {
......@@ -1359,12 +1360,26 @@
13591360 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
13601361 }
13611362
1363 // Handles both WalkResult and TypeRef
13621364 function getDeclValTypeId(decl) {
1363 while ( "decl_ref" in decl.value) {
1364 decl = zigAnalysis.decls[decl.value.decl_ref];
1365 var val = decl.value;
1366 while (true) {
1367 if ( "declRef" in val) {
1368 val = zigAnalysis.decls[val.declRef].value;
1369 continue;
1370 }
1371
1372 if ("int" in val) {
1373 val = val.int.typeRef;
1374 }
1375
1376 if ("type" in val) {
1377 return val.type;
1378 }
1379
1380 console.assert("type" in val);
13651381 }
1366 console.assert("type" in decl.value);
1367 return decl.value.type;
1382 return val.type;
13681383 }
13691384
13701385 function computeCanonDeclPaths() {
src/Autodoc.zig+199-34
......@@ -210,7 +210,7 @@ const DocData = struct {
210210 name: []const u8,
211211 kind: []const u8, // TODO: where do we find this info?
212212 src: usize, // index into astNodes
213 type: usize, // index into types
213 // typeRef: TypeRef,
214214 value: WalkResult,
215215 };
216216
......@@ -231,28 +231,65 @@ const DocData = struct {
231231 pubDecls: ?[]usize = null, // index into decls
232232 fields: ?[]WalkResult = null, // (use src->fields to find names)
233233 };
234 const TypeRef = union(enum) {
235 unspecified,
236 declRef: usize, // index in `decls`
237 type: usize, // index in `types`
238 pub fn jsonStringify(
239 self: TypeRef,
240 _: std.json.StringifyOptions,
241 w: anytype,
242 ) !void {
243 switch (self) {
244 .unspecified => {
245 try w.print(
246 \\{{ "unspecified":{{}} }}
247 , .{});
248 },
249 .declRef, .type => |v| {
250 try w.print(
251 \\{{ "{s}":{} }}
252 , .{ @tagName(self), v });
253 },
254 }
255 }
256 };
234257
235258 const WalkResult = union(enum) {
236 failure: bool,
259 void,
260 @"unreachable",
261 @"null": TypeRef,
262 @"undefined": TypeRef,
263 @"struct": struct {
264 typeRef: TypeRef,
265 fieldVals: []struct {
266 name: []const u8,
267 val: WalkResult,
268 },
269 },
270 bool: bool,
237271 type: usize, // index in `types`
238 decl_ref: usize, // index in `decls`
272 declRef: usize, // index in `decls`
239273 int: struct {
240 type: usize, // index in `types`
274 typeRef: TypeRef,
241275 value: usize, // direct value
242276 negated: bool = false,
243277 },
278
244279 pub fn jsonStringify(
245280 self: WalkResult,
246 _: std.json.StringifyOptions,
281 options: std.json.StringifyOptions,
247282 w: anytype,
248283 ) !void {
249284 switch (self) {
250 .failure => |v| {
285 .void,
286 .@"unreachable",
287 => {
251288 try w.print(
252 \\{{ "failure":{} }}
253 , .{v});
289 \\{{ "{s}":{{}} }}
290 , .{@tagName(self)});
254291 },
255 .type, .decl_ref => |v| {
292 .type, .declRef => |v| {
256293 try w.print(
257294 \\{{ "{s}":{} }}
258295 , .{ @tagName(self), v });
......@@ -260,10 +297,21 @@ const DocData = struct {
260297 .int => |v| {
261298 const neg = if (v.negated) "-" else "";
262299 try w.print(
263 \\{{ "int": {{ "type": {}, "value": {s}{} }} }}
264 , .{ v.type, neg, v.value });
300 \\{{ "int": {{ "typeRef":
301 , .{});
302 try v.typeRef.jsonStringify(options, w);
303 try w.print(
304 \\, "value": {s}{} }} }}
305 , .{ neg, v.value });
265306 },
266
307 .bool => |v| {
308 try w.print(
309 \\{{ "bool":{} }}
310 , .{v});
311 },
312 .@"undefined" => |v| try std.json.stringify(v, options, w),
313 .@"null" => |v| try std.json.stringify(v, options, w),
314 .@"struct" => |v| try std.json.stringify(v, options, w),
267315 // .decl_ref => |v| {
268316 // try w.print(
269317 // \\{{ "{s}":"{s}" }}
......@@ -288,17 +336,16 @@ fn walkInstruction(
288336
289337 switch (tags[inst_index]) {
290338 else => {
291 std.debug.print(
339 std.debug.panic(
292340 "TODO: implement `walkInstruction` for {s}\n\n",
293341 .{@tagName(tags[inst_index])},
294342 );
295 return DocData.WalkResult{ .failure = true };
296343 },
297344 .int => {
298345 const int = data[inst_index].int;
299346 return DocData.WalkResult{
300347 .int = .{
301 .type = @enumToInt(Ref.comptime_int_type),
348 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
302349 .value = int,
303350 },
304351 };
......@@ -313,16 +360,34 @@ fn walkInstruction(
313360 const pl_node = data[inst_index].pl_node;
314361 const extra = zir.extraData(Zir.Inst.As, pl_node.payload_index);
315362 const dest_type_walk = try self.walkRef(zir, parent_scope, extra.data.dest_type);
316 const dest_type = dest_type_walk.type; // asserts that we got a type
363 const dest_type_ref = walkResultToTypeRef(dest_type_walk);
317364
318365 var operand = try self.walkRef(zir, parent_scope, extra.data.operand);
319 operand.int.type = dest_type; // only support ints for now
366
367 switch (operand) {
368 else => std.debug.panic(
369 "TODO: handle {s} in `walkInstruction.as_node`\n",
370 .{@tagName(operand)},
371 ),
372 .declRef => {},
373 // we don't do anything because up until now,
374 // I've only seen this used as such:
375 // @as(@as(type, Baz), .{})
376 // and we don't want to toss away the
377 // decl_val information (eg by replacing it with
378 // a WalkResult.type).
379
380 .int => operand.int.typeRef = dest_type_ref,
381 .@"struct" => operand.@"struct".typeRef = dest_type_ref,
382 .@"undefined" => operand.@"undefined" = dest_type_ref,
383 }
384
320385 return operand;
321386 },
322387 .decl_val => {
323388 const str_tok = data[inst_index].str_tok;
324389 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
325 return DocData.WalkResult{ .decl_ref = decls_slot_index };
390 return DocData.WalkResult{ .declRef = decls_slot_index };
326391 },
327392 .int_type => {
328393 const int_type = data[inst_index].int_type;
......@@ -348,23 +413,16 @@ fn walkInstruction(
348413 });
349414
350415 const break_operand = data[break_index].@"break".operand;
351 return if (Zir.refToIndex(break_operand)) |bi|
352 self.walkInstruction(zir, parent_scope, bi)
353 else if (@enumToInt(break_operand) <= @enumToInt(Ref.anyerror_void_error_union_type))
354 // we append all the types in ref first, so we can just do this if we encounter a ref that is a type
355 return DocData.WalkResult{ .type = @enumToInt(break_operand) }
356 else
357 std.debug.todo("generate WalkResults for refs that are not types");
416 return self.walkRef(zir, parent_scope, break_operand);
358417 },
359418 .extended => {
360419 const extended = data[inst_index].extended;
361420 switch (extended.opcode) {
362421 else => {
363 std.debug.print(
422 std.debug.panic(
364423 "TODO: implement `walkInstruction` (inside .extended case) for {s}\n\n",
365424 .{@tagName(extended.opcode)},
366425 );
367 return DocData.WalkResult{ .failure = true };
368426 },
369427 .struct_decl => {
370428 var scope: Scope = .{ .parent = parent_scope };
......@@ -457,6 +515,13 @@ fn walkInstruction(
457515 }
458516}
459517
518/// Called by `walkInstruction` when encountering a container type,
519/// iterates over all decl definitions in its body.
520/// It also analyzes each decl's body recursively.
521///
522/// Does not append to `self.decls` directly because `walkInstruction`
523/// is expected to (look-ahead) scan all decls and reserve `body_len`
524/// slots in `self.decls`, which are then filled out by `walkDecls`.
460525fn walkDecls(
461526 self: *Autodoc,
462527 zir: Zir,
......@@ -562,15 +627,25 @@ fn walkDecls(
562627 try priv_decl_indexes.append(self.arena, decls_slot_index);
563628 }
564629
565 const decl_type = switch (walk_result) {
566 .int => |i| i.type,
567 else => @enumToInt(Ref.type_type),
568 };
630 // // decl.typeRef == decl.val...typeRef
631 // const decl_type_ref: DocData.TypeRef = switch (walk_result) {
632 // .int => |i| i.typeRef,
633 // .void => .{ .type = @enumToInt(Ref.void_type) },
634 // .@"undefined", .@"null" => |v| v,
635 // .@"unreachable" => .{ .type = @enumToInt(Ref.noreturn_type) },
636 // .@"struct" => |s| s.typeRef,
637 // .bool => .{ .type = @enumToInt(Ref.bool_type) },
638 // .type => .{ .type = @enumToInt(Ref.type_type) },
639 // // this last case is special becauese it's not pointing
640 // // at the type of the value, but rather at the value itself
641 // // the js better be aware ot this!
642 // .declRef => |d| .{ .declRef = d },
643 // };
569644
570645 self.decls.items[decls_slot_index] = .{
571646 .name = name,
572647 .src = ast_node_index,
573 .type = decl_type,
648 // .typeRef = decl_type_ref,
574649 .value = walk_result,
575650 .kind = "const", // find where this information can be found
576651 };
......@@ -649,11 +724,101 @@ fn walkRef(
649724 ref: Ref,
650725) !DocData.WalkResult {
651726 const enum_value = @enumToInt(ref);
652 if (enum_value < Zir.Inst.Ref.typed_value_map.len) {
653 // TODO: well... Refs are not all types
727 if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) {
728 // We can just return a type that indexes into `types` with the
729 // enum value because in the beginning we pre-filled `types` with
730 // the types that are listed in `Ref`.
654731 return DocData.WalkResult{ .type = enum_value };
732 } else if (enum_value < Ref.typed_value_map.len) {
733 switch (ref) {
734 else => {
735 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
736 @tagName(ref),
737 });
738 },
739 .undef => {
740 return DocData.WalkResult{ .@"undefined" = .unspecified };
741 },
742 .zero => {
743 return DocData.WalkResult{ .int = .{
744 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
745 .value = 0,
746 } };
747 },
748 .one => {
749 return DocData.WalkResult{ .int = .{
750 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
751 .value = 1,
752 } };
753 },
754
755 .void_value => {
756 return DocData.WalkResult{ .void = {} };
757 },
758 .unreachable_value => {
759 return DocData.WalkResult{ .@"unreachable" = {} };
760 },
761 .null_value => {
762 return DocData.WalkResult{ .@"null" = .unspecified };
763 },
764 .bool_true => {
765 return DocData.WalkResult{ .bool = true };
766 },
767 .bool_false => {
768 return DocData.WalkResult{ .bool = false };
769 },
770 .empty_struct => {
771 return DocData.WalkResult{ .@"struct" = .{
772 .typeRef = .unspecified,
773 .fieldVals = &.{},
774 } };
775 },
776 .zero_usize => {
777 return DocData.WalkResult{ .int = .{
778 .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
779 .value = 0,
780 } };
781 },
782 .one_usize => {
783 return DocData.WalkResult{ .int = .{
784 .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
785 .value = 1,
786 } };
787 },
788 // TODO: dunno what to do with those
789 // .calling_convention_c => {
790 // return DocData.WalkResult{ .int = .{
791 // .type = @enumToInt(Ref.comptime_int_type),
792 // .value = 1,
793 // } };
794 // },
795 // .calling_convention_inline => {
796 // return DocData.WalkResult{ .int = .{
797 // .type = @enumToInt(Ref.comptime_int_type),
798 // .value = 1,
799 // } };
800 // },
801 // .generic_poison => {
802 // return DocData.WalkResult{ .int = .{
803 // .type = @enumToInt(Ref.comptime_int_type),
804 // .value = 1,
805 // } };
806 // },
807 }
655808 } else {
656809 const zir_index = enum_value - Ref.typed_value_map.len;
657810 return self.walkInstruction(zir, parent_scope, zir_index);
658811 }
659812}
813
814fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef {
815 return switch (wr) {
816 else => std.debug.panic(
817 "TODO: handle `{s}` in `walkInstruction.as_node.dest_type`\n",
818 .{@tagName(wr)},
819 ),
820
821 .declRef => |v| .{ .declRef = v },
822 .type => |v| .{ .type = v },
823 };
824}