summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2026-06-04 16:37:16 +0200
committerTaylan Kammer <taylan.kammer@gmail.com>2026-06-04 16:37:16 +0200
commit8de05de165cc7e7f900fb2320a58262ac8d0be5f (patch)
tree7c914020c41dd56953a5407989c0373a2883af9b
parent1a0a55692988fe8e22ebb397a70b60424d653a5e (diff)
We can read and print back various strings now.
-rw-r--r--src/zisp/io/Parser.zig17
-rw-r--r--src/zisp/io/print.zig79
-rw-r--r--src/zisp/value.zig5
-rw-r--r--src/zisp/value/array.zig32
-rw-r--r--src/zisp/value/istr.zig15
-rw-r--r--src/zisp/value/sstr.zig8
6 files changed, 112 insertions, 44 deletions
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig
index a56a61b..73c0187 100644
--- a/src/zisp/io/Parser.zig
+++ b/src/zisp/io/Parser.zig
@@ -181,11 +181,11 @@ fn addChar(p: *Parser, c: u8) !void {
fn addUnicode(p: *Parser, uc: u21) !void {
const n = std.unicode.utf8CodepointSequenceLength(uc) catch {
- return p.err(.UnicodeLengthError, "UTF-8 injection");
+ return p.err(.UnicodeLengthError, "Unicode/UTF-8 escape");
};
const buf = try p.chars.addManyAsSlice(p.alloc, n);
const n2 = std.unicode.utf8Encode(uc, buf) catch {
- return p.err(.UnicodeEncodeError, "UTF-8 injection");
+ return p.err(.UnicodeEncodeError, "Unicode/UTF-8 escape");
};
std.debug.assert(n == n2);
}
@@ -193,13 +193,12 @@ fn addUnicode(p: *Parser, uc: u21) !void {
fn getCharsAsString(p: *Parser) !Value {
defer p.chars.clearRetainingCapacity();
const s = p.chars.items;
- if (value.sstr.isValidSstr(s)) {
- return value.sstr.pack(s);
- } else if (value.istr.isValidIstr(s)) {
- return value.istr.intern(s);
- } else {
- @panic("not implemented"); // TODO
- }
+ return if (value.sstr.isValidSstr(s))
+ value.sstr.pack(s)
+ else if (value.istr.isValidIstr(s))
+ value.istr.intern(s)
+ else
+ value.array.newString(p.alloc, s);
}
fn getCharsAsRune(p: *Parser) Value {
diff --git a/src/zisp/io/print.zig b/src/zisp/io/print.zig
index 0873767..b1647cc 100644
--- a/src/zisp/io/print.zig
+++ b/src/zisp/io/print.zig
@@ -48,8 +48,7 @@ pub fn rune(w: Writer, v: Value) !void {
pub fn sstr(w: Writer, v: Value) !void {
// TODO: Check if pipes/escapes necessary.
- const str = value.sstr.unpack(v);
- try w.writeAll(str.slice());
+ try w.writeAll(value.sstr.unpack(&v));
}
pub fn char(w: Writer, v: Value) !void {
@@ -78,26 +77,68 @@ pub fn srat(w: Writer, v: Value) !void {
}
pub fn pair(w: Writer, p: PairPtr) !void {
- const car = p.car;
- //const cdr = p.cdr;
- if (car.eq(Parser.PQSTR)) {
- //try pipeString(w, cdr);
- @panic("");
- } else if (car.eq(Parser.DQSTR)) {
- //try quotString(w, cdr);
- @panic("");
- } else if (car.eq(Parser.ATSTR)) {
- //try atString(w, cdr);
- @panic("");
- } else if (car.eq(Parser.LABEL)) {
- //try label(w, cdr);
- @panic("");
- } else {
- try list(w, p);
- }
+ try switch (p.car.bits) {
+ Parser.PQSTR.bits => quotString(w, p.cdr, '|'),
+ Parser.DQSTR.bits => quotString(w, p.cdr, '"'),
+ Parser.ATSTR.bits => atString(w, p.cdr),
+ Parser.LABEL.bits => label(w, p.cdr),
+ else => list(w, p),
+ };
+}
+
+fn quotString(w: Writer, s: Value, comptime qchar: u8) !void {
+ try w.writeByte(qchar);
+ // TODO: use string.zig (when it exists) to get []u8 generically
+ const str = try getStr(&s);
+ for (str) |c| switch (c) {
+ qchar => {
+ try w.writeByte('\\');
+ try w.writeByte(qchar);
+ },
+ '\\' => {
+ try w.writeByte('\\');
+ try w.writeByte('\\');
+ },
+ else => {
+ try w.writeByte(c);
+ },
+ };
+ try w.writeByte(qchar);
+}
+
+pub fn atString(w: Writer, at_str_pair: Value) !void {
+ const p = value.pair.assert(at_str_pair);
+ const b = value.fixnum.unpack(p.car);
+ std.debug.assert(b <= 255);
+ const str = try getStr(&p.cdr);
+ try w.writeByte('@');
+ try w.writeByte(@intCast(b));
+ try w.writeAll(str);
+ try w.writeByte(@intCast(b));
+}
+
+// TODO: belongs in string.zig
+fn getStr(s: *const Value) ![]const u8 {
+ return if (value.sstr.check(s.*))
+ value.sstr.unpack(s)
+ else if (value.istr.check(s.*)) |istr_ptr|
+ istr_ptr.str()
+ else if (value.array.check(s.*)) |array_ptr|
+ array_ptr.str()
+ else {
+ s.dump();
+ @panic("This is not a string.");
+ };
+}
+
+pub fn label(w: Writer, v: Value) !void {
+ _ = w;
+ _ = v;
+ @panic("not implemented");
}
pub fn istr(w: Writer, p: IstrPtr) !void {
+ // TODO: This assumes it needs no quoting
try w.writeAll(p.str());
}
diff --git a/src/zisp/value.zig b/src/zisp/value.zig
index 1a32dc5..5bfeb37 100644
--- a/src/zisp/value.zig
+++ b/src/zisp/value.zig
@@ -338,6 +338,11 @@ pub const Value = packed union {
, .{ v.bits, sign, exp, quiet, rest });
}
+ /// To treat the 64-bit value as an 8-byte array.
+ pub fn bytes(v: *const Value) *const [8]u8 {
+ return @ptrCast(&v);
+ }
+
/// Checks for bit-equality i.e. == comprison.
pub fn eq(v1: Value, v2: Value) bool {
return v1.bits == v2.bits;
diff --git a/src/zisp/value/array.zig b/src/zisp/value/array.zig
index ef2bcd6..67a5f37 100644
--- a/src/zisp/value/array.zig
+++ b/src/zisp/value/array.zig
@@ -4,6 +4,8 @@ const std = @import("std");
const gc = @import("../gc.zig");
const value = @import("../value.zig");
+const Alloc = std.mem.Allocator;
+
const Value = value.Value;
/// Pointer to header for an array of various element types and sizes.
@@ -46,12 +48,12 @@ const Value = value.Value;
/// another array with the same buffer pointer and different type info.
///
/// Other remaining bits provide information about element type and size.
-pub const ArrayPtr = *align(8) ArrayHeader;
+pub const ArrayPtr = *align(@alignOf(value.Zptr)) ArrayHeader;
pub const ArrayHeader = packed struct(u64) {
len_or_ptr: u48,
- is_slice: bool,
- is_ptr: bool,
+ is_slice: bool = false,
+ is_ptr: bool = false,
type: enum(u2) { int, float, value, string },
info: packed union {
int: packed struct(u12) {
@@ -69,13 +71,12 @@ pub const ArrayHeader = packed struct(u64) {
_: u11,
},
string: packed struct(u12) {
- encoding: enum(u10) {
+ encoding: enum(u11) {
utf8,
utf16,
utf24,
utf32,
} = .utf8,
- interned: bool = false,
endian: Endian = .native,
},
},
@@ -97,7 +98,10 @@ pub const ArrayHeader = packed struct(u64) {
fn eltSize(self: *@This()) u16 {
std.debug.assert(!self.is_ptr);
- @panic("");
+ return switch (self.type) {
+ .string => 1,
+ else => @panic("not implemented"),
+ };
}
fn size(self: *@This()) usize {
@@ -160,6 +164,22 @@ const Endian = enum(u1) {
};
};
+pub fn newString(alloc: Alloc, s: []const u8) !Value {
+ std.debug.assert(s.len <= std.math.maxInt(u48));
+ const algn = std.mem.Alignment.of(ArrayPtr);
+ const size = @sizeOf(ArrayHeader) + s.len;
+ const ptr = try alloc.alignedAlloc(u8, algn, size);
+ const arr: ArrayPtr = @ptrCast(ptr);
+ arr.* = .{
+ .len_or_ptr = @intCast(s.len),
+ .type = .string,
+ .info = .{ .string = .{} },
+ };
+ const buf = arr.bufContent();
+ @memcpy(buf[0..s.len], s);
+ return value.ptr.pack(arr, .array);
+}
+
pub fn check(v: Value) ?ArrayPtr {
if (v.getPtr(.array)) |p| {
return @ptrCast(p);
diff --git a/src/zisp/value/istr.zig b/src/zisp/value/istr.zig
index cadf849..504ffe7 100644
--- a/src/zisp/value/istr.zig
+++ b/src/zisp/value/istr.zig
@@ -13,7 +13,7 @@ const Value = value.Value;
///
/// First 64 bits are a cached hash, of which the lowest 8 bits are actually the
/// length of the string: u64hash = (real_u64hash << 8) | u8length
-pub const IstrPtr = *align(8) IstrHeader;
+pub const IstrPtr = *align(@alignOf(value.Zptr)) IstrHeader;
const IstrHeader = packed union {
hash: u64,
@@ -29,20 +29,23 @@ const IstrHeader = packed union {
pub fn putStr(self: *@This(), s: []const u8) void {
std.debug.assert(s.len <= 255);
const buf = self.bufU8();
- @memcpy(buf[8 .. 8 + s.len], s);
+ const start = @sizeOf(IstrHeader);
+ @memcpy(buf[start .. start + s.len], s);
}
pub fn str(self: *@This()) []const u8 {
const buf = self.bufU8();
- return buf[8 .. 8 + self.meta.len];
+ const start = @sizeOf(IstrHeader);
+ return buf[start .. start + self.meta.len];
}
};
pub fn new(alloc: Alloc, hash: u64, s: []const u8) !IstrPtr {
- const aln = std.mem.Alignment.of(IstrPtr);
- const ptr = try alloc.alignedAlloc(u8, aln, 8 + s.len);
+ const algn = std.mem.Alignment.of(IstrPtr);
+ const size = @sizeOf(IstrHeader) + s.len;
+ const ptr = try alloc.alignedAlloc(u8, algn, size);
const istr: IstrPtr = @ptrCast(ptr);
- istr.hash = hash;
+ istr.* = .{ .hash = hash };
istr.putStr(s);
return istr;
}
diff --git a/src/zisp/value/sstr.zig b/src/zisp/value/sstr.zig
index a91bfa2..8435800 100644
--- a/src/zisp/value/sstr.zig
+++ b/src/zisp/value/sstr.zig
@@ -38,11 +38,11 @@ pub fn pack(s: []const u8) Value {
return .{ .sstr = .{ .string = @bitCast(buf) } };
}
-pub fn unpack(v: Value) ShortString {
- assert(v);
- const buf: [6]u8 = @bitCast(v.sstr.string);
+pub fn unpack(v: *const Value) []const u8 {
+ assert(v.*);
+ const buf = v.bytes();
const len = value.sstrLen(v.bits);
- return .{ .buf = buf, .len = len };
+ return buf[0..len];
}
// No Zisp API for sstr specifically, since it's a string. See string.zig.