| 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,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 | }; |
| 15 | 17 | ||
| 16 | pub const Element = struct { | 18 | pub 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 | }; |
| 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,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"); |
| 29 | const astgen = @import("./astgen.zig"); | 29 | const astgen = @import("./astgen.zig"); |
| 30 | 30 | ||
| 31 | pub fn parse(comptime input: []const u8) astgen.Value { | 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 | pub fn compile(writer: anytype, comptime value: astgen.Value, data: anytype) !void { | 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,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 | |||
| 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,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", .{}); |