diff --git a/src/template/lib.zig b/src/template/lib.zig index 4ab839c..3e014e5 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -1,7 +1,10 @@ const std = @import("std"); pub fn main() !void { - try execute(std.io.getStdOut().writer(), @embedFile("./test.tmp.html"), .{ .community = .{ .name = "abcd" } }); + try execute(std.io.getStdOut().writer(), @embedFile("./test.tmp.html"), .{ + .community = .{ .name = "abcd" }, + .foo = [_][]const u8{ "5", "4", "3", "2", "1" }, + }); } const logging = false; @@ -22,23 +25,42 @@ fn executeTemplate(writer: anytype, comptime items: []const TemplateItem, args: fn executeStatement(writer: anytype, comptime stmt: Statement, args: anytype) !void { switch (stmt) { .expression => |expr| switch (expr) { - .arg_deref => |fields| try argDeref(writer, fields, args), + .arg_deref => |fields| { + const arg = argDeref(args, fields); + try print(writer, arg); + }, }, - .for_loop => { - try writer.writeAll("For loop"); + .for_loop => |loop| { + const fields = loop.iterable.arg_deref; + const iterable = argDeref(args, fields); + for (iterable) |str| { + try writer.writeAll(str); + } }, else => @compileError("TODO"), } } -fn argDeref(writer: anytype, comptime names: []const []const u8, arg: anytype) !void { - if (names.len == 0) { - const T = @TypeOf(arg); - if (comptime std.meta.trait.isZigString(T)) return writer.writeAll(arg); - return std.fmt.format(writer, "{any}", .{arg}); - } +fn print(writer: anytype, arg: anytype) !void { + if (comptime std.meta.trait.isZigString(@TypeOf(arg))) return writer.writeAll(arg); - return argDeref(writer, names[1..], @field(arg, names[0])); + @compileError("TODO"); +} + +fn ArgDeref(comptime T: type, comptime names: []const []const u8) type { + if (names.len == 0) return T; + + // Compiler segfaults when I use std.meta to get this info so we search it manually + const field = for (@typeInfo(T).Struct.fields) |f| { + if (std.mem.eql(u8, f.name, names[0])) break f; + } else @compileError("Unknown field " ++ names[0] ++ " in type " ++ @typeName(T)); + + return ArgDeref(field.field_type, names[1..]); +} + +fn argDeref(arg: anytype, comptime names: []const []const u8) ArgDeref(@TypeOf(arg), names) { + if (names.len == 0) return arg; + return argDeref(@field(arg, names[0]), names[1..]); } const TemplateType = enum { @@ -146,8 +168,8 @@ fn parseStatement(comptime tokens: TokenIter) ParseResult(Statement) { fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) { comptime { - const indexable = parseExpression(tokens); - var iter = indexable.new_iter; + const iterable = parseExpression(tokens); + var iter = iterable.new_iter; while (iter.next()) |token| switch (token) { .whitespace => {}, .close_bracket => break, @@ -157,7 +179,7 @@ fn parseForLoop(comptime tokens: TokenIter) ParseResult(ForLoop) { const subtemplate = parseTemplate(iter, .subtemplate); return .{ .new_iter = subtemplate.new_iter, .item = .{ - .indexable = indexable.item, + .iterable = iterable.item, .subtemplate = subtemplate.item, } }; } @@ -224,7 +246,7 @@ const Expression = union(enum) { const ForLoop = struct { subtemplate: []const TemplateItem, - indexable: Expression, + iterable: Expression, }; const Statement = union(enum) { diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index 30e772a..c00d1c4 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -9,7 +9,7 @@

{{ REAL BRACKETS }}

- {#for .community} + {#for .foo} {#end_for} {{#for args.notes |$note, $i|}}

Note no. {{$i}}