authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-08-19 19:48:05-10:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-08-19 19:48:05-10:00
log2aa18b909765a48878d3f30f638e79d6eee1b584
treeac69655efd29969860646d9a97582b8c25e9e3e5
parent3dbed54294bc6769f64fc8bd23b98605d009677c
parente0447c6ddd71d400fc501bf33c4cb33dde4e3300
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3090 from ziglang/fmt-internal

fmt changes

4 files changed, 76 insertions(+), 79 deletions(-)

std/fmt.zig+72-75
......@@ -69,7 +69,6 @@ pub fn format(
6969 FormatFillAndAlign,
7070 FormatWidth,
7171 FormatPrecision,
72 Pointer,
7372 };
7473
7574 comptime var start_index = 0;
......@@ -109,9 +108,6 @@ pub fn format(
109108 state = .Start;
110109 start_index = i;
111110 },
112 '*' => {
113 state = .Pointer;
114 },
115111 ':' => {
116112 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
117113 specifier_end = i;
......@@ -256,19 +252,6 @@ pub fn format(
256252 @compileError("Unexpected character in precision value: " ++ [_]u8{c});
257253 },
258254 },
259 .Pointer => switch (c) {
260 '}' => {
261 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
262
263 try output(context, @typeName(@typeOf(args[arg_to_print]).Child));
264 try output(context, "@");
265 try formatInt(@ptrToInt(args[arg_to_print]), 16, false, 0, context, Errors, output);
266
267 state = .Start;
268 start_index = i + 1;
269 },
270 else => @compileError("Unexpected format character after '*'"),
271 },
272255 }
273256 }
274257 comptime {
......@@ -293,12 +276,19 @@ pub fn format(
293276pub fn formatType(
294277 value: var,
295278 comptime fmt: []const u8,
296 comptime options: FormatOptions,
279 options: FormatOptions,
297280 context: var,
298281 comptime Errors: type,
299282 output: fn (@typeOf(context), []const u8) Errors!void,
300283 max_depth: usize,
301284) Errors!void {
285 if (comptime std.mem.eql(u8, fmt, "*")) {
286 try output(context, @typeName(@typeOf(value).Child));
287 try output(context, "@");
288 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);
289 return;
290 }
291
302292 const T = @typeOf(value);
303293 switch (@typeInfo(T)) {
304294 .ComptimeInt, .Int, .Float => {
......@@ -438,15 +428,15 @@ pub fn formatType(
438428fn formatValue(
439429 value: var,
440430 comptime fmt: []const u8,
441 comptime options: FormatOptions,
431 options: FormatOptions,
442432 context: var,
443433 comptime Errors: type,
444434 output: fn (@typeOf(context), []const u8) Errors!void,
445435) Errors!void {
446436 if (comptime std.mem.eql(u8, fmt, "B")) {
447 return formatBytes(value, options.width, 1000, context, Errors, output);
437 return formatBytes(value, options, 1000, context, Errors, output);
448438 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
449 return formatBytes(value, options.width, 1024, context, Errors, output);
439 return formatBytes(value, options, 1024, context, Errors, output);
450440 }
451441
452442 const T = @typeOf(value);
......@@ -460,7 +450,7 @@ fn formatValue(
460450pub fn formatIntValue(
461451 value: var,
462452 comptime fmt: []const u8,
463 comptime options: FormatOptions,
453 options: FormatOptions,
464454 context: var,
465455 comptime Errors: type,
466456 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -479,7 +469,7 @@ pub fn formatIntValue(
479469 uppercase = false;
480470 } else if (comptime std.mem.eql(u8, fmt, "c")) {
481471 if (@typeOf(int_value).bit_count <= 8) {
482 return formatAsciiChar(u8(int_value), context, Errors, output);
472 return formatAsciiChar(u8(int_value), options, context, Errors, output);
483473 } else {
484474 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
485475 }
......@@ -496,21 +486,21 @@ pub fn formatIntValue(
496486 @compileError("Unknown format string: '" ++ fmt ++ "'");
497487 }
498488
499 return formatInt(int_value, radix, uppercase, options.width orelse 0, context, Errors, output);
489 return formatInt(int_value, radix, uppercase, options, context, Errors, output);
500490}
501491
502492fn formatFloatValue(
503493 value: var,
504494 comptime fmt: []const u8,
505 comptime options: FormatOptions,
495 options: FormatOptions,
506496 context: var,
507497 comptime Errors: type,
508498 output: fn (@typeOf(context), []const u8) Errors!void,
509499) Errors!void {
510500 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
511 return formatFloatScientific(value, options.precision, context, Errors, output);
501 return formatFloatScientific(value, options, context, Errors, output);
512502 } else if (comptime std.mem.eql(u8, fmt, "d")) {
513 return formatFloatDecimal(value, options.precision, context, Errors, output);
503 return formatFloatDecimal(value, options, context, Errors, output);
514504 } else {
515505 @compileError("Unknown format string: '" ++ fmt ++ "'");
516506 }
......@@ -519,7 +509,7 @@ fn formatFloatValue(
519509pub fn formatText(
520510 bytes: []const u8,
521511 comptime fmt: []const u8,
522 comptime options: FormatOptions,
512 options: FormatOptions,
523513 context: var,
524514 comptime Errors: type,
525515 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -527,11 +517,10 @@ pub fn formatText(
527517 if (fmt.len == 0) {
528518 return output(context, bytes);
529519 } else if (comptime std.mem.eql(u8, fmt, "s")) {
530 if (options.width) |w| return formatBuf(bytes, w, context, Errors, output);
531 return formatBuf(bytes, 0, context, Errors, output);
520 return formatBuf(bytes, options, context, Errors, output);
532521 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
533522 for (bytes) |c| {
534 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
523 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);
535524 }
536525 return;
537526 } else {
......@@ -541,6 +530,7 @@ pub fn formatText(
541530
542531pub fn formatAsciiChar(
543532 c: u8,
533 options: FormatOptions,
544534 context: var,
545535 comptime Errors: type,
546536 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -550,15 +540,16 @@ pub fn formatAsciiChar(
550540
551541pub fn formatBuf(
552542 buf: []const u8,
553 width: usize,
543 options: FormatOptions,
554544 context: var,
555545 comptime Errors: type,
556546 output: fn (@typeOf(context), []const u8) Errors!void,
557547) Errors!void {
558548 try output(context, buf);
559549
550 const width = options.width orelse 0;
560551 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
561 const pad_byte: u8 = ' ';
552 const pad_byte: u8 = options.fill;
562553 while (leftover_padding > 0) : (leftover_padding -= 1) {
563554 try output(context, (*const [1]u8)(&pad_byte)[0..1]);
564555 }
......@@ -569,7 +560,7 @@ pub fn formatBuf(
569560// same type unambiguously.
570561pub fn formatFloatScientific(
571562 value: var,
572 maybe_precision: ?usize,
563 options: FormatOptions,
573564 context: var,
574565 comptime Errors: type,
575566 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -591,7 +582,7 @@ pub fn formatFloatScientific(
591582 if (x == 0.0) {
592583 try output(context, "0");
593584
594 if (maybe_precision) |precision| {
585 if (options.precision) |precision| {
595586 if (precision != 0) {
596587 try output(context, ".");
597588 var i: usize = 0;
......@@ -610,7 +601,7 @@ pub fn formatFloatScientific(
610601 var buffer: [32]u8 = undefined;
611602 var float_decimal = errol.errol3(x, buffer[0..]);
612603
613 if (maybe_precision) |precision| {
604 if (options.precision) |precision| {
614605 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
615606
616607 try output(context, float_decimal.digits[0..1]);
......@@ -650,13 +641,13 @@ pub fn formatFloatScientific(
650641 if (exp > -10 and exp < 10) {
651642 try output(context, "0");
652643 }
653 try formatInt(exp, 10, false, 0, context, Errors, output);
644 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
654645 } else {
655646 try output(context, "-");
656647 if (exp > -10 and exp < 10) {
657648 try output(context, "0");
658649 }
659 try formatInt(-exp, 10, false, 0, context, Errors, output);
650 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
660651 }
661652}
662653
......@@ -664,7 +655,7 @@ pub fn formatFloatScientific(
664655// By default floats are printed at full precision (no rounding).
665656pub fn formatFloatDecimal(
666657 value: var,
667 maybe_precision: ?usize,
658 options: FormatOptions,
668659 context: var,
669660 comptime Errors: type,
670661 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -686,7 +677,7 @@ pub fn formatFloatDecimal(
686677 if (x == 0.0) {
687678 try output(context, "0");
688679
689 if (maybe_precision) |precision| {
680 if (options.precision) |precision| {
690681 if (precision != 0) {
691682 try output(context, ".");
692683 var i: usize = 0;
......@@ -707,7 +698,7 @@ pub fn formatFloatDecimal(
707698 var buffer: [32]u8 = undefined;
708699 var float_decimal = errol.errol3(x, buffer[0..]);
709700
710 if (maybe_precision) |precision| {
701 if (options.precision) |precision| {
711702 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
712703
713704 // exp < 0 means the leading is always 0 as errol result is normalized.
......@@ -809,7 +800,7 @@ pub fn formatFloatDecimal(
809800
810801pub fn formatBytes(
811802 value: var,
812 width: ?usize,
803 options: FormatOptions,
813804 comptime radix: usize,
814805 context: var,
815806 comptime Errors: type,
......@@ -833,7 +824,7 @@ pub fn formatBytes(
833824 else => unreachable,
834825 };
835826
836 try formatFloatDecimal(new_value, width, context, Errors, output);
827 try formatFloatDecimal(new_value, options, context, Errors, output);
837828
838829 if (suffix == ' ') {
839830 return output(context, "B");
......@@ -851,7 +842,7 @@ pub fn formatInt(
851842 value: var,
852843 base: u8,
853844 uppercase: bool,
854 width: usize,
845 options: FormatOptions,
855846 context: var,
856847 comptime Errors: type,
857848 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -863,9 +854,9 @@ pub fn formatInt(
863854 value;
864855
865856 if (@typeOf(int_value).is_signed) {
866 return formatIntSigned(int_value, base, uppercase, width, context, Errors, output);
857 return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);
867858 } else {
868 return formatIntUnsigned(int_value, base, uppercase, width, context, Errors, output);
859 return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);
869860 }
870861}
871862
......@@ -873,26 +864,30 @@ fn formatIntSigned(
873864 value: var,
874865 base: u8,
875866 uppercase: bool,
876 width: usize,
867 options: FormatOptions,
877868 context: var,
878869 comptime Errors: type,
879870 output: fn (@typeOf(context), []const u8) Errors!void,
880871) Errors!void {
872 const new_options = FormatOptions{
873 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
874 .precision = options.precision,
875 .fill = options.fill,
876 };
877
881878 const uint = @IntType(false, @typeOf(value).bit_count);
882879 if (value < 0) {
883880 const minus_sign: u8 = '-';
884881 try output(context, (*const [1]u8)(&minus_sign)[0..]);
885882 const new_value = @intCast(uint, -(value + 1)) + 1;
886 const new_width = if (width == 0) 0 else (width - 1);
887 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
888 } else if (width == 0) {
889 return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
883 return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
884 } else if (options.width == null or options.width.? == 0) {
885 return formatIntUnsigned(@intCast(uint, value), base, uppercase, options, context, Errors, output);
890886 } else {
891887 const plus_sign: u8 = '+';
892888 try output(context, (*const [1]u8)(&plus_sign)[0..]);
893889 const new_value = @intCast(uint, value);
894 const new_width = if (width == 0) 0 else (width - 1);
895 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
890 return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
896891 }
897892}
898893
......@@ -900,7 +895,7 @@ fn formatIntUnsigned(
900895 value: var,
901896 base: u8,
902897 uppercase: bool,
903 width: usize,
898 options: FormatOptions,
904899 context: var,
905900 comptime Errors: type,
906901 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -921,31 +916,32 @@ fn formatIntUnsigned(
921916 }
922917
923918 const digits_buf = buf[index..];
919 const width = options.width orelse 0;
924920 const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
925921
926922 if (padding > index) {
927 const zero_byte: u8 = '0';
923 const zero_byte: u8 = options.fill;
928924 var leftover_padding = padding - index;
929925 while (true) {
930926 try output(context, (*const [1]u8)(&zero_byte)[0..]);
931927 leftover_padding -= 1;
932928 if (leftover_padding == 0) break;
933929 }
934 mem.set(u8, buf[0..index], '0');
930 mem.set(u8, buf[0..index], options.fill);
935931 return output(context, buf);
936932 } else {
937933 const padded_buf = buf[index - padding ..];
938 mem.set(u8, padded_buf[0..padding], '0');
934 mem.set(u8, padded_buf[0..padding], options.fill);
939935 return output(context, padded_buf);
940936 }
941937}
942938
943pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
939pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
944940 var context = FormatIntBuf{
945941 .out_buf = out_buf,
946942 .index = 0,
947943 };
948 formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
944 formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
949945 return context.index;
950946}
951947const FormatIntBuf = struct {
......@@ -1088,23 +1084,23 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
10881084test "bufPrintInt" {
10891085 var buffer: [100]u8 = undefined;
10901086 const buf = buffer[0..];
1091 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
1092 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
1093 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
1094 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
1087 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, FormatOptions{}), "-101111000110000101001110"));
1088 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, FormatOptions{}), "-12345678"));
1089 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, FormatOptions{}), "-bc614e"));
1090 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, FormatOptions{}), "-BC614E"));
10951091
1096 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
1092 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, FormatOptions{}), "12345678"));
10971093
1098 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
1099 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
1100 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
1094 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, FormatOptions{ .width = 6 }), " 666"));
1095 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, FormatOptions{ .width = 6 }), " 1234"));
1096 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, FormatOptions{ .width = 1 }), "1234"));
11011097
1102 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
1103 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
1098 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, FormatOptions{ .width = 3 }), "+42"));
1099 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, FormatOptions{ .width = 3 }), "-42"));
11041100}
11051101
1106fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
1107 return buf[0..formatIntBuf(buf, value, base, uppercase, width)];
1102fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) []u8 {
1103 return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
11081104}
11091105
11101106test "parse u64 digit too big" {
......@@ -1162,7 +1158,8 @@ test "int.specifier" {
11621158}
11631159
11641160test "int.padded" {
1165 try testFmt("u8: '0001'", "u8: '{:4}'", u8(1));
1161 try testFmt("u8: ' 1'", "u8: '{:4}'", u8(1));
1162 try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", u8(1));
11661163}
11671164
11681165test "buffer" {
......@@ -1237,7 +1234,7 @@ test "cstr" {
12371234
12381235test "filesize" {
12391236 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1240 try testFmt("file size: 66.06MB\n", "file size: {B:2}\n", usize(63 * 1024 * 1024));
1237 try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", usize(63 * 1024 * 1024));
12411238}
12421239
12431240test "struct" {
......@@ -1342,7 +1339,7 @@ test "custom" {
13421339 pub fn format(
13431340 self: SelfType,
13441341 comptime fmt: []const u8,
1345 comptime options: FormatOptions,
1342 options: FormatOptions,
13461343 context: var,
13471344 comptime Errors: type,
13481345 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -1548,7 +1545,7 @@ test "formatType max_depth" {
15481545 pub fn format(
15491546 self: SelfType,
15501547 comptime fmt: []const u8,
1551 comptime options: FormatOptions,
1548 options: FormatOptions,
15521549 context: var,
15531550 comptime Errors: type,
15541551 output: fn (@typeOf(context), []const u8) Errors!void,
std/math/big/int.zig+1-1
......@@ -519,7 +519,7 @@ pub const Int = struct {
519519 pub fn format(
520520 self: Int,
521521 comptime fmt: []const u8,
522 comptime options: std.fmt.FormatOptions,
522 options: std.fmt.FormatOptions,
523523 context: var,
524524 comptime FmtError: type,
525525 output: fn (@typeOf(context), []const u8) FmtError!void,
test/compare_output.zig+1-1
......@@ -124,7 +124,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
124124 \\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
125125 \\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126126 \\}
127 , "Hello, world!\n0012 012 a\n");
127 , "Hello, world!\n 12 12 a\n");
128128
129129 cases.addC("number literals",
130130 \\const builtin = @import("builtin");
test/stage1/behavior/enum_with_members.zig+2-2
......@@ -8,8 +8,8 @@ const ET = union(enum) {
88
99 pub fn print(a: *const ET, buf: []u8) anyerror!usize {
1010 return switch (a.*) {
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
11 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
12 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
1313 };
1414 }
1515};