feat: semantics for if statements and multi-prong if statements

This commit is contained in:
Brett Broadhurst 2026-03-10 16:52:13 -06:00
parent 9658c8a308
commit ce5385ebac
Failed to generate hash of commit
6 changed files with 553 additions and 317 deletions

View file

@ -24,6 +24,8 @@ pub const Inst = struct {
decl_var,
decl_ref,
block,
condbr,
@"break",
alloc_local,
load_local,
store_local,
@ -33,11 +35,19 @@ pub const Inst = struct {
div,
mod,
neg,
not,
cmp_eq,
cmp_neq,
cmp_gt,
cmp_gte,
cmp_lt,
cmp_lte,
true_literal,
false_literal,
integer,
string,
content,
content_push,
content_flush,
};
pub const Data = union {
@ -45,11 +55,11 @@ pub const Inst = struct {
payload_index: u32,
},
un: struct {
lhs: Inst.Index,
lhs: Index,
},
bin: struct {
lhs: Inst.Index,
rhs: Inst.Index,
lhs: Index,
rhs: Index,
},
integer: struct {
value: u64,
@ -66,7 +76,7 @@ pub const Inst = struct {
pub const Declaration = struct {
name: NullTerminatedString,
value: Inst.Index,
value: Index,
};
pub const Knot = struct {
@ -80,6 +90,16 @@ pub const Inst = struct {
pub const Block = struct {
body_len: u32,
};
pub const Break = struct {
block_inst: Index,
};
pub const CondBr = struct {
condition: Index,
then_body_len: u32,
else_body_len: u32,
};
};
pub const Global = struct {
@ -112,29 +132,6 @@ pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
ir.* = undefined;
}
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);
}
};
const Render = struct {
gpa: std.mem.Allocator,
prefix: Prefix,
@ -145,6 +142,29 @@ const Render = struct {
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 renderSimple(r: *Render, inst: Inst) Error!void {
const io_w = r.writer;
return io_w.print("{s}(?)", .{@tagName(inst.tag)});
@ -183,6 +203,26 @@ const Render = struct {
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}(%{d}, ", .{ @tagName(inst.tag), extra.data.condition });
try renderBodyInner(r, ir, then_body);
try io_w.writeAll(", ");
try renderBodyInner(r, ir, else_body);
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);
@ -244,6 +284,8 @@ const Render = struct {
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),
.alloc_local => try r.renderSimple(inst),
.load_local => try r.renderUnary(inst),
.store_local => try r.renderBinary(inst),
@ -254,6 +296,13 @@ const Render = struct {
.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),
.true_literal => {
try io_w.print("{s}", .{@tagName(inst.tag)});
},
@ -268,7 +317,8 @@ const Render = struct {
const str_bytes = inst.data.string.get(ir);
try io_w.print("{s}(\"{s}\")", .{ @tagName(inst.tag), str_bytes });
},
.content => try r.renderUnary(inst),
.content_push => try r.renderSimple(inst),
.content_flush => try r.renderUnary(inst),
}
try io_w.writeAll("\n");
}