authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-08-06 02:20:25 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-08-06 02:20:25 -07:00
log250e56a7821a3c6db9453ded696f9f3c622c94b0
tree1b5cf522e70063b2aa29d5f1eef9038eb64a3f58
parent4e552999e6eaa5503943d47d2a75ef4ae1cb36f1

add functions and the `#each` helper


3 files changed, 70 insertions(+), 1 deletions(-)

src/astgen.zig+38
...@@ -11,6 +11,8 @@ pub const Value = union(enum) {...@@ -11,6 +11,8 @@ pub const Value = union(enum) {
11 attr: Attr,11 attr: Attr,
12 string: string,12 string: string,
13 replacement: []const string,13 replacement: []const string,
14 block: Block,
15 function: Fn,
14};16};
1517
16pub const Element = struct {18pub const Element = struct {
...@@ -24,6 +26,21 @@ pub const Attr = struct {...@@ -24,6 +26,21 @@ pub const Attr = struct {
24 value: string,26 value: string,
25};27};
2628
29pub const Block = struct {
30 name: Type,
31 args: []const string,
32 body: []const Value,
33
34 pub const Type = enum {
35 each,
36 };
37};
38
39pub const Fn = struct {
40 name: string,
41 args: []const string,
42};
43
27//44//
28//45//
2946
...@@ -107,6 +124,27 @@ const Parser = struct {...@@ -107,6 +124,27 @@ const Parser = struct {
107 return Value{ .string = self.eat(.string) };124 return Value{ .string = self.eat(.string) };
108 }125 }
109 if (self.tryEatSymbol("{")) {126 if (self.tryEatSymbol("{")) {
127 if (self.tryEatSymbol("#")) {
128 const w = self.eat(.word);
129 if (std.meta.stringToEnum(Block.Type, w)) |name| {
130 const args = self.doReplacement();
131 var children: []const Value = &.{};
132 while (!self.tryEatSymbol("/")) {
133 children = children ++ &[_]Value{self.doValue()};
134 }
135 std.debug.assert(std.mem.eql(u8, @tagName(name), self.eat(.word)));
136 self.eatSymbol("/");
137 return Value{ .block = Block{
138 .name = name,
139 .args = args,
140 .body = children,
141 } };
142 }
143 return Value{ .function = .{
144 .name = w,
145 .args = self.doReplacement(),
146 } };
147 }
110 return Value{ .replacement = self.doReplacement() };148 return Value{ .replacement = self.doReplacement() };
111 }149 }
112 return Value{ .element = self.doElement() };150 return Value{ .element = self.doElement() };
src/lib.zig+18-1
...@@ -29,7 +29,7 @@ const tokenize = @import("./tokenize.zig");...@@ -29,7 +29,7 @@ const tokenize = @import("./tokenize.zig");
29const astgen = @import("./astgen.zig");29const astgen = @import("./astgen.zig");
3030
31pub fn parse(comptime input: []const u8) astgen.Value {31pub fn parse(comptime input: []const u8) astgen.Value {
32 return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}' })) };32 return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}', '#', '/' })) };
33}33}
3434
35pub fn compile(writer: anytype, comptime value: astgen.Value, data: anytype) !void {35pub 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...@@ -82,6 +82,23 @@ fn do(writer: anytype, comptime value: astgen.Value, data: anytype, indent: usiz
82 try do(writer, astgen.Value{ .replacement = v[1..] }, x, indent, flag1);82 try do(writer, astgen.Value{ .replacement = v[1..] }, x, indent, flag1);
83 }83 }
84 },84 },
85 .block => |v| {
86 const x = comptime search(data, v.args);
87
88 switch (v.name) {
89 .each => {
90 inline for (x) |item| {
91 inline for (v.body) |val| {
92 try do(writer, val, item, indent, flag1);
93 }
94 }
95 },
96 }
97 },
85 else => unreachable,98 else => unreachable,
86 }99 }
87}100}
101
102fn 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..])) {
103 return if (args.len == 1) @field(T, args[0]) else search(@TypeOf(@field(T, args[0])), args[1..]);
104}
src/main.zig+14
...@@ -14,6 +14,13 @@ const example_document =...@@ -14,6 +14,13 @@ const example_document =
14 \\ p("This is an example HTML document written in "a[href="https://github.com/nektro/zig-pek"]("Pek")".")14 \\ p("This is an example HTML document written in "a[href="https://github.com/nektro/zig-pek"]("Pek")".")
15 \\ p("Pek is written by "{author}".")15 \\ p("Pek is written by "{author}".")
16 \\ p("Her favorite plant is the "{favorite flower})16 \\ p("Her favorite plant is the "{favorite flower})
17 \\ br
18 \\ p("The most populous US cities are:")
19 \\ ul(
20 \\ {#each top_cities}
21 \\ li({name})
22 \\ /each/
23 \\ )
17 \\ )24 \\ )
18 \\)25 \\)
19;26;
...@@ -28,6 +35,13 @@ pub fn main() !void {...@@ -28,6 +35,13 @@ pub fn main() !void {
28 .favorite = .{35 .favorite = .{
29 .flower = "Sunflower",36 .flower = "Sunflower",
30 },37 },
38 .top_cities = .{
39 .{ .name = "New York" },
40 .{ .name = "Los Angeles" },
41 .{ .name = "Chicago" },
42 .{ .name = "Houston" },
43 .{ .name = "Phoenix" },
44 },
31 };45 };
32 try pek.compile(std.io.getStdErr().writer(), doc, data);46 try pek.compile(std.io.getStdErr().writer(), doc, data);
33 std.debug.print("\n", .{});47 std.debug.print("\n", .{});