| ... | ... | @@ -4,6 +4,7 @@ const Autodoc = @This(); |
| 4 | 4 | const Compilation = @import("Compilation.zig"); |
| 5 | 5 | const Module = @import("Module.zig"); |
| 6 | 6 | const File = Module.File; |
| 7 | const Package = @import("Package.zig"); |
| 7 | 8 | const Zir = @import("Zir.zig"); |
| 8 | 9 | const Ref = Zir.Inst.Ref; |
| 9 | 10 | |
| ... | ... | @@ -14,8 +15,8 @@ arena: std.mem.Allocator, |
| 14 | 15 | // The goal of autodoc is to fill up these arrays |
| 15 | 16 | // that will then be serialized as JSON and consumed |
| 16 | 17 | // by the JS frontend. |
| 17 | | pkgs: std.ArrayListUnmanaged(DocData.Package) = .{}, |
| 18 | | files: std.AutoHashMapUnmanaged(*File, usize) = .{}, |
| 18 | packages: std.AutoArrayHashMapUnmanaged(*Package, DocData.DocPackage) = .{}, |
| 19 | files: std.AutoArrayHashMapUnmanaged(*File, usize) = .{}, |
| 19 | 20 | calls: std.ArrayListUnmanaged(DocData.Call) = .{}, |
| 20 | 21 | types: std.ArrayListUnmanaged(DocData.Type) = .{}, |
| 21 | 22 | decls: std.ArrayListUnmanaged(DocData.Decl) = .{}, |
| ... | ... | @@ -171,28 +172,17 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 171 | 172 | ); |
| 172 | 173 | } |
| 173 | 174 | } |
| 174 | | |
| 175 | | |
| 176 | | |
| 177 | | const main_type_index = self.types.items.len; |
| 178 | | const rootName = blk: { |
| 179 | | const rootName = std.fs.path.basename(self.module.main_pkg.root_src_path); |
| 180 | | break :blk rootName[0..rootName.len - 4]; |
| 181 | | }; |
| 182 | | |
| 183 | | try self.pkgs.append(self.arena, .{ |
| 184 | | .name = rootName, |
| 185 | | .table = .{.data = std.StringHashMapUnmanaged(usize){}}, |
| 186 | | }); |
| 187 | | |
| 188 | 175 | |
| 176 | const main_type_index = self.types.items.len; |
| 189 | 177 | { |
| 190 | | const rootPkg: *DocData.Package = &self.pkgs.items[0]; |
| 191 | | try rootPkg.table.data.put(self.arena, rootName, 0); |
| 192 | | |
| 193 | | rootPkg.main = main_type_index; |
| 194 | | rootPkg.name = rootName; |
| 178 | try self.packages.put(self.arena, self.module.main_pkg, .{ |
| 179 | .name = "root", |
| 180 | .main = main_type_index, |
| 181 | .table = .{ .data = std.StringHashMapUnmanaged(usize){} }, |
| 182 | }); |
| 183 | try self.packages.entries.items(.value)[0].table.data.put(self.arena, "root", 0); |
| 195 | 184 | } |
| 185 | |
| 196 | 186 | var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index }; |
| 197 | 187 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); |
| 198 | 188 | try self.files.put(self.arena, file, main_type_index); |
| ... | ... | @@ -209,12 +199,15 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 209 | 199 | if (self.pending_ref_paths.count() > 0) { |
| 210 | 200 | @panic("some decl paths were never fully analized"); |
| 211 | 201 | } |
| 212 | | |
| 213 | 202 | |
| 214 | | |
| 203 | const rootName = blk: { |
| 204 | const rootName = std.fs.path.basename(self.module.main_pkg.root_src_path); |
| 205 | break :blk rootName[0 .. rootName.len - 4]; |
| 206 | }; |
| 215 | 207 | var data = DocData{ |
| 216 | | .params = .{ .rootName = rootName }, |
| 217 | | .packages = self.pkgs.items, |
| 208 | .rootPkgName = rootName, |
| 209 | .params = .{ .rootName = "root" }, |
| 210 | .packages = self.packages.values(), |
| 218 | 211 | .files = .{ .data = self.files }, |
| 219 | 212 | .calls = self.calls.items, |
| 220 | 213 | .types = self.types.items, |
| ... | ... | @@ -224,8 +217,6 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 224 | 217 | .comptimeExprs = self.comptime_exprs.items, |
| 225 | 218 | }; |
| 226 | 219 | |
| 227 | | |
| 228 | | |
| 229 | 220 | if (self.doc_location.directory) |d| { |
| 230 | 221 | d.handle.makeDir( |
| 231 | 222 | self.doc_location.basename, |
| ... | ... | @@ -306,6 +297,7 @@ const Scope = struct { |
| 306 | 297 | const DocData = struct { |
| 307 | 298 | typeKinds: []const []const u8 = std.meta.fieldNames(DocTypeKinds), |
| 308 | 299 | rootPkg: u32 = 0, |
| 300 | rootPkgName: []const u8, |
| 309 | 301 | params: struct { |
| 310 | 302 | zigId: []const u8 = "arst", |
| 311 | 303 | zigVersion: []const u8 = build_options.version, |
| ... | ... | @@ -315,7 +307,7 @@ const DocData = struct { |
| 315 | 307 | .{ .target = "arst" }, |
| 316 | 308 | }, |
| 317 | 309 | }, |
| 318 | | packages: []const Package, |
| 310 | packages: []const DocPackage, |
| 319 | 311 | errors: []struct {} = &.{}, |
| 320 | 312 | |
| 321 | 313 | // non-hardcoded stuff |
| ... | ... | @@ -323,7 +315,7 @@ const DocData = struct { |
| 323 | 315 | calls: []Call, |
| 324 | 316 | files: struct { |
| 325 | 317 | // this struct is a temporary hack to support json serialization |
| 326 | | data: std.AutoHashMapUnmanaged(*File, usize), |
| 318 | data: std.AutoArrayHashMapUnmanaged(*File, usize), |
| 327 | 319 | pub fn jsonStringify( |
| 328 | 320 | self: @This(), |
| 329 | 321 | opt: std.json.StringifyOptions, |
| ... | ... | @@ -403,53 +395,53 @@ const DocData = struct { |
| 403 | 395 | const ComptimeExpr = struct { |
| 404 | 396 | code: []const u8, |
| 405 | 397 | }; |
| 406 | | const Package = struct { |
| 398 | const DocPackage = struct { |
| 407 | 399 | name: []const u8 = "(root)", |
| 408 | 400 | file: usize = 0, // index into `files` |
| 409 | | main: usize = 0, // index into `decls` |
| 401 | main: usize = 0, // index into `types` |
| 410 | 402 | table: struct { |
| 411 | | // this struct is a temporary hack to support json serialization |
| 412 | | data: std.StringHashMapUnmanaged(usize), |
| 413 | | pub fn jsonStringify( |
| 414 | | self: @This(), |
| 415 | | opt: std.json.StringifyOptions, |
| 416 | | w: anytype, |
| 417 | | ) !void { |
| 418 | | var idx: usize = 0; |
| 419 | | var it = self.data.iterator(); |
| 420 | | try w.writeAll("{\n"); |
| 421 | | |
| 422 | | var options = opt; |
| 423 | | if (options.whitespace) |*ws| ws.indent_level += 1; |
| 424 | | while (it.next()) |kv| : (idx += 1) { |
| 425 | | if (options.whitespace) |ws| try ws.outputIndent(w); |
| 426 | | const builtin = @import("builtin"); |
| 427 | | if (builtin.target.os.tag == .windows) { |
| 428 | | try w.print("\"", .{}); |
| 429 | | for (kv.key_ptr.*) |c| { |
| 430 | | if (c == '\\') { |
| 431 | | try w.print("\\\\", .{}); |
| 432 | | } else { |
| 433 | | try w.print("{c}", .{c}); |
| 403 | // this struct is a temporary hack to support json serialization |
| 404 | data: std.StringHashMapUnmanaged(usize), |
| 405 | pub fn jsonStringify( |
| 406 | self: @This(), |
| 407 | opt: std.json.StringifyOptions, |
| 408 | w: anytype, |
| 409 | ) !void { |
| 410 | var idx: usize = 0; |
| 411 | var it = self.data.iterator(); |
| 412 | try w.writeAll("{\n"); |
| 413 | |
| 414 | var options = opt; |
| 415 | if (options.whitespace) |*ws| ws.indent_level += 1; |
| 416 | while (it.next()) |kv| : (idx += 1) { |
| 417 | if (options.whitespace) |ws| try ws.outputIndent(w); |
| 418 | const builtin = @import("builtin"); |
| 419 | if (builtin.target.os.tag == .windows) { |
| 420 | try w.print("\"", .{}); |
| 421 | for (kv.key_ptr.*) |c| { |
| 422 | if (c == '\\') { |
| 423 | try w.print("\\\\", .{}); |
| 424 | } else { |
| 425 | try w.print("{c}", .{c}); |
| 426 | } |
| 434 | 427 | } |
| 428 | try w.print("\"", .{}); |
| 429 | try w.print(": {d}", .{ |
| 430 | kv.value_ptr.*, |
| 431 | }); |
| 432 | } else { |
| 433 | try w.print("\"{s}\": {d}", .{ |
| 434 | kv.key_ptr.*, |
| 435 | kv.value_ptr.*, |
| 436 | }); |
| 435 | 437 | } |
| 436 | | try w.print("\"", .{}); |
| 437 | | try w.print(": {d}", .{ |
| 438 | | kv.value_ptr.*, |
| 439 | | }); |
| 440 | | } else { |
| 441 | | try w.print("\"{s}\": {d}", .{ |
| 442 | | kv.key_ptr.*, |
| 443 | | kv.value_ptr.*, |
| 444 | | }); |
| 438 | if (idx != self.data.count() - 1) try w.writeByte(','); |
| 439 | try w.writeByte('\n'); |
| 445 | 440 | } |
| 446 | | if (idx != self.data.count() - 1) try w.writeByte(','); |
| 447 | | try w.writeByte('\n'); |
| 441 | if (opt.whitespace) |ws| try ws.outputIndent(w); |
| 442 | try w.writeAll("}"); |
| 448 | 443 | } |
| 449 | | if (opt.whitespace) |ws| try ws.outputIndent(w); |
| 450 | | try w.writeAll("}"); |
| 451 | | } |
| 452 | | }, |
| 444 | }, |
| 453 | 445 | }; |
| 454 | 446 | |
| 455 | 447 | const Decl = struct { |
| ... | ... | @@ -1035,15 +1027,59 @@ fn walkInstruction( |
| 1035 | 1027 | const path = str_tok.get(file.zir); |
| 1036 | 1028 | // importFile cannot error out since all files |
| 1037 | 1029 | // are already loaded at this point |
| 1038 | | if (file.pkg.table.get(path) != null) { |
| 1039 | | const cte_slot_index = self.comptime_exprs.items.len; |
| 1040 | | try self.comptime_exprs.append(self.arena, .{ |
| 1041 | | .code = path, |
| 1042 | | }); |
| 1043 | | return DocData.WalkResult{ |
| 1044 | | .typeRef = .{ .type = @enumToInt(Ref.type_type) }, |
| 1045 | | .expr = .{ .comptimeExpr = cte_slot_index }, |
| 1030 | if (file.pkg.table.get(path)) |other_package| { |
| 1031 | const result = try self.packages.getOrPut(self.arena, other_package); |
| 1032 | |
| 1033 | // Immediately add this package to the import table of our |
| 1034 | // current package, regardless of wether it's new or not. |
| 1035 | const current_package = self.packages.getPtr(file.pkg).?; |
| 1036 | _ = try current_package.table.data.getOrPutValue( |
| 1037 | self.arena, |
| 1038 | path, |
| 1039 | self.packages.getIndex(other_package).?, |
| 1040 | ); |
| 1041 | |
| 1042 | if (result.found_existing) { |
| 1043 | return DocData.WalkResult{ |
| 1044 | .typeRef = .{ .type = @enumToInt(Ref.type_type) }, |
| 1045 | .expr = .{ .type = result.value_ptr.main }, |
| 1046 | }; |
| 1047 | } |
| 1048 | |
| 1049 | // create a new package entry |
| 1050 | const main_type_index = self.types.items.len; |
| 1051 | result.value_ptr.* = .{ |
| 1052 | .name = path, |
| 1053 | .main = main_type_index, |
| 1054 | .table = .{ |
| 1055 | .data = std.StringHashMapUnmanaged(usize){}, |
| 1056 | }, |
| 1046 | 1057 | }; |
| 1058 | |
| 1059 | |
| 1060 | // TODO: Add this package as a dependency to the current pakcage |
| 1061 | // TODO: this seems something that could be done in bulk |
| 1062 | // at the beginning or the end, or something. |
| 1063 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 1064 | const dir = |
| 1065 | if (other_package.root_src_directory.path) |rp| |
| 1066 | std.os.realpath(rp, &buf) catch unreachable |
| 1067 | else |
| 1068 | std.os.getcwd(&buf) catch unreachable; |
| 1069 | const root_file_path = other_package.root_src_path; |
| 1070 | const abs_root_path = try std.fs.path.join(self.arena, &.{ dir, root_file_path }); |
| 1071 | defer self.arena.free(abs_root_path); |
| 1072 | const new_file = self.module.import_table.get(abs_root_path).?; |
| 1073 | |
| 1074 | var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index }; |
| 1075 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); |
| 1076 | try self.files.put(self.arena, new_file, main_type_index); |
| 1077 | return self.walkInstruction( |
| 1078 | new_file, |
| 1079 | &root_scope, |
| 1080 | Zir.main_struct_inst, |
| 1081 | false, |
| 1082 | ); |
| 1047 | 1083 | } |
| 1048 | 1084 | |
| 1049 | 1085 | const new_file = self.module.importFile(file, path) catch unreachable; |