feat: zig rewrite

This commit is contained in:
Grace Yoder 2026-07-17 19:54:15 -06:00
commit 9d4345b098
Signed by: grace
SSH key fingerprint: SHA256:oG9v0ZlohsoMAg083HAwBGOcaPLF3nIuOlAW4MtASMo
16 changed files with 838 additions and 0 deletions

76
src/root.zig Executable file
View file

@ -0,0 +1,76 @@
const std = @import("std");
const Io = std.Io;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const SplitIterator = std.mem.SplitIterator;
const DelimiterType = std.mem.DelimiterType;
const ArrayList = std.ArrayList;
const StringArrayHashMap = std.StringArrayHashMapUnmanaged;
pub const tags = @import("tags.zig");
pub const utils = @import("utils.zig");
pub const ParserFn =
fn (
arena: *ArenaAllocator,
io: Io,
state: *Parser,
reader: *Io.Reader,
writer: *Io.Writer,
attrs: *SplitIterator(u8, DelimiterType.scalar),
) anyerror!void;
pub const ParserTag = struct {
name: []const u8,
parse_fn: *const ParserFn,
};
pub const Parser = struct {
component_resolver: *const fn (alloc: *ArenaAllocator, io: Io, path: []const u8) anyerror!*Io.Reader,
exported_parts: StringArrayHashMap([]const u8),
tags: []const ParserTag,
tag_stack: ArrayList([]const u8),
};
pub fn parseTemplate(arena: *ArenaAllocator, io: Io, state: *Parser, reader: *Io.Reader, writer: *Io.Writer) !void {
outer: while (true) {
_ = reader.streamDelimiter(writer, '<') catch |err| {
if (err == Io.Reader.Error.EndOfStream) break else return err;
};
// consume '<'
_ = try reader.takeByte();
if (try reader.peekByte() == '/') {
// consume '/'
_ = try reader.takeByte();
const last_tag = state.tag_stack.getLastOrNull() orelse "";
// if reached closing tag, send execution back up the stack
if (std.mem.eql(u8, last_tag, try reader.peekDelimiterExclusive('>'))) {
// consume closing tag
_ = try reader.takeDelimiterInclusive('>');
return;
} else {
try writer.writeAll("</");
continue :outer;
}
}
const inside = reader.takeDelimiterExclusive('>') catch |err| {
if (err == error.StreamTooLong) {
try writer.writeByte('<');
break :outer;
} else return err;
};
var it = std.mem.splitScalar(u8, inside, ' ');
const tag_name = it.first();
for (state.tags) |tag| {
if (std.mem.eql(u8, tag.name, tag_name) == true) {
// consume '>'
_ = try reader.takeByte();
try tag.parse_fn(arena, io, state, reader, writer, &it);
continue :outer;
}
}
try writer.writeByte('<');
try writer.writeAll(inside);
}
}