╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ IncrementalDebugServer.zig ───────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
193 194 fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const u8) error{ WriteFailed, OutOfMemory }!void { 195 const ip = &zcu.intern_pool; 196 if (std.mem.eql(u8, cmd_str, "help")) { 197 try w.writeAll(help_str); 198 } else if (std.mem.eql(u8, cmd_str, "summary")) { 199 try w.print( 200 \\last generation: {d} 201 \\total container types: {d} 202 \\total NAVs: {d} 203 \\total units: {d} 204 \\ 205 , .{ 206 zcu.generation - 1, 207 zcu.incremental_debug_state.types.count(), 208 zcu.incremental_debug_state.navs.count(), 209 zcu.incremental_debug_state.units.count(), 210 }); 211 } else if (std.mem.eql(u8, cmd_str, "nav_info")) { 212 const nav_index: InternPool.Nav.Index = @fromBackingInt(@intCast(parseIndex(arg_str) orelse return w.writeAll("malformed nav index"))); 213 const create_gen = zcu.incremental_debug_state.navs.get(nav_index) orelse return w.writeAll("unknown nav index"); 214 const nav = ip.getNav(nav_index); 215 try w.print( 216 \\name: '{f}' 217 \\fqn: '{f}' 218 \\created on generation: {d} 219 \\ 220 , .{ 221 nav.name.fmt(ip), 222 nav.fqn.fmt(ip), 223 create_gen, 224 }); 225 if (nav.resolved) |r| { 226 try w.writeAll("status: resolved\n type: "); 227 try printType(.fromInterned(r.type), zcu, w); 228 try w.writeAll("\n value: "); 229 if (r.value == .none) { 230 try w.writeAll("(unresolved)"); 231 } else { 232 try printType(.fromInterned(r.type), zcu, w); 233 } 234 try w.writeByte('\n'); 235 } else { 236 try w.writeAll("status: unresolved\n"); 237 } 238 } else if (std.mem.eql(u8, cmd_str, "find_type")) { 239 if (arg_str.len == 0) return w.writeAll("bad usage"); 240 const anchor_start = arg_str[0] == '^'; 241 const anchor_end = arg_str[arg_str.len - 1] == '$'; 242 const query = arg_str[@intFromBool(anchor_start) .. arg_str.len - @intFromBool(anchor_end)]; 243 var num_results: usize = 0; 244 for (zcu.incremental_debug_state.types.keys()) |type_ip_index| { 245 const ty: Type = .fromInterned(type_ip_index); 246 const ty_name = ty.containerTypeName(ip).fqn.toSlice(ip); 247 const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) { 248 0b00 => std.mem.find(u8, ty_name, query) != null, 249 0b01 => std.mem.endsWith(u8, ty_name, query), 250 0b10 => std.mem.startsWith(u8, ty_name, query), 251 0b11 => std.mem.eql(u8, ty_name, query), 252 }; 253 if (success) { 254 num_results += 1; 255 try w.print("* type {d} ('{s}')\n", .{ @backingInt(type_ip_index), ty_name }); 256 } 257 } 258 try w.print("Found {d} results\n", .{num_results}); 259 } else if (std.mem.eql(u8, cmd_str, "find_nav")) { 260 if (arg_str.len == 0) return w.writeAll("bad usage"); 261 const anchor_start = arg_str[0] == '^'; 262 const anchor_end = arg_str[arg_str.len - 1] == '$'; 263 const query = arg_str[@intFromBool(anchor_start) .. arg_str.len - @intFromBool(anchor_end)]; 264 var num_results: usize = 0; 265 for (zcu.incremental_debug_state.navs.keys()) |nav_index| { 266 const nav = ip.getNav(nav_index); 267 const nav_fqn = nav.fqn.toSlice(ip); 268 const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) { 269 0b00 => std.mem.find(u8, nav_fqn, query) != null, 270 0b01 => std.mem.endsWith(u8, nav_fqn, query), 271 0b10 => std.mem.startsWith(u8, nav_fqn, query), 272 0b11 => std.mem.eql(u8, nav_fqn, query), 273 }; 274 if (success) { 275 num_results += 1; 276 try w.print("* nav {d} ('{s}')\n", .{ @backingInt(nav_index), nav_fqn }); 277 } 278 } 279 try w.print("Found {d} results\n", .{num_results}); 280 } else if (std.mem.eql(u8, cmd_str, "unit_info")) { 281 const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); 282 const unit_info = zcu.incremental_debug_state.units.get(unit) orelse return w.writeAll("unknown anal unit"); 283 var ref_str_buf: [32]u8 = undefined; 284 const ref_str: []const u8 = ref: { 285 const refs = try zcu.resolveReferences(); 286 const ref = refs.get(unit) orelse break :ref "<unreferenced>"; 287 const referencer = (ref orelse break :ref "<analysis root>").referencer; 288 break :ref printAnalUnit(referencer, &ref_str_buf); 289 }; 290 try w.print( 291 \\last update generation: {d} 292 \\current referencer: {s} 293 \\ 294 , .{ 295 unit_info.last_update_gen, 296 ref_str, 297 }); 298 if (zcu.failed_analysis.get(unit)) |err_msg| { 299 try w.print("analysis result: failure ({q})\n", .{err_msg.msg}); 300 } else if (zcu.transitive_failed_analysis.get(unit)) |reason| { 301 switch (reason) { 302 .astgen_error => try w.writeAll("analysis result: transitive failure (astgen error)\n"), 303 .dependency_loop => try w.writeAll("analysis result: transitive failure (dependency loop)\n"), 304 .lost_tracking => try w.writeAll("analysis result: transitive failure (lost tracking for zir inst)\n"), 305 .failed_unit => |other_unit| { 306 var buf: [32]u8 = undefined; 307 try w.print("analysis result: transitive failure (failed unit: {s})\n", .{printAnalUnit(other_unit, &buf)}); 308 }, 309 .func_nav_val_changed => |func_index| try w.print("analysis result: transitive failure (owner nav of func '{d}' changed value)\n", .{@backingInt(func_index)}), 310 } 311 } else { 312 try w.writeAll("analysis result: success\n"); 313 } 314 if (unit.unwrap() == .func) { 315 const nav_id = zcu.intern_pool.indexToKey(unit.unwrap().func).func.owner_nav; 316 try w.print("owner nav: {d}\n", .{@backingInt(nav_id)}); 317 } 318 } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) { 319 const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); 320 const unit_info = zcu.incremental_debug_state.units.get(unit) orelse return w.writeAll("unknown anal unit"); 321 for (unit_info.deps.items, 0..) |dependee, i| { 322 try w.print("[{d}] ", .{i}); 323 switch (dependee) { 324 .src_hash, .namespace, .namespace_name, .source_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), 325 .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @backingInt(nav) }), 326 .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @backingInt(ip_index) }), 327 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), 328 } 329 try w.writeByte('\n'); 330 } 331 } else if (std.mem.eql(u8, cmd_str, "unit_trace")) { 332 const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); 333 if (!zcu.incremental_debug_state.units.contains(unit)) return w.writeAll("unknown anal unit"); 334 const refs = try zcu.resolveReferences(); 335 if (!refs.contains(unit)) return w.writeAll("not referenced"); 336 var opt_cur: ?AnalUnit = unit; 337 while (opt_cur) |cur| { 338 var buf: [32]u8 = undefined; 339 try w.print("* {s}\n", .{printAnalUnit(cur, &buf)}); 340 opt_cur = if (refs.get(cur).?) |ref| ref.referencer else null; 341 } 342 } else if (std.mem.eql(u8, cmd_str, "type_info")) { 343 const ip_index: InternPool.Index = @fromBackingInt(@intCast(parseIndex(arg_str) orelse return w.writeAll("malformed ip index"))); 344 const create_gen = zcu.incremental_debug_state.types.get(ip_index) orelse return w.writeAll("unknown type"); 345 try w.print( 346 \\name: '{f}' 347 \\created on generation: {d} 348 \\ 349 , .{ 350 Type.fromInterned(ip_index).containerTypeName(ip).fqn.fmt(ip), 351 create_gen, 352 }); 353 } else if (std.mem.eql(u8, cmd_str, "type_namespace")) { 354 const ip_index: InternPool.Index = @fromBackingInt(@intCast(parseIndex(arg_str) orelse return w.writeAll("malformed ip index"))); 355 if (!zcu.incremental_debug_state.types.contains(ip_index)) return w.writeAll("unknown type"); 356 const ns = zcu.namespacePtr(Type.fromInterned(ip_index).getNamespaceIndex(zcu)); 357 try w.print("{d} pub decls:\n", .{ns.pub_decls.count()}); 358 for (ns.pub_decls.keys()) |nav| { 359 try w.print("* nav {d}\n", .{@backingInt(nav)}); 360 } 361 try w.print("{d} non-pub decls:\n", .{ns.priv_decls.count()}); 362 for (ns.priv_decls.keys()) |nav| { 363 try w.print("* nav {d}\n", .{@backingInt(nav)}); 364 } 365 try w.print("{d} comptime decls:\n", .{ns.comptime_decls.items.len}); 366 for (ns.comptime_decls.items) |id| { 367 try w.print("* comptime {d}\n", .{@backingInt(id)}); 368 } 369 try w.print("{d} tests:\n", .{ns.test_decls.items.len}); 370 for (ns.test_decls.items) |nav| { 371 try w.print("* nav {d}\n", .{@backingInt(nav)}); 372 } 373 } else { 374 try w.writeAll("command not found; run 'help' for a command list"); 375 } 376 } 377 378 fn parseIndex(str: []const u8) ?u32 { 379 return std.fmt.parseInt(u32, str, 10) catch null; 380 } 381 fn parseAnalUnit(str: []const u8) ?AnalUnit { 382 const split_idx = std.mem.findScalar(u8, str, ' ') orelse return null; 383 const kind = str[0..split_idx]; 384 const idx_str = str[split_idx + 1 ..]; 385 if (std.mem.eql(u8, kind, "comptime")) { 386 return .wrap(.{ .@"comptime" = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 387 } else if (std.mem.eql(u8, kind, "nav_val")) { 388 return .wrap(.{ .nav_val = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 389 } else if (std.mem.eql(u8, kind, "nav_ty")) { 390 return .wrap(.{ .nav_ty = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 391 } else if (std.mem.eql(u8, kind, "type_layout")) { 392 return .wrap(.{ .type_layout = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 393 } else if (std.mem.eql(u8, kind, "struct_defaults")) { 394 return .wrap(.{ .struct_defaults = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 395 } else if (std.mem.eql(u8, kind, "func")) { 396 return .wrap(.{ .func = @fromBackingInt(@intCast(parseIndex(idx_str) orelse return null)) }); 397 } else if (std.mem.eql(u8, kind, "memoized_state")) { 398 return .wrap(.{ .memoized_state = std.meta.stringToEnum( 399 InternPool.MemoizedStateStage, 400 idx_str, 401 ) orelse return null }); 402 } else { 403 return null; 404 } 405 } 406 fn printAnalUnit(unit: AnalUnit, buf: *[32]u8) []const u8 { 407 const idx: u32 = switch (unit.unwrap()) { 408 .memoized_state => |stage| return std.mem.print(buf, "memoized_state {s}", .{@tagName(stage)}) catch unreachable, 409 inline else => |i| @backingInt(i), 410 }; 411 return std.mem.print(buf, "{s} {d}", .{ @tagName(unit.unwrap()), idx }) catch unreachable; 412 } 413 414 fn printType(ty: Type, zcu: *const Zcu, w: *Io.Writer) Io.Writer.Error!void { 415 const ip = &zcu.intern_pool; 416 switch (ip.indexToKey(ty.toIntern())) { 417 .int_type => |int| try w.print("{c}{d}", .{ 418 @as(u8, if (int.signedness == .unsigned) 'u' else 'i'), 419 int.bits, 420 }), 421 .tuple_type => try w.writeAll("(tuple)"), 422 .error_set_type => try w.writeAll("(error set)"), 423 .inferred_error_set_type => try w.writeAll("(inferred error set)"), 424 .func_type => try w.writeAll("(function)"), 425 .anyframe_type => try w.writeAll("(anyframe)"), 426 .vector_type => { 427 try w.print("@Vector({d}, ", .{ty.vectorLen(zcu)}); 428 try printType(ty.childType(zcu), zcu, w); 429 try w.writeByte(')'); 430 }, 431 .array_type => { 432 try w.print("[{d}]", .{ty.arrayLen(zcu)}); 433 try printType(ty.childType(zcu), zcu, w); 434 }, 435 .opt_type => { 436 try w.writeByte('?'); 437 try printType(ty.optionalChild(zcu), zcu, w); 438 }, 439 .error_union_type => { 440 try printType(ty.errorUnionSet(zcu), zcu, w); 441 try w.writeByte('!'); 442 try printType(ty.errorUnionPayload(zcu), zcu, w); 443 }, 444 .ptr_type => { 445 try w.writeAll("*(attrs) "); 446 try printType(ty.childType(zcu), zcu, w); 447 }, 448 .simple_type => |simple| try w.writeAll(@tagName(simple)), 449 450 .struct_type, 451 .union_type, 452 .enum_type, 453 .opaque_type, 454 => try w.print("{f}[{d}]", .{ ty.containerTypeName(ip).fqn.fmt(ip), @backingInt(ty.toIntern()) }), 455 456 else => unreachable, 457 } 458 } 459 460 const std = @import("std"); 461 const Io = std.Io; 462 const Allocator = std.mem.Allocator; 463 const log = std.log.scoped(.incremental_debug_server); 464 465 const Compilation = @import("Compilation.zig"); 466 const Zcu = @import("Zcu.zig"); 467 const InternPool = @import("InternPool.zig"); 468 const Type = @import("Type.zig"); 469 const AnalUnit = InternPool.AnalUnit; 470 471 const IncrementalDebugServer = @This(); 472