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