summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2025-02-28 14:38:57 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2025-02-28 14:38:57 +0100
commit472f3e89a61ec51218cefe65305ec6f0a0d95fbf (patch)
treea64ef16a6b23a822ab09e02b9d967f3b8bb3d17e /src
parent34de389fe744018e808f2c8b301648d504ab610d (diff)
update
Diffstat (limited to 'src')
-rw-r--r--src/libzisp.zig30
-rw-r--r--src/libzisp/gc.zig13
-rw-r--r--src/libzisp/io/parser.zig199
-rw-r--r--src/libzisp/io/unparser.zig101
-rw-r--r--src/libzisp/value.zig43
-rw-r--r--src/libzisp/value/boole.zig5
-rw-r--r--src/libzisp/value/char.zig2
-rw-r--r--src/libzisp/value/eof.zig2
-rw-r--r--src/libzisp/value/istr.zig3
-rw-r--r--src/libzisp/value/misc.zig8
-rw-r--r--src/libzisp/value/nil.zig2
-rw-r--r--src/libzisp/value/pair.zig2
-rw-r--r--src/libzisp/value/ptr.zig54
-rw-r--r--src/libzisp/value/rune.zig13
-rw-r--r--src/libzisp/value/sstr.zig10
15 files changed, 281 insertions, 206 deletions
diff --git a/src/libzisp.zig b/src/libzisp.zig
index 79a54b4..b2c8283 100644
--- a/src/libzisp.zig
+++ b/src/libzisp.zig
@@ -5,13 +5,13 @@ const std = @import("std");
const builtin = @import("builtin");
const testing = std.testing;
-pub const gc = @import("libzisp/gc.zig");
pub const io = @import("libzisp/io.zig");
pub const lib = @import("libzisp/lib.zig");
pub const value = @import("libzisp/value.zig");
pub const ShortString = value.ShortString;
pub const Value = value.Value;
+pub const Hval = value.Hval;
test "double" {
const d1: f64 = 0.123456789;
@@ -46,12 +46,12 @@ test "fixnum" {
test "ptr" {
const ptr = value.ptr;
- const val: [*]gc.Bucket = @ptrFromInt(256);
- const tag = ptr.Tag.string;
+ const val: [*]Hval = @ptrFromInt(256);
+ const tag = ptr.Tag.istr;
const p = ptr.pack(val, tag);
try std.testing.expect(ptr.check(p));
- try std.testing.expect(ptr.checkZisp(p, tag));
+ try std.testing.expect(ptr.checkZispTag(p, tag));
try std.testing.expect(ptr.checkStrong(p));
const pv, const pt = ptr.unpack(p);
@@ -60,7 +60,7 @@ test "ptr" {
var w = ptr.makeWeak(p);
try std.testing.expect(ptr.check(w));
- try std.testing.expect(ptr.checkZisp(w, tag));
+ try std.testing.expect(ptr.checkZispTag(w, tag));
try std.testing.expect(ptr.checkWeak(w));
try std.testing.expectEqual(true, value.boole.unpack(ptr.predWeak(w)));
try std.testing.expectEqual(false, value.boole.unpack(ptr.predWeakNull(w)));
@@ -258,7 +258,7 @@ test "parse" {
test "parse2" {
const val = io.parser.parse(
\\ ;; Testing some crazy datum comments
- \\ ##;"bar"#;([x #"y"]{##`,'z})"foo"
+ \\ #;"bar"#;([x #"y"]{##`,'z}) #"foo"
\\ ;; end
);
@@ -299,8 +299,20 @@ test "parse4" {
}
test "unparse" {
- try std.testing.expectEqualStrings(
- "#foo",
- io.unparser.unparse(io.parser.parse("#foo")),
+ const unparse = io.unparser.unparse;
+
+ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
+ var out: std.ArrayList(u8) = .init(gpa.allocator());
+
+ const w = out.writer();
+ const v = io.parser.parse("#foo");
+ try unparse(w, v);
+ try std.testing.expectEqualStrings("#foo", try out.toOwnedSlice());
+}
+
+test "unparse2" {
+ try io.unparser.unparse(
+ std.io.getStdErr().writer(),
+ io.parser.parse("#{foo bar['x]}"),
);
}
diff --git a/src/libzisp/gc.zig b/src/libzisp/gc.zig
index 819fa0b..6704102 100644
--- a/src/libzisp/gc.zig
+++ b/src/libzisp/gc.zig
@@ -1,15 +1,12 @@
const std = @import("std");
-const Value = @import("value.zig").Value;
+const value = @import("value.zig");
+
+const Hval = value.Hval;
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");
+pub fn alloc(count: usize) []Hval {
+ return gpa.alloc(Hval, count) catch @panic("OOM");
}
diff --git a/src/libzisp/io/parser.zig b/src/libzisp/io/parser.zig
index 1e61385..6449431 100644
--- a/src/libzisp/io/parser.zig
+++ b/src/libzisp/io/parser.zig
@@ -25,17 +25,19 @@
//
// The following table summarizes the other supported transformations:
//
-// [...] -> (#SQUARE ...) #datum -> (#HASH . datum)
+// #datum -> (#HASH . datum) #rune(...) -> (#rune ...)
//
-// {...} -> (#BRACE ...) #rune(...) -> (#rune ...)
+// [...] -> (#SQUARE ...) dat1dat2 -> (#JOIN dat1 . dat2)
//
-// #<...> -> (#ANGLE ...) dat1dat2 -> (#JOIN dat1 . dat2)
+// {...} -> (#BRACE ...) dat1.dat2 -> (#DOT dat1 . dat2)
//
-// 'datum -> (#QUOTE . datum) dat1.dat2 -> (#DOT dat1 . dat2)
+// 'datum -> (#QUOTE . datum) dat1:dat2 -> (#COLON dat1 . dat2)
//
-// `datum -> (#GRAVE . datum) #n#=datum -> (#LABEL n . datum)
+// `datum -> (#GRAVE . datum) dat1|dat2 -> (#PIPE dat1 . dat2)
//
-// ,datum -> (#COMMA . datum) #n# -> (#LABEL . n)
+// ,datum -> (#COMMA . datum) #n#=datum -> (#LABEL n . datum)
+//
+// #n# -> (#LABEL . n)
//
// Notes:
//
@@ -64,10 +66,6 @@
// The parser will see this as an attempt to use an 8-letter rune name, and
// raise an error, since rune names are limited to 6 characters.
//
-// * The #<...> form is a special case; the less-than and greater-than symbols
-// are not otherwise treated as brackets; e.g., <a b c d> is actually four
-// strings: "<a", "b", "c", "d>".
-//
// Syntax sugar can combine arbitrarily; some examples follow:
//
// #{...} -> (#HASH #BRACE ...)
@@ -105,7 +103,7 @@
//
// #{x} -> (#HASH (#BRACE (x))) #{x} -> (#HASH #BRACE x)
//
-// foo(x y) -> (#JOIN foo (x y)) foo(bar) -> (#JOIN foo x y)
+// foo(x y) -> (#JOIN foo (x y)) foo(x y) -> (#JOIN foo x y)
//
//
// === Decoder ===
@@ -249,11 +247,11 @@ const State = struct {
parent: ?*State = null,
retval: Value = undefined,
- // To store accumulated context, such as list elements.
+ // To store a value for context, such as a list of accumulated elements.
context: Value = undefined,
- // To remember what kind of list we're in: () [] {}
- opening_bracket: u8 = undefined,
+ // To store a character for context, such as the type of opening bracket.
+ char_context: u8 = undefined,
fn eof(s: *State) bool {
return s.top.pos >= s.top.input.len;
@@ -264,6 +262,7 @@ const State = struct {
}
fn skip(s: *State) void {
+ // std.debug.print("{c}\n", .{s.top.input[s.top.pos]});
s.top.pos += 1;
}
@@ -284,13 +283,10 @@ const State = struct {
// Consumes whitespace and line comments.
fn consumeBlanks(s: *State) void {
while (!s.eof()) {
- if (s.isWhitespace()) {
- s.skip();
- } else if (s.peek() == ';') {
- s.skip();
- s.consumeLineComment();
- } else {
- return;
+ switch (s.peek()) {
+ '\t', '\n', ' ' => s.skip(),
+ ';' => s.consumeLineComment(),
+ else => return,
}
}
}
@@ -360,11 +356,10 @@ fn readShortString(
const Fn = enum {
start_parse,
start_datum,
- end_dotted_datum,
- end_joined_datum,
- end_datum_label,
+ end_join_datum,
+ end_label_datum,
end_hash_datum,
- end_quote,
+ end_quote_datum,
continue_list,
finish_improper_list,
end_improper_list,
@@ -380,19 +375,21 @@ pub fn parse(input: []const u8) Value {
var top = TopState{ .alloc = alloc, .input = input };
var s0 = State{ .top = &top };
var s = &s0;
- while (true) s = switch (s.next) {
- .start_parse => startParse(s),
- .start_datum => startDatum(s),
- .end_dotted_datum => endDottedDatum(s),
- .end_joined_datum => endJoinedDatum(s),
- .end_datum_label => endDatumLabel(s),
- .end_hash_datum => endHashDatum(s),
- .end_quote => endQuote(s),
- .continue_list => continueList(s),
- .finish_improper_list => finishImproperList(s),
- .end_improper_list => endImproperList(s),
- .perform_return => s.performReturn() orelse return s.retval,
- };
+ while (true) {
+ // std.debug.print("{}\n", .{s.next});
+ s = switch (s.next) {
+ .start_parse => startParse(s),
+ .start_datum => startDatum(s),
+ .end_join_datum => endJoinedDatum(s),
+ .end_label_datum => endLabelDatum(s),
+ .end_hash_datum => endHashDatum(s),
+ .end_quote_datum => endQuoteDatum(s),
+ .continue_list => continueList(s),
+ .finish_improper_list => finishImproperList(s),
+ .end_improper_list => endImproperList(s),
+ .perform_return => s.performReturn() orelse return s.retval,
+ };
+ }
}
fn startParse(s: *State) *State {
@@ -441,11 +438,8 @@ fn startDatum(s: *State) *State {
fn endDatum(s: *State, d: Value) *State {
//
- // We're at the end of a datum; check for dot and join notations:
- //
- // DATUM|.DATUM2
- //
- // DATUM|DATUM2
+ // We're at the end of a datum; check for the various ways data can be
+ // joined together, like DATUM|DATUM or DATUM|.DATUM etc.
//
if (isEndOfDatum(s)) {
@@ -453,28 +447,32 @@ fn endDatum(s: *State, d: Value) *State {
return s.returnDatum(d);
}
- s.context = d;
+ // There's a stupid special-case we have to handle here, where a datum
+ // comment may fool us into thinking there's something to join: foo|#;bar
- if (s.peek() == '.') {
- s.skip();
- return s.recurParse(.start_datum, .end_dotted_datum);
+ const c = s.peek();
+ switch (c) {
+ '.', ':', '|' => s.skip(),
+ '#' => if (checkTrailingDatumComment(s)) {
+ return s.returnDatum(d);
+ },
+ else => {},
}
-
- return s.recurParse(.start_datum, .end_joined_datum);
-}
-
-fn endDottedDatum(s: *State) *State {
- const rune = value.rune.pack("DOT");
- const first = s.context;
- const second = s.retval;
- return endDatum(s, value.pair.cons(rune, value.pair.cons(first, second)));
+ s.context = d;
+ s.char_context = c;
+ return s.recurParse(.start_datum, .end_join_datum);
}
-fn endJoinedDatum(s: *State) *State {
- const rune = value.rune.pack("JOIN");
- const first = s.context;
- const second = s.retval;
- return endDatum(s, value.pair.cons(rune, value.pair.cons(first, second)));
+fn checkTrailingDatumComment(s: *State) bool {
+ const pos = s.pos();
+ s.skip();
+ if (s.eof()) {
+ // Error, but let it be handled later.
+ return false;
+ }
+ const c = s.peek();
+ s.resetPos(pos);
+ return c == ';';
}
fn isEndOfDatum(s: *State) bool {
@@ -484,20 +482,29 @@ fn isEndOfDatum(s: *State) bool {
};
}
+fn endJoinedDatum(s: *State) *State {
+ const rune = value.rune.pack(switch (s.char_context) {
+ '.' => "DOT",
+ ':' => "COLON",
+ '|' => "PIPE",
+ else => "JOIN",
+ });
+ const joined = value.pair.cons(s.context, s.retval);
+ return endDatum(s, value.pair.cons(rune, joined));
+}
+
fn handleHash(s: *State) *State {
s.skip();
//
// We just consumed a hash. Possibilities include:
//
- // #|foo ;rune
- //
- // #n#=DATUM ;datum with numeric label
+ // #|foo ;rune
//
- // #n# ;reference to datum label
+ // #|n#[=DATUM] ;datum label, with or without datum
//
- // #|;DATUM ;datum comment
+ // #|;DATUM ;datum comment
//
- // #|DATUM ;hash-datum
+ // #|DATUM ;hash-datum
//
if (s.eof()) {
@@ -507,29 +514,17 @@ fn handleHash(s: *State) *State {
return err(s, "whitespace after hash");
}
- // Is it a rune? #foo
switch (s.peek()) {
'a'...'z', 'A'...'Z' => return handleRune(s),
- else => {},
- }
-
- // Is it a datum label / reference?
- switch (s.peek()) {
'0'...'9' => return handleDatumLabel(s),
- else => {},
- }
-
- // Is it a datum comment? #;DATUM
- if (s.peek() == ';') {
- s.skip();
- // Don't change s.next in this case. Just let the parser try to redo
- // what it was doing as soon as the commented-out datum has been read.
- return s.recurParse(.start_datum, s.next);
+ ';' => {
+ s.skip();
+ // Don't change s.next in this case. Just let the parser redo what
+ // it was doing as soon as the commented-out datum has been read.
+ return s.recurParse(.start_datum, s.next);
+ },
+ else => return s.recurParse(.start_datum, .end_hash_datum),
}
-
- // Otherwise, it must be a hash-datum. #DATUM
-
- return s.recurParse(.start_datum, .end_hash_datum);
}
fn handleRune(s: *State) *State {
@@ -560,7 +555,7 @@ fn handleDatumLabel(s: *State) *State {
if (s.eof() or s.isWhitespace()) {
const rune = value.rune.pack("LABEL");
- return s.returnDatum(value.pair.cons(rune, n));
+ return endDatum(s, value.pair.cons(rune, n));
}
if (s.getc() != '=') {
@@ -568,22 +563,22 @@ fn handleDatumLabel(s: *State) *State {
}
s.context = n;
- return s.recurParse(.start_datum, .end_datum_label);
+ return s.recurParse(.start_datum, .end_label_datum);
}
fn readDatumLabel(s: *State) ?Value {
return readShortString(s, std.ascii.isDigit, value.sstr.pack);
}
-fn endDatumLabel(s: *State) *State {
+fn endLabelDatum(s: *State) *State {
const rune = value.rune.pack("LABEL");
const payload = value.pair.cons(s.context, s.retval);
- return s.returnDatum(value.pair.cons(rune, payload));
+ return endDatum(s, value.pair.cons(rune, payload));
}
fn endHashDatum(s: *State) *State {
const rune = value.rune.pack("HASH");
- return s.returnDatum(value.pair.cons(rune, s.retval));
+ return endDatum(s, value.pair.cons(rune, s.retval));
}
fn startQuotedString(s: *State) *State {
@@ -591,7 +586,7 @@ fn startQuotedString(s: *State) *State {
s.skip();
const str = readQuotedString(s) catch return err(s, "unclosed string");
- return s.returnDatum(str);
+ return endDatum(s, str);
}
// RQS = Read Quoted String
@@ -611,7 +606,7 @@ fn readQuotedSstr(s: *State) !?Value {
const c = s.getc();
if (c == '"') {
// ok, return what we accumulated
- return value.sstr.packLiteral(buf[0..i]);
+ return value.sstr.packQuoted(buf[0..i]);
}
if (i == 6) {
// failed; reset and bail out
@@ -637,7 +632,7 @@ fn startBareString(s: *State) *State {
fn readBareSstr(s: *State) ?*State {
const sp = s.pos();
if (readShortString(s, isSstrChar, value.sstr.pack)) |sstr| {
- return s.returnDatum(sstr);
+ return endDatum(s, sstr);
} else {
s.resetPos(sp);
return null;
@@ -666,11 +661,11 @@ fn startQuote(s: *State) *State {
',' => "COMMA",
else => unreachable,
});
- return s.recurParse(.start_datum, .end_quote);
+ return s.recurParse(.start_datum, .end_quote_datum);
}
-fn endQuote(s: *State) *State {
- return s.returnDatum(value.pair.cons(s.context, s.retval));
+fn endQuoteDatum(s: *State) *State {
+ return endDatum(s, value.pair.cons(s.context, s.retval));
}
// List processing is, unsurprisingly, the most complicated, and it's made even
@@ -689,7 +684,7 @@ fn startList(s: *State) *State {
}
s.context = value.nil.nil;
- s.opening_bracket = open;
+ s.char_context = open;
return if (isEndOfList(s))
endList(s)
else
@@ -704,19 +699,19 @@ fn isEndOfList(s: *State) bool {
}
fn endList(s: *State) *State {
- const open = s.opening_bracket;
+ const open = s.char_context;
const char = s.getc();
if (open == '(' and char == ')') {
- return s.returnDatum(s.context);
+ return endDatum(s, s.context);
}
if (open == '[' and char == ']') {
const rune = value.rune.pack("SQUARE");
- return s.returnDatum(value.pair.cons(rune, s.context));
+ return endDatum(s, value.pair.cons(rune, s.context));
}
if (open == '{' and char == '}') {
const rune = value.rune.pack("BRACE");
- return s.returnDatum(value.pair.cons(rune, s.context));
+ return endDatum(s, value.pair.cons(rune, s.context));
}
return err(s, "wrong closing bracket for list");
diff --git a/src/libzisp/io/unparser.zig b/src/libzisp/io/unparser.zig
index d835924..c25e918 100644
--- a/src/libzisp/io/unparser.zig
+++ b/src/libzisp/io/unparser.zig
@@ -3,19 +3,100 @@ const std = @import("std");
const value = @import("../value.zig");
const ShortString = value.ShortString;
+const OtherTag = value.OtherTag;
const Value = value.Value;
+const Hval = value.Hval;
-// const State = struct {
+pub fn unparse(w: anytype, v: Value) anyerror!void {
+ try if (value.double.check(v))
+ unparseDouble(w, v)
+ else if (value.fixnum.check(v))
+ unparseFixnum(w, v)
+ else if (value.ptr.checkZisp(v))
+ unparseHeap(w, v)
+ else
+ unparseOther(w, v);
+}
+
+fn unparseDouble(w: anytype, v: Value) !void {
+ _ = w;
+ _ = v;
+ @panic("not implemented");
+}
+
+fn unparseFixnum(w: anytype, v: Value) !void {
+ _ = w;
+ _ = v;
+ @panic("not implemented");
+}
-// }
+fn unparseHeap(w: anytype, v: Value) !void {
+ const p, const t = value.ptr.unpack(v);
+ try switch (t) {
+ .pair => unparsePair(w, p),
+ .istr => @panic("not implemented"),
+ .proc => @panic("not implemented"),
+ };
+}
+
+fn unparseOther(w: anytype, v: Value) !void {
+ try switch (v.other.tag) {
+ .rune => unparseRune(w, v),
+ .sstr => unparseSstr(w, v),
+ .qstr => unparseQstr(w, v),
+ .char => unparseChar(w, v),
+ .misc => unparseMisc(w, v),
+ };
+}
+
+fn unparseRune(w: anytype, v: Value) !void {
+ const name = value.rune.unpack(v);
+ try w.writeByte('#');
+ try w.writeAll(name.constSlice());
+}
-pub fn unparse(v: Value) []u8 {
- var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
- var out: std.ArrayList(u8) = .init(gpa.allocator());
- if (value.rune.check(v)) {
- const name = value.rune.unpack(v);
- out.append('#') catch @panic("");
- out.appendSlice(name.slice()) catch @panic("");
+fn unparseSstr(w: anytype, v: Value) !void {
+ const str = value.sstr.unpack(v);
+ try w.writeAll(str.constSlice());
+}
+
+fn unparseQstr(w: anytype, v: Value) !void {
+ const str = value.sstr.unpack(v);
+ try w.writeByte('"');
+ try w.writeAll(str.constSlice());
+ try w.writeByte('"');
+}
+
+fn unparseChar(w: anytype, v: Value) !void {
+ var buf: [4]u8 = undefined;
+ const len = try std.unicode.utf8Encode(v.char.value, &buf);
+ try w.writeAll(buf[0..len]);
+}
+
+fn unparseMisc(w: anytype, v: Value) !void {
+ try switch (v.misc.value) {
+ .f => w.writeAll("#f"),
+ .t => w.writeAll("#t"),
+ .nil => w.writeAll("()"),
+ .eof => w.writeAll("#eof"),
+ .undef => w.writeAll("#undef"),
+ };
+}
+
+fn unparsePair(w: anytype, p: [*]Hval) !void {
+ const vs: *[2]Value = @ptrCast(p);
+ try w.writeByte('(');
+ try unparse(w, vs[0]);
+ var cdr = vs[1];
+ while (value.pair.check(cdr)) : (cdr = value.pair.cdr(cdr)) {
+ try w.writeByte(' ');
+ try unparse(w, value.pair.car(cdr));
+ }
+ if (!value.nil.check(cdr)) {
+ try w.writeByte(' ');
+ try w.writeByte('.');
+ try w.writeByte(' ');
+ try unparse(w, cdr);
}
- return out.toOwnedSlice() catch @panic("");
+ try w.writeByte(')');
}
diff --git a/src/libzisp/value.zig b/src/libzisp/value.zig
index 273c659..fbe7dbe 100644
--- a/src/libzisp/value.zig
+++ b/src/libzisp/value.zig
@@ -165,7 +165,9 @@ const FILL = 0x7ff;
// Used when dealing with runes and short strings.
pub const ShortString = std.BoundedArray(u8, 6);
-pub const OtherTag = enum(u3) { rune, sstr, sstr_lit, char, misc };
+pub const OtherTag = enum(u3) { rune, sstr, qstr, char, misc };
+
+pub const MiscValue = enum(u8) { f, t, nil, eof, undef = 255 };
/// Represents a Zisp value/object.
pub const Value = packed union {
@@ -266,7 +268,7 @@ pub const Value = packed union {
/// For initializing and reading misc values aka singletons.
misc: packed struct {
- value: u8,
+ value: MiscValue,
_reserved: u40 = 0,
_tag: OtherTag = .misc,
_is_ptr: bool = false,
@@ -274,11 +276,9 @@ pub const Value = packed union {
_is_fixnum: bool = false,
},
- const Self = @This();
-
/// Hexdumps the value.
- pub fn dump(self: Self) void {
- std.debug.dumpHex(std.mem.asBytes(&self));
+ pub inline fn dump(v: Value) void {
+ std.debug.dumpHex(std.mem.asBytes(&v));
}
// The following aren't type predicates per se, but rather determine which
@@ -286,32 +286,37 @@ pub const Value = packed union {
// 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;
+ pub inline fn isDouble(v: Value) bool {
+ return v.ieee.exp != FILL or v.ieee.rest == 0;
}
/// Checks for a non-double Zisp value packed into a NaN.
- pub fn isPacked(self: Self) bool {
- return !self.isDouble();
+ pub inline fn isPacked(v: Value) bool {
+ return !v.isDouble();
}
/// Checks for a fixnum.
- pub fn isFixnum(self: Self) bool {
- return self.isPacked() and self.ieee.sign;
+ pub inline fn isFixnum(v: Value) bool {
+ return v.isPacked() and v.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;
+ pub inline fn isPtr(v: Value) bool {
+ return v.isPacked() and !v.ieee.sign and v.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 inline fn isOther(v: Value) bool {
+ return v.isPacked() and !v.ieee.sign and !v.ieee.quiet;
}
- /// Checks for any "other" type of value.
- pub fn isOther(self: Self, tag: OtherTag) bool {
- return self._isOther() and self.other.tag == tag;
+ /// Checks for an other type of value based on tag.
+ pub inline fn isOtherTag(v: Value, tag: OtherTag) bool {
+ return v.isOther() and v.other.tag == tag;
}
};
+
+/// A "heap value" that could be a Value or object header.
+pub const Hval = packed union {
+ value: Value,
+};
diff --git a/src/libzisp/value/boole.zig b/src/libzisp/value/boole.zig
index 623dbc2..2e94e4d 100644
--- a/src/libzisp/value/boole.zig
+++ b/src/libzisp/value/boole.zig
@@ -1,8 +1,7 @@
const Value = @import("../value.zig").Value;
-const misc = @import("misc.zig");
-pub const f = misc.f;
-pub const t = misc.t;
+pub const f = Value{ .misc = .{ .value = .f } };
+pub const t = Value{ .misc = .{ .value = .t } };
// Zig API
diff --git a/src/libzisp/value/char.zig b/src/libzisp/value/char.zig
index eb4bbc9..09a3034 100644
--- a/src/libzisp/value/char.zig
+++ b/src/libzisp/value/char.zig
@@ -5,7 +5,7 @@ const Value = value.Value;
// Zig API
pub fn check(v: Value) bool {
- return v.isOther(.char);
+ return v.isOtherTag(.char);
}
pub fn assert(v: Value) void {
diff --git a/src/libzisp/value/eof.zig b/src/libzisp/value/eof.zig
index 367a86c..4b16669 100644
--- a/src/libzisp/value/eof.zig
+++ b/src/libzisp/value/eof.zig
@@ -2,7 +2,7 @@ const value = @import("../value.zig");
const Value = value.Value;
-pub const eof = @import("misc.zig").eof;
+pub const eof = Value{ .misc = .{ .value = .eof } };
// Zig API
diff --git a/src/libzisp/value/istr.zig b/src/libzisp/value/istr.zig
new file mode 100644
index 0000000..5937531
--- /dev/null
+++ b/src/libzisp/value/istr.zig
@@ -0,0 +1,3 @@
+const std = @import("std");
+
+const value = @import("../value.zig");
diff --git a/src/libzisp/value/misc.zig b/src/libzisp/value/misc.zig
deleted file mode 100644
index 30cbf84..0000000
--- a/src/libzisp/value/misc.zig
+++ /dev/null
@@ -1,8 +0,0 @@
-const Value = @import("../value.zig").Value;
-
-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 14bd800..f95ecad 100644
--- a/src/libzisp/value/nil.zig
+++ b/src/libzisp/value/nil.zig
@@ -2,7 +2,7 @@ const value = @import("../value.zig");
const Value = value.Value;
-pub const nil = @import("misc.zig").nil;
+pub const nil = Value{ .misc = .{ .value = .nil } };
// Zig API
diff --git a/src/libzisp/value/pair.zig b/src/libzisp/value/pair.zig
index 541a5f5..1c34096 100644
--- a/src/libzisp/value/pair.zig
+++ b/src/libzisp/value/pair.zig
@@ -9,7 +9,7 @@ const Value = value.Value;
// Zig API
pub fn check(v: Value) bool {
- return ptr.checkZisp(v, .pair);
+ return ptr.checkZispTag(v, .pair);
}
pub fn assert(v: Value) void {
diff --git a/src/libzisp/value/ptr.zig b/src/libzisp/value/ptr.zig
index e1fadf2..115cc2d 100644
--- a/src/libzisp/value/ptr.zig
+++ b/src/libzisp/value/ptr.zig
@@ -2,8 +2,8 @@ const std = @import("std");
const value = @import("../value.zig");
const gc = @import("../gc.zig");
-const Bucket = gc.Bucket;
const Value = value.Value;
+const Hval = value.Hval;
// Zig API
@@ -42,19 +42,19 @@ pub fn unpackForeign(v: Value) u50 {
// Zisp Pointers
-fn _checkZisp(v: Value) bool {
+pub fn checkZisp(v: Value) bool {
return check(v) and !v.ptr.is_foreign;
}
-fn _assertZisp(v: Value) void {
- if (!_checkZisp(v)) {
+pub 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.zptr.is_weak;
+ return checkZisp(v) and v.zptr.is_weak;
}
pub fn assertWeak(v: Value) void {
@@ -64,19 +64,19 @@ pub fn assertWeak(v: Value) void {
}
}
-pub fn checkZisp(v: Value, tag: Tag) bool {
- return _checkZisp(v) and unpack(v).@"1" == tag;
+pub fn checkZispTag(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)) {
+pub fn assertZispTag(v: Value, tag: Tag) void {
+ if (!checkZispTag(v, tag)) {
v.dump();
@panic("not zisp pointer or wrong tag");
}
}
pub fn checkStrong(v: Value) bool {
- return _checkZisp(v) and !v.zptr.is_weak;
+ return checkZisp(v) and !v.zptr.is_weak;
}
pub fn assertStrong(v: Value) void {
@@ -86,24 +86,24 @@ pub fn assertStrong(v: Value) void {
}
}
-pub fn packZisp(ptr: [*]Bucket, tag: Tag, is_weak: bool) Value {
+pub fn packZisp(ptr: [*]Hval, tag: Tag, is_weak: bool) Value {
return .{ .zptr = .{
.tagged_value = tagPtr(ptr, tag),
.is_weak = is_weak,
} };
}
-pub fn pack(ptr: [*]Bucket, tag: Tag) Value {
+pub fn pack(ptr: [*]Hval, tag: Tag) Value {
return packZisp(ptr, tag, false);
}
-pub fn packWeak(ptr: [*]Bucket, tag: Tag) Value {
+pub fn packWeak(ptr: [*]Hval, tag: Tag) Value {
return packZisp(ptr, tag, true);
}
// Unpacks weak as well; no need for a separate fn.
-pub fn unpack(v: Value) struct { [*]Bucket, Tag } {
- _assertZisp(v);
+pub fn unpack(v: Value) struct { [*]Hval, Tag } {
+ assertZisp(v);
return untagPtr(v.zptr.tagged_value);
}
@@ -117,37 +117,27 @@ pub fn isWeakNull(v: Value) bool {
return v.zptr.tagged_value == 0;
}
-fn tagPtr(ptr: [*]Bucket, tag: Tag) u48 {
+fn tagPtr(ptr: [*]Hval, tag: Tag) u48 {
const int: usize = @intFromPtr(ptr);
const untagged: u48 = @intCast(int);
return untagged | @intFromEnum(tag);
}
-fn untagPtr(tagged: u48) struct { [*]Bucket, Tag } {
+fn untagPtr(tagged: u48) struct { [*]Hval, Tag } {
const untagged: u48 = tagged & 0xfffffffffff8;
- const ptr: [*]Bucket = @ptrFromInt(untagged);
+ const ptr: [*]Hval = @ptrFromInt(untagged);
const int: u3 = @truncate(tagged);
const tag: Tag = @enumFromInt(int);
return .{ ptr, tag };
}
pub const Tag = enum(u3) {
- /// 0. Strings / Symbols
- string,
- /// 1. Bignums / Ratnums
- number,
- /// 2. Pairs ([2]Value)
+ /// *[2]Value
pair,
- /// 3. Collections: Vector, table, etc.
- coll,
- /// 4. OOP: Classes, instances, etc.
- oop,
- /// 5. String buffers
- text,
- /// 6. Procedures
+ /// Interned string (symbol)
+ istr,
+ /// Procedure
proc,
- /// 7. Others
- other,
};
// Zisp API
diff --git a/src/libzisp/value/rune.zig b/src/libzisp/value/rune.zig
index 3a4dc61..a6152b1 100644
--- a/src/libzisp/value/rune.zig
+++ b/src/libzisp/value/rune.zig
@@ -8,7 +8,7 @@ const Value = value.Value;
// Zig API
pub fn check(v: Value) bool {
- return v.isOther(.rune);
+ return v.isOtherTag(.rune);
}
pub fn assert(v: Value) void {
@@ -50,15 +50,12 @@ pub fn pack(s: []const u8) Value {
}
pub fn unpack(v: Value) ShortString {
- var s = ShortString{ .buffer = @bitCast(v.sstr.string) };
+ assert(v);
+ const s: [6]u8 = @bitCast(v.rune.name);
inline for (0..6) |i| {
- if (s.buffer[i] == 0) {
- s.len = i;
- return s;
- }
+ if (s[i] == 0) return .{ .buffer = s, .len = i };
}
- s.len = 6;
- return s;
+ return .{ .buffer = s, .len = 6 };
}
// Zisp API
diff --git a/src/libzisp/value/sstr.zig b/src/libzisp/value/sstr.zig
index 1c9812e..b02fd3d 100644
--- a/src/libzisp/value/sstr.zig
+++ b/src/libzisp/value/sstr.zig
@@ -9,7 +9,7 @@ const Value = value.Value;
// Zig API
pub fn check(v: Value) bool {
- return v.isOther(.sstr) or v.isOther(.sstr_lit);
+ return v.isOtherTag(.sstr) or v.isOtherTag(.qstr);
}
pub fn assert(v: Value) void {
@@ -19,6 +19,10 @@ pub fn assert(v: Value) void {
}
}
+pub fn checkQuoted(v: Value) bool {
+ return v.isOtherTag(.qstr);
+}
+
// For now, ignore encoding, just treat it as []u8.
pub fn isValidSstr(s: []const u8) bool {
@@ -50,8 +54,8 @@ pub fn pack(s: []const u8) Value {
return _pack(s, .sstr);
}
-pub fn packLiteral(s: []const u8) Value {
- return _pack(s, .sstr_lit);
+pub fn packQuoted(s: []const u8) Value {
+ return _pack(s, .qstr);
}
fn _pack(s: []const u8, tag: OtherTag) Value {