| ... | ... | @@ -22,7 +22,8 @@ pub fn parse(comptime input: string) astgen.Value { |
| 22 | 22 | |
| 23 | 23 | pub fn compile(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.Value, data: anytype) !void { |
| 24 | 24 | try writer.writeAll("<!DOCTYPE html>\n"); |
| 25 | | try do(Ctx, alloc, writer, value, data, data, .{ |
| 25 | try do(alloc, writer, value, data, data, .{ |
| 26 | .Ctx = Ctx, |
| 26 | 27 | .indent = 0, |
| 27 | 28 | .flag1 = false, |
| 28 | 29 | }); |
| ... | ... | @@ -31,10 +32,10 @@ pub fn compile(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, co |
| 31 | 32 | |
| 32 | 33 | pub const Writer = std.ArrayList(u8).Writer; |
| 33 | 34 | |
| 34 | | inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.Value, data: anytype, ctx: anytype, opts: DoOptions) anyerror!void { |
| 35 | inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.Value, data: anytype, ctx: anytype, comptime opts: DoOptions) anyerror!void { |
| 35 | 36 | switch (comptime value) { |
| 36 | 37 | .element => |v| { |
| 37 | | const hastext = for (v.children) |x| { |
| 38 | const hastext = comptime for (v.children) |x| { |
| 38 | 39 | switch (x) { |
| 39 | 40 | .string, .replacement, .function => break true, |
| 40 | 41 | .element, .attr, .block, .body => {}, |
| ... | ... | @@ -50,7 +51,7 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 50 | 51 | .string => try writer.print(" {s}=\"{}\"", .{ it.key, std.zig.fmtEscapes(it.value.string[1 .. it.value.string.len - 1]) }), |
| 51 | 52 | .body => { |
| 52 | 53 | try writer.print(" {s}=\"", .{it.key}); |
| 53 | | try do(Ctx, alloc, writer, astgen.Value{ .body = it.value.body }, data, ctx, opts); |
| 54 | try do(alloc, writer, astgen.Value{ .body = it.value.body }, data, ctx, opts); |
| 54 | 55 | try writer.print("\"", .{}); |
| 55 | 56 | }, |
| 56 | 57 | } |
| ... | ... | @@ -67,7 +68,8 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 67 | 68 | |
| 68 | 69 | if (!hastext) try writer.writeAll("\n"); |
| 69 | 70 | inline for (v.children) |it| { |
| 70 | | try do(Ctx, alloc, writer, it, data, ctx, .{ |
| 71 | try do(alloc, writer, it, data, ctx, .{ |
| 72 | .Ctx = opts.Ctx, |
| 71 | 73 | .indent = opts.indent + 1, |
| 72 | 74 | .flag1 = !hastext, |
| 73 | 75 | }); |
| ... | ... | @@ -117,25 +119,25 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 117 | 119 | switch (v.name) { |
| 118 | 120 | .each => { |
| 119 | 121 | comptime assertEqual(v.args.len, 1); |
| 120 | | for (x) |item| try do(Ctx, alloc, writer, body, item, ctx, opts); |
| 122 | for (x) |item| try do(alloc, writer, body, item, ctx, opts); |
| 121 | 123 | }, |
| 122 | 124 | .@"if" => { |
| 123 | 125 | comptime assertEqual(v.args.len, 1); |
| 124 | 126 | if (comptime std.meta.trait.isIndexable(T)) { |
| 125 | | try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, x.len > 0); |
| 127 | try doif(alloc, writer, body, bottom, data, ctx, opts, x.len > 0); |
| 126 | 128 | return; |
| 127 | 129 | } |
| 128 | 130 | switch (comptime TI) { |
| 129 | | .Bool => try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, x), |
| 130 | | .Optional => try docap(Ctx, alloc, writer, body, bottom, data, ctx, opts, x), |
| 131 | .Bool => try doif(alloc, writer, body, bottom, data, ctx, opts, x), |
| 132 | .Optional => try docap(alloc, writer, body, bottom, data, ctx, opts, x), |
| 131 | 133 | else => @compileError(std.fmt.comptimePrint("pek: unable to use '{s}' in an #if block", .{@typeName(T)})), |
| 132 | 134 | } |
| 133 | 135 | }, |
| 134 | 136 | .ifnot => { |
| 135 | 137 | comptime assertEqual(v.args.len, 1); |
| 136 | 138 | switch (comptime TI) { |
| 137 | | .Bool => try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, !x), |
| 138 | | .Optional => try docap(Ctx, alloc, writer, body, bottom, data, ctx, opts, !x), |
| 139 | .Bool => try doif(alloc, writer, body, bottom, data, ctx, opts, !x), |
| 140 | .Optional => try docap(alloc, writer, body, bottom, data, ctx, opts, !x), |
| 139 | 141 | else => @compileError(std.fmt.comptimePrint("pek: unable to use '{s}' in an #ifnot block", .{@typeName(T)})), |
| 140 | 142 | } |
| 141 | 143 | }, |
| ... | ... | @@ -143,31 +145,31 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 143 | 145 | comptime assertEqual(v.args.len, 2); |
| 144 | 146 | const y = if (comptime std.mem.eql(u8, v.args[1][0], "this")) search(v.args[1][1..], data) else search(v.args[1], ctx); |
| 145 | 147 | if (@typeInfo(@TypeOf(x)) == .Enum and comptime std.meta.trait.isZigString(@TypeOf(y))) { |
| 146 | | return try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); |
| 148 | return try doif(alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); |
| 147 | 149 | } |
| 148 | | try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, x == y); |
| 150 | try doif(alloc, writer, body, bottom, data, ctx, opts, x == y); |
| 149 | 151 | }, |
| 150 | 152 | .ifnotequal => { |
| 151 | 153 | comptime assertEqual(v.args.len, 2); |
| 152 | 154 | const y = if (comptime std.mem.eql(u8, v.args[1][0], "this")) search(v.args[1][1..], data) else search(v.args[1], ctx); |
| 153 | 155 | if (@typeInfo(@TypeOf(x)) == .Enum and comptime std.meta.trait.isZigString(@TypeOf(y))) { |
| 154 | | return try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); |
| 156 | return try doif(alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); |
| 155 | 157 | } |
| 156 | | try doif(Ctx, alloc, writer, body, bottom, data, ctx, opts, x != y); |
| 158 | try doif(alloc, writer, body, bottom, data, ctx, opts, x != y); |
| 157 | 159 | }, |
| 158 | 160 | } |
| 159 | 161 | }, |
| 160 | 162 | .body => |v| { |
| 161 | 163 | inline for (v) |val| { |
| 162 | | try do(Ctx, alloc, writer, val, data, ctx, opts); |
| 164 | try do(alloc, writer, val, data, ctx, opts); |
| 163 | 165 | } |
| 164 | 166 | }, |
| 165 | 167 | .function => |v| { |
| 166 | 168 | var arena = std.heap.ArenaAllocator.init(alloc); |
| 167 | 169 | defer arena.deinit(); |
| 168 | 170 | |
| 169 | | if (!v.raw and @hasDecl(Ctx, "pek_" ++ v.name)) { |
| 170 | | const func = @field(Ctx, "pek_" ++ v.name); |
| 171 | if (!v.raw and @hasDecl(opts.Ctx, "pek_" ++ v.name)) { |
| 172 | const func = @field(opts.Ctx, "pek_" ++ v.name); |
| 171 | 173 | var list = std.ArrayList(u8).init(arena.allocator()); |
| 172 | 174 | errdefer list.deinit(); |
| 173 | 175 | var args: std.meta.ArgsTuple(@TypeOf(func)) = undefined; |
| ... | ... | @@ -179,30 +181,35 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 179 | 181 | } |
| 180 | 182 | const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; |
| 181 | 183 | try @call(.auto, func, args); |
| 182 | | try do(Ctx, alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); |
| 184 | try do(alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); |
| 183 | 185 | return; |
| 184 | 186 | } |
| 185 | | if (v.raw and @hasDecl(Ctx, "pek__" ++ v.name)) { |
| 186 | | const func = @field(Ctx, "pek__" ++ v.name); |
| 187 | if (v.raw and @hasDecl(opts.Ctx, "pek__" ++ v.name)) { |
| 188 | const func = @field(opts.Ctx, "pek__" ++ v.name); |
| 187 | 189 | var list = std.ArrayList(u8).init(arena.allocator()); |
| 188 | 190 | errdefer list.deinit(); |
| 189 | | var args: std.meta.ArgsTuple(@TypeOf(func)) = undefined; |
| 190 | | args.@"0" = alloc; |
| 191 | | args.@"1" = list.writer(); |
| 192 | | args[2] = opts; |
| 191 | const AT = std.meta.ArgsTuple(@TypeOf(func)); |
| 192 | const ATT = std.meta.fieldInfo(AT, .@"3").type; |
| 193 | var tupargs = @as(ATT, undefined); |
| 194 | var args = .{ |
| 195 | alloc, |
| 196 | list.writer(), |
| 197 | opts, |
| 198 | tupargs, |
| 199 | }; |
| 193 | 200 | inline for (v.args, 0..) |arg, i| { |
| 194 | | const field_name = comptime std.fmt.comptimePrint("{d}", .{i + 3}); |
| 195 | | @field(args, field_name) = if (comptime std.mem.eql(u8, arg[0], "this")) search(arg[1..], data) else search(arg, ctx); |
| 201 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i}); |
| 202 | @field(args[3], field_name) = if (comptime std.mem.eql(u8, arg[0], "this")) search(arg[1..], data) else search(arg, ctx); |
| 196 | 203 | } |
| 197 | 204 | const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; |
| 198 | 205 | try @call(.auto, func, args); |
| 199 | | try do(Ctx, alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); |
| 206 | try do(alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); |
| 200 | 207 | return; |
| 201 | 208 | } |
| 202 | | if (v.raw and @hasDecl(Ctx, "pek_" ++ v.name)) { |
| 209 | if (v.raw and @hasDecl(opts.Ctx, "pek_" ++ v.name)) { |
| 203 | 210 | @compileError("pek: attempted to call safe custom function: '" ++ v.name ++ "' but did not use '{" ++ v.name ++ "}'"); |
| 204 | 211 | } |
| 205 | | if (!v.raw and @hasDecl(Ctx, "pek__" ++ v.name)) { |
| 212 | if (!v.raw and @hasDecl(opts.Ctx, "pek__" ++ v.name)) { |
| 206 | 213 | @compileError("pek: attempted to call raw custom function: '_" ++ v.name ++ "' but did not use '{#" ++ v.name ++ "}'"); |
| 207 | 214 | } |
| 208 | 215 | @compileError("pek: unknown custom function: " ++ v.name); |
| ... | ... | @@ -212,6 +219,7 @@ inline fn do(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comp |
| 212 | 219 | } |
| 213 | 220 | |
| 214 | 221 | pub const DoOptions = struct { |
| 222 | Ctx: type, |
| 215 | 223 | indent: usize, |
| 216 | 224 | flag1: bool, |
| 217 | 225 | }; |
| ... | ... | @@ -328,18 +336,18 @@ fn contains(haystack: []const string, needle: string) bool { |
| 328 | 336 | return false; |
| 329 | 337 | } |
| 330 | 338 | |
| 331 | | fn doif(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comptime top: astgen.Value, comptime bottom: astgen.Value, data: anytype, ctx: anytype, opts: DoOptions, flag2: bool) anyerror!void { |
| 339 | fn doif(alloc: std.mem.Allocator, writer: anytype, comptime top: astgen.Value, comptime bottom: astgen.Value, data: anytype, ctx: anytype, comptime opts: DoOptions, flag2: bool) anyerror!void { |
| 332 | 340 | if (flag2) { |
| 333 | | try do(Ctx, alloc, writer, top, data, ctx, opts); |
| 341 | try do(alloc, writer, top, data, ctx, opts); |
| 334 | 342 | } else { |
| 335 | | try do(Ctx, alloc, writer, bottom, data, ctx, opts); |
| 343 | try do(alloc, writer, bottom, data, ctx, opts); |
| 336 | 344 | } |
| 337 | 345 | } |
| 338 | 346 | |
| 339 | | fn docap(comptime Ctx: type, alloc: std.mem.Allocator, writer: anytype, comptime top: astgen.Value, comptime bottom: astgen.Value, data: anytype, ctx: anytype, opts: DoOptions, flag2: anytype) anyerror!void { |
| 347 | fn docap(alloc: std.mem.Allocator, writer: anytype, comptime top: astgen.Value, comptime bottom: astgen.Value, data: anytype, ctx: anytype, comptime opts: DoOptions, flag2: anytype) anyerror!void { |
| 340 | 348 | if (flag2) |_| { |
| 341 | | try do(Ctx, alloc, writer, top, data, ctx, opts); |
| 349 | try do(alloc, writer, top, data, ctx, opts); |
| 342 | 350 | } else { |
| 343 | | try do(Ctx, alloc, writer, bottom, data, ctx, opts); |
| 351 | try do(alloc, writer, bottom, data, ctx, opts); |
| 344 | 352 | } |
| 345 | 353 | } |