From e072b045c6ddd03363897f2c67ffe3a2de90d451 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Wed, 7 Dec 2022 23:24:32 -0800 Subject: [PATCH 1/2] Parse template calls --- src/template/lib.zig | 43 ++++++++++++++++++++++++++++++++++++++ src/template/test.tmp.html | 2 ++ 2 files changed, 45 insertions(+) diff --git a/src/template/lib.zig b/src/template/lib.zig index ff4ea23..1a1e9bb 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -8,6 +8,7 @@ pub fn main() !void { &.{ "5", "4", "3", "2", "1" }, &.{ "5", "4", "3", "2", "1" }, }, + .bar = .{ .x = "x" }, .qux = false, .quxx = true, }); @@ -61,6 +62,9 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca }; } }, + .call_template => |call| { + std.log.debug("calling template {s} with arg {any}", .{ call.template_name, call.args }); + }, //else => @compileError("TODO"), } } @@ -251,6 +255,11 @@ fn parseTemplate( break cb else @compileError("Unexpected #else tag"), + .call_template => |call| { + items = items ++ [_]TemplateItem{.{ + .statement = .{ .call_template = call }, + }}; + }, } }, } @@ -377,6 +386,11 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken iter = result.new_iter; break .{ .elif_header = result.item }; }, + .template => { + const result = parseCallTemplate(iter); + iter = result.new_iter; + break .{ .call_template = result.item }; + }, //else => @compileError("TODO"), } @@ -529,6 +543,27 @@ fn parseDeref(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, [ } } +fn parseCallTemplate(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, CallTemplate) { + comptime { + var iter = tokens; + const template_name = while (iter.next()) |token| switch (token) { + .text => |t| break t, + .whitespace => {}, + else => @compileError("Unexpected token"), + } else @compileError("Unexpected end of template"); + + const args = parseExpression(iter); + + return .{ + .new_iter = args.new_iter, + .item = .{ + .template_name = template_name, + .args = args.item, + }, + }; + } +} + fn ParseResult(comptime It: type, comptime T: type) type { return struct { new_iter: It, @@ -565,6 +600,11 @@ const If = struct { }, }; +const CallTemplate = struct { + template_name: []const u8, + args: Expression, +}; + const IfHeader = struct { condition: Expression, }; @@ -573,6 +613,7 @@ const Statement = union(enum) { expression: Expression, @"for": For, @"if": If, + call_template: CallTemplate, }; const ControlBlock = struct { @@ -584,6 +625,7 @@ const ControlBlock = struct { end_if: void, @"else": void, elif_header: IfHeader, + call_template: CallTemplate, }; block: Data, strip_before: bool, @@ -595,6 +637,7 @@ const Keyword = enum { @"if", @"else", @"elif", + @"template", }; const EndKeyword = enum { diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index d8b0353..77b0b5c 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -21,6 +21,8 @@ {=#else=} neither {=/if} + + {#template test_tmpl .bar} From 8c0548fc741522016fb7953dbfc7994a230593fd Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Wed, 7 Dec 2022 23:34:57 -0800 Subject: [PATCH 2/2] (#63) Allow invoking other templates Closes #63 --- src/main/controllers.zig | 2 +- src/template/lib.zig | 46 ++++++++++++++++++++++---------------- src/template/test.tmp.html | 2 +- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/main/controllers.zig b/src/main/controllers.zig index d60e0eb..64415fb 100644 --- a/src/main/controllers.zig +++ b/src/main/controllers.zig @@ -227,7 +227,7 @@ pub const Response = struct { defer stream.close(); const writer = stream.writer(); - try @import("template").execute(writer, templ, data); + try @import("template").execute(writer, .{}, templ, data); try stream.finish(); } diff --git a/src/template/lib.zig b/src/template/lib.zig index 1a1e9bb..8fcec6c 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -1,37 +1,42 @@ const std = @import("std"); pub fn main() !void { - try execute(std.io.getStdOut().writer(), @embedFile("./test.tmp.html"), .{ - .community = .{ .name = "abcd" }, - .foo = [_][]const u8{ "5", "4", "3", "2", "1" }, - .baz = [_][]const []const u8{ - &.{ "5", "4", "3", "2", "1" }, - &.{ "5", "4", "3", "2", "1" }, + try execute( + std.io.getStdOut().writer(), + .{ .test_tmpl = "{.x}" }, + @embedFile("./test.tmp.html"), + .{ + .community = .{ .name = "abcd" }, + .foo = [_][]const u8{ "5", "4", "3", "2", "1" }, + .baz = [_][]const []const u8{ + &.{ "5", "4", "3", "2", "1" }, + &.{ "5", "4", "3", "2", "1" }, + }, + .bar = .{ .x = "x" }, + .qux = false, + .quxx = true, }, - .bar = .{ .x = "x" }, - .qux = false, - .quxx = true, - }); + ); } -pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void { +pub fn execute(writer: anytype, comptime other_templates: anytype, comptime template: []const u8, args: anytype) !void { @setEvalBranchQuota(@intCast(u32, template.len * 8)); const tokens = comptime parseTemplateTokens(ControlTokenIter{ .text = template }); const tmpl = comptime parseTemplate(tokens, 0, .root); - try executeTemplate(writer, tmpl.items, args, .{}); + try executeTemplate(writer, other_templates, tmpl.items, args, .{}); } -fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype, captures: anytype) !void { +fn executeTemplate(writer: anytype, comptime templates: anytype, comptime items: []const TemplateItem, args: anytype, captures: anytype) !void { inline for (items) |it| { switch (it) { .text => |text| try writer.writeAll(text), - .statement => |stmt| try executeStatement(writer, stmt, args, captures), + .statement => |stmt| try executeStatement(writer, templates, stmt, args, captures), } } } -fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, captures: anytype) !void { +fn executeStatement(writer: anytype, comptime templates: anytype, comptime stmt: Statement, args: anytype, captures: anytype) !void { switch (stmt) { .expression => |expr| { const val = evaluateExpression(expr, args, captures); @@ -44,6 +49,7 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca for (iterable) |v| { try executeTemplate( writer, + templates, subtemplate, args, addCapture(captures, loop.header.capture, v), @@ -54,16 +60,18 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca const condition = evaluateExpression(if_stmt.header.condition, args, captures); const subtemplate = if_stmt.subtemplate; if (condition) { - try executeTemplate(writer, subtemplate, args, captures); + try executeTemplate(writer, templates, subtemplate, args, captures); } else { if (if_stmt.else_branch) |branch| switch (branch) { - .@"else" => |subtmpl| try executeTemplate(writer, subtmpl, args, captures), - .elif => |elif| try executeStatement(writer, .{ .@"if" = elif.* }, args, captures), + .@"else" => |subtmpl| try executeTemplate(writer, templates, subtmpl, args, captures), + .elif => |elif| try executeStatement(writer, templates, .{ .@"if" = elif.* }, args, captures), }; } }, .call_template => |call| { - std.log.debug("calling template {s} with arg {any}", .{ call.template_name, call.args }); + const new_template = @field(templates, call.template_name); + try execute(writer, templates, new_template, evaluateExpression(call.args, args, captures)); + //std.log.debug("calling template {s} with arg {any}", .{ call.template_name, call.args }); }, //else => @compileError("TODO"), } diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index 77b0b5c..4e575bf 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -22,7 +22,7 @@ neither {=/if} - {#template test_tmpl .bar} +