it is poggers now
This commit is contained in:
parent
7301699729
commit
d2e1b746e2
1 changed files with 139 additions and 79 deletions
186
bf.zig
186
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)
|
// 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();
|
||||||
|
|
Loading…
Reference in a new issue