From 517eae148163b8ea4535d4b134153358afd29571 Mon Sep 17 00:00:00 2001 From: Brett Broadhurst Date: Wed, 18 Mar 2026 01:37:42 -0600 Subject: [PATCH] refactor: clean up ir print writer --- src/Ir.zig | 387 +---------------------------------------------- src/Story.zig | 2 +- src/print_ir.zig | 314 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+), 384 deletions(-) create mode 100644 src/print_ir.zig diff --git a/src/Ir.zig b/src/Ir.zig index 1cbc7fd..52452bf 100644 --- a/src/Ir.zig +++ b/src/Ir.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Ast = @import("Ast.zig"); +const Writer = @import("print_ir.zig").Writer; const assert = std.debug.assert; const Ir = @This(); @@ -205,390 +206,10 @@ pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void { ir.* = undefined; } -const Render = struct { - gpa: std.mem.Allocator, - prefix: Prefix, - code: Ir, - writer: *std.Io.Writer, - - pub const Error = error{ - OutOfMemory, - WriteFailed, - }; - - const Prefix = struct { - buf: std.ArrayListUnmanaged(u8) = .empty, - - pub fn deinit(self: *Prefix, gpa: std.mem.Allocator) void { - self.buf.deinit(gpa); - } - - pub fn writeIndent(self: *const Prefix, writer: *std.Io.Writer) !void { - try writer.writeAll(self.buf.items); - } - - pub fn pushChildPrefix(self: *Prefix, gpa: std.mem.Allocator) !usize { - const old_len = self.buf.items.len; - const seg: []const u8 = " "; - try self.buf.appendSlice(gpa, seg); - return old_len; - } - - pub fn restore(self: *Prefix, new_len: usize) void { - self.buf.shrinkRetainingCapacity(new_len); - } - }; - - fn renderInstIndex(r: *Render, index: Inst.Index) !void { - const io_w = r.writer; - return io_w.print("%{d}", .{@intFromEnum(index)}); - } - - fn renderInstRef(r: *Render, ref: Inst.Ref) !void { - const io_w = r.writer; - if (ref == .none) { - return io_w.writeAll(".none"); - } else if (ref.toIndex()) |i| { - return r.renderInstIndex(i); - } else { - return io_w.print("@{s}", .{@tagName(ref)}); - } - } - - fn renderSimple(r: *Render, inst: Inst) Error!void { - const io_w = r.writer; - return io_w.print("{s}(?)", .{@tagName(inst.tag)}); - } - - fn renderUnary(r: *Render, inst: Inst) Error!void { - const io_w = r.writer; - const data = inst.data.un; - try io_w.print("{s}(", .{@tagName(inst.tag)}); - - const lhs = data.lhs; - try renderInstRef(r, lhs); - return io_w.writeAll(")"); - } - - fn renderBinary(r: *Render, inst: Inst) Error!void { - const io_w = r.writer; - const data = inst.data.bin; - try io_w.print("{s}(", .{@tagName(inst.tag)}); - try renderInstRef(r, data.lhs); - try io_w.writeAll(", "); - try renderInstRef(r, data.rhs); - return io_w.writeAll(")"); - } - - fn renderBodyInner(r: *Render, ir: Ir, body_list: []const Inst.Index) Error!void { - const io_w = r.writer; - try r.prefix.writeIndent(io_w); - try io_w.writeAll("{\n"); - { - const old_len = try r.prefix.pushChildPrefix(r.gpa); - defer r.prefix.restore(old_len); - - for (body_list) |inst| try r.renderInst(ir, inst); - } - try r.prefix.writeIndent(io_w); - try io_w.writeAll("}"); - } - - fn renderBlock(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Block, inst.data.payload.payload_index); - const body_slice = ir.bodySlice(extra.end, extra.data.body_len); - - try io_w.print("{s}(", .{@tagName(inst.tag)}); - try renderBodyInner(r, ir, body_slice); - try io_w.writeAll(")"); - } - - fn renderBreak(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Break, inst.data.payload.payload_index); - - try io_w.print("{s}(%{d})", .{ @tagName(inst.tag), extra.data.block_inst }); - } - - fn renderCondbr(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.CondBr, inst.data.payload.payload_index); - const then_body = ir.bodySlice(extra.end, extra.data.then_body_len); - const else_body = ir.bodySlice(extra.end + then_body.len, extra.data.else_body_len); - - try io_w.print("{s}(", .{@tagName(inst.tag)}); - try renderInstRef(r, extra.data.condition); - try io_w.writeAll(", "); - try renderBodyInner(r, ir, then_body); - try io_w.writeAll(", "); - try renderBodyInner(r, ir, else_body); - try io_w.writeAll(")"); - } - - fn renderSwitchBr(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const switch_node = inst.data.payload; - const switch_extra = ir.extraData(Inst.SwitchBr, switch_node.payload_index); - const cases_slice = ir.bodySlice(switch_extra.end, switch_extra.data.cases_len); - - try io_w.print("{s}(", .{@tagName(inst.tag)}); - try renderInstRef(r, switch_extra.data.operand); - try io_w.print(", \n", .{}); - for (cases_slice) |case_index| { - const case_extra = ir.extraData(Inst.SwitchBr.Case, @intFromEnum(case_index)); - const body_slice = ir.bodySlice(case_extra.end, case_extra.data.body_len); - const old_len = try r.prefix.pushChildPrefix(r.gpa); - defer r.prefix.restore(old_len); - - try r.prefix.writeIndent(io_w); - try renderInstRef(r, case_extra.data.operand); - try io_w.print(" = ", .{}); - try renderBodyInner(r, ir, body_slice); - try io_w.writeAll(",\n"); - } - - const else_body = ir.bodySlice( - switch_extra.end + switch_extra.data.cases_len, - switch_extra.data.else_body_len, - ); - { - const old_len = try r.prefix.pushChildPrefix(r.gpa); - defer r.prefix.restore(old_len); - - try r.prefix.writeIndent(io_w); - try io_w.print("else = ", .{}); - try renderBodyInner(r, ir, else_body); - } - try io_w.writeAll(")"); - } - - fn renderChoiceBr(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const data = inst.data.payload; - const choice_extra = ir.extraData(Inst.ChoiceBr, data.payload_index); - const options_slice = ir.bodySlice(choice_extra.end, choice_extra.data.cases_len); - - try io_w.print("{s}(\n", .{@tagName(inst.tag)}); - - for (options_slice) |option_index| { - const case_extra = ir.extraData(Inst.ChoiceBr.Case, @intFromEnum(option_index)); - const body_slice = ir.bodySlice(case_extra.end, case_extra.data.body_len); - const old_len = try r.prefix.pushChildPrefix(r.gpa); - defer r.prefix.restore(old_len); - - try r.prefix.writeIndent(io_w); - try renderInstRef(r, case_extra.data.operand_1); - try io_w.writeAll(", "); - try renderInstRef(r, case_extra.data.operand_2); - try io_w.writeAll(", "); - try renderInstRef(r, case_extra.data.operand_3); - - try io_w.print(" = ", .{}); - try renderBodyInner(r, ir, body_slice); - try io_w.writeAll(",\n"); - } - try r.prefix.writeIndent(io_w); - try io_w.writeAll(")"); - } - - fn renderKnotDecl(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Knot, inst.data.payload.payload_index); - const body_slice = ir.bodySlice(extra.end, extra.data.body_len); - - try io_w.print("{s}(body=", .{@tagName(inst.tag)}); - try renderBodyInner(r, ir, body_slice); - try io_w.writeAll(")"); - } - - fn renderVarDecl(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Knot, inst.data.payload.payload_index); - const body_slice = ir.bodySlice(extra.end, extra.data.body_len); - - try io_w.print("{s}(body=", .{@tagName(inst.tag)}); - try renderBodyInner(r, ir, body_slice); - try io_w.writeAll(")"); - } - - fn renderDeclaration(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Declaration, inst.data.payload.payload_index); - const ident_str = ir.nullTerminatedString(extra.data.name); - - try io_w.print("{s}(name=\"{s}\", value={{\n", .{ @tagName(inst.tag), ident_str }); - { - const old_len = try r.prefix.pushChildPrefix(r.gpa); - defer r.prefix.restore(old_len); - try renderInst(r, ir, extra.data.value); - } - try r.prefix.writeIndent(io_w); - return io_w.writeAll(")"); - } - - fn renderFile(r: *Render, ir: Ir, inst: Inst) Error!void { - const io_w = r.writer; - const extra = ir.extraData(Inst.Block, inst.data.payload.payload_index); - const body_slice = ir.bodySlice(extra.end, extra.data.body_len); - - try io_w.print("{s}(", .{@tagName(inst.tag)}); - try renderBodyInner(r, ir, body_slice); - return io_w.writeAll(")"); - } - - fn writeTag(_: *Render, w: *std.Io.Writer, inst: Ir.Inst) Error!void { - return w.print("{s}", .{@tagName(inst.tag)}); - } - - fn writeIndent(self: *Render, w: *std.Io.Writer) Error!void { - return self.prefix.writeIndent(w); - } - - fn writeString(self: *Render, w: *std.Io.Writer, str: Ir.NullTerminatedString) Error!void { - return w.print("\"{s}\"", .{self.code.nullTerminatedString(str)}); - } - - fn writeFieldPtr(self: *Render, w: *std.Io.Writer, inst: Ir.Inst) Error!void { - const data = inst.data.payload; - const extra = self.code.extraData(Inst.Field, data.payload_index).data; - - try self.writeTag(w, inst); - try w.writeAll("("); - try self.renderInstRef(extra.lhs); - try w.writeAll(", "); - try self.writeString(w, extra.field_name_start); - return w.writeAll(")"); - } - - fn writeCall( - self: *Render, - w: *std.Io.Writer, - inst: Ir.Inst, - comptime kind: enum { - field, - direct, - }, - ) Error!void { - const ExtraType = switch (kind) { - .direct => Ir.Inst.Call, - .field => Ir.Inst.FieldCall, - }; - const data = inst.data.payload; - const extra = self.code.extraData(ExtraType, data.payload_index); - const args_len = extra.data.args_len; - const body = self.code.extra[extra.end..]; - - try self.writeTag(w, inst); - try w.writeAll("("); - - switch (kind) { - .direct => try self.renderInstRef(extra.data.callee), - .field => { - try self.renderInstRef(extra.data.obj_ptr); - try w.writeAll(", "); - try self.writeString(w, extra.data.field_name_start); - }, - } - try w.writeAll(", "); - try w.writeAll("[\n"); - - var arg_start: u32 = args_len; - var i: u32 = 0; - while (i < args_len) : (i += 1) { - const old_len = try self.prefix.pushChildPrefix(self.gpa); - defer self.prefix.restore(old_len); - - const arg_end = self.code.extra[extra.end + i]; - defer arg_start = arg_end; - const arg_body = body[arg_start..arg_end]; - try self.renderBodyInner(self.code, @ptrCast(arg_body)); - try w.writeAll(",\n"); - } - - try self.writeIndent(w); - try w.writeAll("]"); - return w.writeAll(")"); - } - - fn writeParam(self: *Render, w: *std.Io.Writer, inst: Ir.Inst) Error!void { - const data = inst.data.string.start; - try self.writeTag(w, inst); - try w.writeAll("("); - try self.writeString(w, data); - return w.writeAll(")"); - } - - fn renderInst(r: *Render, ir: Ir, index: Inst.Index) Error!void { - const io_w = r.writer; - const inst_index: u32 = @intFromEnum(index); - const inst = ir.instructions[inst_index]; - - try r.prefix.writeIndent(io_w); - try io_w.print("%{d} = ", .{inst_index}); - switch (inst.tag) { - .file => try r.renderFile(ir, inst), - .declaration => try r.renderDeclaration(ir, inst), - .decl_knot => try r.renderKnotDecl(ir, inst), - .decl_var => try r.renderVarDecl(ir, inst), - .decl_ref => { - const str_bytes = inst.data.string.get(ir); - try io_w.print("{s}(\"{s}\")", .{ @tagName(inst.tag), str_bytes }); - }, - .condbr => try r.renderCondbr(ir, inst), - .@"break" => try r.renderBreak(ir, inst), - .switch_br => try r.renderSwitchBr(ir, inst), - .alloc => try r.renderSimple(inst), - .load => try r.renderUnary(inst), - .store => try r.renderBinary(inst), - .block => try r.renderBlock(ir, inst), - .add => try r.renderBinary(inst), - .sub => try r.renderBinary(inst), - .mul => try r.renderBinary(inst), - .div => try r.renderBinary(inst), - .mod => try r.renderBinary(inst), - .neg => try r.renderUnary(inst), - .not => try r.renderUnary(inst), - .cmp_eq => try r.renderBinary(inst), - .cmp_neq => try r.renderBinary(inst), - .cmp_gt => try r.renderBinary(inst), - .cmp_gte => try r.renderBinary(inst), - .cmp_lt => try r.renderBinary(inst), - .cmp_lte => try r.renderBinary(inst), - .integer => { - const value = inst.data.integer.value; - try io_w.print("{s}({d})", .{ @tagName(inst.tag), value }); - }, - .string => { - const str_bytes = inst.data.string.get(ir); - try io_w.print("{s}(\"{s}\")", .{ @tagName(inst.tag), str_bytes }); - }, - .content_push => try r.renderUnary(inst), - .content_flush => try r.renderUnary(inst), - .choice_br => try r.renderChoiceBr(ir, inst), - .implicit_ret => try r.renderUnary(inst), - .call => try r.writeCall(r.writer, inst, .direct), - .divert => try r.writeCall(r.writer, inst, .direct), - .field_call => try r.writeCall(r.writer, inst, .field), - .field_divert => try r.writeCall(r.writer, inst, .field), - .field_ptr => try r.writeFieldPtr(r.writer, inst), - .param => try r.writeParam(r.writer, inst), - } - try io_w.writeAll("\n"); - } -}; - -pub fn render(ir: Ir, gpa: std.mem.Allocator, writer: *std.Io.Writer) !void { +pub fn render(ir: Ir, writer: *std.Io.Writer) !void { assert(ir.instructions.len > 0); - var r = Render{ - .gpa = gpa, - .writer = writer, - .prefix = .{}, - .code = ir, - }; - defer r.prefix.deinit(gpa); - - try r.renderInst(ir, @enumFromInt(0)); + var w: Writer = .{ .code = ir }; + try w.writeInst(writer, .file_inst); return writer.flush(); } diff --git a/src/Story.zig b/src/Story.zig index e563383..ef27685 100644 --- a/src/Story.zig +++ b/src/Story.zig @@ -572,7 +572,7 @@ pub fn loadFromString( if (options.dump_writer) |w| { try w.writeAll("=== Semantic IR ===\n"); try sem_ir.dumpInfo(w); - try sem_ir.render(gpa, w); + try sem_ir.render(w); } } diff --git a/src/print_ir.zig b/src/print_ir.zig new file mode 100644 index 0000000..467f7f1 --- /dev/null +++ b/src/print_ir.zig @@ -0,0 +1,314 @@ +const std = @import("std"); +const Ir = @import("Ir.zig"); + +pub const Writer = struct { + code: Ir, + indent_level: usize = 0, + indent_size: usize = 2, + + pub const Error = error{ + OutOfMemory, + WriteFailed, + }; + + fn writeIndent(self: *Writer, w: *std.Io.Writer) Error!void { + try w.splatByteAll(' ', self.indent_level); + } + + fn pushIndent(self: *Writer) void { + self.indent_level += self.indent_size; + } + + fn popIndent(self: *Writer) void { + if (self.indent_level >= self.indent_size) { + self.indent_level -= self.indent_size; + } + } + + fn writeTag(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)]; + try w.print("{s}", .{@tagName(data.tag)}); + } + + fn writeStringRef(self: *Writer, w: *std.Io.Writer, str: Ir.NullTerminatedString) Error!void { + try w.print("\"{s}\"", .{self.code.nullTerminatedString(str)}); + } + + fn writeInstIndex(_: *Writer, w: *std.Io.Writer, index: Ir.Inst.Index) !void { + try w.print("%{d}", .{@intFromEnum(index)}); + } + + fn writeInstRef(self: *Writer, w: *std.Io.Writer, ref: Ir.Inst.Ref) !void { + if (ref == .none) { + return w.writeAll(".none"); + } else if (ref.toIndex()) |index| { + return self.writeInstIndex(w, index); + } else { + return w.print("@{s}", .{@tagName(ref)}); + } + } + + fn writeIntegerInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.integer; + try w.print("{d}", .{data.value}); + } + + fn writeStringInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.string; + try self.writeStringRef(w, data.start); + } + + fn writeUnaryInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.un; + try self.writeInstRef(w, data.lhs); + } + + fn writeBinaryInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.bin; + try self.writeInstRef(w, data.lhs); + try w.writeAll(", "); + try self.writeInstRef(w, data.rhs); + } + + fn writeFieldPtrInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Field, data.payload_index).data; + try self.writeInstRef(w, extra.lhs); + try w.writeAll(", "); + try self.writeStringRef(w, extra.field_name_start); + } + + fn writeCallInst( + self: *Writer, + w: *std.Io.Writer, + inst: Ir.Inst.Index, + comptime kind: enum { + field, + direct, + }, + ) Error!void { + const ExtraType = switch (kind) { + .direct => Ir.Inst.Call, + .field => Ir.Inst.FieldCall, + }; + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(ExtraType, data.payload_index); + const args_len = extra.data.args_len; + const body = self.code.extra[extra.end..]; + + switch (kind) { + .direct => try self.writeInstRef(w, extra.data.callee), + .field => { + try self.writeInstRef(w, extra.data.obj_ptr); + try w.writeAll(", "); + try self.writeStringRef(w, extra.data.field_name_start); + }, + } + try w.writeAll(", "); + try w.writeAll("[\n"); + + var arg_start: u32 = args_len; + var i: u32 = 0; + while (i < args_len) : (i += 1) { + self.pushIndent(); + const arg_end = self.code.extra[extra.end + i]; + defer arg_start = arg_end; + const arg_body = body[arg_start..arg_end]; + try self.writeBodyInner(w, @ptrCast(arg_body)); + try w.writeAll(",\n"); + self.popIndent(); + } + + try self.writeIndent(w); + try w.writeAll("]"); + } + + fn writeParamInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.string; + try self.writeStringRef(w, data.start); + } + + fn writeBreakInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Break, data.payload_index); + try self.writeInstIndex(w, extra.data.block_inst); + } + + fn writeCondbrInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.CondBr, data.payload_index); + const then_body = self.code.bodySlice(extra.end, extra.data.then_body_len); + const else_body = self.code.bodySlice(extra.end + then_body.len, extra.data.else_body_len); + try self.writeInstRef(w, extra.data.condition); + try w.writeAll(", "); + try self.writeBodyInner(w, then_body); + try w.writeAll(", "); + try self.writeBodyInner(w, else_body); + } + + fn writeSwitchBrInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.SwitchBr, data.payload_index); + const cases_slice = self.code.bodySlice(extra.end, extra.data.cases_len); + + try self.writeInstRef(w, extra.data.operand); + try w.writeAll(", \n"); + for (cases_slice) |case_index| { + const case_extra = self.code.extraData(Ir.Inst.SwitchBr.Case, @intFromEnum(case_index)); + const body_slice = self.code.bodySlice(case_extra.end, case_extra.data.body_len); + + self.pushIndent(); + try self.writeIndent(w); + try self.writeInstRef(w, case_extra.data.operand); + try w.writeAll(" = "); + try self.writeBodyInner(w, body_slice); + try w.writeAll(",\n"); + self.popIndent(); + } + + const else_body = self.code.bodySlice( + extra.end + extra.data.cases_len, + extra.data.else_body_len, + ); + + self.pushIndent(); + try self.writeIndent(w); + try w.writeAll("else = "); + try self.writeBodyInner(w, else_body); + try w.writeAll(")"); + self.popIndent(); + } + + fn writeChoiceBrInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.ChoiceBr, data.payload_index); + const options_slice = self.code.bodySlice(extra.end, extra.data.cases_len); + for (options_slice) |option_index| { + const case_extra = self.code.extraData(Ir.Inst.ChoiceBr.Case, @intFromEnum(option_index)); + const body_slice = self.code.bodySlice(case_extra.end, case_extra.data.body_len); + + self.pushIndent(); + + try self.writeIndent(w); + try self.writeInstRef(w, case_extra.data.operand_1); + try w.writeAll(", "); + try self.writeInstRef(w, case_extra.data.operand_2); + try w.writeAll(", "); + try self.writeInstRef(w, case_extra.data.operand_3); + + try w.writeAll(" = "); + try self.writeBodyInner(w, body_slice); + try w.writeAll(",\n"); + self.popIndent(); + } + try self.writeIndent(w); + } + + fn writeKnotDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Knot, data.payload_index); + const body_slice = self.code.bodySlice(extra.end, extra.data.body_len); + try w.writeAll("body="); + try self.writeBodyInner(w, body_slice); + } + + fn writeVarDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Knot, data.payload_index); + const body_slice = self.code.bodySlice(extra.end, extra.data.body_len); + try w.writeAll("body="); + try self.writeBodyInner(w, body_slice); + } + + fn writeDeclarationInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Declaration, data.payload_index); + try w.writeAll("name="); + try self.writeStringRef(w, extra.data.name); + try w.writeAll(", "); + try w.writeAll("value={\n"); + self.pushIndent(); + try self.writeInst(w, extra.data.value); + self.popIndent(); + try self.writeIndent(w); + try w.writeAll("}"); + } + + fn writeBodyInner( + self: *Writer, + w: *std.Io.Writer, + body_list: []const Ir.Inst.Index, + ) Error!void { + try w.writeAll("{\n"); + self.pushIndent(); + for (body_list) |inst| try self.writeInst(w, inst); + self.popIndent(); + try self.writeIndent(w); + try w.writeAll("}"); + } + + fn writeBlockInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Block, data.payload_index); + const body_slice = self.code.bodySlice(extra.end, extra.data.body_len); + try self.writeBodyInner(w, body_slice); + } + + fn writeFileInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const data = self.code.instructions[@intFromEnum(inst)].data.payload; + const extra = self.code.extraData(Ir.Inst.Block, data.payload_index); + const body_slice = self.code.bodySlice(extra.end, extra.data.body_len); + try self.writeBodyInner(w, body_slice); + } + + pub fn writeInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void { + const tmp = self.code.instructions[@intFromEnum(inst)]; + try self.writeIndent(w); + try self.writeInstIndex(w, inst); + try w.writeAll(" = "); + try self.writeTag(w, inst); + try w.writeAll("("); + + switch (tmp.tag) { + .file => try self.writeFileInst(w, inst), + .declaration => try self.writeDeclarationInst(w, inst), + .decl_knot => try self.writeKnotDeclInst(w, inst), + .decl_var => try self.writeVarDeclInst(w, inst), + .decl_ref => try self.writeStringInst(w, inst), + .condbr => try self.writeCondbrInst(w, inst), + .@"break" => try self.writeBreakInst(w, inst), + .switch_br => try self.writeSwitchBrInst(w, inst), + .alloc => {}, + .load => try self.writeUnaryInst(w, inst), + .store => try self.writeBinaryInst(w, inst), + .block => try self.writeBlockInst(w, inst), + .add => try self.writeBinaryInst(w, inst), + .sub => try self.writeBinaryInst(w, inst), + .mul => try self.writeBinaryInst(w, inst), + .div => try self.writeBinaryInst(w, inst), + .mod => try self.writeBinaryInst(w, inst), + .neg => try self.writeUnaryInst(w, inst), + .not => try self.writeUnaryInst(w, inst), + .cmp_eq => try self.writeBinaryInst(w, inst), + .cmp_neq => try self.writeBinaryInst(w, inst), + .cmp_gt => try self.writeBinaryInst(w, inst), + .cmp_gte => try self.writeBinaryInst(w, inst), + .cmp_lt => try self.writeBinaryInst(w, inst), + .cmp_lte => try self.writeBinaryInst(w, inst), + .integer => try self.writeIntegerInst(w, inst), + .string => try self.writeStringInst(w, inst), + .content_push => try self.writeUnaryInst(w, inst), + .content_flush => try self.writeUnaryInst(w, inst), + .choice_br => try self.writeChoiceBrInst(w, inst), + .implicit_ret => try self.writeUnaryInst(w, inst), + .call => try self.writeCallInst(w, inst, .direct), + .divert => try self.writeCallInst(w, inst, .direct), + .field_call => try self.writeCallInst(w, inst, .field), + .field_divert => try self.writeCallInst(w, inst, .field), + .field_ptr => try self.writeFieldPtrInst(w, inst), + .param => try self.writeParamInst(w, inst), + } + try w.writeAll(")"); + try w.writeAll("\n"); + } +};