summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2026-06-10 05:15:15 +0200
committerTaylan Kammer <taylan.kammer@gmail.com>2026-06-10 05:15:15 +0200
commite4514285f2148d1fed1a0871494a2fda23a3e503 (patch)
treedf6a015e747e3127566512b89c2780814af1e5ff
parent79469e08b9920fa0b10d5e6dcc3dffc30e96928b (diff)
Parser: Cleanup & performance improvement.
-rw-r--r--src/zisp/io/Parser.zig120
1 files changed, 70 insertions, 50 deletions
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig
index 9d36a57..d4a0a68 100644
--- a/src/zisp/io/Parser.zig
+++ b/src/zisp/io/Parser.zig
@@ -83,10 +83,12 @@ pub const Error = enum {
pub const Context = struct {
// What to do next.
next: ?Fn = undefined,
- // For storing a context value, like accumulated list elements.
+ // For storing a context value, like datum to join in join syntax.
val: Value = undefined,
// For storing a context char, like list opening bracket.
char: u8 = undefined,
+ // Count of list elements on current parse level.
+ list_len: usize = undefined,
};
alloc: Alloc,
@@ -96,8 +98,9 @@ pair_pool: *PairPool,
input: *Reader = undefined,
context: Context = .{},
-stack: List(Context) = undefined,
-chars: List(u8) = undefined,
+ctx_stack: List(Context) = undefined,
+str_chars: List(u8) = undefined,
+list_elts: List(Value) = undefined,
result: Value = undefined,
unread_char: ?u8 = null,
@@ -106,13 +109,14 @@ err_msg: []const u8 = undefined,
pub fn init(alloc: Alloc) !Parser {
const istr_set = gc.mainIstrSet();
const pair_pool = gc.mainPairPool();
- return initCustom(alloc, 32, 2048, istr_set, pair_pool);
+ return initCustom(alloc, 32, 2048, 32, istr_set, pair_pool);
}
pub fn initCustom(
alloc: Alloc,
init_ctx_stack_cap: usize,
init_str_chars_cap: usize,
+ init_list_elts_cap: usize,
istr_set: ?*IstrSet,
pair_pool: *PairPool,
) !Parser {
@@ -121,14 +125,16 @@ pub fn initCustom(
.istr_set = istr_set,
.pair_pool = pair_pool,
};
- p.stack = try .initCapacity(alloc, init_ctx_stack_cap);
- p.chars = try .initCapacity(alloc, init_str_chars_cap);
+ p.ctx_stack = try .initCapacity(alloc, init_ctx_stack_cap);
+ p.str_chars = try .initCapacity(alloc, init_str_chars_cap);
+ p.list_elts = try .initCapacity(alloc, init_list_elts_cap);
return p;
}
pub fn deinit(p: *Parser) void {
- p.stack.deinit(p.alloc);
- p.chars.deinit(p.alloc);
+ p.ctx_stack.deinit(p.alloc);
+ p.str_chars.deinit(p.alloc);
+ p.list_elts.deinit(p.alloc);
}
//
@@ -176,14 +182,14 @@ fn getUnread(p: *Parser) ?u8 {
//
fn addChar(p: *Parser, c: u8) !void {
- try p.chars.append(p.alloc, c);
+ try p.str_chars.append(p.alloc, c);
}
fn addUnicode(p: *Parser, uc: u21) !void {
const n = std.unicode.utf8CodepointSequenceLength(uc) catch {
return p.err(.UnicodeLengthError, "Unicode/UTF-8 escape");
};
- const buf = try p.chars.addManyAsSlice(p.alloc, n);
+ const buf = try p.str_chars.addManyAsSlice(p.alloc, n);
const n2 = std.unicode.utf8Encode(uc, buf) catch {
return p.err(.UnicodeEncodeError, "Unicode/UTF-8 escape");
};
@@ -191,8 +197,8 @@ fn addUnicode(p: *Parser, uc: u21) !void {
}
fn getCharsAsString(p: *Parser) !Value {
- defer p.chars.clearRetainingCapacity();
- const s = p.chars.items;
+ defer p.str_chars.clearRetainingCapacity();
+ const s = p.str_chars.items;
if (value.sstr.isValidSstr(s)) {
return value.sstr.pack(s);
} else if (value.istr.isValidIstr(s)) {
@@ -211,16 +217,30 @@ fn getIstr(p: *Parser, s: []const u8) !Value {
}
fn getCharsAsRune(p: *Parser) Value {
- defer p.chars.clearRetainingCapacity();
- return value.rune.pack(p.chars.items);
+ defer p.str_chars.clearRetainingCapacity();
+ return value.rune.pack(p.str_chars.items);
}
//
-// Pair consing
+// Pair consing & list creation
//
-fn cons(p: *Parser, car: Value, cdr: Value) Value {
- return value.pair.consInPool(p.pair_pool, car, cdr) catch @panic("OOM"); // TODO
+fn cons(p: *Parser, car: Value, cdr: Value) !Value {
+ return value.pair.consInPool(p.pair_pool, car, cdr);
+}
+
+fn addListElt(p: *Parser, elt: Value) !void {
+ try p.list_elts.append(p.alloc, elt);
+ p.context.list_len += 1;
+}
+
+fn getList(p: *Parser, tail: Value) !Value {
+ var list = tail;
+ for (0..p.context.list_len) |_| {
+ const elt = p.list_elts.pop() orelse unreachable;
+ list = try p.cons(elt, list);
+ }
+ return list;
}
//
@@ -277,7 +297,7 @@ pub fn run(p: *Parser, input: *Reader) !Value {
}
fn printStack(p: *Parser) void {
- const stack = p.stack.items;
+ const stack = p.ctx_stack.items;
std.debug.print("\n\n{}:{any} ctx:'{c}' unread:'{c}' \n", .{
stack.len,
p.context.next,
@@ -308,19 +328,20 @@ fn err(
}
fn push(p: *Parser, next: Fn) !void {
- try p.stack.append(p.alloc, .{ .next = next });
+ try p.ctx_stack.append(p.alloc, .{ .next = next });
}
fn pushContext(p: *Parser, next: Fn) !void {
- try p.stack.append(p.alloc, .{
+ try p.ctx_stack.append(p.alloc, .{
.next = next,
.val = p.context.val,
.char = p.context.char,
+ .list_len = p.context.list_len,
});
}
fn ret(p: *Parser) void {
- if (p.stack.pop()) |c| {
+ if (p.ctx_stack.pop()) |c| {
p.context = c;
} else {
p.context.next = null;
@@ -434,7 +455,7 @@ fn endJoinDatum(p: *Parser) !void {
':' => COLON,
else => unreachable,
};
- const joined = p.cons(rune, p.cons(prev, p.result));
+ const joined = try p.cons(rune, try p.cons(prev, p.result));
return p.jump(.parseJoin, joined);
}
@@ -490,8 +511,8 @@ fn getString(p: *Parser, comptime close: u8) !Value {
};
const s = try p.getCharsAsString();
return switch (close) {
- '|' => p.cons(PQSTR, s),
- '"' => p.cons(DQSTR, s),
+ '|' => try p.cons(PQSTR, s),
+ '"' => try p.cons(DQSTR, s),
else => unreachable,
};
}
@@ -504,7 +525,7 @@ fn getAtString(p: *Parser) !Value {
}
const str = try p.getCharsAsString();
const byte = value.fixnum.pack(stop);
- return p.cons(ATSTR, p.cons(byte, str));
+ return try p.cons(ATSTR, try p.cons(byte, str));
}
fn skipStringLfEscape(p: *Parser) !u8 {
@@ -571,7 +592,7 @@ fn parseHashExpr(p: *Parser, next: Fn) !void {
'\\' => {
const c1 = try p.readNoEof("hash-backslash");
const bs = try p.getBareString(c1);
- return p.jump(next, p.cons(HASH, bs));
+ return p.jump(next, try p.cons(HASH, bs));
},
'!' => return p.parseHashBang(next),
'%' => return p.parseLabel(next),
@@ -590,7 +611,7 @@ fn endHashDatum(p: *Parser) !void {
if (p.result.eq(value.none)) {
return p.err(.InvalidCharacter, "hash datum");
}
- return p.retval(p.cons(HASH, p.result));
+ return p.retval(try p.cons(HASH, p.result));
}
fn getRune(p: *Parser, c1: u8) !Value {
@@ -614,11 +635,11 @@ fn parseRuneEnd(p: *Parser, r: Value, next: Fn) !void {
switch (c) {
'\\' => {
const c1 = try p.readNoEof("rune-backslash");
- return p.jump(next, p.cons(r, try p.getBareString(c1)));
+ return p.jump(next, try p.cons(r, try p.getBareString(c1)));
},
- '"' => return p.jump(next, p.cons(r, try p.getString('"'))),
- '|' => return p.jump(next, p.cons(r, try p.getString('|'))),
- '@' => return p.jump(next, p.cons(r, try p.getAtString())),
+ '"' => return p.jump(next, try p.cons(r, try p.getString('"'))),
+ '|' => return p.jump(next, try p.cons(r, try p.getString('|'))),
+ '@' => return p.jump(next, try p.cons(r, try p.getAtString())),
'#', '(', '[', '{', '\'', '`', ',' => {
p.unread(c);
try p.push(next);
@@ -633,12 +654,12 @@ fn parseRuneEnd(p: *Parser, r: Value, next: Fn) !void {
}
fn endRuneDatum(p: *Parser) !void {
- return p.retval(p.cons(p.context.val, p.result));
+ return p.retval(try p.cons(p.context.val, p.result));
}
fn parseHashBang(p: *Parser, next: Fn) !void {
const val = try p.getHashBangValue();
- return p.jump(next, p.cons(SHBANG, val));
+ return p.jump(next, try p.cons(SHBANG, val));
}
fn getHashBangValue(p: *Parser) !Value {
@@ -654,7 +675,7 @@ fn getHashBangValue(p: *Parser) !Value {
};
const interp = try p.getCharsAsString();
if (try p.getHashBangArgLine()) |arg_line| {
- return p.cons(interp, arg_line);
+ return try p.cons(interp, arg_line);
} else {
return interp;
}
@@ -683,7 +704,7 @@ 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)),
+ '%' => return p.jump(next, try p.cons(LABEL, l)),
'=' => {
try p.push(next);
p.context.val = l;
@@ -697,25 +718,24 @@ fn endLabelDatum(p: *Parser) !void {
if (p.result.eq(value.none)) {
return p.err(.InvalidCharacter, "label datum");
}
- return p.retval(p.cons(LABEL, p.cons(p.context.val, p.result)));
+ return p.retval(try p.cons(LABEL, try p.cons(p.context.val, p.result)));
}
fn parseList(p: *Parser, open: u8, next: Fn) !void {
- const head = switch (open) {
- '(' => value.nil,
- '[' => p.cons(SQUARE, value.nil),
- '{' => p.cons(BRACE, value.nil),
- else => unreachable,
- };
- const close: u8 = switch (open) {
+ try p.push(next);
+ p.context.char = switch (open) {
'(' => ')',
'[' => ']',
'{' => '}',
else => unreachable,
};
- try p.push(next);
- p.context.val = head;
- p.context.char = close;
+ p.context.list_len = 0;
+ switch (open) {
+ '(' => {},
+ '[' => try p.addListElt(SQUARE),
+ '{' => try p.addListElt(BRACE),
+ else => unreachable,
+ }
return p.subr(.parseUnit, .continueList);
}
@@ -736,20 +756,20 @@ fn continueList(p: *Parser) !void {
return p.err(.InvalidCharacter, "list");
}
- p.context.val = p.cons(p.result, p.context.val);
+ try p.addListElt(p.result);
return p.subr(.parseUnit, .continueList);
}
fn endList(p: *Parser) !void {
- return p.retval(lib.list.reverse(p.context.val));
+ return p.retval(try p.getList(value.nil));
}
fn endImproperList(p: *Parser) !void {
if (p.result.eq(value.none)) {
return p.err(.InvalidCharacter, "list tail");
}
- p.context.val = lib.list.reverseWithTail(p.context.val, p.result);
+ p.context.val = try p.getList(p.result);
return p.closeImproperList();
}
@@ -788,7 +808,7 @@ fn endQuoteExpr(p: *Parser) !void {
if (p.result.eq(value.none)) {
return p.err(.InvalidCharacter, "quote expression datum");
}
- return p.retval(p.cons(p.context.val, p.result));
+ return p.retval(try p.cons(p.context.val, p.result));
}
// Helpers