diff --git a/src/template/lib.zig b/src/template/lib.zig index 1d4f830..a35cc20 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -7,32 +7,15 @@ pub fn main() !void { const logging = false; pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void { - @setEvalBranchQuota(@intCast(u32, template.len * 6)); - comptime var iter = TokenIter{ .text = template }; - inline while (comptime iter.next()) |token| { - if (logging) @compileLog(token); - switch (token) { - .text => |text| try writer.writeAll(text), - .open_bracket => { - const next = comptime iter.peek() orelse @compileError("Unexpected end of template"); - if (next == .open_bracket) { - try writer.writeByte('{'); - _ = comptime iter.next(); - } else { - const result = comptime parseStatement(iter); - try executeStatement(writer, result.item, args); - iter = result.new_iter; - } - }, - .close_bracket => { - const next = comptime iter.next() orelse @compileError("Unexpected end of template"); - if (comptime next == .close_bracket) try writer.writeByte('}') else @compileError("Unpaired close bracket, did you mean \"}}\"?"); - }, - .whitespace => |wsp| try writer.writeAll(wsp), - .period => try writer.writeByte('.'), - .pound => try writer.writeByte('#'), - } - } + const items = comptime parseTemplate(template); + try executeTemplate(writer, items, args); +} + +fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype) !void { + inline for (items) |it| switch (it) { + .text => |text| try writer.writeAll(text), + .statement => |stmt| try executeStatement(writer, stmt, args), + }; } fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype) !void { @@ -54,6 +37,49 @@ fn argDeref(writer: anytype, comptime names: []const []const u8, arg: anytype) ! return argDeref(writer, names[1..], @field(arg, names[0])); } +fn parseTemplate(comptime template: []const u8) []const TemplateItem { + comptime { + @setEvalBranchQuota(@intCast(u32, template.len * 6)); + var iter = TokenIter{ .text = template }; + var items: []const TemplateItem = &.{}; + var current_text: []const u8 = ""; + + while (iter.next()) |token| { + if (logging) @compileLog(token); + switch (token) { + .whitespace, .text => |text| current_text = current_text ++ text, + .open_bracket => { + const next = iter.peek() orelse @compileError("Unexpected end of template"); + if (next == .open_bracket) { + current_text = current_text ++ "{"; + _ = iter.next(); + } else { + if (current_text.len != 0) { + items = items ++ [_]TemplateItem{.{ .text = current_text }}; + current_text = ""; + } + const result = parseStatement(iter); + iter = result.new_iter; + items = items ++ [_]TemplateItem{.{ .statement = result.item }}; + } + }, + .close_bracket => { + const next = iter.next() orelse @compileError("Unexpected end of template"); + if (next == .close_bracket) current_text = current_text ++ "}" else @compileError("Unpaired close bracket, did you mean \"}}\"?"); + }, + .period => current_text = current_text ++ ".", + .pound => current_text = current_text ++ "#", + } + } + + if (current_text.len != 0) { + items = items ++ [_]TemplateItem{.{ .text = current_text }}; + } + + return items; + } +} + fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) { comptime { var iter = tokens; @@ -122,6 +148,11 @@ fn ParseResult(comptime T: type) type { }; } +const TemplateItem = union(enum) { + text: []const u8, + statement: Statement, +}; + const Expression = union(enum) { arg_deref: []const []const u8, };