diff options
| author | Taylan Kammer <taylan.kammer@gmail.com> | 2025-02-18 22:48:57 +0100 |
|---|---|---|
| committer | Taylan Kammer <taylan.kammer@gmail.com> | 2025-02-18 22:48:57 +0100 |
| commit | 4d0db1a1065f18d879b3ff90da6ecb14e9e1ae31 (patch) | |
| tree | 7c5c275e7f3dae7bf96377560269b5a1bfa1fb99 /src/libzisp/read.zig | |
| parent | 2384a31c42f480c961785bcf0520bb0688b8e028 (diff) | |
update
Diffstat (limited to 'src/libzisp/read.zig')
| -rw-r--r-- | src/libzisp/read.zig | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/libzisp/read.zig b/src/libzisp/read.zig new file mode 100644 index 0000000..9ef9891 --- /dev/null +++ b/src/libzisp/read.zig @@ -0,0 +1,105 @@ +const std = @import("std"); + +const gc = @import("gc.zig"); +const value = @import("value.zig"); + +const Value = value.Value; + +const State = struct { + alloc: std.mem.Allocator, + input: []const u8, + pos: usize = 0, + + next: enum { + start, + + list, + list_end, + + err, + + done, + } = .start, + + retval: Value = value.eof.eof, + + parent: ?*State = null, +}; + +pub fn read(input: []const u8) Value { + var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; + var top = State{ .alloc = gpa.allocator(), .input = input }; + var s = ⊤ + while (s.pos <= s.input.len) : (s.pos += 1) { + s = switch (s.next) { + .start => start(s), + + .list => list(s), + .list_end => list(s), + + .err => err(s), + + .done => ret: { + if (s.parent) |parent| { + s.alloc.destroy(s); + break :ret parent; + } else { + return s.retval; + } + }, + }; + } + unreachable; +} + +fn start(s: *State) *State { + switch (s.input[s.pos]) { + 0...8 => s.next = .err, + + '\t', '\n' => {}, + + 11...31 => s.next = .err, + + ' ' => {}, + + '!' => s.next = .err, + + '"' => quotedString(s), + + else => s.next = .err, + } + return s; +} + +fn quotedString(s: *State) void { + var buf: [6]u8 = .{0} ** 6; + const len = readString(&buf, s); + s.retval = value.pair.cons( + value.sstr.pack("quote"), + value.pair.cons( + value.sstr.pack(buf[0..len]), + value.nil.nil, + ), + ); + s.next = .done; +} + +fn readString(buf: []u8, s: *State) usize { + s.pos += 1; // skip opening quote + for (s.input[s.pos..], 0..) |c, i| { + if (c == '"') { + s.pos += i; + return i; + } + buf[i] = c; + } + unreachable; +} + +fn list(s: *State) *State { + return s; +} + +fn err(s: *State) *State { + return s; +} |
