diff options
| author | Taylan Kammer <taylan.kammer@gmail.com> | 2026-06-10 05:15:15 +0200 |
|---|---|---|
| committer | Taylan Kammer <taylan.kammer@gmail.com> | 2026-06-10 05:15:15 +0200 |
| commit | e4514285f2148d1fed1a0871494a2fda23a3e503 (patch) | |
| tree | df6a015e747e3127566512b89c2780814af1e5ff | |
| parent | 79469e08b9920fa0b10d5e6dcc3dffc30e96928b (diff) | |
Parser: Cleanup & performance improvement.
| -rw-r--r-- | src/zisp/io/Parser.zig | 120 |
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 |
