debug.zig (6261B)
1 const std = @import("std"); 2 3 const value = @import("value.zig"); 4 5 const Obj = @import("gc.zig").GC.Obj; 6 const Error = Obj.Error; 7 const OP = @import("op.zig").OP; 8 const Compiler = @import("vm.zig").VM.Compiler; 9 const print = std.debug.print; 10 11 pub fn disassembleChunk(ch: *const Obj.Chunk) Error!void { 12 print("/=======\\\n", .{}); 13 14 var offset: usize = 0; 15 16 while (offset < ch.code.ptr().len) { 17 offset = try _disassembleInstruction(ch, offset, true); 18 } 19 print("\\=======/\n", .{}); 20 } 21 22 pub fn print_offset(ch: *const Obj.Chunk, offset: usize) !void { 23 print("{d:0>4} ", .{offset}); 24 const line = ch.lines.ptr().get(offset).?; 25 if (offset > 0 and line == ch.lines.ptr().get(offset - 1).?) { 26 print(" | ", .{}); 27 } else { 28 print("{d:4} ", .{line}); 29 } 30 } 31 32 pub fn disassembleInstruction(ch: *const Obj.Chunk, offset: usize) Error!usize { 33 return _disassembleInstruction(ch, offset, false); 34 } 35 36 fn _disassembleInstruction(ch: *const Obj.Chunk, offset: usize, print_fn: bool) Error!usize { 37 try print_offset(ch, offset); 38 39 const op = ch.code.ptr().get(offset).?; 40 const name = @tagName(@as(OP, @enumFromInt(op))); 41 42 return switch (op) { 43 @intFromEnum(OP.RETURN) => simpleInstruction(name, offset), 44 @intFromEnum(OP.NEGATE) => simpleInstruction(name, offset), 45 @intFromEnum(OP.ADD) => simpleInstruction(name, offset), 46 @intFromEnum(OP.SUBTRACT) => simpleInstruction(name, offset), 47 @intFromEnum(OP.DIVIDE) => simpleInstruction(name, offset), 48 @intFromEnum(OP.MULTIPLY) => simpleInstruction(name, offset), 49 @intFromEnum(OP.TRUE) => simpleInstruction(name, offset), 50 @intFromEnum(OP.FALSE) => simpleInstruction(name, offset), 51 @intFromEnum(OP.EQUAL) => simpleInstruction(name, offset), 52 @intFromEnum(OP.LESS) => simpleInstruction(name, offset), 53 @intFromEnum(OP.GREATER) => simpleInstruction(name, offset), 54 @intFromEnum(OP.NIL) => simpleInstruction(name, offset), 55 @intFromEnum(OP.NOT) => simpleInstruction(name, offset), 56 @intFromEnum(OP.CONSTANT) => try constantInstruction(name, ch, offset, print_fn), 57 @intFromEnum(OP.DEFINE_GLOBAL) => try constantInstruction(name, ch, offset, print_fn), 58 @intFromEnum(OP.METHOD) => try constantInstruction(name, ch, offset, print_fn) + 1, 59 @intFromEnum(OP.DEFINE_GLOBAL_CONSTANT) => try constantInstruction(name, ch, offset, print_fn), 60 @intFromEnum(OP.GET_GLOBAL) => try constantInstruction(name, ch, offset, print_fn), 61 @intFromEnum(OP.SET_GLOBAL) => try constantInstruction(name, ch, offset, print_fn), 62 @intFromEnum(OP.PRINT) => simpleInstruction(name, offset), 63 @intFromEnum(OP.POP) => simpleInstruction(name, offset), 64 @intFromEnum(OP.GET_LOCAL) => try byteInstruction(name, ch, offset), 65 @intFromEnum(OP.SET_LOCAL) => try byteInstruction(name, ch, offset), 66 @intFromEnum(OP.GET_UPVALUE) => try byteInstruction(name, ch, offset), 67 @intFromEnum(OP.SET_UPVALUE) => try byteInstruction(name, ch, offset), 68 @intFromEnum(OP.GET_PROPERTY) => try byteInstruction(name, ch, offset), 69 @intFromEnum(OP.SET_PROPERTY) => try byteInstruction(name, ch, offset), 70 @intFromEnum(OP.GET_SUPER) => try constantInstruction(name, ch, offset, print_fn), 71 @intFromEnum(OP.JUMP_IF_FALSE) => try jumpInstruction(name, true, ch, offset), 72 @intFromEnum(OP.JUMP_POP) => simpleInstruction(name, offset), 73 @intFromEnum(OP.JUMP) => try jumpInstruction(name, true, ch, offset), 74 @intFromEnum(OP.LOOP) => try jumpInstruction(name, false, ch, offset), 75 @intFromEnum(OP.SET_INDEX) => simpleInstruction(name, offset), 76 @intFromEnum(OP.GET_INDEX) => simpleInstruction(name, offset), 77 @intFromEnum(OP.CALL) => try byteInstruction(name, ch, offset), 78 @intFromEnum(OP.CLOSURE) => try closureInstruction(name, ch, offset), 79 @intFromEnum(OP.CLOSE_UPVALUE) => simpleInstruction(name, offset), 80 @intFromEnum(OP.INHERIT) => simpleInstruction(name, offset), 81 else => blk: { 82 print("Unknown opcode {d} {s}\n", .{ op, name }); 83 break :blk offset + 1; 84 }, 85 }; 86 } 87 88 fn simpleInstruction(name: []const u8, offset: usize) usize { 89 print("{s}\n", .{name}); 90 return offset + 1; 91 } 92 93 fn constantInstruction(name: []const u8, ch: *const Obj.Chunk, offset: usize, print_fn: bool) Error!usize { 94 const constant = ch.code.ptr().get(offset + 1).?; 95 const constval = ch.constants.ptr().get(constant).?; 96 print("{s:<32} {d:4} '{f}'\n", .{ name, constant, constval }); 97 if (print_fn) { 98 if (constval.cast_if(Obj.Type.Function)) |function| { 99 try disassembleChunk(function.chunk.ptr()); 100 } else if (constval.cast_if(Obj.Type.Chunk)) |chunk| { 101 try disassembleChunk(chunk); 102 } 103 } 104 return offset + 2; 105 } 106 107 fn byteInstruction(name: []const u8, ch: *const Obj.Chunk, offset: usize) Error!usize { 108 print("{s:<32} {d:4}\n", .{ name, ch.code.ptr().get(offset + 1).? }); 109 return offset + 2; 110 } 111 112 fn jumpInstruction(name: []const u8, sign: bool, ch: *const Obj.Chunk, offset: usize) !usize { 113 const msb: u16 = ch.code.ptr().get(offset + 1).?; 114 const lsb: u16 = ch.code.ptr().get(offset + 2).?; 115 const jump = (msb << 8) | lsb; 116 117 print("{s:<32} {d:4} -> {d}\n", .{ name, offset, if (sign) offset + 3 + jump else offset + 3 - jump }); 118 return offset + 3; 119 } 120 121 fn closureInstruction(name: []const u8, ch: *const Obj.Chunk, offset: usize) Error!usize { 122 var off = offset + 1; 123 const constant = ch.code.ptr().get(off).?; 124 const arity = ch.code.ptr().get(off + 1).?; 125 const count = ch.code.ptr().get(off + 2).?; 126 off += 3; 127 128 const constval = ch.constants.ptr().get(constant).?; 129 const chunk = try constval.obj.cast(.Chunk); 130 131 print("{s:<32} {d:4} {d}\n", .{ name, arity, count }); 132 for (0..count) |_| { 133 const tp = ch.code.ptr().get(off).?; 134 const idx = ch.code.ptr().get(off + 1).?; 135 try print_offset(ch, off + 1); 136 print("{s:<38}|-> {s} {d}\n", .{ "", @tagName(@as(Compiler.Upvalue.Type, @enumFromInt(tp))), idx }); 137 off += 2; 138 } 139 140 try disassembleChunk(chunk); 141 142 return off + 1; 143 }