refactor: clean up ir print writer
This commit is contained in:
parent
20292bcc6a
commit
517eae1481
3 changed files with 319 additions and 384 deletions
387
src/Ir.zig
387
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
314
src/print_ir.zig
Normal file
314
src/print_ir.zig
Normal file
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue