From d2e1b746e26cb2a81196a3d261c59497d8a6506f Mon Sep 17 00:00:00 2001 From: mehbark Date: Mon, 24 Jun 2024 22:54:53 -0400 Subject: [PATCH] it is poggers now --- bf.zig | 218 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 139 insertions(+), 79 deletions(-) diff --git a/bf.zig b/bf.zig index df07f07..30cee03 100644 --- a/bf.zig +++ b/bf.zig @@ -15,10 +15,16 @@ const Level1 = union(enum) { // well, might as well use the extra space (union is bigger than its biggest member) in: u16, out: u16, - loop_start, - loop_end, + + // u24s because i arbitrarily chose 2^24 as the limit + // maybe u32 would be more efficient idk this union should fit in a u32 + // hm we can probably go way lower bc level1 is so much more compact than prog_unfiltered + // shouldn't be necessary + loop_start: u24, + loop_end: u24, const Self = @This(); + fn pointless(self: Self) bool { return switch (self) { .inc, .shift => |n| n == 0, @@ -26,127 +32,181 @@ const Level1 = union(enum) { else => false, }; } -}; -const Level2 = union(enum) { - inc: i16, - shift: i16, - in: u16, - out: u16, - // only difference - // u24s because i arbitrarily chose 2^24 as the limit - // maybe u32 would be more efficient idk this union should fit in a u32 - // hm we can probably go way lower bc level1 is so much more compact than prog_unfiltered - // shouldn't be necessary - loop_start: u24, - loop_end: u24, + fn nothing() Self { + return .{ .inc = 0 }; + } + + // the default fmt is human and machine readable..... but idc xd lol pog + pub fn format( + self: Self, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + + switch (self) { + .inc => |n| try writer.print("INC {d: >4}", .{n}), + .shift => |n| try writer.print("SHF {d: >4}", .{n}), + .in => |n| try writer.print("INP {d: >4}", .{n}), + .out => |n| try writer.print("OUT {d: >4}", .{n}), + .loop_start => |n| try writer.print("JEZ {d:0>4}", .{n}), + .loop_end => |n| try writer.print("JNZ {d:0>4}", .{n}), + } + } }; // we'll do the discarding of comment chars here fn compileLevel1(allocator: mem.Allocator, src: []const u8) !ArrayList(Level1) { - var cur: ?Level1 = null; + var cur = Level1.nothing(); var out = ArrayList(Level1).init(allocator); + var openers = ArrayList(u24).init(allocator); + errdefer { + out.deinit(); + openers.deinit(); + } for (src) |b| { switch (b) { '+', '-' => { const n: i16 = if (b == '+') 1 else -1; - if (cur) |*ins| { - switch (ins.*) { - .inc => |*ns| ns.* += n, - else => { - if (!ins.pointless()) try out.append(ins.*); - cur = .{ .inc = n }; - }, - } - } else { - cur = .{ .inc = n }; + switch (cur) { + .inc => |*ns| ns.* += n, + else => { + if (!cur.pointless()) try out.append(cur); + cur = .{ .inc = n }; + }, } }, '>', '<' => { const n: i16 = if (b == '>') 1 else -1; - if (cur) |*ins| { - switch (ins.*) { - .shift => |*ns| ns.* += n, - else => { - if (!ins.pointless()) try out.append(ins.*); - cur = .{ .shift = n }; - }, - } - } else { - cur = .{ .shift = n }; + switch (cur) { + .shift => |*ns| ns.* += n, + else => { + if (!cur.pointless()) try out.append(cur); + cur = .{ .shift = n }; + }, } }, - '[', ']' => { - if (cur) |ins| { - if (!ins.pointless()) try out.append(ins); - cur = null; - } - try out.append(if (b == '[') .loop_start else .loop_end); + '[' => { + if (!cur.pointless()) try out.append(cur); + cur = .{ .loop_start = 0 }; + try openers.append(@as(u24, @truncate(out.items.len))); + }, + ']' => { + if (!cur.pointless()) try out.append(cur); + const opener_idx = openers.popOrNull() orelse return error.UnopenedCloser; + out.items[opener_idx].loop_start = @as(u24, @truncate(out.items.len)); + cur = .{ .loop_end = opener_idx }; }, ',' => { - if (cur) |*ins| { - switch (ins.*) { - .in => |*ns| ns.* += 1, - else => { - if (!ins.pointless()) try out.append(ins.*); - cur = .{ .in = 1 }; - }, - } - } else { - cur = .{ .in = 1 }; + switch (cur) { + .in => |*ns| ns.* += 1, + else => { + if (!cur.pointless()) try out.append(cur); + cur = .{ .in = 1 }; + }, } }, '.' => { - if (cur) |*ins| { - switch (ins.*) { - .out => |*ns| ns.* += 1, - else => { - if (!ins.pointless()) try out.append(ins.*); - cur = .{ .out = 1 }; - }, - } - } else { - cur = .{ .out = 1 }; + switch (cur) { + .out => |*ns| ns.* += 1, + else => { + if (!cur.pointless()) try out.append(cur); + cur = .{ .out = 1 }; + }, } }, else => {}, } } - if (cur) |ins| { - if (!ins.pointless()) try out.append(ins); - } + if (!cur.pointless()) try out.append(cur); + + const unclosed_openers = openers.items.len; + if (unclosed_openers > 0) return error.UnclosedOpener; + openers.deinit(); return out; } -test "level 1" { - const src = "+++-- [ >><<< +- ] ...,,,"; - +fn testLevel1(src: []const u8, expected: []const Level1) !void { const level1 = try compileLevel1(testing.allocator, src); defer level1.deinit(); - std.debug.print("{any}\n", .{level1.items}); + errdefer { + std.debug.print("{s}\n", .{src}); + std.debug.print(" OBTAINED EXPECTED\n", .{}); + if (level1.items.len < expected.len) { + for (level1.items, expected[0..level1.items.len], 0..) |a, b, i| { + std.debug.print("{:0>4}: {} {}\n", .{ i, a, b }); + } + for (expected[level1.items.len..], level1.items.len..) |b, i| { + std.debug.print("{:0>4}: -------- {}\n", .{ i, b }); + } + } else { + for (level1.items[0..expected.len], expected, 0..) |a, b, i| { + std.debug.print("{:0>4}: {} {}\n", .{ i, a, b }); + } + for (level1.items[expected.len..], expected.len..) |a, i| { + std.debug.print("{:0>4}: {} --------\n", .{ i, a }); + } + } + } - const should_be = [_]Level1{ - .{ .inc = 1 }, - .loop_start, - .{ .shift = -1 }, - .loop_end, - .{ .out = 3 }, - .{ .in = 3 }, - }; - try testing.expectEqual(should_be.len, level1.items.len); + try testing.expectEqual(expected.len, level1.items.len); for ( level1.items, - &should_be, + expected, ) |a, b| { try testing.expectEqual(a, b); } } +test "level 1" { + try testLevel1( + "+++-- [ >><<< +- ] ...,,,", + &[_]Level1{ + .{ .inc = 1 }, + .{ .loop_start = 3 }, + .{ .shift = -1 }, + .{ .loop_end = 1 }, + .{ .out = 3 }, + .{ .in = 3 }, + }, + ); + try testLevel1( + \\ 0 [ + \\ 1 [ + \\ 2 ] + \\ 3 [ + \\ 4 [ + \\ 5 ] + \\ 6 [ + \\ 7 ] + \\ 8 ] + \\ 9 ] + , + &[_]Level1{ + .{ .loop_start = 9 }, + .{ .loop_start = 2 }, + .{ .loop_end = 1 }, + .{ .loop_start = 8 }, + .{ .loop_start = 5 }, + .{ .loop_end = 4 }, + .{ .loop_start = 7 }, + .{ .loop_end = 6 }, + .{ .loop_end = 3 }, + .{ .loop_end = 0 }, + }, + ); + testLevel1("bla bla - [ ++ ", &[_]Level1{}) catch |err| try testing.expectEqual(err, error.UnclosedOpener); + testLevel1("wow wow += ]", &[_]Level1{}) catch |err| try testing.expectEqual(err, error.UnopenedCloser); +} + pub fn main() !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var allocator = arena.allocator();