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