| ... | @@ -94,19 +94,12 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V | ... | @@ -94,19 +94,12 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 94 | }, | 94 | }, |
| 95 | .replacement => |repl| { | 95 | .replacement => |repl| { |
| 96 | const v = repl.arms; | 96 | const v = repl.arms; |
| 97 | const x = if (comptime std.mem.eql(u8, v[0], "this")) search(v[1..], data) else search(v, ctx); | 97 | const x = search(v, ctx); |
| 98 | const TO = @TypeOf(x); | 98 | const TO = @TypeOf(x); |
| 99 | const TI = @typeInfo(TO); | 99 | const TI = @typeInfo(TO); |
| 100 | | 100 | |
| 101 | if (comptime extras.isZigString(TO)) { | 101 | if (comptime extras.isZigString(TO)) { |
| 102 | if (repl.raw) { | 102 | return writeReplacementString(writer, repl.raw, opts.escaped, x); |
| 103 | try writer.writeAll(x); | | |
| 104 | return; | | |
| 105 | } | | |
| 106 | const s = std.mem.trim(u8, x, "\n"); | | |
| 107 | if (opts.escaped) try writeEscaped(s, writer); | | |
| 108 | if (!opts.escaped) try writer.writeAll(s); | | |
| 109 | return; | | |
| 110 | } | 103 | } |
| 111 | if (TI == .int or TI == .float or TI == .comptime_int or TI == .comptime_float) { | 104 | if (TI == .int or TI == .float or TI == .comptime_int or TI == .comptime_float) { |
| 112 | try writer.print("{d}", .{x}); | 105 | try writer.print("{d}", .{x}); |
| ... | @@ -145,8 +138,25 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V | ... | @@ -145,8 +138,25 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 145 | const TI = @typeInfo(T); | 138 | const TI = @typeInfo(T); |
| 146 | switch (v.name) { | 139 | switch (v.name) { |
| 147 | .each => { | 140 | .each => { |
| 148 | comptime assertEqual(v.args.len, 1); | 141 | switch (v.args.len) { |
| 149 | for (x) |item| try do(alloc, writer, body, item, ctx, opts); | 142 | 1 => { |
| | 143 | for (x) |item| { |
| | 144 | if (@hasField(@TypeOf(ctx), "this")) { |
| | 145 | // handle nested loops, should be temporary |
| | 146 | try do(alloc, writer, body, null, extras.join(.{ extras.omit(ctx, "this"), .{ .this = item } }), opts); |
| | 147 | } else { |
| | 148 | try do(alloc, writer, body, null, extras.join(.{ ctx, .{ .this = item } }), opts); |
| | 149 | } |
| | 150 | } |
| | 151 | }, |
| | 152 | 2 => { |
| | 153 | const y = try resolveArg(v.args[1], alloc, data, ctx, opts); |
| | 154 | for (x, y) |item, jtem| { |
| | 155 | try do(alloc, writer, body, null, extras.join(.{ ctx, .{ .this = item, .that = jtem } }), opts); |
| | 156 | } |
| | 157 | }, |
| | 158 | else => @compileError(std.fmt.comptimePrint("#each block cannot have {d} iterators", .{v.args.len})), |
| | 159 | } |
| 150 | }, | 160 | }, |
| 151 | .@"if" => { | 161 | .@"if" => { |
| 152 | if (v.func) |n| { | 162 | if (v.func) |n| { |
| ... | @@ -255,9 +265,8 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V | ... | @@ -255,9 +265,8 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 255 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i + 2}); | 265 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i + 2}); |
| 256 | @field(args, field_name) = try resolveArg(arg, alloc, data, ctx, opts); | 266 | @field(args, field_name) = try resolveArg(arg, alloc, data, ctx, opts); |
| 257 | } | 267 | } |
| 258 | const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; | | |
| 259 | try @call(.auto, func, args); | 268 | try @call(.auto, func, args); |
| 260 | try do(alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); | 269 | try writeReplacementString(writer, v.raw, opts.escaped, try list.toOwnedSlice()); |
| 261 | return; | 270 | return; |
| 262 | } | 271 | } |
| 263 | if (v.raw and @hasDecl(opts.Ctx, "pek__" ++ v.name)) { | 272 | if (v.raw and @hasDecl(opts.Ctx, "pek__" ++ v.name)) { |
| ... | @@ -279,9 +288,8 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V | ... | @@ -279,9 +288,8 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 279 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i}); | 288 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i}); |
| 280 | @field(args[3], field_name) = try resolveArg(arg, alloc, data, ctx, opts); | 289 | @field(args[3], field_name) = try resolveArg(arg, alloc, data, ctx, opts); |
| 281 | } | 290 | } |
| 282 | const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; | | |
| 283 | try @call(.auto, func, args); | 291 | try @call(.auto, func, args); |
| 284 | try do(alloc, writer, repvalue, try list.toOwnedSlice(), ctx, opts); | 292 | try writeReplacementString(writer, v.raw, opts.escaped, list.items); |
| 285 | return; | 293 | return; |
| 286 | } | 294 | } |
| 287 | if (v.raw and @hasDecl(opts.Ctx, "pek_" ++ v.name)) { | 295 | if (v.raw and @hasDecl(opts.Ctx, "pek_" ++ v.name)) { |
| ... | @@ -306,7 +314,7 @@ pub const DoOptions = struct { | ... | @@ -306,7 +314,7 @@ pub const DoOptions = struct { |
| 306 | fn resolveArg(comptime arg: astgen.Arg, alloc: std.mem.Allocator, data: anytype, ctx: anytype, comptime opts: DoOptions) !ResolveArg(arg, @TypeOf(data), @TypeOf(ctx)) { | 314 | fn resolveArg(comptime arg: astgen.Arg, alloc: std.mem.Allocator, data: anytype, ctx: anytype, comptime opts: DoOptions) !ResolveArg(arg, @TypeOf(data), @TypeOf(ctx)) { |
| 307 | return switch (arg) { | 315 | return switch (arg) { |
| 308 | .plain => |av| av[1 .. av.len - 1], | 316 | .plain => |av| av[1 .. av.len - 1], |
| 309 | .lookup => |av| if (comptime std.mem.eql(u8, av[0], "this")) search(av[1..], data) else search(av, ctx), | 317 | .lookup => |av| search(av, ctx), |
| 310 | .int => |av| av, | 318 | .int => |av| av, |
| 311 | .value => |av| { | 319 | .value => |av| { |
| 312 | var list = std.ArrayList(u8).init(alloc); | 320 | var list = std.ArrayList(u8).init(alloc); |
| ... | @@ -319,9 +327,10 @@ fn resolveArg(comptime arg: astgen.Arg, alloc: std.mem.Allocator, data: anytype, | ... | @@ -319,9 +327,10 @@ fn resolveArg(comptime arg: astgen.Arg, alloc: std.mem.Allocator, data: anytype, |
| 319 | } | 327 | } |
| 320 | | 328 | |
| 321 | fn ResolveArg(comptime arg: astgen.Arg, comptime This: type, comptime Ctx: type) type { | 329 | fn ResolveArg(comptime arg: astgen.Arg, comptime This: type, comptime Ctx: type) type { |
| | 330 | _ = This; |
| 322 | return switch (arg) { | 331 | return switch (arg) { |
| 323 | .plain => string, | 332 | .plain => string, |
| 324 | .lookup => |av| if (comptime std.mem.eql(u8, av[0], "this")) FieldSearch(This, av[1..]) else FieldSearch(Ctx, av), | 333 | .lookup => |av| FieldSearch(Ctx, av), |
| 325 | .int => u64, | 334 | .int => u64, |
| 326 | .value => string, | 335 | .value => string, |
| 327 | }; | 336 | }; |
| ... | @@ -358,7 +367,8 @@ fn Field(comptime T: type, comptime field_name: string) type { | ... | @@ -358,7 +367,8 @@ fn Field(comptime T: type, comptime field_name: string) type { |
| 358 | return fld.type; | 367 | return fld.type; |
| 359 | } | 368 | } |
| 360 | } | 369 | } |
| 361 | @compileError(std.fmt.comptimePrint("pek: unknown field {s} on type {s}", .{ field_name, @typeName(T) })); | 370 | @compileLog(std.meta.fieldNames(T)); |
| | 371 | _ = @field(@as(T, undefined), field_name); |
| 362 | } | 372 | } |
| 363 | | 373 | |
| 364 | pub fn writeEscaped(s: string, writer: anytype) !void { | 374 | pub fn writeEscaped(s: string, writer: anytype) !void { |
| ... | @@ -374,6 +384,16 @@ pub fn writeEscaped(s: string, writer: anytype) !void { | ... | @@ -374,6 +384,16 @@ pub fn writeEscaped(s: string, writer: anytype) !void { |
| 374 | } | 384 | } |
| 375 | } | 385 | } |
| 376 | | 386 | |
| | 387 | fn writeReplacementString(writer: anytype, raw: bool, escaped: bool, bytes: []const u8) !void { |
| | 388 | if (raw) { |
| | 389 | try writer.writeAll(bytes); |
| | 390 | return; |
| | 391 | } |
| | 392 | const s = std.mem.trim(u8, bytes, "\n"); |
| | 393 | if (escaped) try writeEscaped(s, writer); |
| | 394 | if (!escaped) try writer.writeAll(s); |
| | 395 | } |
| | 396 | |
| 377 | fn nextCodepointSliceLossy(it: *std.unicode.Utf8Iterator) ?[]const u8 { | 397 | fn nextCodepointSliceLossy(it: *std.unicode.Utf8Iterator) ?[]const u8 { |
| 378 | if (it.i >= it.bytes.len) return null; | 398 | if (it.i >= it.bytes.len) return null; |
| 379 | const cp_len = std.unicode.utf8ByteSequenceLength(it.bytes[it.i]) catch { | 399 | const cp_len = std.unicode.utf8ByteSequenceLength(it.bytes[it.i]) catch { |