lore/src/cli.zig
torque c8375d6d3a
mostly functioning config parser
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).
2023-09-14 23:42:31 -07:00

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();
}