From aa56929ff7e03cd563d951782ba72e06be2a6935 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sat, 30 Jul 2022 00:31:14 +0200 Subject: Reworked io functions to take a configurable reader or writer --- src/interpreter.zig | 10 ++++----- src/io.zig | 65 +++++++++++++++++++++++++---------------------------- src/main.zig | 8 +++---- src/pointer.zig | 46 +++++++++++++++++++++++-------------- 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{}); } -- cgit v1.2.3