| ... | ... | @@ -94,19 +94,12 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 94 | 94 | }, |
| 95 | 95 | .replacement => |repl| { |
| 96 | 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 | 98 | const TO = @TypeOf(x); |
| 99 | 99 | const TI = @typeInfo(TO); |
| 100 | 100 | |
| 101 | 101 | if (comptime extras.isZigString(TO)) { |
| 102 | | if (repl.raw) { |
| 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; |
| 102 | return writeReplacementString(writer, repl.raw, opts.escaped, x); |
| 110 | 103 | } |
| 111 | 104 | if (TI == .int or TI == .float or TI == .comptime_int or TI == .comptime_float) { |
| 112 | 105 | try writer.print("{d}", .{x}); |
| ... | ... | @@ -145,8 +138,25 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 145 | 138 | const TI = @typeInfo(T); |
| 146 | 139 | switch (v.name) { |
| 147 | 140 | .each => { |
| 148 | | comptime assertEqual(v.args.len, 1); |
| 149 | | for (x) |item| try do(alloc, writer, body, item, ctx, opts); |
| 141 | switch (v.args.len) { |
| 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 | 161 | .@"if" => { |
| 152 | 162 | if (v.func) |n| { |
| ... | ... | @@ -255,9 +265,8 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V |
| 255 | 265 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i + 2}); |
| 256 | 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 | 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 | 270 | return; |
| 262 | 271 | } |
| 263 | 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 | 288 | const field_name = comptime std.fmt.comptimePrint("{d}", .{i}); |
| 280 | 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 | 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 | 293 | return; |
| 286 | 294 | } |
| 287 | 295 | if (v.raw and @hasDecl(opts.Ctx, "pek_" ++ v.name)) { |
| ... | ... | @@ -306,7 +314,7 @@ pub const DoOptions = struct { |
| 306 | 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 | 315 | return switch (arg) { |
| 308 | 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 | 318 | .int => |av| av, |
| 311 | 319 | .value => |av| { |
| 312 | 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 | 327 | } |
| 320 | 328 | |
| 321 | 329 | fn ResolveArg(comptime arg: astgen.Arg, comptime This: type, comptime Ctx: type) type { |
| 330 | _ = This; |
| 322 | 331 | return switch (arg) { |
| 323 | 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 | 334 | .int => u64, |
| 326 | 335 | .value => string, |
| 327 | 336 | }; |
| ... | ... | @@ -358,7 +367,8 @@ fn Field(comptime T: type, comptime field_name: string) type { |
| 358 | 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 | 374 | 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 | 397 | fn nextCodepointSliceLossy(it: *std.unicode.Utf8Iterator) ?[]const u8 { |
| 378 | 398 | if (it.i >= it.bytes.len) return null; |
| 379 | 399 | const cp_len = std.unicode.utf8ByteSequenceLength(it.bytes[it.i]) catch { |