summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2026-06-05 23:56:01 +0200
committerTaylan Kammer <taylan.kammer@gmail.com>2026-06-05 23:56:01 +0200
commit3a66abbf1d54c441828d48a29dbed9fdde68da5b (patch)
tree36ef28908d6db605c6c8b67956074f0014a866bb
parent3749ae3cdadc86656faeb642d5f260240ff18c0c (diff)
Big code cleanup; make stuff more configurable.
-rw-r--r--src/main.zig4
-rw-r--r--src/test/parse.zig31
-rw-r--r--src/test/strings.zig6
-rw-r--r--src/test/values.zig8
-rw-r--r--src/zisp/gc.zig71
-rw-r--r--src/zisp/gc/IstrSet.zig45
-rw-r--r--src/zisp/gc/PairPool.zig35
-rw-r--r--src/zisp/io/Parser.zig71
-rw-r--r--src/zisp/io/parse.zig19
-rw-r--r--src/zisp/io/print.zig2
-rw-r--r--src/zisp/value/istr.zig27
-rw-r--r--src/zisp/value/pair.zig16
12 files changed, 191 insertions, 144 deletions
diff --git a/src/main.zig b/src/main.zig
index dc1187d..a4a371f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -14,9 +14,9 @@ pub fn main() !u8 {
var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer);
const writer = &stdout_writer.interface;
- zisp.gc.init();
+ try zisp.gc.init();
- var p = try zisp.io.Parser.init(alloc, io);
+ var p = try zisp.io.Parser.init(alloc);
defer p.deinit();
while (true) {
const datum = p.run(reader) catch {
diff --git a/src/test/parse.zig b/src/test/parse.zig
index 53de21d..26d54bd 100644
--- a/src/test/parse.zig
+++ b/src/test/parse.zig
@@ -13,7 +13,7 @@ pub const Value = zisp.Value;
fn parse(str: []const u8) Value {
var fbs = std.Io.Reader.fixed(str);
- return zisp.io.parse.fromReaderNoError(alloc, io, &fbs);
+ return zisp.io.parse.fromReaderNoError(alloc, &fbs);
}
test "parse empty" {
@@ -49,14 +49,13 @@ test "parse short bare string" {
}
test "parse long bare string" {
- const str = value.istr.intern;
- try expect(parse("foobarbaz").eq(str("foobarbaz")));
- try expect(parse(".foo.bar.baz").eq(str(".foo.bar.baz")));
- try expect(parse(":foo:bar:baz").eq(str(":foo:bar:baz")));
- try expect(parse("+foo.bar.baz").eq(str("+foo.bar.baz")));
- try expect(parse("-foo.bar.baz").eq(str("-foo.bar.baz")));
- try expect(parse("0foo.bar.baz").eq(str("0foo.bar.baz")));
- try expect(parse("!$%*+-/<=>?^_~").eq(str("!$%*+-/<=>?^_~")));
+ try expect(parse("foobarbaz").eq(parse("foobarbaz")));
+ try expect(parse(".foo.bar.baz").eq(parse(".foo.bar.baz")));
+ try expect(parse(":foo:bar:baz").eq(parse(":foo:bar:baz")));
+ try expect(parse("+foo.bar.baz").eq(parse("+foo.bar.baz")));
+ try expect(parse("-foo.bar.baz").eq(parse("-foo.bar.baz")));
+ try expect(parse("0foo.bar.baz").eq(parse("0foo.bar.baz")));
+ try expect(parse("!$%*+-/<=>?^_~").eq(parse("!$%*+-/<=>?^_~")));
}
test "parse" {
@@ -75,10 +74,10 @@ test "parse2" {
\\ ;; end
);
- const r = value.rune.unpack(&value.pair.car(val));
+ const r = value.rune.unpack(&value.pair.getCar(val));
try testing.expectEqualStrings("HASH", r);
- const s = value.pair.cdr(value.pair.cdr(val));
+ const s = value.pair.getCdr(value.pair.getCdr(val));
try testing.expect(value.sstr.check(s));
const f = value.sstr.unpack(&s);
@@ -90,8 +89,8 @@ test "parse3" {
\\(foo ;~x ;~(x y) ;~x #bar [#x #"baz"] 'bat)
);
- const car = value.pair.car;
- const cdr = value.pair.cdr;
+ const car = value.pair.getCar;
+ const cdr = value.pair.getCdr;
const e1 = car(val);
const e2 = car(cdr(val));
@@ -107,10 +106,10 @@ test "parse3" {
test "parse4" {
const val = parse("(foo & ;~x bar ;~y)");
- const s = value.sstr.unpack(&value.pair.car(val));
+ const s = value.sstr.unpack(&value.pair.getCar(val));
try testing.expectEqualStrings("foo", s);
- const f = value.sstr.unpack(&value.pair.cdr(val));
+ const f = value.sstr.unpack(&value.pair.getCdr(val));
try testing.expectEqualStrings("bar", f);
}
@@ -175,7 +174,7 @@ fn parseBench(path: []const u8, iters: usize) !void {
var file_reader = file.reader(io, &buf);
const reader = &file_reader.interface;
while (true) {
- const v = zisp.io.parse.fromReaderNoError(alloc, io, reader);
+ const v = zisp.io.parse.fromReaderNoError(alloc, reader);
if (value.eof.eq(v)) break;
}
}
diff --git a/src/test/strings.zig b/src/test/strings.zig
index b8db320..3039615 100644
--- a/src/test/strings.zig
+++ b/src/test/strings.zig
@@ -11,13 +11,13 @@ const fx = value.fixnum;
test "istr" {
const s1 = "foo bar baz";
- const v1 = istr.intern(s1);
+ const v1 = try istr.intern(s1);
const v1_len: usize = @intCast(fx.unpack(istr.len(v1)));
try testing.expectEqualStrings(s1, istr.assert(v1).str());
try testing.expectEqual(s1.len, v1_len);
const s2 = @embedFile("data/string.txt");
- const v2 = istr.intern(s2);
+ const v2 = try istr.intern(s2);
const v2_len: usize = @intCast(fx.unpack(istr.len(v2)));
try testing.expectEqualStrings(s2, istr.assert(v2).str());
try testing.expectEqual(s2.len, v2_len);
@@ -25,7 +25,7 @@ test "istr" {
// Check that modifying a slice doesn't affect the string.
var s3 = "test".*;
- const v3 = istr.intern(&s3);
+ const v3 = try istr.intern(&s3);
s3[0] = 'x';
try testing.expectEqualStrings("test", istr.assert(v3).str());
}
diff --git a/src/test/values.zig b/src/test/values.zig
index 153b53f..e628b33 100644
--- a/src/test/values.zig
+++ b/src/test/values.zig
@@ -213,16 +213,16 @@ test "pair" {
try testing.expect(value.pair.check(p) != null);
try testing.expect(value.boole.unpack(value.pair.pred(p)));
- const car = value.pair.car(p);
- const cdr = value.pair.cdr(p);
+ const car = value.pair.getCar(p);
+ const cdr = value.pair.getCdr(p);
try testing.expectEqual(1, value.fixnum.unpack(car));
try testing.expectEqual(2, value.fixnum.unpack(cdr));
value.pair.setCar(p, v3);
value.pair.setCdr(p, v4);
- const car2 = value.pair.car(p);
- const cdr2 = value.pair.cdr(p);
+ const car2 = value.pair.getCar(p);
+ const cdr2 = value.pair.getCdr(p);
try testing.expectEqual(3, value.fixnum.unpack(car2));
try testing.expectEqual(4, value.fixnum.unpack(cdr2));
}
diff --git a/src/zisp/gc.zig b/src/zisp/gc.zig
index b256ea2..7fc431d 100644
--- a/src/zisp/gc.zig
+++ b/src/zisp/gc.zig
@@ -3,45 +3,44 @@ const std = @import("std");
const value = @import("value.zig");
-//const PairPool = @import("gc/PairPool.zig");
-const PairPool = std.heap.MemoryPool(value.pair.Pair); // TODO
-const IstrSet = @import("gc/IstrSet.zig");
-
-const Value = value.Value;
-
-const PairPtr = value.pair.PairPtr;
-const IstrPtr = value.istr.IstrPtr;
-
-pub const alloc = std.heap.smp_allocator;
-
-// Pairs
-
-var pair_pool: PairPool = undefined;
-
-pub fn makePair(v1: Value, v2: Value) PairPtr {
- init(); // TODO this is only here for the test suite
- const p = pair_pool.create(alloc) catch @panic("OOM");
- p.car = v1;
- p.cdr = v2;
- return p;
+const Alloc = std.mem.Allocator;
+
+pub const PairPool = @import("gc/PairPool.zig");
+pub const IstrSet = @import("gc/IstrSet.zig");
+
+var main_alloc: Alloc = undefined;
+var main_pair_pool: PairPool = undefined;
+var main_istr_set: IstrSet = undefined;
+
+var init_done = false;
+
+pub fn init() !void {
+ if (init_done) return;
+ defer init_done = true;
+ const alloc = std.heap.smp_allocator;
+ initCustom(
+ alloc,
+ try PairPool.init(alloc),
+ try IstrSet.init(alloc),
+ );
}
-// Interned strings
-
-var istr_set: IstrSet = undefined;
-
-pub fn internString(s: []const u8) value.istr.IstrPtr {
- init(); // TODO this is only here for the test suite
- return istr_set.add(alloc, s) catch @panic("OOM");
+pub fn initCustom(
+ alloc: Alloc,
+ pair_pool: PairPool,
+ istr_set: IstrSet,
+) void {
+ main_alloc = alloc;
+ main_pair_pool = pair_pool;
+ main_istr_set = istr_set;
}
-// Init
-
-var need_init = true;
+pub fn mainPairPool() *PairPool {
+ init() catch @panic("OOM"); // TODO this is only here for the test suite
+ return &main_pair_pool;
+}
-pub fn init() void {
- if (!need_init) return;
- defer need_init = false;
- pair_pool = PairPool.initCapacity(alloc, 64) catch @panic("OOM");
- istr_set = IstrSet.init(alloc) catch @panic("OOM");
+pub fn mainIstrSet() *IstrSet {
+ init() catch @panic("OOM"); // TODO this is only here for the test suite
+ return &main_istr_set;
}
diff --git a/src/zisp/gc/IstrSet.zig b/src/zisp/gc/IstrSet.zig
index a97c258..b4575f6 100644
--- a/src/zisp/gc/IstrSet.zig
+++ b/src/zisp/gc/IstrSet.zig
@@ -33,6 +33,7 @@ const Alloc = std.mem.Allocator;
const value = @import("../value.zig");
const IstrPtr = value.istr.IstrPtr;
+const IstrHead = value.istr.IstrHead;
const Set = @This();
@@ -54,6 +55,7 @@ const Bucket = [bucket_sectors][sector_u64_cnt]u64;
const SectorPtr = *align(8) SectorHead;
+// This must remain compatible with IstrHead!
const SectorHead = packed union {
hash: u64,
meta: packed struct(u64) {
@@ -97,7 +99,7 @@ const SectorHead = packed union {
istr.putStr(s);
return istr;
} else {
- const istr = try value.istr.new(alloc, hash, s);
+ const istr = try newIstr(alloc, hash, s);
self.bufU64()[1] = @intFromPtr(istr);
return istr;
}
@@ -107,8 +109,19 @@ const SectorHead = packed union {
const end = sector_u64_cnt;
@memcpy(dest.bufU64()[0..end], self.bufU64()[0..end]);
}
+
+ fn newIstr(alloc: Alloc, hash: u64, s: []const u8) !IstrPtr {
+ const algn = std.mem.Alignment.of(IstrPtr);
+ const size = @sizeOf(IstrHead) + s.len;
+ const ptr = try alloc.alignedAlloc(u8, algn, size);
+ const istr: IstrPtr = @ptrCast(ptr);
+ istr.* = .{ .hash = hash };
+ istr.putStr(s);
+ return istr;
+ }
};
+alloc: Alloc,
buckets: []Bucket = undefined,
used_sectors: usize = 0,
@@ -122,19 +135,19 @@ pub fn init(alloc: Alloc) !Set {
pub fn initCustom(alloc: Alloc, bcount: usize) !Set {
std.debug.assert(@popCount(bcount) == 1); // Must be power of 2.
- var self = Set{};
- try self.allocBuckets(alloc, bcount);
+ var self = Set{ .alloc = alloc };
+ try self.allocBuckets(bcount);
return self;
}
-fn allocBuckets(self: *Set, alloc: Alloc, bcount: usize) !void {
- self.buckets = try alloc.alloc(Bucket, bcount);
+fn allocBuckets(self: *Set, bcount: usize) !void {
+ self.buckets = try self.alloc.alloc(Bucket, bcount);
@memset(self.buckets, std.mem.zeroes(Bucket));
self.used_threshold = bcount * bucket_sectors * max_fill_percent / 100;
}
-pub fn deinit(self: *Set, alloc: Alloc) void {
- alloc.free(self.buckets);
+pub fn deinit(self: *Set) void {
+ self.alloc.free(self.buckets);
}
fn sector(bs: []Bucket, b_idx: usize, s_idx: usize) SectorPtr {
@@ -142,7 +155,7 @@ fn sector(bs: []Bucket, b_idx: usize, s_idx: usize) SectorPtr {
}
/// Add, or get existing, string.
-pub fn add(self: *Set, alloc: Alloc, s: []const u8) !IstrPtr {
+pub fn add(self: *Set, s: []const u8) !IstrPtr {
std.debug.assert(s.len < 256);
const idx_mask = self.buckets.len - 1;
@@ -162,28 +175,28 @@ pub fn add(self: *Set, alloc: Alloc, s: []const u8) !IstrPtr {
};
if (idx -% idx_init >= max_probe_length) {
- try self.resize(alloc);
- return self.add(alloc, s);
+ try self.resize();
+ return self.add(s);
}
self.used_sectors += 1;
if (self.used_sectors >= self.used_threshold) {
- try self.resize(alloc);
- return self.add(alloc, s);
+ try self.resize();
+ return self.add(s);
}
const sec = sector(self.buckets, idx, s_idx);
- return sec.insert(alloc, hash, s);
+ return sec.insert(self.alloc, hash, s);
}
-fn resize(self: *Set, alloc: Alloc) !void {
+fn resize(self: *Set) !void {
const old_bc = self.buckets.len;
const old_bs = self.buckets;
const new_bc = old_bc << 1;
- try self.allocBuckets(alloc, new_bc);
- defer alloc.free(old_bs);
+ try self.allocBuckets(new_bc);
+ defer self.alloc.free(old_bs);
const new_bs = self.buckets;
diff --git a/src/zisp/gc/PairPool.zig b/src/zisp/gc/PairPool.zig
index 70b786d..8a437ae 100644
--- a/src/zisp/gc/PairPool.zig
+++ b/src/zisp/gc/PairPool.zig
@@ -1 +1,34 @@
-// TODO
+const std = @import("std");
+
+const value = @import("../value.zig");
+
+const Alloc = std.mem.Allocator;
+const PairMemPool = std.heap.MemoryPool(value.pair.Pair);
+
+const Value = value.Value;
+const PairPtr = value.pair.PairPtr;
+
+const PairPool = @This();
+
+alloc: Alloc,
+pair_pool: PairMemPool,
+
+const default_init_cap = 1024;
+
+pub fn init(alloc: Alloc) !PairPool {
+ return initCustom(alloc, default_init_cap);
+}
+
+pub fn initCustom(alloc: Alloc, init_cap: usize) !PairPool {
+ return .{
+ .alloc = alloc,
+ .pair_pool = try PairMemPool.initCapacity(alloc, init_cap),
+ };
+}
+
+pub fn cons(self: *PairPool, car: Value, cdr: Value) !PairPtr {
+ var p = try self.pair_pool.create(self.alloc);
+ p.car = car;
+ p.cdr = cdr;
+ return p;
+}
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 => {
diff --git a/src/zisp/io/parse.zig b/src/zisp/io/parse.zig
index 7d8db33..06dfea0 100644
--- a/src/zisp/io/parse.zig
+++ b/src/zisp/io/parse.zig
@@ -5,6 +5,9 @@ const value = @import("../value.zig");
const Parser = @import("Parser.zig");
+const Alloc = std.mem.Allocator;
+const Reader = *std.Io.Reader;
+
const Value = value.Value;
const is_test = builtin.is_test;
@@ -15,22 +18,14 @@ const ParserErrors = error{
OutOfMemory,
};
-pub fn fromReader(
- alloc: std.mem.Allocator,
- io: std.Io,
- input: *std.Io.Reader,
-) ParserErrors!Value {
- var p = try Parser.init(alloc, io);
+pub fn fromReader(alloc: Alloc, input: Reader) ParserErrors!Value {
+ var p = try Parser.init(alloc);
defer p.deinit();
return p.run(input);
}
-pub fn fromReaderNoError(
- alloc: std.mem.Allocator,
- io: std.Io,
- input: *std.Io.Reader,
-) Value {
- var p = Parser.init(alloc, io) catch @panic("OOM");
+pub fn fromReaderNoError(alloc: Alloc, input: Reader) Value {
+ var p = Parser.init(alloc) catch @panic("OOM");
defer p.deinit();
return p.run(input) catch |e| switch (e) {
error.OutOfMemory => @panic("OOM"),
diff --git a/src/zisp/io/print.zig b/src/zisp/io/print.zig
index 85d2b5c..890befd 100644
--- a/src/zisp/io/print.zig
+++ b/src/zisp/io/print.zig
@@ -159,7 +159,7 @@ pub fn list(w: Writer, p: PairPtr) !void {
try w.writeByte('(');
try toWriter(w, p.car);
var cdr = p.cdr;
- while (value.pair.check(cdr)) |p2| : (cdr = value.pair.cdr(cdr)) {
+ while (value.pair.check(cdr)) |p2| : (cdr = p2.cdr) {
try w.writeByte(' ');
try toWriter(w, p2.car);
}
diff --git a/src/zisp/value/istr.zig b/src/zisp/value/istr.zig
index 335a57e..2abfa66 100644
--- a/src/zisp/value/istr.zig
+++ b/src/zisp/value/istr.zig
@@ -5,6 +5,7 @@ const value = @import("../value.zig");
const Alloc = std.mem.Allocator;
+const IstrSet = gc.IstrSet;
const Value = value.Value;
// Zig API
@@ -13,9 +14,9 @@ const Value = value.Value;
///
/// First 64 bits are a cached hash, of which the lowest 8 bits are actually the
/// length of the string: u64hash = (real_u64hash << 8) | u8length
-pub const IstrPtr = *align(@alignOf(value.Zptr)) IstrHeader;
+pub const IstrPtr = *align(@alignOf(value.Zptr)) IstrHead;
-const IstrHeader = packed union {
+pub const IstrHead = packed union {
hash: u64,
meta: packed struct(u64) {
len: u8,
@@ -29,27 +30,17 @@ const IstrHeader = packed union {
pub fn putStr(self: *@This(), s: []const u8) void {
std.debug.assert(s.len <= 255);
const buf = self.bufU8();
- const start = @sizeOf(IstrHeader);
+ const start = @sizeOf(IstrHead);
@memcpy(buf[start .. start + s.len], s);
}
pub fn str(self: *@This()) []const u8 {
const buf = self.bufU8();
- const start = @sizeOf(IstrHeader);
+ const start = @sizeOf(IstrHead);
return buf[start .. start + self.meta.len];
}
};
-pub fn new(alloc: Alloc, hash: u64, s: []const u8) !IstrPtr {
- const algn = std.mem.Alignment.of(IstrPtr);
- const size = @sizeOf(IstrHeader) + s.len;
- const ptr = try alloc.alignedAlloc(u8, algn, size);
- const istr: IstrPtr = @ptrCast(ptr);
- istr.* = .{ .hash = hash };
- istr.putStr(s);
- return istr;
-}
-
pub fn check(v: Value) ?IstrPtr {
if (v.getPtr(.istr)) |p| {
return @ptrCast(p);
@@ -75,9 +66,13 @@ fn assertValidIstr(s: []const u8) void {
}
}
-pub fn intern(s: []const u8) Value {
+pub fn intern(s: []const u8) !Value {
+ return internInSet(gc.mainIstrSet(), s);
+}
+
+pub fn internInSet(set: *IstrSet, s: []const u8) !Value {
assertValidIstr(s);
- const istr = gc.internString(s);
+ const istr = try set.add(s);
return value.ptr.pack(@ptrCast(istr), .istr);
}
diff --git a/src/zisp/value/pair.zig b/src/zisp/value/pair.zig
index c468d4a..edc106d 100644
--- a/src/zisp/value/pair.zig
+++ b/src/zisp/value/pair.zig
@@ -5,6 +5,7 @@ const value = @import("../value.zig");
const ptr = @import("ptr.zig");
+const PairPool = gc.PairPool;
const Value = value.Value;
pub const PairPtr = *align(8) Pair;
@@ -31,22 +32,27 @@ pub fn unpack(v: Value) PairPtr {
return assert(v);
}
+pub fn consInPool(pool: *PairPool, car: Value, cdr: Value) !Value {
+ const pair = try pool.cons(car, cdr);
+ return ptr.pack(@ptrCast(pair), .pair);
+}
+
// Zisp API
pub fn pred(v: Value) Value {
return value.boole.pack(check(v) != null);
}
-pub fn cons(v1: Value, v2: Value) Value {
- const pair = gc.makePair(v1, v2);
- return ptr.pack(@ptrCast(pair), .pair);
+pub fn cons(car: Value, cdr: Value) Value {
+ const pool = gc.mainPairPool();
+ return consInPool(pool, car, cdr) catch @panic("OOM"); // TODO
}
-pub fn car(v: Value) Value {
+pub fn getCar(v: Value) Value {
return unpack(v).car;
}
-pub fn cdr(v: Value) Value {
+pub fn getCdr(v: Value) Value {
return unpack(v).cdr;
}