summaryrefslogtreecommitdiff
path: root/src/zisp/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/zisp/io')
-rw-r--r--src/zisp/io/Parser.zig165
-rw-r--r--src/zisp/io/unparser.zig98
2 files changed, 97 insertions, 166 deletions
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig
index 7d14808..14db959 100644
--- a/src/zisp/io/Parser.zig
+++ b/src/zisp/io/Parser.zig
@@ -188,20 +188,12 @@ fn addChar(p: *Parser, c: u8) !void {
try p.chars.append(p.alloc.chars, c);
}
-fn getBareString(p: *Parser) Value {
+fn getString(p: *Parser) Value {
defer p.chars.clearRetainingCapacity();
- return if (p.chars.items.len <= 6)
+ return if (value.sstr.isValidSstr(p.chars.items))
value.sstr.pack(p.chars.items)
else
- value.istr.intern(p.chars.items, false);
-}
-
-fn getQuotedString(p: *Parser) Value {
- defer p.chars.clearRetainingCapacity();
- return if (p.chars.items.len <= 6)
- value.sstr.packQuoted(p.chars.items)
- else
- value.istr.intern(p.chars.items, true);
+ value.istr.intern(p.chars.items);
}
fn getRune(p: *Parser) Value {
@@ -223,7 +215,6 @@ const Fn = enum {
parseJoin,
parseHashDatum,
endHashDatum,
- parseRuneDatum,
endRuneDatum,
endLabelDatum,
continueList,
@@ -234,22 +225,21 @@ const Fn = enum {
fn call(p: *Parser, f: Fn) !void {
try switch (f) {
- .parseUnit => parseUnit(p),
- .parseDatum => parseDatum(p),
- .endUnit => endUnit(p),
- .returnContext => returnContext(p),
- .endFirstDatum => endFirstDatum(p),
- .endJoinDatum => endJoinDatum(p),
- .parseJoin => parseJoin(p),
- .parseHashDatum => parseHashDatum(p),
- .endHashDatum => endHashDatum(p),
- .parseRuneDatum => parseRuneDatum(p),
- .endRuneDatum => endRuneDatum(p),
- .endLabelDatum => endLabelDatum(p),
- .continueList => continueList(p),
- .endImproperList => endImproperList(p),
- .closeImproperList => closeImproperList(p),
- .endQuoteExpr => endQuoteExpr(p),
+ .parseUnit => p.parseUnit(),
+ .parseDatum => p.parseDatum(),
+ .endUnit => p.endUnit(),
+ .returnContext => p.returnContext(),
+ .endFirstDatum => p.endFirstDatum(),
+ .endJoinDatum => p.endJoinDatum(),
+ .parseJoin => p.parseJoin(),
+ .parseHashDatum => p.parseHashDatum(),
+ .endHashDatum => p.endHashDatum(),
+ .endRuneDatum => p.endRuneDatum(),
+ .endLabelDatum => p.endLabelDatum(),
+ .continueList => p.continueList(),
+ .endImproperList => p.endImproperList(),
+ .closeImproperList => p.closeImproperList(),
+ .endQuoteExpr => p.endQuoteExpr(),
};
}
@@ -257,7 +247,7 @@ pub fn run(p: *Parser, input: std.io.AnyReader) !Value {
p.input = input;
p.context.next = .parseUnit;
while (p.context.next) |next| {
- if (detailed_debug) printStack(p);
+ if (detailed_debug) p.printStack();
try p.call(next);
}
if (p.unread_char) |_| {
@@ -360,7 +350,7 @@ fn endUnit(p: *Parser) !void {
const c = p.getUnread() orelse return p.ret();
switch (try p.checkBlanks(c)) {
.yes => {},
- .skip_unit => return skipUnitAndReturn(p),
+ .skip_unit => return p.skipUnitAndReturn(),
.no => p.unread(c),
}
return p.ret();
@@ -383,7 +373,7 @@ fn endFirstDatum(p: *Parser) !void {
if (p.result.eq(value.none)) {
return p.ret();
}
- return parseJoin(p);
+ return p.parseJoin();
}
fn parseJoin(p: *Parser) !void {
@@ -429,54 +419,27 @@ fn parseOneDatum(p: *Parser, c: u8, next: Fn) !void {
return p.parseCladDatum(c, next);
}
-fn parseBareString(p: *Parser, c: u8) !Value {
- const allow_dots = std.ascii.isDigit(c) or switch (c) {
+fn parseBareString(p: *Parser, c1: u8) !Value {
+ const allow_dots = std.ascii.isDigit(c1) or switch (c1) {
'.', '+', '-' => true,
else => false,
};
- try p.addChar(c);
- return p.parseBareStringRest(allow_dots);
-}
-
-fn parseBareEscString(p: *Parser) !Value {
- try p.addChar(try parseBareEsc(p));
- return p.parseBareStringRest(false);
-}
-
-fn parseBareStringRest(p: *Parser, allow_dots: bool) !Value {
+ try p.addChar(c1);
while (try p.read()) |c| {
if (isBareChar(c) or (allow_dots and c == '.')) {
try p.addChar(c);
- } else if (c == '\\') {
- try p.addChar(try parseBareEsc(p));
} else {
p.unread(c);
break;
}
}
- return p.getBareString();
-}
-
-fn parseBareEsc(p: *Parser) !u8 {
- const c = try p.readNoEof("bare escape");
- if (isBareEsc(c)) {
- return c;
- } else {
- return p.err(.InvalidCharacter, "bare escape");
- }
+ return p.getString();
}
fn parseCladDatum(p: *Parser, c: u8, next: Fn) !void {
- if (c == '\\') {
- return p.jump(next, try parseBareEscString(p));
- }
- if (c == '"') {
- return p.jump(next, try p.parseQuotedString('"'));
- }
- if (c == '|') {
- return p.jump(next, try p.parseQuotedString('|'));
- }
return switch (c) {
+ '|' => p.jump(next, try p.parseEscapedString('|')),
+ '"' => p.jump(next, try p.parseEscapedString('"')),
'#' => p.parseHashExpression(next),
'(', '[', '{' => p.parseList(c, next),
'\'', '`', ',' => p.parseQuoteExpr(c, next),
@@ -484,10 +447,11 @@ fn parseCladDatum(p: *Parser, c: u8, next: Fn) !void {
};
}
-fn parseQuotedString(p: *Parser, close: u8) !Value {
+fn parseEscapedString(p: *Parser, close: u8) !Value {
while (try p.read()) |c| {
if (c == close) {
- return p.getQuotedString();
+ const s = p.getString();
+ return if (close == '"') p.cons(QUOTE, s) else s;
}
if (c != '\\') {
try p.addChar(c);
@@ -500,12 +464,8 @@ fn parseQuotedString(p: *Parser, close: u8) !Value {
fn parseQuotedEsc(p: *Parser, close: u8) !void {
const c = try p.readNoEof("quoted escape");
- if (c == close) {
- return p.addChar(close);
- }
- if (c == 'u') {
- return parseUniHexHandleErrors(p);
- }
+ if (c == close) return p.addChar(close);
+ if (c == 'u') return p.parseUniHexHandleErrors();
try p.addChar(switch (c) {
'\\' => c,
'0' => 0,
@@ -523,7 +483,7 @@ fn parseQuotedEsc(p: *Parser, close: u8) !void {
}
fn parseUniHexHandleErrors(p: *Parser) !void {
- return parseUniHex(p) catch |e| switch (e) {
+ return p.parseUniHex() catch |e| switch (e) {
error.Utf8CannotEncodeSurrogateHalf => p.err(
.UnicodeError,
"unicode escape",
@@ -552,16 +512,16 @@ fn parseUniHex(p: *Parser) !void {
fn parseHashExpression(p: *Parser, next: Fn) !void {
const c = try p.readNoEof("hash expression");
- if (try p.checkBlanks(c) != .no) {
- return p.err(.InvalidCharacter, "hash expression");
- }
if (std.ascii.isAlphabetic(c)) {
const r = try p.parseRune(c);
return p.parseRuneEnd(r, next);
}
+ if (c == '\\') {
+ const c1 = try p.readNoEof("bare string after hash");
+ return p.jump(next, p.cons(HASH, try p.parseBareString(c1)));
+ }
if (c == '%') {
- const l = try parseLabel(p);
- return p.parseLabelEnd(l, next);
+ return p.parseLabel(next);
}
p.unread(c);
return p.subr(.parseHashDatum, next);
@@ -594,53 +554,42 @@ fn parseRune(p: *Parser, c1: u8) !Value {
fn parseRuneEnd(p: *Parser, r: Value, next: Fn) !void {
const c = p.getUnread() orelse return p.jump(next, r);
if (c == '\\') {
- return p.jump(next, p.cons(r, try p.parseBareString(c)));
+ const c1 = try p.readNoEof("bare string at rune end");
+ return p.jump(next, p.cons(r, try p.parseBareString(c1)));
}
if (c == '"') {
- return p.jump(next, p.cons(r, try p.parseQuotedString('"')));
+ return p.jump(next, p.cons(r, try p.parseEscapedString('"')));
}
if (c == '|') {
- return p.jump(next, p.cons(r, try p.parseQuotedString('|')));
+ return p.jump(next, p.cons(r, try p.parseEscapedString('|')));
}
p.unread(c);
switch (c) {
'#', '(', '[', '{', '\'', '`', ',' => {
try p.push(next);
p.context.val = r;
- // Use jump to prevent recursion.
- return p.jump(.parseRuneDatum, null);
+ return p.subr(.parseDatum, .endRuneDatum);
},
else => return p.jump(next, r),
}
}
-fn parseRuneDatum(p: *Parser) !void {
- return p.parseCladDatum(p.getUnread().?, .endRuneDatum);
-}
-
fn endRuneDatum(p: *Parser) !void {
- if (p.result.eq(value.none)) {
- p.retval(p.context.val);
- }
return p.retval(p.cons(p.context.val, p.result));
}
-fn parseLabel(p: *Parser) !Value {
- const label = try p.parseHex(u48, "datum label");
- return value.fixnum.pack(label);
-}
-
-fn parseLabelEnd(p: *Parser, l: Value, next: Fn) !void {
- const c = p.getUnread() orelse return p.err(.UnexpectedEof, "datum label");
- if (c == '%') {
- return p.jump(next, p.cons(LABEL, l));
- }
- if (c == '=') {
- try p.push(next);
- p.context.val = l;
- return p.subr(.parseDatum, .endLabelDatum);
+fn parseLabel(p: *Parser, next: Fn) !void {
+ const n = try p.parseHex(u48, "datum label");
+ const l = value.fixnum.pack(n);
+ switch (p.getUnread() orelse try p.readNoEof("datum label")) {
+ '%' => return p.jump(next, p.cons(LABEL, l)),
+ '=' => {
+ try p.push(next);
+ p.context.val = l;
+ return p.subr(.parseDatum, .endLabelDatum);
+ },
+ else => return p.err(.InvalidCharacter, "datum label"),
}
- return p.err(.InvalidCharacter, "datum label");
}
fn endLabelDatum(p: *Parser) !void {
@@ -696,7 +645,7 @@ fn continueList(p: *Parser) !void {
if (p.result.eq(value.none)) {
const c = p.getUnread().?;
if (c == close) {
- return endList(p);
+ return p.endList();
}
return p.err(.InvalidCharacter, "list");
}
@@ -710,7 +659,7 @@ fn continueList(p: *Parser) !void {
var c1 = p.getUnread() orelse try p.read();
while (c1) |c| : (c1 = try p.read()) {
if (c == close) {
- return endList(p);
+ return p.endList();
}
switch (try p.checkBlanks(c)) {
.yes => {},
@@ -736,7 +685,7 @@ fn endImproperList(p: *Parser) !void {
return p.err(.InvalidCharacter, "list tail");
}
p.context.val = lib.list.reverseWithTail(p.context.val, p.result);
- return closeImproperList(p);
+ return p.closeImproperList();
}
fn closeImproperList(p: *Parser) !void {
diff --git a/src/zisp/io/unparser.zig b/src/zisp/io/unparser.zig
index e72f130..64e18d0 100644
--- a/src/zisp/io/unparser.zig
+++ b/src/zisp/io/unparser.zig
@@ -1,23 +1,27 @@
const std = @import("std");
+const gc = @import("../gc.zig");
const value = @import("../value.zig");
const istr = value.istr;
const seq = value.seq;
const ShortString = value.ShortString;
-const OtherTag = value.OtherTag;
const Value = value.Value;
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);
+ // zig fmt: off
+ try if (v.isDouble()) unparseDouble(w, v)
+ else if (v.isFixnum()) unparseFixnum(w, v)
+ else if (v.getPtr(.pair)) |p| unparsePair(w, @ptrCast(p))
+ else if (v.getPtr(.seq)) |p| unparseSeq(w, @ptrCast(p))
+ else if (v.isRune()) unparseRune(w, v)
+ else if (v.isChar()) unparseChar(w, v)
+ else if (v.isMisc()) unparseMisc(w, v)
+ else if (v.isSrat()) unparseSrat(w, v)
+ else if (v.isSstr()) unparseSstr(w, v)
+ ;
+ // zig fmt: on
}
fn unparseDouble(w: anytype, v: Value) !void {
@@ -32,25 +36,6 @@ fn unparseFixnum(w: anytype, v: Value) !void {
@panic("not implemented");
}
-fn unparseHeap(w: anytype, v: Value) !void {
- const p, const t = value.ptr.unpack(v);
- try switch (t) {
- .pair => unparsePair(w, @ptrCast(p)),
- .seq => unparseSeq(w, @ptrCast(p)),
- else => @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('#');
@@ -58,41 +43,43 @@ fn unparseRune(w: anytype, v: Value) !void {
}
fn unparseSstr(w: anytype, v: Value) !void {
+ // TODO: Check if pipes/escapes necessary.
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 {
+ const uc: u21 = value.char.unpack(v);
var buf: [4]u8 = undefined;
- const len = try std.unicode.utf8Encode(v.char.value, &buf);
+ const len = try std.unicode.utf8Encode(uc, &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"),
- .none => w.writeAll("#NONE"),
- .undef => w.writeAll("#UNDEF"),
+ try switch (v.bits) {
+ value.f.bits => w.writeAll("#f"),
+ value.t.bits => w.writeAll("#t"),
+ value.nil.bits => w.writeAll("()"),
+ value.eof.bits => w.writeAll("#EOF"),
+ value.none.bits => w.writeAll("#NONE"),
+ value.undef.bits => w.writeAll("#UNDEF"),
+ else => @panic("not implemented"),
};
}
+fn unparseSrat(w: anytype, v: Value) !void {
+ _ = w;
+ _ = v;
+ @panic("not implemented");
+}
+
fn unparsePair(w: anytype, p: *[2]Value) !void {
try w.writeByte('(');
try unparse(w, p[0]);
var cdr = p[1];
- while (value.pair.check(cdr)) : (cdr = value.pair.cdr(cdr)) {
+ while (value.pair.check(cdr)) |p2| : (cdr = value.pair.cdr(cdr)) {
try w.writeByte(' ');
- try unparse(w, value.pair.car(cdr));
+ try unparse(w, p2[0]);
}
if (!value.nil.eq(cdr)) {
try w.writeByte(' ');
@@ -103,21 +90,16 @@ fn unparsePair(w: anytype, p: *[2]Value) !void {
try w.writeByte(')');
}
-fn unparseSeq(w: anytype, p: *seq.Header) !void {
- const h = istr.getHeaderFromPtr(@ptrCast(p));
- switch (h.type) {
- .string => try unparseString(w, h),
+fn unparseSeq(w: anytype, s: *seq.Header) !void {
+ switch (s.type) {
+ .string => try unparseString(w, s),
else => @panic("not implemented"),
}
}
-fn unparseString(w: anytype, h: *seq.Header) !void {
- const info = h.info.string;
- if (info.quoted) {
- try w.writeByte('"');
- }
- try w.writeAll(h.bytes());
- if (info.quoted) {
- try w.writeByte('"');
- }
+fn unparseString(w: anytype, s: *seq.Header) !void {
+ // TODO: Check if pipes/escapes necessary.
+ try w.writeByte('|');
+ try w.writeAll(s.bytes());
+ try w.writeByte('|');
}