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 | |
| parent | 2384a31c42f480c961785bcf0520bb0688b8e028 (diff) | |
update
Diffstat (limited to 'src/libzisp')
| -rw-r--r-- | src/libzisp/gc.zig | 15 | ||||
| -rw-r--r-- | src/libzisp/read.zig | 105 | ||||
| -rw-r--r-- | src/libzisp/value.zig | 161 | ||||
| -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 |
13 files changed, 421 insertions, 154 deletions
diff --git a/src/libzisp/gc.zig b/src/libzisp/gc.zig new file mode 100644 index 0000000..819fa0b --- /dev/null +++ b/src/libzisp/gc.zig @@ -0,0 +1,15 @@ +const std = @import("std"); + +const Value = @import("value.zig").Value; + +var _gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; +const gpa = _gpa.allocator(); + +pub const Bucket = packed union { + bits: u64, + value: Value, +}; + +pub fn alloc(count: usize) []Bucket { + return gpa.alloc(Bucket, count) catch @panic("OOM"); +} diff --git a/src/libzisp/read.zig b/src/libzisp/read.zig new file mode 100644 index 0000000..9ef9891 --- /dev/null +++ b/src/libzisp/read.zig @@ -0,0 +1,105 @@ +const std = @import("std"); + +const gc = @import("gc.zig"); +const value = @import("value.zig"); + +const Value = value.Value; + +const State = struct { + alloc: std.mem.Allocator, + input: []const u8, + pos: usize = 0, + + next: enum { + start, + + list, + list_end, + + err, + + done, + } = .start, + + retval: Value = value.eof.eof, + + parent: ?*State = null, +}; + +pub fn read(input: []const u8) Value { + var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; + var top = State{ .alloc = gpa.allocator(), .input = input }; + var s = ⊤ + while (s.pos <= s.input.len) : (s.pos += 1) { + s = switch (s.next) { + .start => start(s), + + .list => list(s), + .list_end => list(s), + + .err => err(s), + + .done => ret: { + if (s.parent) |parent| { + s.alloc.destroy(s); + break :ret parent; + } else { + return s.retval; + } + }, + }; + } + unreachable; +} + +fn start(s: *State) *State { + switch (s.input[s.pos]) { + 0...8 => s.next = .err, + + '\t', '\n' => {}, + + 11...31 => s.next = .err, + + ' ' => {}, + + '!' => s.next = .err, + + '"' => quotedString(s), + + else => s.next = .err, + } + return s; +} + +fn quotedString(s: *State) void { + var buf: [6]u8 = .{0} ** 6; + const len = readString(&buf, s); + s.retval = value.pair.cons( + value.sstr.pack("quote"), + value.pair.cons( + value.sstr.pack(buf[0..len]), + value.nil.nil, + ), + ); + s.next = .done; +} + +fn readString(buf: []u8, s: *State) usize { + s.pos += 1; // skip opening quote + for (s.input[s.pos..], 0..) |c, i| { + if (c == '"') { + s.pos += i; + return i; + } + buf[i] = c; + } + unreachable; +} + +fn list(s: *State) *State { + return s; +} + +fn err(s: *State) *State { + return s; +} diff --git a/src/libzisp/value.zig b/src/libzisp/value.zig index da67af7..dd9df3c 100644 --- a/src/libzisp/value.zig +++ b/src/libzisp/value.zig @@ -58,28 +58,26 @@ // // === Pointers === // -// Pointers are further subdivided as follows based on the remaining 51 bits: +// Pointers are further subdivided as follows based on the remaining 51 bits, +// with the first three bits used as a sort of tag: // -// MSb = 1 :: Foreign Pointer (or a "special 50-bit fixnum") +// 000 :: Pointer to Zisp heap object (string, vector, etc.) // -// MSb = 0, SSb = 0 :: Pointer to heap object (string, vector, etc.) +// 001 :: Weak pointer to Zisp heap object // -// MSb = 0, SSb = 1 :: Weak pointer to heap object +// 01. :: Undefined // -// (SSb = Second-most significant bit) -// -// This means regular pointers to the Zisp heap are 49 bits. Of these, we only -// really need 45, since 64-bit platforms are in practice limited to 48-bit -// addresses, and allocations happen at 8-byte boundaries, meaning the least -// significant 3 bit are always 0. Thus, we are able to store 4-bit tags in -// those 49-bit pointers alongside the actual, multiple-of-8, 48-bit address. +// 1.. :: Undefined // -// Note that foreign pointers avoid stepping on any forbidden value, thanks to -// bit 51 being set. +// This means pointers to the Zisp heap are 48 bits. Of those, we only really +// need 45, since 64-bit platforms are in practice limited to 48-bit addresses, +// and allocations happen at 8-byte boundaries, meaning the least significant 3 +// bit are always 0. Thus, we are able to store yet another 3-bit tag in those +// 48-bit pointers alongside the actual, multiple-of-8, 48-bit address. // // The forbidden value 3, Positive cqNaN, is avoided thanks to the fact that a // regular Zisp heap pointer can never be null. Weak pointers, which can be -// null, avoid stepping on that forbidden value thanks to bit 50 being set. +// null, avoid stepping on that forbidden value thanks to bit 49 being set. // // // === Other values === @@ -88,7 +86,7 @@ // // 000 :: Undefined // -// 001 :: Small string +// 001 :: Short string // // 010 :: Unicode code point // @@ -106,14 +104,16 @@ // // There may also be uninterned strings on the heap that are also as short but // ended up on the heap due to being uninterned. Calling intern on them will -// return the equivalent small string. +// return the equivalent short string. // // Unicode code points need a maximum of 21 bits, yet we have 48 available. // This may be exploited for a future extension. // // Similarly, it's extremely unlikely that we will ever need more than a few // dozen singleton values (false, true, null, and so on). As such, this range -// of bit patterns may be subdivided further in the future. +// of bit patterns may be subdivided in the future. Right now, only the lowest +// 8 bits are allowed to be set, with the other 40 being reserved, so there's a +// limit of 256 singleton values that can be defined. // // And on top of all that we still have a 48-bit and a 50-bit range left! // @@ -142,72 +142,109 @@ pub const boole = @import("value/boole.zig"); pub const nil = @import("value/nil.zig"); pub const eof = @import("value/eof.zig"); +pub const pair = @import("value/pair.zig"); + /// To fill up the u11 exponent part of a NaN. const FILL = 0x7ff; /// Represents a Zisp value/object. pub const Value = packed union { + /// To get the value as a regular double. double: f64, + + /// To get an agnostic value for direct comparison with == i.e. eq?. bits: u64, - nan: packed struct { + // Some of the structs below are just for inspection, whereas others are to + // initialize a new value of that category as well as read it that way. + + /// Inspection through the lens of the general IEEE 754 double layout. + ieee: packed struct { rest: u51, - quiet: u1, - exp: u11 = FILL, - sign: u1, + quiet: bool, + exp: u11, + sign: bool, }, + /// For initializing and reading fixnums. fixnum: packed struct { code: u51, negative: bool, _: u11 = FILL, - is_fixnum: bool = true, + _is_fixnum: bool = true, }, + /// Inspection through the lens of the ptr category. ptr: packed struct { - // if foreign, we don't actually use value and is_weak - value: u49, - weak: bool = false, - foreign: bool = false, - is_ptr: bool = true, - _: u11 = FILL, - _fixnum: bool = false, + _value: u48, + is_weak: bool, + _unused: bool, + is_foreign: bool, + _is_ptr: bool, + _: u11, + _is_fixnum: bool, }, + /// For initializing and reading foreign pointers. fptr: packed struct { value: u50, - _foreign: bool = true, - _ptr: bool = true, + _is_foreign: bool = true, + _is_ptr: bool = true, _: u11 = FILL, - _fixnum: bool = false, + _is_fixnum: bool = false, + }, + + /// For initializing and reading Zisp heap pointers. + zptr: packed struct { + tagged_value: u48, + is_weak: bool = false, + _unused: bool = false, + _is_foreign: bool = false, + _is_ptr: bool = true, + _: u11 = FILL, + _is_fixnum: bool = false, + }, + + /// Inspection as an other (non-fixnum, non-pointer) packed value. + other: packed struct { + _value: u48, + tag: OtherTag, + _is_ptr: bool, + _: u11, + _is_ifxnum: bool, }, + /// For initializing and reading short strings. sstr: packed struct { - // packed struct cannot contain array - value: u48, - tag: Tag = .sstr, - ptr: bool = false, + // actually [6]u8 but packed struct cannot contain arrays + string: u48, + _tag: OtherTag = .sstr, + _is_ptr: bool = false, _: u11 = FILL, - fixnum: bool = false, + _is_fixnum: bool = false, }, + /// For initializing and reading characters. char: packed struct { - value: u48, - tag: Tag = .char, - ptr: bool = false, + char: u21, + _reserved: u27 = 0, + _tag: OtherTag = .char, + _is_ptr: bool = false, _: u11 = FILL, - fixnum: bool = false, + _is_fixnum: bool = false, }, + /// For initializing and reading misc values aka singletons. misc: packed struct { - value: u48, - tag: Tag = .misc, - ptr: bool = false, + value: u8, + _reserved: u40 = 0, + _tag: OtherTag = .misc, + _is_ptr: bool = false, _: u11 = FILL, - fixnum: bool = false, + _is_fixnum: bool = false, }, - const Tag = enum(u3) { sstr = 1, char = 2, misc = 3 }; + const OtherTag = enum(u3) { sstr = 1, char = 2, misc = 3 }; const Self = @This(); @@ -216,8 +253,36 @@ pub const Value = packed union { std.debug.dumpHex(std.mem.asBytes(&self)); } - /// Checks for a Zisp value (non-double) packed into a NaN. + // The following aren't type predicates per se, but rather determine which + // general category the value is in. The exceptions are fixnum and double, + // since those aren't sub-categorized into further types. + + /// Checks for a Zisp double, including: +nan.0, -nan.0, +inf.0, -inf.0 + pub fn isDouble(self: Self) bool { + return self.ieee.exp != FILL or self.ieee.rest == 0; + } + + /// Checks for a non-double Zisp value packed into a NaN. pub fn isPacked(self: Self) bool { - return self.nan.exp == FILL and self.nan.rest != 0; + return !self.isDouble(); + } + + /// Checks for a fixnum. + pub fn isFixnum(self: Self) bool { + return self.isPacked() and self.ieee.sign; + } + + /// Checks for any kind of pointer. + pub fn isPtr(self: Self) bool { + return self.isPacked() and !self.ieee.sign and self.ieee.quiet; + } + + /// Checks for a non-double, non-fixnum, non-pointer Zisp value. + fn _isOther(self: Self) bool { + return self.isPacked() and !self.ieee.sign and !self.ieee.quiet; + } + + pub fn isOther(self: Self, tag: OtherTag) bool { + return self._isOther() and self.other.tag == tag; } }; 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. |
