summaryrefslogtreecommitdiff
path: root/src/libzisp/value
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2025-03-18 21:39:51 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2025-03-18 21:39:51 +0100
commitf1c256884b0d59683e8bd43160b048561191a809 (patch)
tree804f356fccb0e1a2b77f61e25bc81cbfc2452b03 /src/libzisp/value
parentc43c3c22e5d0f872168c5b687141c7b08a188c5d (diff)
Implement istr.
Diffstat (limited to 'src/libzisp/value')
-rw-r--r--src/libzisp/value/fixnum.zig12
-rw-r--r--src/libzisp/value/istr.zig55
-rw-r--r--src/libzisp/value/pair.zig1
-rw-r--r--src/libzisp/value/ptr.zig6
-rw-r--r--src/libzisp/value/seq.zig56
5 files changed, 119 insertions, 11 deletions
diff --git a/src/libzisp/value/fixnum.zig b/src/libzisp/value/fixnum.zig
index c705880..80fb4ae 100644
--- a/src/libzisp/value/fixnum.zig
+++ b/src/libzisp/value/fixnum.zig
@@ -19,19 +19,15 @@ pub fn assert(v: Value) void {
}
// See detailed NaN packing docs for why the +/- 1.
-const fixnum_min = std.math.minInt(i52) + 1;
-const fixnum_max = std.math.maxInt(i52) - 1;
-
-pub fn isValidRange(int: i64) bool {
- return fixnum_min < int and int < fixnum_max;
-}
+pub const min = std.math.minInt(i52) + 1;
+pub const max = std.math.maxInt(i52) - 1;
fn assertValidRange(int: i64) void {
- if (int < fixnum_min) {
+ if (int < min) {
std.debug.print("int too small for fixnum: {}\n", .{int});
@panic("int too small for fixnum");
}
- if (int > fixnum_max) {
+ if (int > max) {
std.debug.print("int too large for fixnum: {}\n", .{int});
@panic("int too large for fixnum");
}
diff --git a/src/libzisp/value/istr.zig b/src/libzisp/value/istr.zig
index 5937531..8056d98 100644
--- a/src/libzisp/value/istr.zig
+++ b/src/libzisp/value/istr.zig
@@ -1,3 +1,58 @@
const std = @import("std");
const value = @import("../value.zig");
+const gc = @import("../gc.zig");
+
+const ptr = @import("ptr.zig");
+const seq = @import("seq.zig");
+
+const Value = value.Value;
+
+// Zig API
+
+pub fn check(v: Value) bool {
+ return ptr.checkZispTag(v, .seq);
+}
+
+pub fn assert(v: Value) void {
+ if (!check(v)) {
+ v.dump();
+ @panic("not istr");
+ }
+}
+
+pub fn intern(str: []const u8, quoted: bool) Value {
+ if (str.len > value.fixnum.max) {
+ @panic("String length out of fixnum range.");
+ }
+ const header: seq.Header = .{
+ .type = .string,
+ .info = .{ .string = .{
+ .enc = .utf8,
+ .quoted = quoted,
+ .interned = true,
+ } },
+ .size = @intCast(str.len),
+ };
+ const bytes_ptr = gc.intern(header, str);
+ return ptr.pack(bytes_ptr, .seq);
+}
+
+pub fn getHeader(v: Value) *seq.Header {
+ assert(v);
+ return gc.istrHeader(ptr.unpack(v).@"0");
+}
+
+// Zisp API
+
+pub fn pred(v: Value) Value {
+ return value.boole.pack(check(v));
+}
+
+pub fn len(v: Value) Value {
+ const l = getHeader(v).size;
+ if (l > value.fixnum.max) {
+ @panic("string length out of range");
+ }
+ return value.fixnum.pack(@intCast(l));
+}
diff --git a/src/libzisp/value/pair.zig b/src/libzisp/value/pair.zig
index 87e18e7..6ea1edf 100644
--- a/src/libzisp/value/pair.zig
+++ b/src/libzisp/value/pair.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+
const value = @import("../value.zig");
const gc = @import("../gc.zig");
diff --git a/src/libzisp/value/ptr.zig b/src/libzisp/value/ptr.zig
index 115cc2d..b07acc4 100644
--- a/src/libzisp/value/ptr.zig
+++ b/src/libzisp/value/ptr.zig
@@ -132,10 +132,10 @@ fn untagPtr(tagged: u48) struct { [*]Hval, Tag } {
}
pub const Tag = enum(u3) {
- /// *[2]Value
+ /// Pair aka cons cell aka *[2]Value
pair,
- /// Interned string (symbol)
- istr,
+ /// Sequence of various kinds (16-bit meta, 48-bit length, then data)
+ seq,
/// Procedure
proc,
};
diff --git a/src/libzisp/value/seq.zig b/src/libzisp/value/seq.zig
new file mode 100644
index 0000000..5382a7e
--- /dev/null
+++ b/src/libzisp/value/seq.zig
@@ -0,0 +1,56 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const value = @import("../value.zig");
+const gc = @import("../gc.zig");
+
+const Value = value.Value;
+
+const Endian = enum(u1) {
+ little,
+ big,
+
+ const native: Endian = switch (builtin.target.cpu.arch.endian()) {
+ .little => .little,
+ .big => .big,
+ };
+};
+
+pub const Header = packed struct(u64) {
+ type: enum(u2) {
+ values,
+ string,
+ ints,
+ floats,
+ },
+ info: packed union {
+ values: packed struct(u14) {
+ weak: bool = false,
+ _: u13 = 0,
+ },
+ string: packed struct(u14) {
+ enc: enum(u4) { utf8, utf16, utf24, utf32 },
+ endian: Endian = .native,
+ quoted: bool,
+ interned: bool,
+ _: u7 = 0,
+ },
+ ints: packed struct(u14) {
+ signed: bool,
+ endian: Endian = .native,
+ size: u12,
+ },
+ floats: packed struct(u14) {
+ double: bool,
+ endian: Endian = .native,
+ _: u12 = 0,
+ },
+ },
+ size: u48,
+
+ pub fn bytes(self: *Header) []u8 {
+ const ptr: [*]u8 = @ptrCast(self);
+ const end = 8 + self.size;
+ return ptr[8..end];
+ }
+};