it is poggers now

This commit is contained in:
mehbark 2024-06-24 22:54:53 -04:00
parent 7301699729
commit d2e1b746e2

186
bf.zig
View file

@ -15,10 +15,16 @@ const Level1 = union(enum) {
// well, might as well use the extra space (union is bigger than its biggest member) // well, might as well use the extra space (union is bigger than its biggest member)
in: u16, in: u16,
out: 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(); const Self = @This();
fn pointless(self: Self) bool { fn pointless(self: Self) bool {
return switch (self) { return switch (self) {
.inc, .shift => |n| n == 0, .inc, .shift => |n| n == 0,
@ -26,127 +32,181 @@ const Level1 = union(enum) {
else => false, else => false,
}; };
} }
};
const Level2 = union(enum) { fn nothing() Self {
inc: i16, return .{ .inc = 0 };
shift: i16, }
in: u16,
out: u16, // the default fmt is human and machine readable..... but idc xd lol pog
// only difference pub fn format(
// u24s because i arbitrarily chose 2^24 as the limit self: Self,
// maybe u32 would be more efficient idk this union should fit in a u32 comptime fmt: []const u8,
// hm we can probably go way lower bc level1 is so much more compact than prog_unfiltered options: std.fmt.FormatOptions,
// shouldn't be necessary writer: anytype,
loop_start: u24, ) !void {
loop_end: u24, _ = 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 // we'll do the discarding of comment chars here
fn compileLevel1(allocator: mem.Allocator, src: []const u8) !ArrayList(Level1) { 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 out = ArrayList(Level1).init(allocator);
var openers = ArrayList(u24).init(allocator);
errdefer {
out.deinit();
openers.deinit();
}
for (src) |b| { for (src) |b| {
switch (b) { switch (b) {
'+', '-' => { '+', '-' => {
const n: i16 = if (b == '+') 1 else -1; const n: i16 = if (b == '+') 1 else -1;
if (cur) |*ins| { switch (cur) {
switch (ins.*) {
.inc => |*ns| ns.* += n, .inc => |*ns| ns.* += n,
else => { else => {
if (!ins.pointless()) try out.append(ins.*); if (!cur.pointless()) try out.append(cur);
cur = .{ .inc = n }; cur = .{ .inc = n };
}, },
} }
} else {
cur = .{ .inc = n };
}
}, },
'>', '<' => { '>', '<' => {
const n: i16 = if (b == '>') 1 else -1; const n: i16 = if (b == '>') 1 else -1;
if (cur) |*ins| { switch (cur) {
switch (ins.*) {
.shift => |*ns| ns.* += n, .shift => |*ns| ns.* += n,
else => { else => {
if (!ins.pointless()) try out.append(ins.*); if (!cur.pointless()) try out.append(cur);
cur = .{ .shift = n }; cur = .{ .shift = n };
}, },
} }
} else {
cur = .{ .shift = n };
}
}, },
'[', ']' => { '[' => {
if (cur) |ins| { if (!cur.pointless()) try out.append(cur);
if (!ins.pointless()) try out.append(ins); cur = .{ .loop_start = 0 };
cur = null; try openers.append(@as(u24, @truncate(out.items.len)));
} },
try out.append(if (b == '[') .loop_start else .loop_end); ']' => {
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 (cur) {
switch (ins.*) {
.in => |*ns| ns.* += 1, .in => |*ns| ns.* += 1,
else => { else => {
if (!ins.pointless()) try out.append(ins.*); if (!cur.pointless()) try out.append(cur);
cur = .{ .in = 1 }; cur = .{ .in = 1 };
}, },
} }
} else {
cur = .{ .in = 1 };
}
}, },
'.' => { '.' => {
if (cur) |*ins| { switch (cur) {
switch (ins.*) {
.out => |*ns| ns.* += 1, .out => |*ns| ns.* += 1,
else => { else => {
if (!ins.pointless()) try out.append(ins.*); if (!cur.pointless()) try out.append(cur);
cur = .{ .out = 1 }; cur = .{ .out = 1 };
}, },
} }
} else {
cur = .{ .out = 1 };
}
}, },
else => {}, else => {},
} }
} }
if (cur) |ins| { if (!cur.pointless()) try out.append(cur);
if (!ins.pointless()) try out.append(ins);
} const unclosed_openers = openers.items.len;
if (unclosed_openers > 0) return error.UnclosedOpener;
openers.deinit();
return out; return out;
} }
test "level 1" { fn testLevel1(src: []const u8, expected: []const Level1) !void {
const src = "+++-- [ >><<< +- ] ...,,,";
const level1 = try compileLevel1(testing.allocator, src); const level1 = try compileLevel1(testing.allocator, src);
defer level1.deinit(); 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{ try testing.expectEqual(expected.len, level1.items.len);
.{ .inc = 1 },
.loop_start,
.{ .shift = -1 },
.loop_end,
.{ .out = 3 },
.{ .in = 3 },
};
try testing.expectEqual(should_be.len, level1.items.len);
for ( for (
level1.items, level1.items,
&should_be, expected,
) |a, b| { ) |a, b| {
try testing.expectEqual(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 { pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var allocator = arena.allocator(); var allocator = arena.allocator();