1
0
Fork 0

Reworked io functions to take a configurable reader or writer

This commit is contained in:
Julien Dessaux 2022-07-30 00:31:14 +02:00
parent 35c2f5e626
commit aa56929ff7
Signed by: adyxax
GPG key ID: F92E51B86E07177E
4 changed files with 68 additions and 61 deletions

View file

@ -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 {

View file

@ -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;
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 decimalInput() IOErrors!i64 {
// TODO
return error.NotImplemented;
}
fn characterOutput(v: i64) IOErrors!void {
std.debug.print("{c}", .{@intCast(u8, 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" {

View file

@ -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);
}

View file

@ -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{});
}