diff options
| author | Grace Yoder <grace_yoder@outlook.com> | 2026-07-17 19:54:15 -0600 |
|---|---|---|
| committer | Grace Yoder <grace_yoder@outlook.com> | 2026-07-17 20:08:24 -0600 |
| commit | 55a1697e7175c4c82989c0633ef2227fb0295b8e (patch) | |
| tree | e3592665ca7f051849debe716a2cfc2f2592110b /src/root.zig | |
Diffstat (limited to 'src/root.zig')
| -rwxr-xr-x | src/root.zig | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/root.zig b/src/root.zig new file mode 100755 index 0000000..3ddfe78 --- /dev/null +++ b/src/root.zig @@ -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); + } +} |
