From 4e3450de4e8043dd9cdc2e309ae1aaac6392cb1b Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Sat, 10 Dec 2022 00:02:04 -0800 Subject: [PATCH] Add equals operator to template engine --- src/template/lib.zig | 57 ++++++++++++++++++++++++++++++++------ src/template/test.tmp.html | 2 ++ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/template/lib.zig b/src/template/lib.zig index 8fbcbe1..4c13fc8 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -15,6 +15,7 @@ pub fn main() !void { .bar = .{ .x = "x" }, .qux = false, .quxx = true, + .quxx2 = true, .maybe_foo = @as(?[]const u8, "foo"), .maybe_bar = @as(?[]const u8, null), .x = "y", @@ -168,6 +169,7 @@ fn EvaluateExpression( .arg_deref => |names| Deref(Args, names), .capture_deref => |names| Deref(Captures, names), .context_deref => |names| Deref(Context, names), + .equals => bool, }; } @@ -181,6 +183,16 @@ fn evaluateExpression( .arg_deref => |names| deref(args, names), .capture_deref => |names| deref(captures, names), .context_deref => |names| deref(context, names), + .equals => |eql| { + const lhs = evaluateExpression(eql.lhs, args, captures, context); + const rhs = evaluateExpression(eql.rhs, args, captures, context); + const T = @TypeOf(lhs, rhs); + if (comptime std.meta.trait.isZigString(T)) { + return std.mem.eql(u8, lhs, rhs); + } else if (comptime std.meta.trait.isContainer(T) and @hasDecl(T, "eql")) { + return T.eql(lhs, rhs); + } else return lhs == rhs; + }, }; } @@ -400,29 +412,50 @@ fn parseExpression(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIt comptime { var iter = tokens; - var expr: Expression = while (iter.next()) |token| switch (token) { + var last_valid_iter: ?ControlTokenIter = null; + var expr: ?Expression = null; + while (iter.next()) |token| switch (token) { .whitespace => {}, .period => { const names = parseDeref(iter); iter = names.new_iter; - break .{ .arg_deref = names.item }; + expr = .{ .arg_deref = names.item }; + last_valid_iter = iter; }, .dollar => { const names = parseDeref(iter); iter = names.new_iter; - break .{ .capture_deref = names.item }; + expr = .{ .capture_deref = names.item }; + last_valid_iter = iter; }, .percent => { const names = parseDeref(iter); iter = names.new_iter; - break .{ .context_deref = names.item }; + expr = .{ .context_deref = names.item }; + last_valid_iter = iter; }, - else => @compileError("TODO"), + .equals => { + const next = iter.next() orelse break; + if (next == .equals) { + const lhs = expr orelse break; + const rhs = parseExpression(iter); + iter = rhs.new_iter; + + expr = .{ + .equals = &.{ + .lhs = lhs, + .rhs = rhs.item, + }, + }; + last_valid_iter = iter; + } else break; + }, + else => break, }; return .{ - .new_iter = iter, - .item = expr, + .new_iter = last_valid_iter orelse @compileError("Invalid Expression"), + .item = expr orelse @compileError("Invalid Expression"), }; } } @@ -518,7 +551,7 @@ fn parseControlBlock(comptime tokens: ControlTokenIter) ParseResult(ControlToken }, else => { @compileLog(iter.row); - @compileError("TODO" ++ @tagName(token)); + @compileError("TODO " ++ @tagName(token) ++ " " ++ token.text); }, }; @@ -702,10 +735,16 @@ const TemplateItem = union(enum) { statement: Statement, }; +const EqualsExpr = struct { + lhs: Expression, + rhs: Expression, +}; + const Expression = union(enum) { arg_deref: []const []const u8, capture_deref: []const []const u8, context_deref: []const []const u8, + equals: *const EqualsExpr, }; const For = struct { @@ -830,7 +869,7 @@ const ControlTokenIter = 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 29930ed..2dc07ff 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -14,6 +14,8 @@ {$b}: {= /for =} {= /for} + {#if .quxx == .quxx2}eql{#else}neq{/if} + {#if .quxx == .qux}eql{#else}neq{/if} {#if .qux=} qux {=#elif .quxx=}