diff --git a/src/template/lib.zig b/src/template/lib.zig index ff4ea23..f1e141d 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -8,8 +8,8 @@ pub fn main() !void { &.{ "5", "4", "3", "2", "1" }, &.{ "5", "4", "3", "2", "1" }, }, - .qux = false, - .quxx = true, + .qux = true, + .quxx = false, }); } @@ -18,7 +18,7 @@ pub fn execute(writer: anytype, comptime template: []const u8, args: anytype) !v const tokens = comptime parseTemplateTokens(ControlTokenIter{ .text = template }); const tmpl = comptime parseTemplate(tokens, 0, .root); - try executeTemplate(writer, tmpl.items, args, .{}); + try executeTemplate(writer, tmpl.item, args, .{}); } fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: anytype, captures: anytype) !void { @@ -52,14 +52,7 @@ fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype, ca .@"if" => |if_stmt| { const condition = evaluateExpression(if_stmt.header.condition, args, captures); const subtemplate = if_stmt.subtemplate; - if (condition) { - try executeTemplate(writer, 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), - }; - } + if (condition) try executeTemplate(writer, subtemplate, args, captures); }, //else => @compileError("TODO"), } @@ -135,77 +128,25 @@ const TemplateType = enum { root, for_block, if_block, - if_else_block, }; -const TemplateParseResult = struct { - new_idx: usize, - items: []const TemplateItem, - closing_block: ?ControlBlock, -}; - -fn parseIfBlock( - comptime header: IfHeader, - comptime tokens: []const TemplateToken, - comptime start: usize, -) ParseResult(usize, If) { - const subtemplate = parseTemplate(tokens, start, .if_block); - - switch (subtemplate.closing_block.?.block) { - .end_if => return .{ - .new_iter = subtemplate.new_idx, - .item = If{ - .header = header, - .subtemplate = subtemplate.items, - .else_branch = null, - }, - }, - .@"else" => { - const else_subtemplate = parseTemplate(tokens, subtemplate.new_idx + 1, .if_else_block); - return .{ - .new_iter = else_subtemplate.new_idx, - .item = If{ - .header = header, - .subtemplate = subtemplate.items, - .else_branch = .{ .@"else" = else_subtemplate.items }, - }, - }; - }, - .elif_header => |elif_header| { - const else_if = parseIfBlock(elif_header, tokens, subtemplate.new_idx + 1); - return .{ - .new_iter = else_if.new_iter, - .item = If{ - .header = header, - .subtemplate = subtemplate.items, - .else_branch = .{ .elif = &else_if.item }, - }, - }; - }, - else => unreachable, - } -} - fn parseTemplate( comptime tokens: []const TemplateToken, comptime start: usize, comptime template_type: TemplateType, -) TemplateParseResult { +) ParseResult(usize, []const TemplateItem) { comptime { var i: usize = start; var current_text: []const u8 = ""; var items: []const TemplateItem = &.{}; - const closing_block: ?ControlBlock = while (i < tokens.len) : (i += 1) { + while (i < tokens.len) : (i += 1) { switch (tokens[i]) { .text => |text| current_text = current_text ++ text, .whitespace => |wsp| { - if (i != tokens.len - 1 and tokens[i + 1] == .control_block) { - if (tokens[i + 1].control_block.strip_before) continue; - } - if (i != 0 and tokens[i - 1] == .control_block) { - if (tokens[i - 1].control_block.strip_after) continue; - } + if (i != tokens.len - 1 and tokens[i + 1] == .control_block) + if (tokens[i + 1].control_block.strip_before) + continue; current_text = current_text ++ wsp; }, .control_block => |cb| { @@ -217,53 +158,55 @@ fn parseTemplate( switch (cb.block) { .expression => |expr| items = items ++ [_]TemplateItem{.{ .statement = .{ .expression = expr } }}, .if_header => |header| { - const parsed = parseIfBlock(header, tokens, i + 1); - i = parsed.new_iter; - items = items ++ [_]TemplateItem{.{ - .statement = .{ .@"if" = parsed.item }, - }}; - }, - .for_header => |header| { - const subtemplate = parseTemplate(tokens, i + 1, .for_block); + if (i != tokens.len - 1 and tokens[i + 1] == .whitespace and cb.strip_after) i += 1; + const subtemplate = parseTemplate(tokens, i + 1, .if_block); items = items ++ [_]TemplateItem{.{ .statement = .{ - .@"for" = .{ - .subtemplate = subtemplate.items, + .@"if" = .{ + .subtemplate = subtemplate.item, .header = header, }, }, }}; - i = subtemplate.new_idx; + i = subtemplate.new_iter; + }, + .for_header => |header| { + if (i != tokens.len - 1 and tokens[i + 1] == .whitespace and cb.strip_after) i += 1; + const subtemplate = parseTemplate(tokens, i + 1, .for_block); + items = items ++ [_]TemplateItem{.{ + .statement = .{ + .@"for" = .{ + .subtemplate = subtemplate.item, + .header = header, + }, + }, + }}; + i = subtemplate.new_iter; }, .end_for => if (template_type == .for_block) - break cb + break else @compileError("Unexpected /for tag"), - .end_if => if (template_type == .if_block or template_type == .if_else_block) - break cb + .end_if => if (template_type == .if_block) + break else @compileError("Unexpected /if tag"), - .elif_header => if (template_type == .if_block) - break cb - else - @compileError("Unexpected #elif tag"), - .@"else" => if (template_type == .if_block) - break cb - else - @compileError("Unexpected #else tag"), + } + + if (i != tokens.len - 1 and tokens[i] == .control_block) { + if (tokens[i].control_block.strip_after and tokens[i + 1] == .whitespace) { + i += 1; + } } }, } - } else null; + } else if (template_type != .root) @compileError("End tag not found"); if (current_text.len != 0) items = items ++ [_]TemplateItem{.{ .text = current_text }}; - if (template_type != .root and closing_block == null) @compileError("End tag not found"); - return .{ - .new_idx = i, - .items = items, - .closing_block = closing_block, + .new_iter = i, + .item = items, }; } } @@ -371,12 +314,6 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken iter = result.new_iter; break .{ .if_header = result.item }; }, - .@"else" => break .{ .@"else" = {} }, - .@"elif" => { - const result = parseIfHeader(iter); - iter = result.new_iter; - break .{ .elif_header = result.item }; - }, //else => @compileError("TODO"), } @@ -559,10 +496,6 @@ const ForHeader = struct { const If = struct { subtemplate: []const TemplateItem, header: IfHeader, - else_branch: ?union(enum) { - @"else": []const TemplateItem, - elif: *const If, - }, }; const IfHeader = struct { @@ -582,8 +515,6 @@ const ControlBlock = struct { end_for: void, if_header: IfHeader, end_if: void, - @"else": void, - elif_header: IfHeader, }; block: Data, strip_before: bool, @@ -593,8 +524,6 @@ const ControlBlock = struct { const Keyword = enum { @"for", @"if", - @"else", - @"elif", }; const EndKeyword = enum { @@ -688,12 +617,4 @@ test "template" { try testCase("{#if .val}1{/if}", .{ .val = true }, "1"); try testCase("{#for .vals |$v|}{$v}{/for}", .{ .vals = [_]u8{ 1, 2, 3 } }, "123"); try testCase("{#for .vals |$v|=} {$v} {=/for}", .{ .vals = [_]u8{ 1, 2, 3 } }, "123"); - try testCase("{#if .val}1{#else}0{/if}", .{ .val = true }, "1"); - try testCase("{#if .val}1{#else}0{/if}", .{ .val = false }, "0"); - try testCase("{#if .val}1{#elif .foo}2{/if}", .{ .val = false, .foo = true }, "2"); - try testCase("{#if .val}1{#elif .foo}2{/if}", .{ .val = false, .foo = false }, ""); - try testCase("{#if .val}1{#elif .foo}2{#else}0{/if}", .{ .val = false, .foo = false }, "0"); - try testCase("{#if .val}1{#elif .foo}2{#else}0{/if}", .{ .val = true, .foo = false }, "1"); - try testCase("{#if .val}1{#elif .foo}2{#else}0{/if}", .{ .val = false, .foo = true }, "2"); - try testCase("{#if .val}1{#elif .foo}2{#else}0{/if}", .{ .val = true, .foo = true }, "1"); } diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index d8b0353..72435f4 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -14,13 +14,8 @@ {$b}: {= /for =} {= /for} - {#if .qux=} - qux - {=#elif .quxx=} - quxx - {=#else=} - neither - {=/if} + {#if .qux}qux!{/if=} + {#if .quxx}quxx!{/if}