authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-04 20:43:43+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
logeced8c065d8f90e81af5673ba8086078bd22b9d2
tree11ab9c73b901c4ecf7dc53911f4bc4d6af7828d4
parent8bb529b39598f53939f7429257b862b513fb3091

autodoc: add support for solving decl paths depending on other

decl paths

1 files changed, 106 insertions(+), 11 deletions(-)

src/Autodoc.zig+106-11
...@@ -15,6 +15,10 @@ types: std.ArrayListUnmanaged(DocData.Type) = .{},...@@ -15,6 +15,10 @@ types: std.ArrayListUnmanaged(DocData.Type) = .{},
15decls: std.ArrayListUnmanaged(DocData.Decl) = .{},15decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
16ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},16ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
17comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},17comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
18pending_decl_paths: std.AutoHashMapUnmanaged(
19 *usize, // pointer to declpath head (ie `&decl_path[0]`)
20 std.ArrayListUnmanaged(DeclPathResumeInfo),
21) = .{},
18decl_paths_pending_on_decls: std.AutoHashMapUnmanaged(22decl_paths_pending_on_decls: std.AutoHashMapUnmanaged(
19 usize,23 usize,
20 std.ArrayListUnmanaged(DeclPathResumeInfo),24 std.ArrayListUnmanaged(DeclPathResumeInfo),
...@@ -154,6 +158,10 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -154,6 +158,10 @@ pub fn generateZirData(self: *Autodoc) !void {
154 @panic("some decl paths were never fully analized (pending on types)");158 @panic("some decl paths were never fully analized (pending on types)");
155 }159 }
156160
161 if (self.pending_decl_paths.count() > 0) {
162 @panic("some decl paths were never fully analized");
163 }
164
157 var data = DocData{165 var data = DocData{
158 .files = .{ .data = self.files },166 .files = .{ .data = self.files },
159 .calls = self.calls.items,167 .calls = self.calls.items,
...@@ -733,15 +741,49 @@ fn walkInstruction(...@@ -733,15 +741,49 @@ fn walkInstruction(
733 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs741 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
734 }742 }
735743
736 if (tags[lhs] != .decl_val and tags[lhs] != .decl_ref) {744 switch (tags[lhs]) {
737 std.debug.panic(745 else => {
738 "TODO: handle `{s}` endings in walkInstruction.field_val",746 std.debug.panic(
739 .{@tagName(tags[lhs])},747 "TODO: handle `{s}` endings in walkInstruction.field_val",
740 );748 .{@tagName(tags[lhs])},
749 );
750 },
751 .import => {
752 const walk_result = try self.walkInstruction(file, parent_scope, lhs);
753
754 // astnode
755 const ast_node_index = idx: {
756 const idx = self.ast_nodes.items.len;
757 try self.ast_nodes.append(self.arena, .{
758 .file = 0,
759 .line = 0,
760 .col = 0,
761 .docs = "",
762 .fields = null, // walkInstruction will fill `fields` if necessary
763 });
764 break :idx idx;
765 };
766 const str_tok = data[inst_index].str_tok;
767 const file_path = str_tok.get(file.zir);
768
769 const name = try std.fmt.allocPrint(self.arena, "@import({s})", .{file_path});
770 const decls_slot_index = self.decls.items.len;
771 try self.decls.append(self.arena, .{
772 ._analyzed = true,
773 .name = name,
774 .src = ast_node_index,
775 // .typeRef = decl_type_ref,
776 .value = walk_result,
777 .kind = "const", // find where this information can be found
778 });
779 try path.append(self.arena, decls_slot_index);
780 },
781 .decl_val, .decl_ref => {
782 const str_tok = data[lhs].str_tok;
783 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
784 try path.append(self.arena, decls_slot_index);
785 },
741 }786 }
742 const str_tok = data[lhs].str_tok;
743 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
744 try path.append(self.arena, decls_slot_index);
745787
746 // Righ now, every element of `path` is the first index of a788 // Righ now, every element of `path` is the first index of a
747 // decl name except for the final element, which instead points to789 // decl name except for the final element, which instead points to
...@@ -1458,7 +1500,7 @@ fn tryResolveDeclPath(...@@ -1458,7 +1500,7 @@ fn tryResolveDeclPath(
1458 /// File from which the decl path originates.1500 /// File from which the decl path originates.
1459 file: *File,1501 file: *File,
1460 path: []usize,1502 path: []usize,
1461) !void {1503) error{OutOfMemory}!void {
1462 var i: usize = path.len;1504 var i: usize = path.len;
1463 while (i > 1) {1505 while (i > 1) {
1464 i -= 1;1506 i -= 1;
...@@ -1467,12 +1509,19 @@ fn tryResolveDeclPath(...@@ -1467,12 +1509,19 @@ fn tryResolveDeclPath(
14671509
1468 const parent = self.decls.items[decl_index];1510 const parent = self.decls.items[decl_index];
1469 if (!parent._analyzed) {1511 if (!parent._analyzed) {
1512 // This decl path is pending completion
1513 {
1514 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1515 if (!res.found_existing) res.value_ptr.* = .{};
1516 }
1517
1470 const res = try self.decl_paths_pending_on_decls.getOrPut(self.arena, decl_index);1518 const res = try self.decl_paths_pending_on_decls.getOrPut(self.arena, decl_index);
1471 if (!res.found_existing) res.value_ptr.* = .{};1519 if (!res.found_existing) res.value_ptr.* = .{};
1472 try res.value_ptr.*.append(self.arena, .{1520 try res.value_ptr.*.append(self.arena, .{
1473 .file = file,1521 .file = file,
1474 .path = path[0 .. i + 1],1522 .path = path[0 .. i + 1],
1475 });1523 });
1524
1476 return;1525 return;
1477 }1526 }
14781527
...@@ -1480,10 +1529,37 @@ fn tryResolveDeclPath(...@@ -1480,10 +1529,37 @@ fn tryResolveDeclPath(
1480 switch (parent.value) {1529 switch (parent.value) {
1481 else => {1530 else => {
1482 std.debug.panic(1531 std.debug.panic(
1483 "TODO: handle `{s}`in walkInstruction.field_val\n",1532 "TODO: handle `{s}`in walkInstruction.field_val\n \"{s}\":{}",
1484 .{@tagName(parent.value)},1533 .{ @tagName(parent.value), parent.name, parent.value },
1485 );1534 );
1486 },1535 },
1536 .declPath => |dp| {
1537 if (self.pending_decl_paths.getPtr(&dp[0])) |waiter_list| {
1538 try waiter_list.append(self.arena, .{
1539 .file = file,
1540 .path = path[0 .. i + 1],
1541 });
1542
1543 // This decl path is pending completion
1544 {
1545 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1546 if (!res.found_existing) res.value_ptr.* = .{};
1547 }
1548
1549 return;
1550 }
1551
1552 const final_decl_index = dp[0];
1553 // For the purpose of being able to call tryResolveDeclPath again,
1554 // we momentarily replace the decl index present in `path[i]`
1555 // with the final decl in `dp`.
1556 // We then write the original value back as soon as we're done with the
1557 // recoursive call. This will work out correctly even if the path
1558 // will not get fully resolved.
1559 path[i] = final_decl_index;
1560 try self.tryResolveDeclPath(file, path);
1561 path[i] = decl_index;
1562 },
1487 .type => |t_index| switch (self.types.items[t_index]) {1563 .type => |t_index| switch (self.types.items[t_index]) {
1488 else => {1564 else => {
1489 std.debug.panic(1565 std.debug.panic(
...@@ -1492,6 +1568,12 @@ fn tryResolveDeclPath(...@@ -1492,6 +1568,12 @@ fn tryResolveDeclPath(
1492 );1568 );
1493 },1569 },
1494 .Unanalyzed => {1570 .Unanalyzed => {
1571 // This decl path is pending completion
1572 {
1573 const res = try self.pending_decl_paths.getOrPut(self.arena, &path[0]);
1574 if (!res.found_existing) res.value_ptr.* = .{};
1575 }
1576
1495 const res = try self.decl_paths_pending_on_types.getOrPut(1577 const res = try self.decl_paths_pending_on_types.getOrPut(
1496 self.arena,1578 self.arena,
1497 t_index,1579 t_index,
...@@ -1501,6 +1583,7 @@ fn tryResolveDeclPath(...@@ -1501,6 +1583,7 @@ fn tryResolveDeclPath(
1501 .file = file,1583 .file = file,
1502 .path = path[0 .. i + 1],1584 .path = path[0 .. i + 1],
1503 });1585 });
1586
1504 return;1587 return;
1505 },1588 },
1506 .Struct => |t_struct| {1589 .Struct => |t_struct| {
...@@ -1526,6 +1609,18 @@ fn tryResolveDeclPath(...@@ -1526,6 +1609,18 @@ fn tryResolveDeclPath(
1526 },1609 },
1527 }1610 }
1528 }1611 }
1612
1613 if (self.pending_decl_paths.get(&path[0])) |waiter_list| {
1614 // It's important to de-register oureslves as pending before
1615 // attempting to resolve any other decl.
1616 _ = self.pending_decl_paths.remove(&path[0]);
1617
1618 for (waiter_list.items) |resume_info| {
1619 try self.tryResolveDeclPath(resume_info.file, resume_info.path);
1620 }
1621 // TODO: this is where we should free waiter_list, but its in the arena
1622 // that said, we might want to store it elsewhere and reclaim memory asap
1623 }
1529}1624}
15301625
1531fn collectUnionFieldInfo(1626fn collectUnionFieldInfo(