diff --git a/src/template/lib.zig b/src/template/lib.zig index a77d3f1..1c33d22 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -15,6 +15,8 @@ pub fn main() !void { .bar = .{ .x = "x" }, .qux = false, .quxx = true, + .maybe_foo = @as(?[]const u8, "foo"), + .maybe_bar = @as(?[]const u8, null), }, .{ .context_foo = "foo", @@ -83,9 +85,33 @@ fn executeStatement( .@"if" => |if_stmt| { const condition = evaluateExpression(if_stmt.header.condition, args, captures, context); const subtemplate = if_stmt.subtemplate; - if (condition) { - try executeTemplate(writer, templates, subtemplate, args, captures, context); + var was_true: bool = false; + if (if_stmt.header.capture) |capture| { + if (condition) |val| { + was_true = true; + try executeTemplate( + writer, + templates, + subtemplate, + args, + addCapture(captures, capture, val), + context, + ); + } } else { + if (condition) { + was_true = true; + try executeTemplate( + writer, + templates, + subtemplate, + args, + captures, + context, + ); + } + } + if (!was_true) { if (if_stmt.else_branch) |branch| switch (branch) { .@"else" => |subtmpl| try executeTemplate(writer, templates, subtmpl, args, captures, context), .elif => |elif| try executeStatement(writer, templates, .{ .@"if" = elif.* }, args, captures, context), @@ -359,6 +385,7 @@ fn parseTemplateTokens(comptime tokens: ControlTokenIter) []const TemplateToken .slash => items = items ++ [_]TemplateToken{.{ .text = "/" }}, .equals => items = items ++ [_]TemplateToken{.{ .text = "=" }}, .at => items = items ++ [_]TemplateToken{.{ .text = "@" }}, + .comma => items = items ++ [_]TemplateToken{.{ .text = "," }}, }; return items; @@ -551,15 +578,62 @@ fn parseForHeader(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIte } } +fn tryParseCapture(comptime tokens: ControlTokenIter) ?ParseResult(ControlTokenIter, []const []const u8) { + comptime { + var iter = tokens; + + iter = skipWhitespace(iter); + if ((iter.next() orelse return null) != .pipe) return null; + iter = skipWhitespace(iter); + var captures: []const []const u8 = &.{}; + while (true) { + if ((iter.next() orelse return null) != .dollar) return null; + iter = skipWhitespace(iter); + const name = switch (iter.next() orelse return null) { + .text => |text| text, + else => return null, + }; + iter = skipWhitespace(iter); + captures = captures ++ &[_][]const u8{name}; + + switch (iter.next() orelse return null) { + .pipe => break, + .comma => {}, + else => return null, + } + iter = skipWhitespace(iter); + } + + return .{ + .new_iter = iter, + .item = captures, + }; + } +} + fn parseIfHeader(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, IfHeader) { comptime { const condition = parseExpression(tokens); var iter = condition.new_iter; + const captures = tryParseCapture(iter); + if (captures) |cap| { + if (cap.item.len == 1) { + return .{ + .new_iter = cap.new_iter, + .item = IfHeader{ + .condition = condition.item, + .capture = cap.item[0], + }, + }; + } else @compileError("Only one capture allowed for if statements"); + } + return .{ .new_iter = iter, .item = .{ .condition = condition.item, + .capture = null, }, }; } @@ -657,6 +731,7 @@ const CallTemplate = struct { const IfHeader = struct { condition: Expression, + capture: ?[]const u8, }; const Statement = union(enum) { @@ -707,6 +782,7 @@ const ControlToken = union(enum) { slash: void, equals: void, at: void, + comma: void, }; const ControlTokenIter = struct { @@ -737,6 +813,7 @@ const ControlTokenIter = struct { '/' => return .{ .slash = {} }, '=' => return .{ .equals = {} }, '@' => return .{ .at = {} }, + ',' => return .{ .comma = {} }, ' ', '\t', '\n', '\r' => { var idx: usize = 0; while (idx < remaining.len and std.mem.indexOfScalar(u8, " \t\n\r", remaining[idx]) != null) : (idx += 1) {} diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index 0922607..ef41e35 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -22,6 +22,9 @@ neither {=/if} + {#if .maybe_foo |$v|}{$v}{#else}null{/if} + {#if .maybe_bar |$v|}{$v}{#else}null{/if} + {@context_foo}