summaryrefslogtreecommitdiff
path: root/src/libzisp/io
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2025-03-17 13:48:14 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2025-03-17 13:48:14 +0100
commit2c33764bcac8b34cdf120f3e8e09dea944af4b21 (patch)
tree1becbc31cdce0bdda17e62e9a54911e18e5305cb /src/libzisp/io
parentbff3e84e7b4083285d5a0a871663db57430401b6 (diff)
Make parser use AnyReader.
Diffstat (limited to 'src/libzisp/io')
-rw-r--r--src/libzisp/io/parser.zig55
1 files changed, 47 insertions, 8 deletions
diff --git a/src/libzisp/io/parser.zig b/src/libzisp/io/parser.zig
index 773e246..839b046 100644
--- a/src/libzisp/io/parser.zig
+++ b/src/libzisp/io/parser.zig
@@ -240,15 +240,28 @@ const Context = struct {
char: u8 = undefined,
};
+// Buffer size is 4096, so index type is u12 (0..4095).
+const BUF_SIZE = 4096;
+const IDX_TYPE = u12;
+
+const debug_mode = @import("builtin").mode == .Debug;
+
const State = struct {
- input: []const u8,
- pos: usize = 0,
+ input: std.io.AnyReader,
+ is_eof: bool = false,
+
+ buf: [BUF_SIZE]u8 = .{0} ** BUF_SIZE,
+ pos: IDX_TYPE = 0,
+ write_pos: IDX_TYPE = 0,
context: Context = .{},
stack: std.ArrayList(Context),
retval: Value = undefined,
- fn init(input: []const u8, alloc: std.mem.Allocator) State {
+ // For debugging.
+ checked_eof: bool = false,
+
+ fn init(input: std.io.AnyReader, alloc: std.mem.Allocator) State {
return .{ .input = input, .stack = .init(alloc) };
}
@@ -274,17 +287,43 @@ const State = struct {
}
}
+ fn fillBuffer(s: *State) !void {
+ if (s.pos != s.write_pos) {
+ return;
+ }
+ // Make sure *not* to overwrite the entire buffer with newly read data,
+ // because we use it as a circular buffer so as to be able to reset to
+ // previous points in it. We overwrite at most BUF_SIZE / 2 bytes, so
+ // we can go back by up to BUF_SIZE / 2 bytes.
+ const avail = BUF_SIZE - @as(u64, s.write_pos);
+ const write_max = std.math.clamp(avail, 0, BUF_SIZE / 2);
+ const write_to = s.write_pos + write_max;
+ const count = try s.input.read(s.buf[s.write_pos..write_to]);
+ s.is_eof = count == 0;
+ s.write_pos +%= @intCast(count);
+ }
+
fn eof(s: *State) bool {
- return s.pos >= s.input.len;
+ if (debug_mode) {
+ s.checked_eof = true;
+ }
+ fillBuffer(s) catch @panic("reader error");
+ return s.is_eof;
}
fn peek(s: *State) u8 {
- return s.input[s.pos];
+ return s.buf[s.pos];
}
fn skip(s: *State) void {
- // std.debug.print("{c}\n", .{s.input[s.pos]});
- s.pos += 1;
+ if (debug_mode) {
+ if (!s.checked_eof) {
+ @panic("Didn't check EOF before calling skip()!");
+ }
+ s.checked_eof = false;
+ }
+ // std.debug.print("{c}\n", .{s.buf[s.pos]});
+ s.pos +%= 1;
}
fn getc(s: *State) u8 {
@@ -352,7 +391,7 @@ const Fn = enum {
done,
};
-pub fn parse(input: []const u8) Value {
+pub fn parse(input: std.io.AnyReader) Value {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
defer if (gpa.deinit() == .leak) @panic("leak");
var s: State = .init(input, gpa.allocator());