feat: code generation for diverts, wip

This commit is contained in:
Brett Broadhurst 2026-03-17 23:19:54 -06:00
parent ee26be6254
commit 20292bcc6a
Failed to generate hash of commit
5 changed files with 699 additions and 149 deletions

View file

@ -77,6 +77,12 @@ pub const Inst = struct {
content_flush,
choice_br,
implicit_ret,
call,
divert,
field_ptr,
field_call,
field_divert,
param,
};
pub const Data = union {
@ -116,6 +122,11 @@ pub const Inst = struct {
body_len: u32,
};
pub const Field = struct {
lhs: Ref,
field_name_start: NullTerminatedString,
};
pub const Block = struct {
body_len: u32,
};
@ -151,6 +162,17 @@ pub const Inst = struct {
body_len: u32,
};
};
pub const Call = struct {
args_len: u32,
callee: Ref,
};
pub const FieldCall = struct {
args_len: u32,
obj_ptr: Ref,
field_name_start: NullTerminatedString,
};
};
pub const Global = struct {
@ -186,6 +208,7 @@ pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
const Render = struct {
gpa: std.mem.Allocator,
prefix: Prefix,
code: Ir,
writer: *std.Io.Writer,
pub const Error = error{
@ -259,6 +282,7 @@ const Render = struct {
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);
@ -413,6 +437,88 @@ const Render = struct {
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);
@ -461,14 +567,25 @@ const Render = struct {
.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 {
std.debug.assert(ir.instructions.len > 0);
var r = Render{ .gpa = gpa, .writer = writer, .prefix = .{} };
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));