From 250e56a7821a3c6db9453ded696f9f3c622c94b0 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Fri, 6 Aug 2021 02:20:25 -0700 Subject: [PATCH] add functions and the `#each` helper --- src/astgen.zig | 38 ++++++++++++++++++++++++++++++++++++++ src/lib.zig | 19 ++++++++++++++++++- src/main.zig | 14 ++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/astgen.zig b/src/astgen.zig index 860fff764a8fa026af7e5e51c47ddcbc768c53ad..08df3cbde58a7103c81ba66ae130816bb3e10aa6 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -11,6 +11,8 @@ pub const Value = union(enum) { attr: Attr, string: string, replacement: []const string, + block: Block, + function: Fn, }; pub const Element = struct { @@ -24,6 +26,21 @@ pub const Attr = struct { value: string, }; +pub const Block = struct { + name: Type, + args: []const string, + body: []const Value, + + pub const Type = enum { + each, + }; +}; + +pub const Fn = struct { + name: string, + args: []const string, +}; + // // @@ -107,6 +124,27 @@ const Parser = struct { return Value{ .string = self.eat(.string) }; } if (self.tryEatSymbol("{")) { + if (self.tryEatSymbol("#")) { + const w = self.eat(.word); + if (std.meta.stringToEnum(Block.Type, w)) |name| { + const args = self.doReplacement(); + var children: []const Value = &.{}; + while (!self.tryEatSymbol("/")) { + children = children ++ &[_]Value{self.doValue()}; + } + std.debug.assert(std.mem.eql(u8, @tagName(name), self.eat(.word))); + self.eatSymbol("/"); + return Value{ .block = Block{ + .name = name, + .args = args, + .body = children, + } }; + } + return Value{ .function = .{ + .name = w, + .args = self.doReplacement(), + } }; + } return Value{ .replacement = self.doReplacement() }; } return Value{ .element = self.doElement() }; diff --git a/src/lib.zig b/src/lib.zig index 5c7e9212e584aecee04ee357fa99812c10a8430f..1e7dfaf83724ac4e1b1a13815fe9cd3a99b3cbf0 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -29,7 +29,7 @@ const tokenize = @import("./tokenize.zig"); const astgen = @import("./astgen.zig"); pub fn parse(comptime input: []const u8) astgen.Value { - return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}' })) }; + return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}', '#', '/' })) }; } pub fn compile(writer: anytype, comptime value: astgen.Value, data: anytype) !void { @@ -82,6 +82,23 @@ fn do(writer: anytype, comptime value: astgen.Value, data: anytype, indent: usiz try do(writer, astgen.Value{ .replacement = v[1..] }, x, indent, flag1); } }, + .block => |v| { + const x = comptime search(data, v.args); + + switch (v.name) { + .each => { + inline for (x) |item| { + inline for (v.body) |val| { + try do(writer, val, item, indent, flag1); + } + } + }, + } + }, else => unreachable, } } + +fn search(comptime T: anytype, comptime args: []const []const u8) @TypeOf(if (args.len == 1) @field(T, args[0]) else search(@TypeOf(@field(T, args[0])), args[1..])) { + return if (args.len == 1) @field(T, args[0]) else search(@TypeOf(@field(T, args[0])), args[1..]); +} diff --git a/src/main.zig b/src/main.zig index 6633f47575df93debc4b8141ea44bfb1c43e0038..195310400e78bae2c16f3ae0135d63cea05fede1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -14,6 +14,13 @@ const example_document = \\ p("This is an example HTML document written in "a[href="https://github.com/nektro/zig-pek"]("Pek")".") \\ p("Pek is written by "{author}".") \\ p("Her favorite plant is the "{favorite flower}) + \\ br + \\ p("The most populous US cities are:") + \\ ul( + \\ {#each top_cities} + \\ li({name}) + \\ /each/ + \\ ) \\ ) \\) ; @@ -28,6 +35,13 @@ pub fn main() !void { .favorite = .{ .flower = "Sunflower", }, + .top_cities = .{ + .{ .name = "New York" }, + .{ .name = "Los Angeles" }, + .{ .name = "Chicago" }, + .{ .name = "Houston" }, + .{ .name = "Phoenix" }, + }, }; try pek.compile(std.io.getStdErr().writer(), doc, data); std.debug.print("\n", .{}); -- 2.54.0