diff options
| author | Taylan Kammer <taylan.kammer@gmail.com> | 2025-02-18 22:48:57 +0100 |
|---|---|---|
| committer | Taylan Kammer <taylan.kammer@gmail.com> | 2025-02-18 22:48:57 +0100 |
| commit | 4d0db1a1065f18d879b3ff90da6ecb14e9e1ae31 (patch) | |
| tree | 7c5c275e7f3dae7bf96377560269b5a1bfa1fb99 /src/libzisp/value | |
| parent | 2384a31c42f480c961785bcf0520bb0688b8e028 (diff) | |
update
Diffstat (limited to 'src/libzisp/value')
| -rw-r--r-- | src/libzisp/value/boole.zig | 2 | ||||
| -rw-r--r-- | src/libzisp/value/char.zig | 21 | ||||
| -rw-r--r-- | src/libzisp/value/double.zig | 7 | ||||
| -rw-r--r-- | src/libzisp/value/eof.zig | 9 | ||||
| -rw-r--r-- | src/libzisp/value/fixnum.zig | 7 | ||||
| -rw-r--r-- | src/libzisp/value/misc.zig | 2 | ||||
| -rw-r--r-- | src/libzisp/value/nil.zig | 9 | ||||
| -rw-r--r-- | src/libzisp/value/pair.zig | 57 | ||||
| -rw-r--r-- | src/libzisp/value/ptr.zig | 156 | ||||
| -rw-r--r-- | src/libzisp/value/sstr.zig | 24 |
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. |
