This hand-rolled wonder of switch statements is capable of parsing a 5 byte document in less than a gigasecond. This was an interesting exercise in writing a non-recursive parser for a nested structure format. There's a lot of very slightly different repetition, which I'm not wild about, but it can handle deeply nested documents. I tested with a 50 mb indented list tree document (10_000 lines of nesting) and a ReleaseFast build was able to parse it in approximately 50 ms with a peak memory footprint of about 100 MB (of which, half was the contents of the document itself, as the file is read into a single allocated buffer that does not get freed until program exit). I don't consider myself to be someone who writes high performance software, but I think those results are quite acceptable, and I doubt any recursive implementation would even be able to parse that document at all (the python NestedText implementation smashes directly into a RecursionError, unsurprisingly). Anyway, let's call this a success. I will actually probably export this to a separate project soon. The main problem is coming up with a name. I also strongly suspect there are some lurking bugs still, and I think I do want to add nested inline map/list support (and also parsing directly into objects).
50 lines
1.2 KiB
Zig
50 lines
1.2 KiB
Zig
const std = @import("std");
|
|
|
|
const noclip = @import("noclip");
|
|
|
|
const config = @import("./config.zig");
|
|
|
|
const scribe_cmd = cmd: {
|
|
var builder = noclip.CommandBuilder(*const std.mem.Allocator){
|
|
.description =
|
|
\\consume lore files and produce rendered output
|
|
\\
|
|
\\
|
|
,
|
|
};
|
|
builder.stringArgument(.{
|
|
.name = "input",
|
|
.description = "document to parse",
|
|
});
|
|
|
|
break :cmd builder;
|
|
};
|
|
|
|
pub fn scribe(alloc: *const std.mem.Allocator, options: scribe_cmd.Output()) !void {
|
|
const buffa = try std.fs.cwd().readFileAlloc(alloc.*, options.input, 4_294_967_295);
|
|
defer alloc.free(buffa);
|
|
|
|
var parser = config.Parser{
|
|
.allocator = alloc.*,
|
|
// .dupe_behavior = .use_last,
|
|
};
|
|
|
|
const document = try parser.parseBuffer(buffa);
|
|
defer document.deinit();
|
|
document.printDebug();
|
|
}
|
|
|
|
pub fn run(alloc: std.mem.Allocator) !void {
|
|
const base = try noclip.commandGroup(alloc, .{
|
|
.description =
|
|
\\produce and manipulate collections of lore
|
|
\\
|
|
,
|
|
});
|
|
defer base.deinitTree();
|
|
|
|
try base.addSubcommand("scribe", try scribe_cmd.createInterface(alloc, scribe, &alloc));
|
|
|
|
try base.execute();
|
|
}
|