Compare commits

...

2 commits

Author SHA1 Message Date
8c0548fc74 (#63) Allow invoking other templates
Closes #63
2022-12-07 23:34:57 -08:00
e072b045c6 Parse template calls 2022-12-07 23:24:32 -08:00
3 changed files with 71 additions and 18 deletions

View file

@ -227,7 +227,7 @@ pub const Response = struct {
defer stream.close(); defer stream.close();
const writer = stream.writer(); const writer = stream.writer();
try @import("template").execute(writer, templ, data); try @import("template").execute(writer, .{}, templ, data);
try stream.finish(); try stream.finish();
} }

View file

@ -1,36 +1,42 @@
const std = @import("std"); const std = @import("std");
pub fn main() !void { pub fn main() !void {
try execute(std.io.getStdOut().writer(), @embedFile("./test.tmp.html"), .{ try execute(
.community = .{ .name = "abcd" }, std.io.getStdOut().writer(),
.foo = [_][]const u8{ "5", "4", "3", "2", "1" }, .{ .test_tmpl = "{.x}" },
.baz = [_][]const []const u8{ @embedFile("./test.tmp.html"),
&.{ "5", "4", "3", "2", "1" }, .{
&.{ "5", "4", "3", "2", "1" }, .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,
}, },
.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)); @setEvalBranchQuota(@intCast(u32, template.len * 8));
const tokens = comptime parseTemplateTokens(ControlTokenIter{ .text = template }); const tokens = comptime parseTemplateTokens(ControlTokenIter{ .text = template });
const tmpl = comptime parseTemplate(tokens, 0, .root); 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| { inline for (items) |it| {
switch (it) { switch (it) {
.text => |text| try writer.writeAll(text), .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) { switch (stmt) {
.expression => |expr| { .expression => |expr| {
const val = evaluateExpression(expr, args, captures); const val = evaluateExpression(expr, args, captures);
@ -43,6 +49,7 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca
for (iterable) |v| { for (iterable) |v| {
try executeTemplate( try executeTemplate(
writer, writer,
templates,
subtemplate, subtemplate,
args, args,
addCapture(captures, loop.header.capture, v), addCapture(captures, loop.header.capture, v),
@ -53,14 +60,19 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca
const condition = evaluateExpression(if_stmt.header.condition, args, captures); const condition = evaluateExpression(if_stmt.header.condition, args, captures);
const subtemplate = if_stmt.subtemplate; const subtemplate = if_stmt.subtemplate;
if (condition) { if (condition) {
try executeTemplate(writer, subtemplate, args, captures); try executeTemplate(writer, templates, subtemplate, args, captures);
} else { } else {
if (if_stmt.else_branch) |branch| switch (branch) { if (if_stmt.else_branch) |branch| switch (branch) {
.@"else" => |subtmpl| try executeTemplate(writer, subtmpl, args, captures), .@"else" => |subtmpl| try executeTemplate(writer, templates, subtmpl, args, captures),
.elif => |elif| try executeStatement(writer, .{ .@"if" = elif.* }, args, captures), .elif => |elif| try executeStatement(writer, templates, .{ .@"if" = elif.* }, args, captures),
}; };
} }
}, },
.call_template => |call| {
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"), //else => @compileError("TODO"),
} }
} }
@ -251,6 +263,11 @@ fn parseTemplate(
break cb break cb
else else
@compileError("Unexpected #else tag"), @compileError("Unexpected #else tag"),
.call_template => |call| {
items = items ++ [_]TemplateItem{.{
.statement = .{ .call_template = call },
}};
},
} }
}, },
} }
@ -377,6 +394,11 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken
iter = result.new_iter; iter = result.new_iter;
break .{ .elif_header = result.item }; break .{ .elif_header = result.item };
}, },
.template => {
const result = parseCallTemplate(iter);
iter = result.new_iter;
break .{ .call_template = result.item };
},
//else => @compileError("TODO"), //else => @compileError("TODO"),
} }
@ -529,6 +551,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 { fn ParseResult(comptime It: type, comptime T: type) type {
return struct { return struct {
new_iter: It, new_iter: It,
@ -565,6 +608,11 @@ const If = struct {
}, },
}; };
const CallTemplate = struct {
template_name: []const u8,
args: Expression,
};
const IfHeader = struct { const IfHeader = struct {
condition: Expression, condition: Expression,
}; };
@ -573,6 +621,7 @@ const Statement = union(enum) {
expression: Expression, expression: Expression,
@"for": For, @"for": For,
@"if": If, @"if": If,
call_template: CallTemplate,
}; };
const ControlBlock = struct { const ControlBlock = struct {
@ -584,6 +633,7 @@ const ControlBlock = struct {
end_if: void, end_if: void,
@"else": void, @"else": void,
elif_header: IfHeader, elif_header: IfHeader,
call_template: CallTemplate,
}; };
block: Data, block: Data,
strip_before: bool, strip_before: bool,
@ -595,6 +645,7 @@ const Keyword = enum {
@"if", @"if",
@"else", @"else",
@"elif", @"elif",
@"template",
}; };
const EndKeyword = enum { const EndKeyword = enum {

View file

@ -21,6 +21,8 @@
{=#else=} {=#else=}
neither neither
{=/if} {=/if}
<template>{#template test_tmpl .bar}</template>
</section> </section>
</body> </body>
</html> </html>