summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2026-01-08 14:56:46 +0100
committerTaylan Kammer <taylan.kammer@gmail.com>2026-01-08 14:56:46 +0100
commit255e2f98680457b611e3e2b93e54da32052e6e55 (patch)
tree32e2eb22a9d4416c87e825a72fff6a5f9a12c658
parent8bdc0ba5704dceeab9f636d267feb15fbe9e929e (diff)
Fix & clean parser.
-rw-r--r--src/main.zig30
-rw-r--r--src/zisp/io/Parser.zig80
2 files changed, 45 insertions, 65 deletions
diff --git a/src/main.zig b/src/main.zig
index 4f1127c..55fecdf 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -2,26 +2,36 @@ const std = @import("std");
const zisp = @import("zisp");
-const gst_io = std.Io.Threaded.global_single_threaded.io();
+const alloc = std.heap.smp_allocator;
+const gstio = std.Io.Threaded.global_single_threaded.io();
-pub fn main() !void {
+pub fn main() !u8 {
var stdin_buffer: [4096]u8 = undefined;
- var stdin_reader = std.Io.File.stdin().reader(gst_io, &stdin_buffer);
+ var stdin_reader = std.Io.File.stdin().reader(gstio, &stdin_buffer);
const reader = &stdin_reader.interface;
var stdout_buffer: [4096]u8 = undefined;
- var stdout_writer = std.Io.File.stdout().writer(gst_io, &stdout_buffer);
+ var stdout_writer = std.Io.File.stdout().writer(gstio, &stdout_buffer);
const writer = &stdout_writer.interface;
+ var sfa = zisp.io.Parser.DefaultSfa.withFallback(alloc);
+ var p = try zisp.io.Parser.initWithSfa(&sfa, gstio);
while (true) {
- try writer.writeAll("> ");
- try writer.flush();
- const datum = zisp.io.parse.fromReader(reader);
+ const datum = p.run(reader) catch {
+ const format = "Parse error: {s}, pos: {d}, unread_char: {s}\n";
+ const err = p.err_msg;
+ const pos = stdin_reader.logicalPos();
+ const unread: [4]u8 =
+ if (p.unread_char) |c|
+ "0x".* ++ std.fmt.hex(c)
+ else
+ "none".*;
+ std.debug.print(format, .{ err, pos, unread });
+ return 1;
+ };
if (datum.eq(zisp.value.eof)) {
- try writer.writeAll("\n");
- return;
+ return 0;
}
- try writer.writeAll("= ");
try zisp.io.print.toWriter(writer, datum);
try writer.writeAll("\n");
try writer.flush();
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig
index 012080b..0fea5f3 100644
--- a/src/zisp/io/Parser.zig
+++ b/src/zisp/io/Parser.zig
@@ -99,9 +99,10 @@ pub const Error = enum {
InvalidCharacter,
UnclosedString,
UnexpectedEof,
- UnicodeError,
OutOfRange,
ReadError,
+ UnicodeLengthError,
+ UnicodeEncodeError,
};
pub const Context = struct {
@@ -319,7 +320,8 @@ fn err(
comptime e: Error,
comptime msg: []const u8,
) error{ParseError} {
- p.err_msg = @tagName(e) ++ " at: " ++ msg;
+ @branchHint(.cold);
+ p.err_msg = @tagName(e) ++ " @ " ++ msg;
return error.ParseError;
}
@@ -376,7 +378,7 @@ fn parseUnit(p: *Parser) !void {
.skip_unit => {
// Queue another parseUnit, but continue the current one, whose
// result will be silently ignored. Simpler alternative to:
- // p.subr(.parseUnit, .parseUnit);
+ // return p.subr(.parseUnit, .parseUnit);
try p.push(.parseUnit);
},
.no => {
@@ -406,7 +408,13 @@ fn returnContext(p: *Parser) !void {
}
fn parseDatum(p: *Parser) !void {
- return p.parseOneDatum(p.getUnread().?, .parseJoin);
+ const c = p.getUnread() orelse try p.readNoEof("datum");
+ if (isBareChar(c) or c == '.') {
+ const s = try p.parseBareString(c);
+ return p.jump(.parseJoin, s);
+ } else {
+ return p.parseCladDatum(c, .parseJoin);
+ }
}
fn parseJoin(p: *Parser) !void {
@@ -448,17 +456,14 @@ fn endJoinDatum(p: *Parser) !void {
return p.jump(.parseJoin, joined);
}
-fn parseOneDatum(p: *Parser, c: u8, next: Fn) !void {
- if (isBareChar(c)) {
- return p.jump(next, try p.parseBareString(c));
- }
- return p.parseCladDatum(c, next);
-}
-
fn parseBareString(p: *Parser, c1: u8) !Value {
+ const allow_dots = std.ascii.isDigit(c1) or switch (c1) {
+ '.', '+', '-' => true,
+ else => false,
+ };
try p.addChar(c1);
while (try p.read()) |c| {
- if (isBareChar(c)) {
+ if (isBareChar(c) or (allow_dots and c == '.')) {
try p.addChar(c);
} else {
p.unread(c);
@@ -546,11 +551,11 @@ fn parseStringUniHexEsc(p: *Parser) !void {
}
const n = std.unicode.utf8CodepointSequenceLength(uc) catch {
- return p.err(.UnicodeError, msg);
+ return p.err(.UnicodeLengthError, msg);
};
const buf = try p.chars.addManyAsSlice(p.alloc.chars, n);
const n2 = std.unicode.utf8Encode(uc, buf) catch {
- return p.err(.UnicodeError, msg);
+ return p.err(.UnicodeEncodeError, msg);
};
std.debug.assert(n == n2);
}
@@ -671,37 +676,19 @@ fn parseList(p: *Parser, open: u8, next: Fn) !void {
'{' => '}',
else => unreachable,
};
- while (try p.read()) |c| {
- if (c == close) {
- return p.jump(next, head);
- }
- switch (try p.checkBlank(c)) {
- .yes => {},
- .skip_unit => {
- try p.listParserSetup(head, close, next);
- return p.subr(.parseUnit, .parseUnit);
- },
- .no => {
- try p.listParserSetup(head, close, next);
- p.unread(c);
- return p.jump(.parseDatum, null);
- },
- }
- }
- return p.err(.UnexpectedEof, "list");
-}
-
-fn listParserSetup(p: *Parser, head: Value, close: u8, next: Fn) !void {
try p.push(next);
p.context.val = head;
p.context.char = close;
- try p.pushContext(.continueList);
+ return p.subr(.parseUnit, .continueList);
}
fn continueList(p: *Parser) !void {
- const close = p.context.char;
+ if (p.result.eq(value.eof)) {
+ return p.err(.UnexpectedEof, "list");
+ }
if (p.result.eq(value.none)) {
+ const close = p.context.char;
const c = p.getUnread().?;
if (c == close) {
return p.endList();
@@ -714,24 +701,7 @@ fn continueList(p: *Parser) !void {
p.context.val = p.cons(p.result, p.context.val);
- var c1 = p.getUnread() orelse try p.read();
- while (c1) |c| : (c1 = try p.read()) {
- if (c == close) {
- return p.endList();
- }
- switch (try p.checkBlank(c)) {
- .yes => {},
- .skip_unit => {
- try p.pushContext(.continueList);
- return p.subr(.parseUnit, .parseUnit);
- },
- .no => {
- p.unread(c);
- return p.subr(.parseDatum, .continueList);
- },
- }
- }
- return p.err(.UnexpectedEof, "list");
+ return p.subr(.parseUnit, .continueList);
}
fn endList(p: *Parser) !void {