Add if statements to templating engine

This commit is contained in:
jaina heartles 2022-11-17 23:39:32 -08:00
parent 5bb9742ab9
commit c9af99d08f
2 changed files with 49 additions and 5 deletions

View file

@ -8,11 +8,13 @@ pub fn main() !void {
&.{ "5", "4", "3", "2", "1" }, &.{ "5", "4", "3", "2", "1" },
&.{ "5", "4", "3", "2", "1" }, &.{ "5", "4", "3", "2", "1" },
}, },
.qux = true,
.quxx = false,
}); });
} }
pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void { pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !void {
@setEvalBranchQuota(@intCast(u32, template.len * 6)); @setEvalBranchQuota(@intCast(u32, template.len * 8));
const tmpl = comptime parseTemplate(TokenIter{ .text = template }, .root); const tmpl = comptime parseTemplate(TokenIter{ .text = template }, .root);
try executeTemplate(writer, tmpl.item, args, .{}); try executeTemplate(writer, tmpl.item, args, .{});
} }
@ -42,6 +44,11 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca
); );
} }
}, },
.if_statement => |if_stmt| {
const condition = evaluateExpression(if_stmt.condition, args, captures);
const subtemplate = if_stmt.subtemplate;
if (condition) try executeTemplate(writer, subtemplate, args, captures);
},
else => @compileError("TODO"), else => @compileError("TODO"),
} }
} }
@ -112,7 +119,8 @@ fn addCapture(root: anytype, comptime name: []const u8, val: anytype) AddCapture
const TemplateType = enum { const TemplateType = enum {
root, root,
subtemplate, for_block,
if_block,
}; };
fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateType) ParseResult([]const TemplateItem) { fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateType) ParseResult([]const TemplateItem) {
@ -137,7 +145,9 @@ fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateTyp
const result = parseExpressionOrStatement(iter, true); const result = parseExpressionOrStatement(iter, true);
iter = result.new_iter; iter = result.new_iter;
if (result.item == .end_for) { if (result.item == .end_for) {
if (template_type == .subtemplate) break :parse_loop else @compileError("Unexpected end statement"); if (template_type == .for_block) break :parse_loop else @compileError("Unexpected end statement");
} else if (result.item == .end_if) {
if (template_type == .if_block) break :parse_loop else @compileError("Unexpected end statement");
} }
items = items ++ [_]TemplateItem{.{ .statement = result.item }}; items = items ++ [_]TemplateItem{.{ .statement = result.item }};
} }
@ -189,6 +199,13 @@ fn parseExpressionOrStatement(
.item = .{ .for_loop = result.item }, .item = .{ .for_loop = result.item },
}; };
}, },
.@"if" => {
const result = parseIfStatement(iter);
return .{
.new_iter = result.new_iter,
.item = .{ .if_statement = result.item },
};
},
//else => @compileError("TODO"), //else => @compileError("TODO"),
} }
@ -202,6 +219,7 @@ fn parseExpressionOrStatement(
switch (keyword) { switch (keyword) {
.@"for" => break .{ .end_for = {} }, .@"for" => break .{ .end_for = {} },
.@"if" => break .{ .end_if = {} },
} }
}, },
.period => { .period => {
@ -283,9 +301,24 @@ fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) {
} }
iter = endStatement(iter); iter = endStatement(iter);
const subtemplate = parseTemplate(iter, .subtemplate); const subtemplate = parseTemplate(iter, .for_block);
return .{ .new_iter = subtemplate.new_iter, .item = .{ .iterable = iterable.item, .subtemplate = subtemplate.item, .capture = capture } }; return .{ .new_iter = subtemplate.new_iter, .item = .{
.iterable = iterable.item,
.subtemplate = subtemplate.item,
.capture = capture,
} };
}
}
fn parseIfStatement(comptime tokens: TokenIter) ParseResult(IfStatement) {
comptime {
const condition = parseExpressionOrStatement(tokens, false);
var iter = endStatement(condition.new_iter);
const subtemplate = parseTemplate(iter, .if_block);
return .{ .new_iter = subtemplate.new_iter, .item = .{ .condition = condition.item, .subtemplate = subtemplate.item } };
} }
} }
@ -339,18 +372,27 @@ const ForLoop = struct {
capture: []const u8, capture: []const u8,
}; };
const IfStatement = struct {
subtemplate: []const TemplateItem,
condition: Expression,
};
const Statement = union(enum) { const Statement = union(enum) {
expression: Expression, expression: Expression,
for_loop: ForLoop, for_loop: ForLoop,
end_for: void, end_for: void,
if_statement: IfStatement,
end_if: void,
}; };
const Keyword = enum { const Keyword = enum {
@"for", @"for",
@"if",
}; };
const EndKeyword = enum { const EndKeyword = enum {
@"for", @"for",
@"if",
}; };
const Token = union(enum) { const Token = union(enum) {

View file

@ -11,6 +11,8 @@
<section> <section>
{#for .baz |$f|}{#for $f |$b|}{$b}:{/for} {#for .baz |$f|}{#for $f |$b|}{$b}:{/for}
{/for} {/for}
{#if .qux}qux!{/if}
{#if .quxx}quxx!{/if}
</section> </section>
</body> </body>
</html> </html>