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 @@...@@ -133,7 +133,7 @@
133 function resolveDeclValue(decl) {133 function resolveDeclValue(decl) {
134 var i = 0;134 var i = 0;
135 while(i < 1000) {135 while(i < 1000) {
136 i += 1; 136 i += 1;
137137
138 if ("declRef" in decl.value) {138 if ("declRef" in decl.value) {
139 decl = zigAnalysis.decls[decl.value.declRef];139 decl = zigAnalysis.decls[decl.value.declRef];
...@@ -149,7 +149,7 @@...@@ -149,7 +149,7 @@
149 function resolveDeclValueTypeId(decl){149 function resolveDeclValueTypeId(decl){
150 var i = 0;150 var i = 0;
151 while(i < 1000) {151 while(i < 1000) {
152 i += 1; 152 i += 1;
153 console.assert(isDecl(decl));153 console.assert(isDecl(decl));
154 if ("type" in decl.value) {154 if ("type" in decl.value) {
155 return typeTypeId;155 return typeTypeId;
...@@ -250,7 +250,7 @@...@@ -250,7 +250,7 @@
250 }250 }
251251
252 var childDeclValue = resolveDeclValue(childDecl);252 var childDeclValue = resolveDeclValue(childDecl);
253 if ("type" in childDeclValue){ 253 if ("type" in childDeclValue){
254 if (i + 1 === curNav.declNames.length) {254 if (i + 1 === curNav.declNames.length) {
255 curNav.declObjs.push(zigAnalysis.types[childDeclValue.type]);255 curNav.declObjs.push(zigAnalysis.types[childDeclValue.type]);
256 break;256 break;
...@@ -1070,7 +1070,7 @@...@@ -1070,7 +1070,7 @@
1070 case "float":1070 case "float":
1071 declValueText += decl.value.float.value;1071 declValueText += decl.value.float.value;
1072 break;1072 break;
1073 default: 1073 default:
1074 console.log("TODO: renderValue for ", Object.keys(decl.value)[0]);1074 console.log("TODO: renderValue for ", Object.keys(decl.value)[0]);
1075 declValueText += "#TODO#";1075 declValueText += "#TODO#";
1076 }1076 }
...@@ -1213,12 +1213,11 @@...@@ -1213,12 +1213,11 @@
1213 domSectFns.classList.remove("hidden");1213 domSectFns.classList.remove("hidden");
1214 }1214 }
12151215
1216 if (container.fields) {1216 var containerNode = zigAnalysis.astNodes[container.src];
1217 resizeDomList(domListFields, container.fields.length, '<div></div>');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 < containerNode.fields.length; i += 1) {
1220 for (var i = 0; i < container.fields.length; i += 1) {
1221 var field = container.fields[i];
1222 var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];1221 var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
1223 var divDom = domListFields.children[i];1222 var divDom = domListFields.children[i];
12241223
...@@ -1227,6 +1226,7 @@...@@ -1227,6 +1226,7 @@
1227 if (container.kind === typeKinds.Enum) {1226 if (container.kind === typeKinds.Enum) {
1228 html += ' = <span class="tok-number">' + field + '</span>';1227 html += ' = <span class="tok-number">' + field + '</span>';
1229 } else {1228 } else {
1229 var field = container.fields[i];
1230 html += ": ";1230 html += ": ";
1231 if (typeof(field) === 'object') {1231 if (typeof(field) === 'object') {
1232 if (field.failure === true) {1232 if (field.failure === true) {
...@@ -1239,7 +1239,7 @@...@@ -1239,7 +1239,7 @@
12391239
1240 var valTypeName = valType.name;1240 var valTypeName = valType.name;
1241 if (valType.kind === typeKinds.Struct) {1241 if (valType.kind === typeKinds.Struct) {
1242 valTypeName = "struct"; 1242 valTypeName = "struct";
1243 }1243 }
12441244
1245 html += '<a href="'+navLinkDecl(decl.name)+'">';1245 html += '<a href="'+navLinkDecl(decl.name)+'">';
...@@ -1423,7 +1423,7 @@...@@ -1423,7 +1423,7 @@
1423 return null;1423 return null;
1424 }1424 }
14251425
1426 1426
14271427
14281428
1429 function computeCanonicalPackagePaths() {1429 function computeCanonicalPackagePaths() {
...@@ -1916,7 +1916,7 @@...@@ -1916,7 +1916,7 @@
1916 if (ev.ctrlKey) name = "Ctrl+" + name;1916 if (ev.ctrlKey) name = "Ctrl+" + name;
1917 return name;1917 return name;
1918 }1918 }
1919 1919
1920 function onWindowKeyDown(ev) {1920 function onWindowKeyDown(ev) {
1921 switch (getKeyString(ev)) {1921 switch (getKeyString(ev)) {
1922 case "Esc":1922 case "Esc":
src/Autodoc.zig+304-22
...@@ -60,10 +60,10 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -60,10 +60,10 @@ pub fn generateZirData(self: *Autodoc) !void {
60 try self.types.append(self.arena, .{60 try self.types.append(self.arena, .{
61 .name = tmpbuf.toOwnedSlice(),61 .name = tmpbuf.toOwnedSlice(),
62 .kind = switch (@intToEnum(Ref, i)) {62 .kind = switch (@intToEnum(Ref, i)) {
63 else => |t| blk: {63 else => blk: {
64 std.debug.print("TODO: categorize `{s}` in typeKinds\n", .{64 //std.debug.print("TODO: categorize `{s}` in typeKinds\n", .{
65 @tagName(t),65 // @tagName(t),
66 });66 //});
67 break :blk 7;67 break :blk 7;
68 },68 },
69 .u1_type,69 .u1_type,
...@@ -302,7 +302,7 @@ const DocData = struct {...@@ -302,7 +302,7 @@ const DocData = struct {
302 .int => |v| {302 .int => |v| {
303 const neg = if (v.negated) "-" else "";303 const neg = if (v.negated) "-" else "";
304 try w.print(304 try w.print(
305 \\{{ "int": {{ "typeRef": 305 \\{{ "int": {{ "typeRef":
306 , .{});306 , .{});
307 try v.typeRef.jsonStringify(options, w);307 try v.typeRef.jsonStringify(options, w);
308 try w.print(308 try w.print(
...@@ -312,7 +312,7 @@ const DocData = struct {...@@ -312,7 +312,7 @@ const DocData = struct {
312 .float => |v| {312 .float => |v| {
313 const neg = if (v.negated) "-" else "";313 const neg = if (v.negated) "-" else "";
314 try w.print(314 try w.print(
315 \\{{ "float": {{ "typeRef": 315 \\{{ "float": {{ "typeRef":
316 , .{});316 , .{});
317 try v.typeRef.jsonStringify(options, w);317 try v.typeRef.jsonStringify(options, w);
318 try w.print(318 try w.print(
...@@ -429,13 +429,6 @@ fn walkInstruction(...@@ -429,13 +429,6 @@ fn walkInstruction(
429 const pl_node = data[inst_index].pl_node;429 const pl_node = data[inst_index].pl_node;
430 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);430 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
431 const break_index = zir.extra[extra.end..][extra.data.body_len - 1];431 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
439 const break_operand = data[break_index].@"break".operand;432 const break_operand = data[break_index].@"break".operand;
440 return self.walkRef(zir, parent_scope, break_operand);433 return self.walkRef(zir, parent_scope, break_operand);
441 },434 },
...@@ -444,10 +437,227 @@ fn walkInstruction(...@@ -444,10 +437,227 @@ fn walkInstruction(
444 switch (extended.opcode) {437 switch (extended.opcode) {
445 else => {438 else => {
446 std.debug.panic(439 std.debug.panic(
447 "TODO: implement `walkInstruction` (inside .extended case) for {s}\n\n",440 "TODO: implement `walkInstruction.extended` for {s}\n\n",
448 .{@tagName(extended.opcode)},441 .{@tagName(extended.opcode)},
449 );442 );
450 },443 },
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 },
451 .struct_decl => {661 .struct_decl => {
452 var scope: Scope = .{ .parent = parent_scope };662 var scope: Scope = .{ .parent = parent_scope };
453663
...@@ -512,7 +722,7 @@ fn walkInstruction(...@@ -512,7 +722,7 @@ fn walkInstruction(
512722
513 var field_type_indexes: std.ArrayListUnmanaged(DocData.WalkResult) = .{};723 var field_type_indexes: std.ArrayListUnmanaged(DocData.WalkResult) = .{};
514 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};724 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
515 try self.collectFieldInfo(725 try self.collectStructFieldInfo(
516 zir,726 zir,
517 &scope,727 &scope,
518 fields_len,728 fields_len,
...@@ -539,12 +749,12 @@ fn walkInstruction(...@@ -539,12 +749,12 @@ fn walkInstruction(
539 }749 }
540}750}
541751
542/// Called by `walkInstruction` when encountering a container type, 752/// Called by `walkInstruction` when encountering a container type,
543/// iterates over all decl definitions in its body.753/// 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.
545///755///
546/// Does not append to `self.decls` directly because `walkInstruction` 756/// Does not append to `self.decls` directly because `walkInstruction`
547/// is expected to (look-ahead) scan all decls and reserve `body_len` 757/// is expected to (look-ahead) scan all decls and reserve `body_len`
548/// slots in `self.decls`, which are then filled out by `walkDecls`.758/// slots in `self.decls`, which are then filled out by `walkDecls`.
549fn walkDecls(759fn walkDecls(
550 self: *Autodoc,760 self: *Autodoc,
...@@ -678,7 +888,7 @@ fn walkDecls(...@@ -678,7 +888,7 @@ fn walkDecls(
678 return extra_index;888 return extra_index;
679}889}
680890
681fn collectFieldInfo(891fn collectUnionFieldInfo(
682 self: *Autodoc,892 self: *Autodoc,
683 zir: Zir,893 zir: Zir,
684 scope: *Scope,894 scope: *Scope,
...@@ -703,9 +913,78 @@ fn collectFieldInfo(...@@ -703,9 +913,78 @@ fn collectFieldInfo(
703 cur_bit_bag = zir.extra[bit_bag_index];913 cur_bit_bag = zir.extra[bit_bag_index];
704 bit_bag_index += 1;914 bit_bag_index += 1;
705 }915 }
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;
707 cur_bit_bag >>= 1;923 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;
709 cur_bit_bag >>= 1;988 cur_bit_bag >>= 1;
710 // const is_comptime = @truncate(u1, cur_bit_bag) != 0;989 // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
711 cur_bit_bag >>= 1;990 cur_bit_bag >>= 1;
...@@ -720,6 +999,9 @@ fn collectFieldInfo(...@@ -720,6 +999,9 @@ fn collectFieldInfo(
720 const doc_comment_index = zir.extra[extra_index];999 const doc_comment_index = zir.extra[extra_index];
721 extra_index += 1;1000 extra_index += 1;
7221001
1002 if (has_align) extra_index += 1;
1003 if (has_default) extra_index += 1;
1004
723 // type1005 // type
724 {1006 {
725 const walk_result = try self.walkRef(zir, scope, field_type);1007 const walk_result = try self.walkRef(zir, scope, field_type);