diff --git a/src/template/lib.zig b/src/template/lib.zig index 7d1eebe..649b30e 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -162,6 +162,7 @@ fn parseTemplate(comptime tokens: TokenIter, comptime template_type: TemplateTyp .pipe => current_text = current_text ++ "|", .dollar => current_text = current_text ++ "$", .slash => current_text = current_text ++ "/", + .equals => current_text = current_text ++ "=", } } @@ -182,78 +183,98 @@ fn parseExpressionOrStatement( ) ParseResult(if (as_statement) Statement else Expression) { comptime { var iter = tokens; - var stmt: ExecutableStatement = while (iter.next()) |token| switch (token) { - .whitespace => {}, - .pound => { - if (!as_statement) @compileError("Unexpected Token"); - const next = iter.next() orelse @compileError("Unexpected end of template"); - if (next != .text) @compileError("Expected keyword following '#' character"); - const text = next.text; - const keyword = std.meta.stringToEnum(Keyword, text) orelse @compileError("Unknown keyword: " ++ text); + var first_token: bool = true; + var strip_before: bool = false; + var stmt: ExecutableStatement = while (iter.next()) |token| { + defer first_token = false; + switch (token) { + .equals => { + if (as_statement and first_token) { + strip_before = true; + } else @compileError("Unexpected '='"); + }, + .whitespace => {}, + .pound => { + if (!as_statement) @compileError("Unexpected Token"); + const next = iter.next() orelse @compileError("Unexpected end of template"); + if (next != .text) @compileError("Expected keyword following '#' character"); + const text = next.text; + const keyword = std.meta.stringToEnum(Keyword, text) orelse @compileError("Unknown keyword: " ++ text); - switch (keyword) { - .@"for" => { - const result = parseForLoop(iter); - // statemnt already finished so just return - return .{ - .new_iter = result.new_iter, - .item = .{ - .executable = .{ .for_loop = result.item }, - .strip_before = false, - .strip_after = false, - }, - }; - }, - .@"if" => { - const result = parseIfStatement(iter); - return .{ - .new_iter = result.new_iter, - .item = .{ - .executable = .{ .if_statement = result.item }, - .strip_before = false, - .strip_after = false, - }, - }; - }, + switch (keyword) { + .@"for" => { + const result = parseForLoop(iter); + // statemnt already finished so just return + return .{ + .new_iter = result.new_iter, + .item = .{ + .executable = .{ .for_loop = result.item }, + .strip_before = false, + .strip_after = false, + }, + }; + }, + .@"if" => { + const result = parseIfStatement(iter); + return .{ + .new_iter = result.new_iter, + .item = .{ + .executable = .{ .if_statement = result.item }, + .strip_before = false, + .strip_after = false, + }, + }; + }, - //else => @compileError("TODO"), - } - }, - .slash => { - if (!as_statement) !@compileError("Unexpected Token"); - const next = iter.next() orelse @compileError("Unexpected end of template"); - if (next != .text) @compileError("Expected keyword following '/' character"); - const text = next.text; - const keyword = std.meta.stringToEnum(EndKeyword, text) orelse @compileError("Unknown keyword: " ++ text); + //else => @compileError("TODO"), + } + }, + .slash => { + if (!as_statement) !@compileError("Unexpected Token"); + const next = iter.next() orelse @compileError("Unexpected end of template"); + if (next != .text) @compileError("Expected keyword following '/' character"); + const text = next.text; + const keyword = std.meta.stringToEnum(EndKeyword, text) orelse @compileError("Unknown keyword: " ++ text); - switch (keyword) { - .@"for" => break .{ .end_for = {} }, - .@"if" => break .{ .end_if = {} }, - } - }, - .period => { - const names = parseDeref(iter); - iter = names.new_iter; - break .{ .expression = .{ .arg_deref = names.item } }; - }, - .dollar => { - const names = parseDeref(iter); - iter = names.new_iter; - break .{ .expression = .{ .capture_deref = names.item } }; - }, - else => if (as_statement) @compileError("TODO") else break, + switch (keyword) { + .@"for" => break .{ .end_for = {} }, + .@"if" => break .{ .end_if = {} }, + } + }, + .period => { + const names = parseDeref(iter); + iter = names.new_iter; + break .{ .expression = .{ .arg_deref = names.item } }; + }, + .dollar => { + const names = parseDeref(iter); + iter = names.new_iter; + break .{ .expression = .{ .capture_deref = names.item } }; + }, + else => if (as_statement) @compileError("TODO") else break, + } }; if (as_statement) { // search for end of statement + var strip_after: bool = false; while (iter.next()) |token| switch (token) { .whitespace => {}, + .equals => { + if (iter.peek()) |t| { + if (t == .close_bracket) { + strip_after = true; + continue; + } + } + @compileError("Unexpected '='"); + }, .close_bracket => return .{ .new_iter = iter, .item = .{ .executable = stmt, - .strip_before = true, - .strip_after = true, + .strip_before = strip_before, + .strip_after = strip_after, }, }, else => { @@ -425,6 +446,7 @@ const Token = union(enum) { pipe: void, dollar: void, slash: void, + equals: void, }; const TokenIter = struct { @@ -453,6 +475,7 @@ const TokenIter = struct { '|' => return .{ .pipe = {} }, '$' => return .{ .dollar = {} }, '/' => return .{ .slash = {} }, + '=' => return .{ .equals = {} }, ' ', '\t', '\n', '\r' => { var idx: usize = 0; while (idx < remaining.len and std.mem.indexOfScalar(u8, " \t\n\r", remaining[idx]) != null) : (idx += 1) {} @@ -464,7 +487,7 @@ const TokenIter = struct { }, else => { var idx: usize = 0; - while (idx < remaining.len and std.mem.indexOfScalar(u8, "{}.#|$/ \t\n\r", remaining[idx]) == null) : (idx += 1) {} + while (idx < remaining.len and std.mem.indexOfScalar(u8, "{}.#|$/= \t\n\r", remaining[idx]) == null) : (idx += 1) {} self.start += idx - 1; return .{ .text = remaining[0..idx] }; diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index 862b080..bbfb3ad 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -1,7 +1,7 @@ - {.community.name} + {= .community.name =} @@ -9,7 +9,7 @@

{{ REAL BRACKETS }}

- {#for .baz |$f|}{#for $f |$b|}{$b}:{/for} + {= #for .baz |$f|}{#for $f |$b|}{$b}:{/for} {/for} {#if .qux}qux!{/if} {#if .quxx}quxx!{/if}