aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Dessaux2022-07-30 00:31:14 +0200
committerJulien Dessaux2022-07-30 00:31:14 +0200
commitaa56929ff7e03cd563d951782ba72e06be2a6935 (patch)
tree54501fa0e6af07581d998ebc5e2fe7fa373828a7
parentRemoved useless imports (diff)
downloadzigfunge98-aa56929ff7e03cd563d951782ba72e06be2a6935.tar.gz
zigfunge98-aa56929ff7e03cd563d951782ba72e06be2a6935.tar.bz2
zigfunge98-aa56929ff7e03cd563d951782ba72e06be2a6935.zip
Reworked io functions to take a configurable reader or writer
-rw-r--r--src/interpreter.zig10
-rw-r--r--src/io.zig65
-rw-r--r--src/main.zig8
-rw-r--r--src/pointer.zig46
4 files changed, 68 insertions, 61 deletions
diff --git a/src/interpreter.zig b/src/interpreter.zig
index a947d6f..05c4516 100644
--- a/src/interpreter.zig
+++ b/src/interpreter.zig
@@ -13,19 +13,19 @@ pub const Interpreter = struct {
self.field.deinit();
self.allocator.destroy(self);
}
- pub fn init(allocator: std.mem.Allocator, reader: anytype, ioFunctions: io.Functions, args: []const []const u8) !*Interpreter {
+ pub fn init(allocator: std.mem.Allocator, fileReader: anytype, args: []const []const u8) !*Interpreter {
var i = try allocator.create(Interpreter);
errdefer allocator.destroy(i);
i.allocator = allocator;
- i.field = try field.Field.init_from_reader(allocator, reader);
+ i.field = try field.Field.init_from_reader(allocator, fileReader);
errdefer i.field.deinit();
- i.pointer = try pointer.Pointer.init(std.testing.allocator, i.field, ioFunctions, args);
+ i.pointer = try pointer.Pointer.init(std.testing.allocator, i.field, args);
errdefer i.pointer.deinit();
return i;
}
- pub fn run(self: *Interpreter) !i64 {
+ pub fn run(self: *Interpreter, ioContext: anytype) !i64 {
while (true) {
- if (try self.pointer.exec()) |ret| {
+ if (try self.pointer.exec(ioContext)) |ret| {
if (ret.code) |code| {
return code;
} else {
diff --git a/src/io.zig b/src/io.zig
index 549711d..5ec3b48 100644
--- a/src/io.zig
+++ b/src/io.zig
@@ -1,42 +1,37 @@
const std = @import("std");
-pub const IOErrors = error{
- IOError,
- NotImplemented,
-};
-
-pub const Functions = struct {
- characterInput: fn () IOErrors!i64,
- decimalInput: fn () IOErrors!i64,
- characterOutput: fn (i64) IOErrors!void,
- decimalOutput: fn (i64) IOErrors!void,
-};
-
-pub const defaultFunctions = Functions{
- .characterInput = characterInput,
- .decimalInput = decimalInput,
- .characterOutput = characterOutput,
- .decimalOutput = decimalOutput,
-};
-
-fn characterInput() IOErrors!i64 {
- // TODO
- return error.NotImplemented;
-}
-
-fn decimalInput() IOErrors!i64 {
- // TODO
- return error.NotImplemented;
-}
-
-fn characterOutput(v: i64) IOErrors!void {
- std.debug.print("{c}", .{@intCast(u8, v)});
- return;
+pub fn Context(readerType: anytype, writerType: anytype) type {
+ return struct {
+ reader: readerType,
+ writer: writerType,
+ pub fn characterInput(self: @This()) !i64 {
+ var buffer = [_]u8{0};
+ var n = try self.reader.read(buffer[0..]);
+ if (n == 1) {
+ return buffer[0];
+ }
+ return error.IOError;
+ }
+ pub fn decimalInput(self: @This()) !i64 {
+ _ = self;
+ return error.NotImplemented;
+ }
+ pub fn characterOutput(self: @This(), v: i64) !void {
+ try self.writer.print("{c}", .{@intCast(u8, v)});
+ return;
+ }
+ pub fn decimalOutput(self: @This(), v: i64) !void {
+ try self.writer.print("{d}", .{v});
+ return;
+ }
+ };
}
-fn decimalOutput(v: i64) IOErrors!void {
- std.debug.print("{d}", .{v});
- return;
+pub fn context(reader: anytype, writer: anytype) Context(@TypeOf(reader), @TypeOf(writer)) {
+ return .{
+ .reader = reader,
+ .writer = writer,
+ };
}
test "all" {
diff --git a/src/main.zig b/src/main.zig
index ff4f09b..4eb46a3 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -15,10 +15,10 @@ pub fn main() anyerror!void {
var file = try std.fs.cwd().openFile("mycology/sanity.bf", .{});
defer file.close();
- var i = try interpreter.Interpreter.init(gpa.allocator(), file.reader(), io.defaultFunctions, args);
+ var i = try interpreter.Interpreter.init(gpa.allocator(), file.reader(), args);
defer i.deinit();
- std.os.exit(@intCast(u8, try i.run()));
+ std.os.exit(@intCast(u8, try i.run(io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer()))));
}
test "all" {
@@ -28,7 +28,7 @@ test "sanity" {
var file = try std.fs.cwd().openFile("mycology/sanity.bf", .{});
defer file.close();
const args = [_][]const u8{"sanity"};
- var i = try interpreter.Interpreter.init(std.testing.allocator, file.reader(), io.defaultFunctions, args[0..]);
+ var i = try interpreter.Interpreter.init(std.testing.allocator, file.reader(), args[0..]);
defer i.deinit();
- try std.testing.expectEqual(try i.run(), 0);
+ try std.testing.expectEqual(try i.run(io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer())), 0);
}
diff --git a/src/pointer.zig b/src/pointer.zig
index 9aae54e..d2d24bb 100644
--- a/src/pointer.zig
+++ b/src/pointer.zig
@@ -23,7 +23,6 @@ pub const Pointer = struct {
stringMode: bool = false, // string mode flags
lastCharWasSpace: bool = false,
ss: *stackStack.StackStack,
- ioFunctions: io.Functions,
argv: []const []const u8,
rand: *std.rand.Random,
@@ -31,7 +30,7 @@ pub const Pointer = struct {
self.ss.deinit();
self.allocator.destroy(self);
}
- fn eval(p: *Pointer, c: i64) pointerErrorType!?pointerReturn {
+ fn eval(p: *Pointer, ioContext: anytype, c: i64) pointerErrorType!?pointerReturn {
// Returns non nil if the pointer terminated, and a return code if
// the program should terminate completely
switch (c) {
@@ -67,9 +66,9 @@ pub const Pointer = struct {
p.x = x;
p.y = y;
if (v != ' ' and v != ';') {
- if (v == 'q' or v == '@') return try p.eval(v);
+ if (v == 'q' or v == '@') return try p.eval(ioContext, v);
var i: usize = 0;
- while (i < n) : (i += 1) _ = try p.eval(v);
+ while (i < n) : (i += 1) _ = try p.eval(ioContext, v);
}
}
},
@@ -168,11 +167,25 @@ pub const Pointer = struct {
const n = p.ss.toss.pop();
try p.field.set(v[0] + p.sox, v[1] + p.soy, n);
},
- '.' => try p.ioFunctions.decimalOutput(p.ss.toss.pop()),
- ',' => try p.ioFunctions.characterOutput(p.ss.toss.pop()),
- '&' => try p.ss.toss.push(try p.ioFunctions.decimalInput()),
- '~' => try p.ss.toss.push(try p.ioFunctions.characterInput()),
- // TODO
+ '.' => ioContext.decimalOutput(p.ss.toss.pop()) catch {
+ p.reverse();
+ return null;
+ },
+ ',' => ioContext.characterOutput(p.ss.toss.pop()) catch p.reverse(),
+ '&' => {
+ const n = ioContext.decimalInput() catch {
+ p.reverse();
+ return null;
+ };
+ p.ss.toss.push(n) catch p.reverse();
+ },
+ '~' => {
+ const n = ioContext.characterInput() catch {
+ p.reverse();
+ return null;
+ };
+ p.ss.toss.push(n) catch p.reverse();
+ },
'y' => return error.NotImplemented,
'(' => {
const n = p.ss.toss.pop();
@@ -208,7 +221,7 @@ pub const Pointer = struct {
}
return null;
}
- pub fn exec(self: *Pointer) !?pointerReturn {
+ pub fn exec(self: *Pointer, ioContext: anytype) !?pointerReturn {
// Advances to the next instruction of the field and executes it
// Returns non nil if the pointer terminated, and a return code if
// the program should terminate completely
@@ -233,18 +246,17 @@ pub const Pointer = struct {
if (c == ';') jumpingMode = !jumpingMode;
c = self.stepAndGet();
}
- result = try self.eval(c);
+ result = try self.eval(ioContext, c);
}
self.step();
return result;
}
- pub fn init(allocator: std.mem.Allocator, f: *field.Field, ioFunctions: io.Functions, argv: []const []const u8) !*Pointer {
+ pub fn init(allocator: std.mem.Allocator, f: *field.Field, argv: []const []const u8) !*Pointer {
var p = try allocator.create(Pointer);
errdefer allocator.destroy(p);
p.allocator = allocator;
p.field = f;
p.ss = try stackStack.StackStack.init(allocator);
- p.ioFunctions = ioFunctions;
p.argv = argv;
p.x = 0;
p.y = 0;
@@ -328,16 +340,16 @@ test "minimal" {
var f = try field.Field.init_from_reader(std.testing.allocator, minimal);
defer f.deinit();
const argv = [_][]const u8{"minimal"};
- var p = try Pointer.init(std.testing.allocator, f, io.defaultFunctions, argv[0..]);
+ var p = try Pointer.init(std.testing.allocator, f, argv[0..]);
defer p.deinit();
- try std.testing.expectEqual(p.exec(), pointerReturn{});
+ try std.testing.expectEqual(p.exec(io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer())), pointerReturn{});
}
test "almost minimal" {
const minimal = std.io.fixedBufferStream(" @").reader();
var f = try field.Field.init_from_reader(std.testing.allocator, minimal);
defer f.deinit();
const argv = [_][]const u8{"minimal"};
- var p = try Pointer.init(std.testing.allocator, f, io.defaultFunctions, argv[0..]);
+ var p = try Pointer.init(std.testing.allocator, f, argv[0..]);
defer p.deinit();
- try std.testing.expectEqual(p.exec(), pointerReturn{});
+ try std.testing.expectEqual(p.exec(io.context(std.io.getStdIn().reader(), std.io.getStdOut().writer())), pointerReturn{});
}