Skip to content

Commit 1560e8a

Browse files
author
Benjamin Feng
committed
Enable recursion!
1 parent 3f0ecdf commit 1560e8a

File tree

1 file changed

+63
-32
lines changed

1 file changed

+63
-32
lines changed

lib/std/fmtgen.zig

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ pub fn format(
150150
comptime var specifier_end = 0;
151151
comptime var options = FormatOptions{};
152152

153+
// TODO: calculate this
154+
var recur_stack: [0x10000]u8 = undefined;
155+
var recur_allocator = std.heap.FixedBufferAllocator.init(&recur_stack);
156+
153157
inline for (fmt) |c, i| {
154158
switch (state) {
155159
.Start => switch (c) {
@@ -207,6 +211,7 @@ pub fn format(
207211
fmt[0..0],
208212
options,
209213
generator,
214+
&recur_allocator.allocator,
210215
default_max_depth,
211216
);
212217

@@ -238,6 +243,7 @@ pub fn format(
238243
fmt[specifier_start..i],
239244
options,
240245
generator,
246+
&recur_allocator.allocator,
241247
default_max_depth,
242248
);
243249
state = .Start;
@@ -283,6 +289,7 @@ pub fn format(
283289
fmt[specifier_start..specifier_end],
284290
options,
285291
generator,
292+
&recur_allocator.allocator,
286293
default_max_depth,
287294
);
288295
state = .Start;
@@ -309,6 +316,7 @@ pub fn format(
309316
fmt[specifier_start..specifier_end],
310317
options,
311318
generator,
319+
&recur_allocator.allocator,
312320
default_max_depth,
313321
);
314322
state = .Start;
@@ -344,6 +352,7 @@ pub fn formatType(
344352
comptime fmt: []const u8,
345353
options: FormatOptions,
346354
generator: *Generator([]const u8),
355+
allocator: *mem.Allocator,
347356
max_depth: usize,
348357
) void {
349358
if (comptime std.mem.eql(u8, fmt, "*")) {
@@ -363,16 +372,24 @@ pub fn formatType(
363372
},
364373
.Optional => {
365374
if (value) |payload| {
366-
return @call(.{ .modifier = .always_tail }, formatType, .{ payload, fmt, options, generator, max_depth });
375+
// return @call(.{ .modifier = .always_tail }, formatType, .{ payload, fmt, options, generator, allocator, max_depth });
376+
var frame = allocator.create(
377+
@TypeOf(async formatType(payload, fmt, options, generator, allocator, max_depth)),
378+
) catch |err| switch (err) {
379+
error.OutOfMemory => return generator.yield(" ??OOM?? "),
380+
};
381+
defer allocator.destroy(frame);
382+
frame.* = async formatType(payload, fmt, options, generator, allocator, max_depth);
383+
await frame.*;
367384
} else {
368385
return generator.yield("null");
369386
}
370387
},
371388
.ErrorUnion => {
372389
if (value) |payload| {
373-
return @call(.{ .modifier = .always_tail }, formatType, .{ payload, fmt, options, generator, max_depth });
390+
return @call(.{ .modifier = .always_tail }, formatType, .{ payload, fmt, options, generator, allocator, max_depth });
374391
} else |err| {
375-
return @call(.{ .modifier = .always_tail }, formatType, .{ err, fmt, options, generator, max_depth });
392+
return @call(.{ .modifier = .always_tail }, formatType, .{ err, fmt, options, generator, allocator, max_depth });
376393
}
377394
},
378395
.ErrorSet => {
@@ -385,7 +402,7 @@ pub fn formatType(
385402
// }
386403
generator.yield(@typeName(T));
387404
generator.yield(".");
388-
return @call(.{ .modifier = .always_tail }, formatType, .{ @tagName(value), "", options, generator, max_depth });
405+
return @call(.{ .modifier = .always_tail }, formatType, .{ @tagName(value), "", options, generator, allocator, max_depth });
389406
},
390407
.Union => {
391408
// if (comptime std.meta.trait.hasFn("format")(T)) {
@@ -402,8 +419,14 @@ pub fn formatType(
402419
generator.yield(" = ");
403420
inline for (info.fields) |u_field| {
404421
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
405-
// TODO: investigate why recursion just works
406-
formatType(@field(value, u_field.name), "", options, generator, max_depth - 1);
422+
var frame = allocator.create(
423+
@TypeOf(async formatType(@field(value, u_field.name), "", options, generator, allocator, max_depth - 1)),
424+
) catch |err| switch (err) {
425+
error.OutOfMemory => return generator.yield(" ??OOM?? "),
426+
};
427+
defer allocator.destroy(frame);
428+
frame.* = async formatType(@field(value, u_field.name), "", options, generator, allocator, max_depth - 1);
429+
await frame.*;
407430
}
408431
}
409432
generator.yield(" }");
@@ -430,7 +453,15 @@ pub fn formatType(
430453
}
431454
generator.yield(@memberName(T, field_i));
432455
generator.yield(" = ");
433-
formatType(@field(value, @memberName(T, field_i)), "", options, generator, max_depth - 1);
456+
457+
var frame = allocator.create(
458+
@TypeOf(async formatType(@field(value, @memberName(T, field_i)), "", options, generator, allocator, max_depth - 1)),
459+
) catch |err| switch (err) {
460+
error.OutOfMemory => return generator.yield(" ??OOM?? "),
461+
};
462+
defer allocator.destroy(frame);
463+
frame.* = async formatType(@field(value, @memberName(T, field_i)), "", options, generator, allocator, max_depth - 1);
464+
await frame.*;
434465
}
435466
generator.yield(" }");
436467
},
@@ -443,7 +474,7 @@ pub fn formatType(
443474
return formatPtr(T.Child, @ptrToInt(value), generator);
444475
},
445476
builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
446-
return @call(.{ .modifier = .always_tail }, formatType, .{ value.*, fmt, options, generator, max_depth });
477+
return @call(.{ .modifier = .always_tail }, formatType, .{ value.*, fmt, options, generator, allocator, max_depth });
447478
},
448479
else => return formatPtr(T.Child, @ptrToInt(value), generator),
449480
},
@@ -481,7 +512,7 @@ pub fn formatType(
481512
.sentinel = null,
482513
},
483514
});
484-
return @call(.{ .modifier = .always_tail }, formatType, .{ @as(Slice, &value), fmt, options, generator, max_depth });
515+
return @call(.{ .modifier = .always_tail }, formatType, .{ @as(Slice, &value), fmt, options, generator, allocator, max_depth });
485516
},
486517
.Fn => {
487518
return formatPtr(T, @ptrToInt(value), generator);
@@ -1510,34 +1541,34 @@ test "enum" {
15101541
try testFmt("E.Two", "{}", .{inst});
15111542
}
15121543

1513-
// test "struct.self-referential" {
1514-
// const S = struct {
1515-
// const SelfType = @This();
1516-
// a: ?*SelfType,
1517-
// };
1544+
test "struct.self-referential" {
1545+
const S = struct {
1546+
const SelfType = @This();
1547+
a: ?*SelfType,
1548+
};
15181549

1519-
// var inst = S{
1520-
// .a = null,
1521-
// };
1522-
// inst.a = &inst;
1550+
var inst = S{
1551+
.a = null,
1552+
};
1553+
inst.a = &inst;
15231554

1524-
// try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
1525-
// }
1555+
try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
1556+
}
15261557

1527-
// test "struct.zero-size" {
1528-
// const A = struct {
1529-
// fn foo() void {}
1530-
// };
1531-
// const B = struct {
1532-
// a: A,
1533-
// c: i32,
1534-
// };
1558+
test "struct.zero-size" {
1559+
const A = struct {
1560+
fn foo() void {}
1561+
};
1562+
const B = struct {
1563+
a: A,
1564+
c: i32,
1565+
};
15351566

1536-
// const a = A{};
1537-
// const b = B{ .a = a, .c = 0 };
1567+
const a = A{};
1568+
const b = B{ .a = a, .c = 0 };
15381569

1539-
// try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
1540-
// }
1570+
try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
1571+
}
15411572

15421573
test "bytes.hex" {
15431574
const some_bytes = "\xCA\xFE\xBA\xBE";

0 commit comments

Comments
 (0)