authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-02-06 18:25:01+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:10-07:00
logef5a2e8d6f9467ea689af93c8400646cdacd6ee8
tree1183882c6f1dc3729eda0ca2fd7bf86122ccab22
parenta04045c709b6b9a8df830e9b270505663164a89e

autodocs: added basic support for unions


2 files changed, 316 insertions(+), 34 deletions(-)

lib/docs/main.js+12-12
......@@ -133,7 +133,7 @@
133133 function resolveDeclValue(decl) {
134134 var i = 0;
135135 while(i < 1000) {
136 i += 1;
136 i += 1;
137137
138138 if ("declRef" in decl.value) {
139139 decl = zigAnalysis.decls[decl.value.declRef];
......@@ -149,7 +149,7 @@
149149 function resolveDeclValueTypeId(decl){
150150 var i = 0;
151151 while(i < 1000) {
152 i += 1;
152 i += 1;
153153 console.assert(isDecl(decl));
154154 if ("type" in decl.value) {
155155 return typeTypeId;
......@@ -250,7 +250,7 @@
250250 }
251251
252252 var childDeclValue = resolveDeclValue(childDecl);
253 if ("type" in childDeclValue){
253 if ("type" in childDeclValue){
254254 if (i + 1 === curNav.declNames.length) {
255255 curNav.declObjs.push(zigAnalysis.types[childDeclValue.type]);
256256 break;
......@@ -1070,7 +1070,7 @@
10701070 case "float":
10711071 declValueText += decl.value.float.value;
10721072 break;
1073 default:
1073 default:
10741074 console.log("TODO: renderValue for ", Object.keys(decl.value)[0]);
10751075 declValueText += "#TODO#";
10761076 }
......@@ -1213,12 +1213,11 @@
12131213 domSectFns.classList.remove("hidden");
12141214 }
12151215
1216 if (container.fields) {
1217 resizeDomList(domListFields, container.fields.length, '<div></div>');
1216 var containerNode = zigAnalysis.astNodes[container.src];
1217 if (containerNode.fields) {
1218 resizeDomList(domListFields, containerNode.fields.length, '<div></div>');
12181219
1219 var containerNode = zigAnalysis.astNodes[container.src];
1220 for (var i = 0; i < container.fields.length; i += 1) {
1221 var field = container.fields[i];
1220 for (var i = 0; i < containerNode.fields.length; i += 1) {
12221221 var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
12231222 var divDom = domListFields.children[i];
12241223
......@@ -1227,6 +1226,7 @@
12271226 if (container.kind === typeKinds.Enum) {
12281227 html += ' = <span class="tok-number">' + field + '</span>';
12291228 } else {
1229 var field = container.fields[i];
12301230 html += ": ";
12311231 if (typeof(field) === 'object') {
12321232 if (field.failure === true) {
......@@ -1239,7 +1239,7 @@
12391239
12401240 var valTypeName = valType.name;
12411241 if (valType.kind === typeKinds.Struct) {
1242 valTypeName = "struct";
1242 valTypeName = "struct";
12431243 }
12441244
12451245 html += '<a href="'+navLinkDecl(decl.name)+'">';
......@@ -1423,7 +1423,7 @@
14231423 return null;
14241424 }
14251425
1426
1426
14271427
14281428
14291429 function computeCanonicalPackagePaths() {
......@@ -1916,7 +1916,7 @@
19161916 if (ev.ctrlKey) name = "Ctrl+" + name;
19171917 return name;
19181918 }
1919
1919
19201920 function onWindowKeyDown(ev) {
19211921 switch (getKeyString(ev)) {
19221922 case "Esc":
src/Autodoc.zig+304-22
......@@ -60,10 +60,10 @@ pub fn generateZirData(self: *Autodoc) !void {
6060 try self.types.append(self.arena, .{
6161 .name = tmpbuf.toOwnedSlice(),
6262 .kind = switch (@intToEnum(Ref, i)) {
63 else => |t| blk: {
64 std.debug.print("TODO: categorize `{s}` in typeKinds\n", .{
65 @tagName(t),
66 });
63 else => blk: {
64 //std.debug.print("TODO: categorize `{s}` in typeKinds\n", .{
65 // @tagName(t),
66 //});
6767 break :blk 7;
6868 },
6969 .u1_type,
......@@ -302,7 +302,7 @@ const DocData = struct {
302302 .int => |v| {
303303 const neg = if (v.negated) "-" else "";
304304 try w.print(
305 \\{{ "int": {{ "typeRef":
305 \\{{ "int": {{ "typeRef":
306306 , .{});
307307 try v.typeRef.jsonStringify(options, w);
308308 try w.print(
......@@ -312,7 +312,7 @@ const DocData = struct {
312312 .float => |v| {
313313 const neg = if (v.negated) "-" else "";
314314 try w.print(
315 \\{{ "float": {{ "typeRef":
315 \\{{ "float": {{ "typeRef":
316316 , .{});
317317 try v.typeRef.jsonStringify(options, w);
318318 try w.print(
......@@ -429,13 +429,6 @@ fn walkInstruction(
429429 const pl_node = data[inst_index].pl_node;
430430 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
431431 const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
432
433 std.debug.print("[instr: {}] body len: {} last instr idx: {}\n", .{
434 inst_index,
435 extra.data.body_len,
436 break_index,
437 });
438
439432 const break_operand = data[break_index].@"break".operand;
440433 return self.walkRef(zir, parent_scope, break_operand);
441434 },
......@@ -444,10 +437,227 @@ fn walkInstruction(
444437 switch (extended.opcode) {
445438 else => {
446439 std.debug.panic(
447 "TODO: implement `walkInstruction` (inside .extended case) for {s}\n\n",
440 "TODO: implement `walkInstruction.extended` for {s}\n\n",
448441 .{@tagName(extended.opcode)},
449442 );
450443 },
444 .union_decl => {
445 var scope: Scope = .{ .parent = parent_scope };
446
447 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
448 var extra_index: usize = extended.operand;
449
450 const src_node: ?i32 = if (small.has_src_node) blk: {
451 const src_node = @bitCast(i32, zir.extra[extra_index]);
452 extra_index += 1;
453 break :blk src_node;
454 } else null;
455 _ = src_node;
456
457 const tag_type: ?Ref = if (small.has_tag_type) blk: {
458 const tag_type = zir.extra[extra_index];
459 extra_index += 1;
460 break :blk @intToEnum(Ref, tag_type);
461 } else null;
462 _ = tag_type;
463
464 const body_len = if (small.has_body_len) blk: {
465 const body_len = zir.extra[extra_index];
466 extra_index += 1;
467 break :blk body_len;
468 } else 0;
469
470 const fields_len = if (small.has_fields_len) blk: {
471 const fields_len = zir.extra[extra_index];
472 extra_index += 1;
473 break :blk fields_len;
474 } else 0;
475 _ = fields_len;
476
477 const decls_len = if (small.has_decls_len) blk: {
478 const decls_len = zir.extra[extra_index];
479 extra_index += 1;
480 break :blk decls_len;
481 } else 0;
482
483 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
484 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
485
486 const decls_first_index = self.decls.items.len;
487 // Decl name lookahead for reserving slots in `scope` (and `decls`).
488 // Done to make sure that all decl refs can be resolved correctly,
489 // even if we haven't fully analyzed the decl yet.
490 {
491 var it = zir.declIterator(@intCast(u32, inst_index));
492 try self.decls.resize(self.arena, decls_first_index + it.decls_len);
493 var decls_slot_index = decls_first_index;
494 while (it.next()) |d| : (decls_slot_index += 1) {
495 const decl_name_index = zir.extra[d.sub_index + 5];
496 try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
497 }
498 }
499
500 extra_index = try self.walkDecls(
501 zir,
502 &scope,
503 decls_first_index,
504 decls_len,
505 &decl_indexes,
506 &priv_decl_indexes,
507 extra_index,
508 );
509
510 // const body = zir.extra[extra_index..][0..body_len];
511 extra_index += body_len;
512
513 var field_type_indexes: std.ArrayListUnmanaged(DocData.WalkResult) = .{};
514 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
515 try self.collectUnionFieldInfo(
516 zir,
517 &scope,
518 fields_len,
519 &field_type_indexes,
520 &field_name_indexes,
521 extra_index,
522 );
523
524 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
525
526 try self.types.append(self.arena, .{
527 .kind = @enumToInt(std.builtin.TypeId.Union),
528 .name = "todo_name",
529 .src = self_ast_node_index,
530 .privDecls = priv_decl_indexes.items,
531 .pubDecls = decl_indexes.items,
532 .fields = field_type_indexes.items,
533 });
534
535 return DocData.WalkResult{ .type = self.types.items.len - 1 };
536 },
537 .enum_decl => {
538 var scope: Scope = .{ .parent = parent_scope };
539
540 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
541 var extra_index: usize = extended.operand;
542
543 const src_node: ?i32 = if (small.has_src_node) blk: {
544 const src_node = @bitCast(i32, zir.extra[extra_index]);
545 extra_index += 1;
546 break :blk src_node;
547 } else null;
548 _ = src_node;
549
550 const tag_type: ?Ref = if (small.has_tag_type) blk: {
551 const tag_type = zir.extra[extra_index];
552 extra_index += 1;
553 break :blk @intToEnum(Ref, tag_type);
554 } else null;
555 _ = tag_type;
556
557 const body_len = if (small.has_body_len) blk: {
558 const body_len = zir.extra[extra_index];
559 extra_index += 1;
560 break :blk body_len;
561 } else 0;
562
563 const fields_len = if (small.has_fields_len) blk: {
564 const fields_len = zir.extra[extra_index];
565 extra_index += 1;
566 break :blk fields_len;
567 } else 0;
568 _ = fields_len;
569
570 const decls_len = if (small.has_decls_len) blk: {
571 const decls_len = zir.extra[extra_index];
572 extra_index += 1;
573 break :blk decls_len;
574 } else 0;
575
576 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
577 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
578
579 const decls_first_index = self.decls.items.len;
580 // Decl name lookahead for reserving slots in `scope` (and `decls`).
581 // Done to make sure that all decl refs can be resolved correctly,
582 // even if we haven't fully analyzed the decl yet.
583 {
584 var it = zir.declIterator(@intCast(u32, inst_index));
585 try self.decls.resize(self.arena, decls_first_index + it.decls_len);
586 var decls_slot_index = decls_first_index;
587 while (it.next()) |d| : (decls_slot_index += 1) {
588 const decl_name_index = zir.extra[d.sub_index + 5];
589 try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
590 }
591 }
592
593 extra_index = try self.walkDecls(
594 zir,
595 &scope,
596 decls_first_index,
597 decls_len,
598 &decl_indexes,
599 &priv_decl_indexes,
600 extra_index,
601 );
602
603 // const body = zir.extra[extra_index..][0..body_len];
604 extra_index += body_len;
605
606 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
607 {
608 var bit_bag_idx = extra_index;
609 var cur_bit_bag: u32 = undefined;
610 extra_index += std.math.divCeil(usize, fields_len, 32) catch unreachable;
611
612 var idx: usize = 0;
613 while (idx < fields_len) : (idx += 1) {
614 if (idx % 32 == 0) {
615 cur_bit_bag = zir.extra[bit_bag_idx];
616 bit_bag_idx += 1;
617 }
618
619 const has_value = @truncate(u1, cur_bit_bag) != 0;
620 cur_bit_bag >>= 1;
621
622 const field_name_index = zir.extra[extra_index];
623 extra_index += 1;
624
625 const doc_comment_index = zir.extra[extra_index];
626 extra_index += 1;
627
628 const value_ref: ?Ref = if (has_value) blk: {
629 const value_ref = zir.extra[extra_index];
630 extra_index += 1;
631 break :blk @intToEnum(Ref, value_ref);
632 } else null;
633 _ = value_ref;
634
635 const field_name = zir.nullTerminatedString(field_name_index);
636
637 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
638 const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
639 zir.nullTerminatedString(doc_comment_index)
640 else
641 null;
642 try self.ast_nodes.append(self.arena, .{
643 .name = field_name,
644 .docs = doc_comment,
645 });
646 }
647 }
648
649 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
650
651 try self.types.append(self.arena, .{
652 .kind = @enumToInt(std.builtin.TypeId.Enum),
653 .name = "todo_name",
654 .src = self_ast_node_index,
655 .privDecls = priv_decl_indexes.items,
656 .pubDecls = decl_indexes.items,
657 });
658
659 return DocData.WalkResult{ .type = self.types.items.len - 1 };
660 },
451661 .struct_decl => {
452662 var scope: Scope = .{ .parent = parent_scope };
453663
......@@ -512,7 +722,7 @@ fn walkInstruction(
512722
513723 var field_type_indexes: std.ArrayListUnmanaged(DocData.WalkResult) = .{};
514724 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
515 try self.collectFieldInfo(
725 try self.collectStructFieldInfo(
516726 zir,
517727 &scope,
518728 fields_len,
......@@ -539,12 +749,12 @@ fn walkInstruction(
539749 }
540750}
541751
542/// Called by `walkInstruction` when encountering a container type,
752/// Called by `walkInstruction` when encountering a container type,
543753/// iterates over all decl definitions in its body.
544/// It also analyzes each decl's body recursively.
754/// It also analyzes each decl's body recursively.
545755///
546/// Does not append to `self.decls` directly because `walkInstruction`
547/// is expected to (look-ahead) scan all decls and reserve `body_len`
756/// Does not append to `self.decls` directly because `walkInstruction`
757/// is expected to (look-ahead) scan all decls and reserve `body_len`
548758/// slots in `self.decls`, which are then filled out by `walkDecls`.
549759fn walkDecls(
550760 self: *Autodoc,
......@@ -678,7 +888,7 @@ fn walkDecls(
678888 return extra_index;
679889}
680890
681fn collectFieldInfo(
891fn collectUnionFieldInfo(
682892 self: *Autodoc,
683893 zir: Zir,
684894 scope: *Scope,
......@@ -703,9 +913,78 @@ fn collectFieldInfo(
703913 cur_bit_bag = zir.extra[bit_bag_index];
704914 bit_bag_index += 1;
705915 }
706 // const has_align = @truncate(u1, cur_bit_bag) != 0;
916 const has_type = @truncate(u1, cur_bit_bag) != 0;
917 cur_bit_bag >>= 1;
918 const has_align = @truncate(u1, cur_bit_bag) != 0;
919 cur_bit_bag >>= 1;
920 const has_tag = @truncate(u1, cur_bit_bag) != 0;
921 cur_bit_bag >>= 1;
922 const unused = @truncate(u1, cur_bit_bag) != 0;
707923 cur_bit_bag >>= 1;
708 // const has_default = @truncate(u1, cur_bit_bag) != 0;
924 _ = unused;
925
926 const field_name = zir.nullTerminatedString(zir.extra[extra_index]);
927 extra_index += 1;
928 const doc_comment_index = zir.extra[extra_index];
929 extra_index += 1;
930 const field_type = if (has_type)
931 @intToEnum(Zir.Inst.Ref, zir.extra[extra_index])
932 else
933 .void_type;
934 extra_index += 1;
935
936 if (has_align) extra_index += 1;
937 if (has_tag) extra_index += 1;
938
939 // type
940 {
941 const walk_result = try self.walkRef(zir, scope, field_type);
942 try field_type_indexes.append(self.arena, walk_result);
943 }
944
945 // ast node
946 {
947 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
948 const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
949 zir.nullTerminatedString(doc_comment_index)
950 else
951 null;
952 try self.ast_nodes.append(self.arena, .{
953 .name = field_name,
954 .docs = doc_comment,
955 });
956 }
957 }
958}
959
960fn collectStructFieldInfo(
961 self: *Autodoc,
962 zir: Zir,
963 scope: *Scope,
964 fields_len: usize,
965 field_type_indexes: *std.ArrayListUnmanaged(DocData.WalkResult),
966 field_name_indexes: *std.ArrayListUnmanaged(usize),
967 ei: usize,
968) !void {
969 if (fields_len == 0) return;
970 var extra_index = ei;
971
972 const bits_per_field = 4;
973 const fields_per_u32 = 32 / bits_per_field;
974 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
975 var bit_bag_index: usize = extra_index;
976 extra_index += bit_bags_count;
977
978 var cur_bit_bag: u32 = undefined;
979 var field_i: u32 = 0;
980 while (field_i < fields_len) : (field_i += 1) {
981 if (field_i % fields_per_u32 == 0) {
982 cur_bit_bag = zir.extra[bit_bag_index];
983 bit_bag_index += 1;
984 }
985 const has_align = @truncate(u1, cur_bit_bag) != 0;
986 cur_bit_bag >>= 1;
987 const has_default = @truncate(u1, cur_bit_bag) != 0;
709988 cur_bit_bag >>= 1;
710989 // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
711990 cur_bit_bag >>= 1;
......@@ -720,6 +999,9 @@ fn collectFieldInfo(
720999 const doc_comment_index = zir.extra[extra_index];
7211000 extra_index += 1;
7221001
1002 if (has_align) extra_index += 1;
1003 if (has_default) extra_index += 1;
1004
7231005 // type
7241006 {
7251007 const walk_result = try self.walkRef(zir, scope, field_type);