diff options
| author | Taylan Kammer <taylan.kammer@gmail.com> | 2025-03-17 13:48:14 +0100 |
|---|---|---|
| committer | Taylan Kammer <taylan.kammer@gmail.com> | 2025-03-17 13:48:14 +0100 |
| commit | 2c33764bcac8b34cdf120f3e8e09dea944af4b21 (patch) | |
| tree | 1becbc31cdce0bdda17e62e9a54911e18e5305cb /src/libzisp/io | |
| parent | bff3e84e7b4083285d5a0a871663db57430401b6 (diff) | |
Make parser use AnyReader.
Diffstat (limited to 'src/libzisp/io')
| -rw-r--r-- | src/libzisp/io/parser.zig | 55 |
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()); |
