summaryrefslogtreecommitdiff
path: root/src/libzisp/value
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2025-02-18 22:48:57 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2025-02-18 22:48:57 +0100
commit4d0db1a1065f18d879b3ff90da6ecb14e9e1ae31 (patch)
tree7c5c275e7f3dae7bf96377560269b5a1bfa1fb99 /src/libzisp/value
parent2384a31c42f480c961785bcf0520bb0688b8e028 (diff)
update
Diffstat (limited to 'src/libzisp/value')
-rw-r--r--src/libzisp/value/boole.zig2
-rw-r--r--src/libzisp/value/char.zig21
-rw-r--r--src/libzisp/value/double.zig7
-rw-r--r--src/libzisp/value/eof.zig9
-rw-r--r--src/libzisp/value/fixnum.zig7
-rw-r--r--src/libzisp/value/misc.zig2
-rw-r--r--src/libzisp/value/nil.zig9
-rw-r--r--src/libzisp/value/pair.zig57
-rw-r--r--src/libzisp/value/ptr.zig156
-rw-r--r--src/libzisp/value/sstr.zig24
10 files changed, 188 insertions, 106 deletions
diff --git a/src/libzisp/value/boole.zig b/src/libzisp/value/boole.zig
index 0af7e22..623dbc2 100644
--- a/src/libzisp/value/boole.zig
+++ b/src/libzisp/value/boole.zig
@@ -30,5 +30,5 @@ pub fn unpack(v: Value) bool {
// Zisp API
pub fn pred(v: Value) Value {
- return if (check(v)) t else f;
+ return pack(check(v));
}
diff --git a/src/libzisp/value/char.zig b/src/libzisp/value/char.zig
index 6a38f0d..98bb26f 100644
--- a/src/libzisp/value/char.zig
+++ b/src/libzisp/value/char.zig
@@ -1,10 +1,11 @@
-const Value = @import("../value.zig").Value;
+const value = @import("../value.zig");
+
+const Value = value.Value;
+
+// Zig API
pub fn check(v: Value) bool {
- return v.isPacked() and
- !v.char.fixnum and
- !v.char.ptr and
- v.char.tag == .char;
+ return v.isOther(.char);
}
pub fn assert(v: Value) void {
@@ -15,10 +16,16 @@ pub fn assert(v: Value) void {
}
pub fn pack(c: u21) Value {
- return .{ .char = .{ .value = c } };
+ return .{ .char = .{ .char = c } };
}
pub fn unpack(v: Value) u21 {
assert(v);
- return @truncate(v.char.value);
+ return @truncate(v.char.char);
+}
+
+// Zisp API
+
+pub fn pred(v: Value) Value {
+ return value.boole.pack(check(v));
}
diff --git a/src/libzisp/value/double.zig b/src/libzisp/value/double.zig
index 5c98324..5cfe6ee 100644
--- a/src/libzisp/value/double.zig
+++ b/src/libzisp/value/double.zig
@@ -1,10 +1,11 @@
-const Value = @import("../value.zig").Value;
+const value = @import("../value.zig");
+const Value = value.Value;
// Zig API
/// Checks for a Zisp double (double, +inf, -inf, or canonical NaN).
pub fn check(v: Value) bool {
- return !v.isPacked();
+ return v.isDouble();
}
/// Asserts check().
@@ -27,7 +28,7 @@ pub fn unpack(v: Value) f64 {
// Zisp API
pub fn pred(v: Value) Value {
- return Value.boole.pack(check(v));
+ return value.boole.pack(check(v));
}
pub fn add(v1: Value, v2: Value) Value {
diff --git a/src/libzisp/value/eof.zig b/src/libzisp/value/eof.zig
index 34ab35d..367a86c 100644
--- a/src/libzisp/value/eof.zig
+++ b/src/libzisp/value/eof.zig
@@ -1,7 +1,8 @@
-const Value = @import("../value.zig").Value;
-const misc = @import("misc.zig");
+const value = @import("../value.zig");
-pub const eof = misc.eof;
+const Value = value.Value;
+
+pub const eof = @import("misc.zig").eof;
// Zig API
@@ -23,5 +24,5 @@ pub fn get() Value {
}
pub fn pred(v: Value) Value {
- return if (check(v)) misc.t else misc.f;
+ return value.boole.pack(check(v));
}
diff --git a/src/libzisp/value/fixnum.zig b/src/libzisp/value/fixnum.zig
index 6d26a9c..888dd3a 100644
--- a/src/libzisp/value/fixnum.zig
+++ b/src/libzisp/value/fixnum.zig
@@ -1,12 +1,13 @@
const std = @import("std");
+const value = @import("../value.zig");
-const Value = @import("../value.zig").Value;
+const Value = value.Value;
// Zig API
/// Checks for a Zisp fixnum.
pub fn check(v: Value) bool {
- return v.isPacked() and v.fixnum.is_fixnum;
+ return v.isFixnum();
}
/// Asserts check().
@@ -77,7 +78,7 @@ pub fn unpack(v: Value) i64 {
// Zisp API
pub fn pred(v: Value) Value {
- return Value.boole.pack(check(v));
+ return value.boole.pack(check(v));
}
pub fn add(v1: Value, v2: Value) Value {
diff --git a/src/libzisp/value/misc.zig b/src/libzisp/value/misc.zig
index 793c60e..30cbf84 100644
--- a/src/libzisp/value/misc.zig
+++ b/src/libzisp/value/misc.zig
@@ -4,3 +4,5 @@ pub const f = Value{ .misc = .{ .value = 0 } };
pub const t = Value{ .misc = .{ .value = 1 } };
pub const nil = Value{ .misc = .{ .value = 2 } };
pub const eof = Value{ .misc = .{ .value = 3 } };
+
+pub const undef = Value{ .misc = .{ .value = 255 } };
diff --git a/src/libzisp/value/nil.zig b/src/libzisp/value/nil.zig
index 1b1a51e..14bd800 100644
--- a/src/libzisp/value/nil.zig
+++ b/src/libzisp/value/nil.zig
@@ -1,7 +1,8 @@
-const Value = @import("../value.zig").Value;
-const misc = @import("misc.zig");
+const value = @import("../value.zig");
-pub const nil = misc.nil;
+const Value = value.Value;
+
+pub const nil = @import("misc.zig").nil;
// Zig API
@@ -23,5 +24,5 @@ pub fn get() Value {
}
pub fn pred(v: Value) Value {
- return if (check(v)) misc.t else misc.f;
+ return value.boole.pack(check(v));
}
diff --git a/src/libzisp/value/pair.zig b/src/libzisp/value/pair.zig
new file mode 100644
index 0000000..541a5f5
--- /dev/null
+++ b/src/libzisp/value/pair.zig
@@ -0,0 +1,57 @@
+const std = @import("std");
+const value = @import("../value.zig");
+const gc = @import("../gc.zig");
+
+const ptr = @import("ptr.zig");
+
+const Value = value.Value;
+
+// Zig API
+
+pub fn check(v: Value) bool {
+ return ptr.checkZisp(v, .pair);
+}
+
+pub fn assert(v: Value) void {
+ if (!check(v)) {
+ v.dump();
+ @panic("not pair");
+ }
+}
+
+// Zisp API
+
+pub fn pred(v: Value) Value {
+ return value.boole.pack(check(v));
+}
+
+pub fn cons(v1: Value, v2: Value) Value {
+ const mem = gc.alloc(2);
+ mem[0] = .{ .value = v1 };
+ mem[1] = .{ .value = v2 };
+ return ptr.pack(mem.ptr, .pair);
+}
+
+fn getMem(v: Value) *[2]Value {
+ return @ptrCast(ptr.unpack(v).@"0");
+}
+
+pub fn car(v: Value) Value {
+ assert(v);
+ return getMem(v)[0];
+}
+
+pub fn cdr(v: Value) Value {
+ assert(v);
+ return getMem(v)[1];
+}
+
+pub fn setcar(v: Value, new: Value) void {
+ assert(v);
+ getMem(v)[0] = new;
+}
+
+pub fn setcdr(v: Value, new: Value) void {
+ assert(v);
+ getMem(v)[1] = new;
+}
diff --git a/src/libzisp/value/ptr.zig b/src/libzisp/value/ptr.zig
index 6a3a6c4..fe13af5 100644
--- a/src/libzisp/value/ptr.zig
+++ b/src/libzisp/value/ptr.zig
@@ -1,11 +1,14 @@
const std = @import("std");
+const value = @import("../value.zig");
+const gc = @import("../gc.zig");
-const Value = @import("../value.zig").Value;
+const Bucket = gc.Bucket;
+const Value = value.Value;
// Zig API
pub fn check(v: Value) bool {
- return v.isPacked() and v.ptr.is_ptr;
+ return v.isPtr();
}
pub fn assert(v: Value) void {
@@ -18,7 +21,7 @@ pub fn assert(v: Value) void {
// Foreign Pointers
pub fn checkForeign(v: Value) bool {
- return check(v) and v.ptr.foreign;
+ return check(v) and v.ptr.is_foreign;
}
pub fn assertForeign(v: Value) void {
@@ -28,151 +31,166 @@ pub fn assertForeign(v: Value) void {
}
}
-pub fn packForeign(int: u50) Value {
- return .{ .fptr = .{int} };
+pub fn checkForeignRange(ptr: *anyopaque) bool {
+ const int = @intFromPtr(ptr);
+ return int <= std.math.maxInt(u50);
}
-pub fn unpackForeign(v: Value) u64 {
+fn assertForeignRange(ptr: *anyopaque) void {
+ if (!checkForeignRange(ptr)) {
+ std.debug.print("foreign pointer out of range: {}\n", .{ptr});
+ @panic("foreign pointer out of range");
+ }
+}
+
+pub fn packForeign(ptr: *anyopaque) Value {
+ assertForeignRange(ptr);
+ const int: u50 = @intCast(@intFromPtr(ptr));
+ return .{ .fptr = .{ .value = int } };
+}
+
+pub fn unpackForeign(v: Value) *anyopaque {
assertForeign(v);
- return v.ptr.value.foreign;
+ return @ptrFromInt(v.fptr.value);
}
// Zisp Pointers
-pub fn checkZisp(v: Value) bool {
- return check(v) and !v.ptr.foreign;
+fn _checkZisp(v: Value) bool {
+ return check(v) and !v.ptr.is_foreign;
}
-pub fn assertZisp(v: Value) void {
- if (!checkZisp(v)) {
+fn _assertZisp(v: Value) void {
+ if (!_checkZisp(v)) {
v.dump();
@panic("not zisp pointer");
}
}
pub fn checkWeak(v: Value) bool {
- return checkZisp(v) and v.ptr.weak;
+ return _checkZisp(v) and v.zptr.is_weak;
}
pub fn assertWeak(v: Value) void {
if (!checkWeak(v)) {
v.dump();
- @panic("not weak zisp pointer");
+ @panic("not zisp weak pointer");
+ }
+}
+
+pub fn checkZisp(v: Value, tag: Tag) bool {
+ return _checkZisp(v) and unpack(v).@"1" == tag;
+}
+
+pub fn assertZisp(v: Value, tag: Tag) void {
+ if (!checkZisp(v, tag)) {
+ v.dump();
+ @panic("not zisp pointer or wrong tag");
}
}
-pub fn checkNormal(v: Value) bool {
- return checkZisp(v) and !v.ptr.weak;
+pub fn checkStrong(v: Value) bool {
+ return _checkZisp(v) and !v.zptr.is_weak;
}
-pub fn assertNormal(v: Value) void {
- if (!checkNormal(v)) {
+pub fn assertStrong(v: Value) void {
+ if (!checkStrong(v)) {
v.dump();
- @panic("not normal zisp pointer");
+ @panic("not zisp strong pointer");
}
}
-pub fn packZisp(ptr: *anyopaque, tag: Tag, weak: bool) Value {
- return .{ .ptr = .{
- .value = tagPtr(ptr, tag),
- .weak = weak,
+pub fn packZisp(ptr: [*]Bucket, tag: Tag, is_weak: bool) Value {
+ return .{ .zptr = .{
+ .tagged_value = tagPtr(ptr, tag),
+ .is_weak = is_weak,
} };
}
-pub fn pack(ptr: *anyopaque, tag: Tag) Value {
+pub fn pack(ptr: [*]Bucket, tag: Tag) Value {
return packZisp(ptr, tag, false);
}
-pub fn packWeak(ptr: *anyopaque, tag: Tag) Value {
+pub fn packWeak(ptr: [*]Bucket, tag: Tag) Value {
return packZisp(ptr, tag, true);
}
// Unpacks weak as well; no need for a separate fn.
-pub fn unpack(v: Value) PtrAndTag {
- assertZisp(v);
- return untagPtr(v.ptr.value);
+pub fn unpack(v: Value) struct { [*]Bucket, Tag } {
+ _assertZisp(v);
+ return untagPtr(v.zptr.tagged_value);
}
-// Weak pointers may be null.
-pub fn isNull(v: Value) bool {
- assertWeak(v);
- const ptr, _ = untagPtr(v.ptr.value);
- return @intFromPtr(ptr) == 0;
+pub fn setWeakNull(v: *Value) void {
+ assertWeak(v.*);
+ v.zptr.tagged_value = 0;
}
-pub fn tagPtr(ptr: *anyopaque, tag: Tag) u49 {
- const int: u64 = @intFromPtr(ptr);
- const untagged: u49 = @truncate(int);
- return untagged << 1 | @intFromEnum(tag);
+pub fn isWeakNull(v: Value) bool {
+ assertWeak(v);
+ return v.zptr.tagged_value == 0;
}
-pub const PtrAndTag = struct { *anyopaque, Tag };
+fn tagPtr(ptr: [*]Bucket, tag: Tag) u48 {
+ const int: usize = @intFromPtr(ptr);
+ const untagged: u48 = @intCast(int);
+ return untagged | @intFromEnum(tag);
+}
-pub fn untagPtr(tagged: u49) PtrAndTag {
- const untagged: u49 = tagged >> 1 & 0xfffffffffff0;
- const ptr: *anyopaque = @ptrFromInt(untagged);
- const int: u4 = @truncate(tagged);
+fn untagPtr(tagged: u48) struct { [*]Bucket, Tag } {
+ const untagged: u48 = tagged & 0xfffffffffff8;
+ const ptr: [*]Bucket = @ptrFromInt(untagged);
+ const int: u3 = @truncate(tagged);
const tag: Tag = @enumFromInt(int);
return .{ ptr, tag };
}
-pub const Tag = enum(u4) {
+pub const Tag = enum(u3) {
/// 0. Strings / Symbols
string,
/// 1. Bignums / Ratnums
number,
/// 2. Pairs ([2]Value)
pair,
- /// 3. Vector, bytevector, etc.
- array,
- /// 4. Ordered hash table
- table,
- /// 5. String buffer
+ /// 3. Collections: Vector, table, etc.
+ coll,
+ /// 4. OOP: Classes, instances, etc.
+ oop,
+ /// 5. String buffers
text,
- /// 6. Class, interface, etc.
- role,
- /// 7. Instance, basically
- actor,
- /// 8. I/O Port
- port,
- /// 9. Procedure
+ /// 6. Procedures
proc,
- /// 10. Continuation
- cont,
- /// Other
- other = 15,
+ /// 7. Others
+ other,
};
// Zisp API
pub fn predForeign(v: Value) Value {
- return Value.boole.pack(checkForeign(v));
+ return value.boole.pack(checkForeign(v));
}
pub fn makeWeak(v: Value) Value {
- assertNormal(v);
+ assertStrong(v);
var copy = v;
- copy.ptr.weak = true;
+ copy.zptr.is_weak = true;
return copy;
}
pub fn predWeak(v: Value) Value {
- const isWeak = checkWeak(v);
- return Value.boole.pack(isWeak);
+ return value.boole.pack(checkWeak(v));
}
pub fn predWeakNull(v: Value) Value {
- assertWeak(v);
- return Value.boole.pack(v.ptr.weak);
+ return value.boole.pack(isWeakNull(v));
}
pub fn getWeak(v: Value) Value {
- assertWeak(v);
- if (isNull(v)) {
- return Value.boole.pack(false);
+ if (isWeakNull(v)) {
+ return value.boole.f;
} else {
var copy = v;
- copy.ptr.weak = false;
+ copy.zptr.is_weak = false;
return copy;
}
}
diff --git a/src/libzisp/value/sstr.zig b/src/libzisp/value/sstr.zig
index 55b3f8b..896b8d7 100644
--- a/src/libzisp/value/sstr.zig
+++ b/src/libzisp/value/sstr.zig
@@ -5,10 +5,7 @@ const Value = @import("../value.zig").Value;
// Zig API
pub fn check(v: Value) bool {
- return v.isPacked() and
- !v.sstr.fixnum and
- !v.sstr.ptr and
- v.sstr.tag == .sstr;
+ return v.isOther(.sstr);
}
pub fn assert(v: Value) void {
@@ -41,25 +38,22 @@ fn assertValidSstr(s: []const u8) void {
// Different ways of doing the following have been tested, including manual
// shifting and bit masking, but memcpy always wins easily according to our
-// micro-benchmarks, both under ReleaseSafe and under ReleaseFast.
+// micro-benchmarks, under both ReleaseSafe and ReleaseFast.
pub fn pack(s: []const u8) Value {
assertValidSstr(s);
- var v = Value{ .sstr = .{ .value = 0 } };
- const dest: [*]u8 = @ptrCast(&v.sstr.value);
+ var v = Value{ .sstr = .{ .string = 0 } };
+ const dest: [*]u8 = @ptrCast(&v.sstr.string);
@memcpy(dest, s);
return v;
}
-// It's tempting to inline for here to eliminate the if statement or prevent
-// need of @truncate but all alternatives were a little slower.
-
pub fn unpack(v: Value) struct { [6]u8, u3 } {
- var s: [6]u8 = undefined;
- const src: *const [6]u8 = @ptrCast(&v.sstr.value);
- @memcpy(&s, src);
- for (0..6) |i| {
- if (s[i] == 0) return .{ s, @intCast(i) };
+ const s: [6]u8 = @bitCast(v.sstr.string);
+ inline for (0..6) |i| {
+ if (s[i] == 0) return .{ s, i };
}
return .{ s, 6 };
}
+
+// No Zisp API for sstr specifically, since it's a string. See string.zig.