summaryrefslogtreecommitdiff
path: root/src/zisp/io/Parser.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/zisp/io/Parser.zig')
-rw-r--r--src/zisp/io/Parser.zig71
1 files changed, 39 insertions, 32 deletions
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig
index 57c3207..3ac0d8c 100644
--- a/src/zisp/io/Parser.zig
+++ b/src/zisp/io/Parser.zig
@@ -35,11 +35,15 @@
const builtin = @import("builtin");
const std = @import("std");
+const gc = @import("../gc.zig");
const lib = @import("../lib.zig");
const value = @import("../value.zig");
+const Alloc = std.mem.Allocator;
const List = std.ArrayListUnmanaged;
+const IstrSet = gc.IstrSet;
+const PairPool = gc.PairPool;
const Value = value.Value;
const Parser = @This();
@@ -65,21 +69,6 @@ pub const SQUARE = value.rune.pack("SQUARE");
pub const BRACE = value.rune.pack("BRACE");
// zig fmt: on
-// We could implement an optimization where we swap in a dummy cons when the
-// parser is handling a commented-out datum, but this would require changes to
-// the algorithm and doesn't seem very important, so it's not implemented.
-
-const Cons = *const fn (v1: Value, v2: Value) Value;
-
-fn dummyCons(v1: Value, v2: Value) Value {
- _ = v1;
- _ = v2;
- return value.undef;
-}
-
-const real_cons = &value.pair.cons;
-const fake_cons = &dummyCons;
-
pub const Error = enum {
ReadError,
UnexpectedEof,
@@ -99,28 +88,38 @@ pub const Context = struct {
char: u8 = undefined,
};
-alloc: std.mem.Allocator,
-io: std.Io,
+alloc: Alloc,
+istr_set: *IstrSet,
+pair_pool: *PairPool,
+
input: *std.Io.Reader = undefined,
+
context: Context = .{},
stack: List(Context) = undefined,
chars: List(u8) = undefined,
-cons: Cons = real_cons,
+
result: Value = undefined,
unread_char: ?u8 = null,
err_msg: []const u8 = undefined,
-pub fn init(alloc: std.mem.Allocator, io: std.Io) !Parser {
- return initCustom(alloc, io, 32, 2048);
+pub fn init(alloc: Alloc) !Parser {
+ const istr_set = gc.mainIstrSet();
+ const pair_pool = gc.mainPairPool();
+ return initCustom(alloc, 32, 2048, istr_set, pair_pool);
}
pub fn initCustom(
- alloc: std.mem.Allocator,
- io: std.Io,
+ alloc: Alloc,
init_ctx_stack_cap: usize,
init_str_chars_cap: usize,
+ istr_set: *IstrSet,
+ pair_pool: *PairPool,
) !Parser {
- var p: Parser = .{ .alloc = alloc, .io = io };
+ var p: Parser = .{
+ .alloc = alloc,
+ .istr_set = istr_set,
+ .pair_pool = pair_pool,
+ };
p.stack = try .initCapacity(alloc, init_ctx_stack_cap);
p.chars = try .initCapacity(alloc, init_str_chars_cap);
return p;
@@ -156,8 +155,8 @@ fn readNoEof(p: *Parser, comptime emsg: []const u8) !u8 {
return try p.read() orelse p.err(.UnexpectedEof, emsg);
}
-// Fake optional, for use in: while (readNoEof2()) |c| { }
-fn readNoEof2(p: *Parser, comptime emsg: []const u8) !?u8 {
+// Fake optional, for use in: while (readNoEofOpt()) |c| { }
+fn readNoEofOpt(p: *Parser, comptime emsg: []const u8) !?u8 {
return try p.read() orelse p.err(.UnexpectedEof, emsg);
}
@@ -196,7 +195,7 @@ fn getCharsAsString(p: *Parser) !Value {
return if (value.sstr.isValidSstr(s))
value.sstr.pack(s)
else if (value.istr.isValidIstr(s))
- value.istr.intern(s)
+ value.istr.internInSet(p.istr_set, s)
else
value.array.newString(p.alloc, s);
}
@@ -207,6 +206,14 @@ fn getCharsAsRune(p: *Parser) Value {
}
//
+// Pair consing
+//
+
+fn cons(p: *Parser, car: Value, cdr: Value) Value {
+ return value.pair.consInPool(p.pair_pool, car, cdr) catch @panic("OOM"); // TODO
+}
+
+//
// Stack management & control flow
//
@@ -451,7 +458,7 @@ fn parseCladDatum(p: *Parser, c: u8, next: Fn) !void {
fn getString(p: *Parser, comptime close: u8) !Value {
const msg = "string(" ++ .{close} ++ ")";
- while (try p.readNoEof2(msg)) |c| sw: switch (c) {
+ while (try p.readNoEofOpt(msg)) |c| sw: switch (c) {
close => break,
'\\' => switch (try p.readNoEof("string backslash escape")) {
'\\', '|', '"' => |c2| try p.addChar(c2),
@@ -481,7 +488,7 @@ fn getString(p: *Parser, comptime close: u8) !Value {
fn getAtString(p: *Parser) !Value {
const stop = try p.readNoEof("at-string");
- while (try p.readNoEof2("at-string")) |c| {
+ while (try p.readNoEofOpt("at-string")) |c| {
if (c == stop) break;
try p.addChar(c);
}
@@ -492,7 +499,7 @@ fn getAtString(p: *Parser) !Value {
fn skipStringLfEscape(p: *Parser) !u8 {
const msg = "string linefeed escape";
- while (try p.readNoEof2(msg)) |c| switch (c) {
+ while (try p.readNoEofOpt(msg)) |c| switch (c) {
'\t', ' ' => continue,
'\n' => return p.skipStringIndent(),
else => return p.err(.InvalidCharacter, msg),
@@ -502,7 +509,7 @@ fn skipStringLfEscape(p: *Parser) !u8 {
fn skipStringIndent(p: *Parser) !u8 {
const msg = "string newline escape";
- while (try p.readNoEof2(msg)) |c| switch (c) {
+ while (try p.readNoEofOpt(msg)) |c| switch (c) {
'\t', ' ' => continue,
else => return c,
};
@@ -511,7 +518,7 @@ fn skipStringIndent(p: *Parser) !u8 {
fn parseStringRawHexEsc(p: *Parser) !void {
const msg = "string raw hex escape";
- while (try p.readNoEof2(msg)) |c1| {
+ while (try p.readNoEofOpt(msg)) |c1| {
if (c1 == ';') break;
const c2 = try p.readNoEof(msg);
const hi = try p.parseHexDigit(c1, msg);
@@ -625,7 +632,7 @@ fn parseHashBang(p: *Parser, next: Fn) !void {
}
fn getHashBangValue(p: *Parser) !Value {
- while (try p.readNoEof2("hash-bang")) |c| switch (c) {
+ while (try p.readNoEofOpt("hash-bang")) |c| switch (c) {
' ', '\t' => continue,
'\n' => return p.err(.InvalidCharacter, "hash-bang"),
else => {