| author | |
| committer | |
| log | 250e56a7821a3c6db9453ded696f9f3c622c94b0 |
| tree | 1b5cf522e70063b2aa29d5f1eef9038eb64a3f58 |
| parent | 4e552999e6eaa5503943d47d2a75ef4ae1cb36f1 |
3 files changed, 70 insertions(+), 1 deletions(-)
src/astgen.zig+38| ... | ... | @@ -11,6 +11,8 @@ pub const Value = union(enum) { |
| 11 | 11 | attr: Attr, |
| 12 | 12 | string: string, |
| 13 | 13 | replacement: []const string, |
| 14 | block: Block, | |
| 15 | function: Fn, | |
| 14 | 16 | }; |
| 15 | 17 | |
| 16 | 18 | pub const Element = struct { |
| ... | ... | @@ -24,6 +26,21 @@ pub const Attr = struct { |
| 24 | 26 | value: string, |
| 25 | 27 | }; |
| 26 | 28 | |
| 29 | pub 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 | ||
| 39 | pub const Fn = struct { | |
| 40 | name: string, | |
| 41 | args: []const string, | |
| 42 | }; | |
| 43 | ||
| 27 | 44 | // |
| 28 | 45 | // |
| 29 | 46 | |
| ... | ... | @@ -107,6 +124,27 @@ const Parser = struct { |
| 107 | 124 | return Value{ .string = self.eat(.string) }; |
| 108 | 125 | } |
| 109 | 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 | 148 | return Value{ .replacement = self.doReplacement() }; |
| 111 | 149 | } |
| 112 | 150 | return Value{ .element = self.doElement() }; |
src/lib.zig+18-1| ... | ... | @@ -29,7 +29,7 @@ const tokenize = @import("./tokenize.zig"); |
| 29 | 29 | const astgen = @import("./astgen.zig"); |
| 30 | 30 | |
| 31 | 31 | pub 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 | } |
| 34 | 34 | |
| 35 | 35 | 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 |
| 82 | 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 | 98 | else => unreachable, |
| 86 | 99 | } |
| 87 | 100 | } |
| 101 | ||
| 102 | 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..])) { | |
| 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 | 14 | \\ p("This is an example HTML document written in "a[href="https://github.com/nektro/zig-pek"]("Pek")".") |
| 15 | 15 | \\ p("Pek is written by "{author}".") |
| 16 | 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 | 35 | .favorite = .{ |
| 29 | 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 | 46 | try pek.compile(std.io.getStdErr().writer(), doc, data); |
| 33 | 47 | std.debug.print("\n", .{}); |