diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.zig | 4 | ||||
| -rw-r--r-- | src/test/parse.zig | 31 | ||||
| -rw-r--r-- | src/test/strings.zig | 6 | ||||
| -rw-r--r-- | src/test/values.zig | 8 | ||||
| -rw-r--r-- | src/zisp/gc.zig | 71 | ||||
| -rw-r--r-- | src/zisp/gc/IstrSet.zig | 45 | ||||
| -rw-r--r-- | src/zisp/gc/PairPool.zig | 35 | ||||
| -rw-r--r-- | src/zisp/io/Parser.zig | 71 | ||||
| -rw-r--r-- | src/zisp/io/parse.zig | 19 | ||||
| -rw-r--r-- | src/zisp/io/print.zig | 2 | ||||
| -rw-r--r-- | src/zisp/value/istr.zig | 27 | ||||
| -rw-r--r-- | src/zisp/value/pair.zig | 16 |
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; } |
