diff --git a/lib/compiler/aro/aro/Diagnostics.zig b/lib/compiler/aro/aro/Diagnostics.zig index 5e92d555cd..dbf6e29af5 100644 --- a/lib/compiler/aro/aro/Diagnostics.zig +++ b/lib/compiler/aro/aro/Diagnostics.zig @@ -461,10 +461,10 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void { try writer.writeByte(@intCast(codepoint)); } else if (codepoint < 0xFFFF) { try writer.writeAll("\\u"); - try writer.printIntOptions(codepoint, 16, .upper, .{ .fill = '0', .width = 4 }); + try writer.printInt(codepoint, 16, .upper, .{ .fill = '0', .width = 4 }); } else { try writer.writeAll("\\U"); - try writer.printIntOptions(codepoint, 16, .upper, .{ .fill = '0', .width = 8 }); + try writer.printInt(codepoint, 16, .upper, .{ .fill = '0', .width = 8 }); } } } diff --git a/lib/compiler/aro/aro/Preprocessor.zig b/lib/compiler/aro/aro/Preprocessor.zig index d71bf4f857..c8695edd6b 100644 --- a/lib/compiler/aro/aro/Preprocessor.zig +++ b/lib/compiler/aro/aro/Preprocessor.zig @@ -3262,7 +3262,7 @@ fn printLinemarker( // containing the same bytes as the input regardless of encoding. else => { try w.writeAll("\\x"); - // TODO try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); + // TODO try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }); try w.print("{x:0>2}", .{byte}); }, }; diff --git a/lib/compiler/aro/aro/Value.zig b/lib/compiler/aro/aro/Value.zig index 670068203e..183c557976 100644 --- a/lib/compiler/aro/aro/Value.zig +++ b/lib/compiler/aro/aro/Value.zig @@ -961,8 +961,7 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w switch (key) { .null => return w.writeAll("nullptr_t"), .int => |repr| switch (repr) { - inline .u64, .i64 => |x| return w.print("{d}", .{x}), - .big_int => |x| return w.print("{fd}", .{x}), + inline .u64, .i64, .big_int => |x| return w.print("{d}", .{x}), }, .float => |repr| switch (repr) { .f16 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000) / 1000}), diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index ba51632c67..870170a02e 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -230,12 +230,7 @@ const ComputeCompareExpected = struct { literal: u64, }, - pub fn format( - value: ComputeCompareExpected, - bw: *Writer, - comptime fmt: []const u8, - ) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, value); + pub fn format(value: ComputeCompareExpected, bw: *Writer) Writer.Error!void { try bw.print("{s} ", .{@tagName(value.op)}); switch (value.value) { .variable => |name| try bw.writeAll(name), @@ -571,7 +566,9 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { null, .of(u64), null, - ) catch |err| return step.fail("unable to read '{f'}': {s}", .{ src_path, @errorName(err) }); + ) catch |err| return step.fail("unable to read '{f}': {s}", .{ + std.fmt.alt(src_path, .formatEscapeChar), @errorName(err), + }); var vars: std.StringHashMap(u64) = .init(gpa); for (check_object.checks.items) |chk| { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 91eed5fee9..91deb9ddc1 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -301,24 +301,13 @@ pub const Os = struct { /// This function is defined to serialize a Zig source code representation of this /// type, that, when parsed, will deserialize into the same data. - pub fn format(ver: WindowsVersion, w: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { - const maybe_name = std.enums.tagName(WindowsVersion, ver); - if (comptime std.mem.eql(u8, f, "s")) { - if (maybe_name) |name| - try w.print(".{s}", .{name}) - else - try w.print(".{d}", .{@intFromEnum(ver)}); - } else if (comptime std.mem.eql(u8, f, "c")) { - if (maybe_name) |name| - try w.print(".{s}", .{name}) - else - try w.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)}); - } else if (f.len == 0) { - if (maybe_name) |name| - try w.print("WindowsVersion.{s}", .{name}) - else - try w.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)}); - } else std.fmt.invalidFmtError(f, ver); + pub fn format(wv: WindowsVersion, w: *std.io.Writer) std.io.Writer.Error!void { + if (std.enums.tagName(WindowsVersion, wv)) |name| { + var vecs: [2][]const u8 = .{ ".", name }; + return w.writeVecAll(&vecs); + } else { + return w.print("@enumFromInt(0x{X:0>8})", .{wv}); + } } }; diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index 611d6581c3..19af1512c2 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -240,6 +240,10 @@ pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri { return uri; } +pub fn format(uri: *const Uri, writer: *std.io.Writer) std.io.Writer.Error!void { + return writeToStream(uri, writer, .all); +} + pub fn writeToStream(uri: *const Uri, writer: *std.io.Writer, flags: Format.Flags) std.io.Writer.Error!void { if (flags.scheme) { try writer.print("{s}:", .{uri.scheme}); @@ -302,6 +306,16 @@ pub const Format = struct { fragment: bool = false, /// When true, include the port part of the URI. Ignored when `port` is null. port: bool = true, + + pub const all: Flags = .{ + .scheme = true, + .authentication = true, + .authority = true, + .path = true, + .query = true, + .fragment = true, + .port = true, + }; }; pub fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void { diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index b5938fcd8f..8588c82139 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -53,16 +53,20 @@ pub const Options = struct { /// - when using a field name, you are required to enclose the field name (an identifier) in square /// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...} /// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below) -/// - *fill* is a single byte which is used to pad the formatted text -/// - *alignment* is one of the three bytes '<', '^', or '>' to make the text left-, center-, or right-aligned, respectively -/// - *width* is the total width of the field in bytes. This is generally only -/// useful for ASCII text, such as numbers. -/// - *precision* specifies how many decimals a formatted number should have +/// - *fill* is a single byte which is used to pad formatted numbers. +/// - *alignment* is one of the three bytes '<', '^', or '>' to make numbers +/// left, center, or right-aligned, respectively. +/// - *width* is the total width of the field in bytes. This only applies to number formatting. +/// - *precision* specifies how many decimals a formatted number should have. /// -/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when -/// all parameters after the separator are omitted. -/// Only exception is the *fill* parameter. If a non-zero *fill* character is required at the same time as *width* is specified, -/// one has to specify *alignment* as well, as otherwise the digit following `:` is interpreted as *width*, not *fill*. +/// Note that most of the parameters are optional and may be omitted. Also you +/// can leave out separators like `:` and `.` when all parameters after the +/// separator are omitted. +/// +/// Only exception is the *fill* parameter. If a non-zero *fill* character is +/// required at the same time as *width* is specified, one has to specify +/// *alignment* as well, as otherwise the digit following `:` is interpreted as +/// *width*, not *fill*. /// /// The *specifier* has several options for types: /// - `x` and `X`: output numeric value in hexadecimal notation, or string in hexadecimal bytes @@ -405,9 +409,9 @@ pub const ArgState = struct { /// Asserts the rendered integer value fits in `buffer`. /// Returns the end index within `buffer`. pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize { - var bw: Writer = .fixed(buffer); - bw.printIntOptions(value, base, case, options) catch unreachable; - return bw.end; + var w: Writer = .fixed(buffer); + w.printInt(value, base, case, options) catch unreachable; + return w.end; } /// Converts values in the range [0, 100) to a base 10 string. @@ -956,35 +960,23 @@ fn expectArrayFmt(expected: []const u8, comptime template: []const u8, comptime } test "array" { - { - const value: [3]u8 = "abc".*; - try expectArrayFmt("array: abc\n", "array: {s}\n", value); - try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {d}\n", value); - try expectArrayFmt("array: 616263\n", "array: {x}\n", value); - try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value); + const value: [3]u8 = "abc".*; + try expectArrayFmt("array: abc\n", "array: {s}\n", value); + try expectArrayFmt("array: 616263\n", "array: {x}\n", value); + try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value); - var buf: [100]u8 = undefined; - try expectFmt( - try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}), - "array: {*}\n", - .{&value}, - ); - } - - { - const value = [2][3]u8{ "abc".*, "def".* }; - - try expectArrayFmt("array: { abc, def }\n", "array: {s}\n", value); - try expectArrayFmt("array: { { 97, 98, 99 }, { 100, 101, 102 } }\n", "array: {d}\n", value); - try expectArrayFmt("array: { 616263, 646566 }\n", "array: {x}\n", value); - } + var buf: [100]u8 = undefined; + try expectFmt( + try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}), + "array: {*}\n", + .{&value}, + ); } test "slice" { { const value: []const u8 = "abc"; try expectFmt("slice: abc\n", "slice: {s}\n", .{value}); - try expectFmt("slice: { 97, 98, 99 }\n", "slice: {d}\n", .{value}); try expectFmt("slice: 616263\n", "slice: {x}\n", .{value}); try expectFmt("slice: { 97, 98, 99 }\n", "slice: {any}\n", .{value}); } @@ -999,17 +991,12 @@ test "slice" { try expectFmt("buf: \x00hello\x00\n", "buf: {s}\n", .{null_term_slice}); } - try expectFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"}); try expectFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"}); { var int_slice = [_]u32{ 1, 4096, 391891, 1111111111 }; - var runtime_zero: usize = 0; - _ = &runtime_zero; - try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {any}", .{int_slice[runtime_zero..]}); - try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {d}", .{int_slice[runtime_zero..]}); - try expectFmt("int: { 1, 1000, 5fad3, 423a35c7 }", "int: {x}", .{int_slice[runtime_zero..]}); - try expectFmt("int: { 00001, 01000, 5fad3, 423a35c7 }", "int: {x:0>5}", .{int_slice[runtime_zero..]}); + const input: []const u32 = &int_slice; + try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {any}", .{input}); } { const S1 = struct { @@ -1054,11 +1041,6 @@ test "cstr" { "cstr: {s}\n", .{@as([*c]const u8, @ptrCast("Test C"))}, ); - try expectFmt( - "cstr: Test C\n", - "cstr: {s:10}\n", - .{@as([*c]const u8, @ptrCast("Test C"))}, - ); } test "struct" { @@ -1428,16 +1410,12 @@ test "enum-literal" { test "padding" { try expectFmt("Simple", "{s}", .{"Simple"}); - try expectFmt(" true", "{:10}", .{true}); - try expectFmt(" true", "{:>10}", .{true}); - try expectFmt("======true", "{:=>10}", .{true}); - try expectFmt("true======", "{:=<10}", .{true}); - try expectFmt(" true ", "{:^10}", .{true}); - try expectFmt("===true===", "{:=^10}", .{true}); - try expectFmt(" Minimum width", "{s:18} width", .{"Minimum"}); - try expectFmt("==================Filled", "{s:=>24}", .{"Filled"}); - try expectFmt(" Centered ", "{s:^24}", .{"Centered"}); - try expectFmt("-", "{s:-^1}", .{""}); + try expectFmt(" 1234", "{:10}", .{1234}); + try expectFmt(" 1234", "{:>10}", .{1234}); + try expectFmt("======1234", "{:=>10}", .{1234}); + try expectFmt("1234======", "{:=<10}", .{1234}); + try expectFmt(" 1234 ", "{:^10}", .{1234}); + try expectFmt("===1234===", "{:=^10}", .{1234}); try expectFmt("====a", "{c:=>5}", .{'a'}); try expectFmt("==a==", "{c:=^5}", .{'a'}); try expectFmt("a====", "{c:=<5}", .{'a'}); @@ -1485,17 +1463,17 @@ test "named arguments" { test "runtime width specifier" { const width: usize = 9; - try expectFmt("~~hello~~", "{s:~^[1]}", .{ "hello", width }); - try expectFmt("~~hello~~", "{s:~^[width]}", .{ .string = "hello", .width = width }); - try expectFmt(" hello", "{s:[1]}", .{ "hello", width }); - try expectFmt("42 hello", "{d} {s:[2]}", .{ 42, "hello", width }); + try expectFmt("~~12345~~", "{d:~^[1]}", .{ 12345, width }); + try expectFmt("~~12345~~", "{d:~^[width]}", .{ .string = 12345, .width = width }); + try expectFmt(" 12345", "{d:[1]}", .{ 12345, width }); + try expectFmt("42 12345", "{d} {d:[2]}", .{ 42, 12345, width }); } test "runtime precision specifier" { const number: f32 = 3.1415; const precision: usize = 2; - try expectFmt("3.14e0", "{:1.[1]}", .{ number, precision }); - try expectFmt("3.14e0", "{:1.[precision]}", .{ .number = number, .precision = precision }); + try expectFmt("3.14e0", "{e:1.[1]}", .{ number, precision }); + try expectFmt("3.14e0", "{e:1.[precision]}", .{ .number = number, .precision = precision }); } test "recursive format function" { diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig index 29376db2e5..a5cb0aded1 100644 --- a/lib/std/io/Writer.zig +++ b/lib/std/io/Writer.zig @@ -777,15 +777,15 @@ pub fn printAddress(w: *Writer, value: anytype) Error!void { .pointer => |info| { try w.writeAll(@typeName(info.child) ++ "@"); if (info.size == .slice) - try w.printIntOptions(@intFromPtr(value.ptr), 16, .lower, .{}) + try w.printInt(@intFromPtr(value.ptr), 16, .lower, .{}) else - try w.printIntOptions(@intFromPtr(value), 16, .lower, .{}); + try w.printInt(@intFromPtr(value), 16, .lower, .{}); return; }, .optional => |info| { if (@typeInfo(info.child) == .pointer) { try w.writeAll(@typeName(info.child) ++ "@"); - try w.printIntOptions(@intFromPtr(value), 16, .lower, .{}); + try w.printInt(@intFromPtr(value), 16, .lower, .{}); return; } }, @@ -804,11 +804,147 @@ pub fn printValue( ) Error!void { const T = @TypeOf(value); - if (fmt.len == 1) switch (fmt[0]) { - '*' => return w.printAddress(value), - 'f' => return value.format(w), + switch (fmt.len) { + 1 => switch (fmt[0]) { + '*' => return w.printAddress(value), + 'f' => return value.format(w), + 'd' => switch (@typeInfo(T)) { + .float, .comptime_float => return printFloat(w, value, .decimal, options), + .int, .comptime_int => return printInt(w, value, 10, .lower, options), + .@"struct" => return value.formatInteger(w, 10, .lower), + .@"enum" => return printInt(w, @intFromEnum(value), 10, .lower, options), + .vector => return printVector(w, fmt, options, value, max_depth), + else => invalidFmtError(fmt, value), + }, + 'c' => return w.printAsciiChar(value, options), + 'u' => return w.printUnicodeCodepoint(value), + 'b' => switch (@typeInfo(T)) { + .int, .comptime_int => return printInt(w, value, 2, .lower, options), + .@"enum" => return printInt(w, @intFromEnum(value), 2, .lower, options), + .@"struct" => return value.formatInteger(w, 2, .lower), + .vector => return printVector(w, fmt, options, value, max_depth), + else => invalidFmtError(fmt, value), + }, + 'o' => switch (@typeInfo(T)) { + .int, .comptime_int => return printInt(w, value, 8, .lower, options), + .@"enum" => return printInt(w, @intFromEnum(value), 8, .lower, options), + .@"struct" => return value.formatInteger(w, 8, .lower), + .vector => return printVector(w, fmt, options, value, max_depth), + else => invalidFmtError(fmt, value), + }, + 'x' => switch (@typeInfo(T)) { + .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options), + .int, .comptime_int => return printInt(w, value, 16, .lower, options), + .@"enum" => return printInt(w, @intFromEnum(value), 16, .lower, options), + .@"struct" => return value.formatInteger(w, 16, .lower), + .pointer => |info| switch (info.size) { + .one, .slice => { + const slice: []const u8 = value; + return printHex(w, slice, .lower); + }, + .many, .c => { + const slice: [:0]const u8 = std.mem.span(value); + return printHex(w, slice, .lower); + }, + }, + .array => { + const slice: []const u8 = &value; + return printHex(w, slice, .lower); + }, + .vector => return printVector(w, fmt, options, value, max_depth), + else => invalidFmtError(fmt, value), + }, + 'X' => switch (@typeInfo(T)) { + .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options), + .int, .comptime_int => return printInt(w, value, 16, .upper, options), + .@"enum" => return printInt(w, @intFromEnum(value), 16, .upper, options), + .@"struct" => return value.formatInteger(w, 16, .upper), + .pointer => |info| switch (info.size) { + .one, .slice => { + const slice: []const u8 = value; + return printHex(w, slice, .upper); + }, + .many, .c => { + const slice: [:0]const u8 = std.mem.span(value); + return printHex(w, slice, .upper); + }, + }, + .array => { + const slice: []const u8 = &value; + return printHex(w, slice, .upper); + }, + .vector => return printVector(w, fmt, options, value, max_depth), + else => invalidFmtError(fmt, value), + }, + 's' => switch (@typeInfo(T)) { + .pointer => |info| switch (info.size) { + .one, .slice => { + const slice: []const u8 = value; + return w.writeAll(slice); + }, + .many, .c => { + const slice: [:0]const u8 = std.mem.span(value); + return w.writeAll(slice); + }, + }, + .array => { + const slice: []const u8 = &value; + return w.writeAll(slice); + }, + else => invalidFmtError(fmt, value), + }, + 'B' => switch (@typeInfo(T)) { + .int, .comptime_int => return w.printByteSize(value, .decimal, options), + .@"struct" => return value.formatByteSize(w, .decimal), + else => invalidFmtError(fmt, value), + }, + 'D' => switch (@typeInfo(T)) { + .int, .comptime_int => return w.printDuration(value, options), + .@"struct" => return value.formatDuration(w), + else => invalidFmtError(fmt, value), + }, + 'e' => switch (@typeInfo(T)) { + .float, .comptime_float => return printFloat(w, value, .scientific, options), + .@"struct" => return value.formatFloat(w, .scientific), + else => invalidFmtError(fmt, value), + }, + 't' => switch (@typeInfo(T)) { + .error_set => return w.writeAll(@errorName(value)), + .@"enum", .@"union" => return w.writeAll(@tagName(value)), + else => invalidFmtError(fmt, value), + }, + else => {}, + }, + 2 => switch (fmt[0]) { + 'B' => switch (fmt[1]) { + 'i' => switch (@typeInfo(T)) { + .int, .comptime_int => return w.printByteSize(value, .binary, options), + .@"struct" => return value.formatByteSize(w, .binary), + else => invalidFmtError(fmt, value), + }, + else => {}, + }, + else => {}, + }, + 3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') switch (@typeInfo(T)) { + .pointer => |info| switch (info.size) { + .one, .slice => { + const slice: []const u8 = value; + return w.printBase64(slice); + }, + .many, .c => { + const slice: [:0]const u8 = std.mem.span(value); + return w.printBase64(slice); + }, + }, + .array => { + const slice: []const u8 = &value; + return w.printBase64(slice); + }, + else => invalidFmtError(fmt, value), + }, else => {}, - }; + } const is_any = comptime std.mem.eql(u8, fmt, ANY); if (!is_any and std.meta.hasMethod(T, "format") and fmt.len == 0) { @@ -817,15 +953,21 @@ pub fn printValue( } switch (@typeInfo(T)) { - .float, .comptime_float => return w.printFloat(if (is_any) "d" else fmt, options, value), - .int, .comptime_int => return w.printInt(if (is_any) "d" else fmt, options, value), + .float, .comptime_float => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return printFloat(w, value, .decimal, options); + }, + .int, .comptime_int => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return printInt(w, value, 10, .lower, options); + }, .bool => { if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return w.alignBufferOptions(if (value) "true" else "false", options); + return w.writeAll(if (value) "true" else "false"); }, .void => { if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return w.alignBufferOptions("void", options); + return w.writeAll("void"); }, .optional => { const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '?') @@ -854,40 +996,18 @@ pub fn printValue( } }, .error_set => { - if (fmt.len == 1 and fmt[0] == 't') return w.writeAll(@errorName(value)); if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - try printErrorSet(w, value); + return printErrorSet(w, value); }, - .@"enum" => { - if (fmt.len == 1 and fmt[0] == 't') { - try w.writeAll(@tagName(value)); - return; + .@"enum" => |info| { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + if (info.is_exhaustive) { + return printEnumExhaustive(w, value); + } else { + return printEnumNonexhaustive(w, value); } - if (!is_any) { - if (fmt.len != 0) return printValue(w, fmt, options, @intFromEnum(value), max_depth); - return printValue(w, ANY, options, value, max_depth); - } - const enum_info = @typeInfo(T).@"enum"; - if (enum_info.is_exhaustive) { - var vecs: [2][]const u8 = .{ ".", @tagName(value) }; - try w.writeVecAll(&vecs); - return; - } - if (std.enums.tagName(T, value)) |tag_name| { - var vecs: [2][]const u8 = .{ ".", tag_name }; - try w.writeVecAll(&vecs); - return; - } - try w.writeAll("@enumFromInt("); - try w.printValue(ANY, options, @intFromEnum(value), max_depth); - try w.writeByte(')'); - return; }, .@"union" => |info| { - if (fmt.len == 1 and fmt[0] == 't') { - try w.writeAll(@tagName(value)); - return; - } if (!is_any) { if (fmt.len != 0) invalidFmtError(fmt, value); return printValue(w, ANY, options, value, max_depth); @@ -971,38 +1091,18 @@ pub fn printValue( else => { var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" }; try w.writeVecAll(&buffers); - try w.printIntOptions(@intFromPtr(value), 16, .lower, options); + try w.printInt(@intFromPtr(value), 16, .lower, options); return; }, }, .many, .c => { - if (ptr_info.sentinel() != null) - return w.printValue(fmt, options, std.mem.span(value), max_depth); - if (fmt.len == 1 and fmt[0] == 's' and ptr_info.child == u8) - return w.alignBufferOptions(std.mem.span(value), options); - if (!is_any and fmt.len == 0) - @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); - if (!is_any and fmt.len != 0) - invalidFmtError(fmt, value); + if (!is_any) @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); try w.printAddress(value); }, .slice => { - if (!is_any and fmt.len == 0) + if (!is_any) @compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})"); - if (max_depth == 0) - return w.writeAll("{ ... }"); - if (ptr_info.child == u8) switch (fmt.len) { - 1 => switch (fmt[0]) { - 's' => return w.alignBufferOptions(value, options), - 'x' => return w.printHex(value, .lower), - 'X' => return w.printHex(value, .upper), - else => {}, - }, - 3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') { - return w.printBase64(value); - }, - else => {}, - }; + if (max_depth == 0) return w.writeAll("{ ... }"); try w.writeAll("{ "); for (value, 0..) |elem, i| { try w.printValue(fmt, options, elem, max_depth - 1); @@ -1013,21 +1113,9 @@ pub fn printValue( try w.writeAll(" }"); }, }, - .array => |info| { - if (fmt.len == 0) - @compileError("cannot format array without a specifier (i.e. {s} or {any})"); - if (max_depth == 0) { - return w.writeAll("{ ... }"); - } - if (info.child == u8) { - if (fmt[0] == 's') { - return w.alignBufferOptions(&value, options); - } else if (fmt[0] == 'x') { - return w.printHex(&value, .lower); - } else if (fmt[0] == 'X') { - return w.printHex(&value, .upper); - } - } + .array => { + if (!is_any) @compileError("cannot format array without a specifier (i.e. {s} or {any})"); + if (max_depth == 0) return w.writeAll("{ ... }"); try w.writeAll("{ "); for (value, 0..) |elem, i| { try w.printValue(fmt, options, elem, max_depth - 1); @@ -1037,33 +1125,23 @@ pub fn printValue( } try w.writeAll(" }"); }, - .vector => |info| { - if (max_depth == 0) { - return w.writeAll("{ ... }"); - } - try w.writeAll("{ "); - var i: usize = 0; - while (i < info.len) : (i += 1) { - try w.printValue(fmt, options, value[i], max_depth - 1); - if (i < info.len - 1) { - try w.writeAll(", "); - } - } - try w.writeAll(" }"); + .vector => { + if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); + return printVector(w, fmt, options, value, max_depth); }, .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), .type => { if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return w.alignBufferOptions(@typeName(value), options); + return w.writeAll(@typeName(value)); }, .enum_literal => { if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - const buffer = [_]u8{'.'} ++ @tagName(value); - return w.alignBufferOptions(buffer, options); + var vecs: [2][]const u8 = .{ ".", @tagName(value) }; + return w.writeVecAll(&vecs); }, .null => { if (!is_any and fmt.len != 0) invalidFmtError(fmt, value); - return w.alignBufferOptions("null", options); + return w.writeAll("null"); }, else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"), } @@ -1074,75 +1152,68 @@ fn printErrorSet(w: *Writer, error_set: anyerror) Error!void { try w.writeVecAll(&vecs); } -pub fn printInt( +fn printEnumExhaustive(w: *Writer, value: anytype) Error!void { + var vecs: [2][]const u8 = .{ ".", @tagName(value) }; + try w.writeVecAll(&vecs); +} + +fn printEnumNonexhaustive(w: *Writer, value: anytype) Error!void { + if (std.enums.tagName(@TypeOf(value), value)) |tag_name| { + var vecs: [2][]const u8 = .{ ".", tag_name }; + try w.writeVecAll(&vecs); + return; + } + try w.writeAll("@enumFromInt("); + try w.printInt(@intFromEnum(value), 10, .lower, .{}); + try w.writeByte(')'); +} + +pub fn printVector( w: *Writer, comptime fmt: []const u8, options: std.fmt.Options, value: anytype, + max_depth: usize, ) Error!void { - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = std.math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - switch (fmt.len) { - 0 => return w.printIntOptions(int_value, 10, .lower, options), - 1 => switch (fmt[0]) { - 'd' => return w.printIntOptions(int_value, 10, .lower, options), - 'c' => { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) { - return w.printAsciiChar(@as(u8, int_value), options); - } else { - @compileError("cannot print integer that is larger than 8 bits as an ASCII character"); - } - }, - 'u' => { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) { - return w.printUnicodeCodepoint(@as(u21, int_value), options); - } else { - @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence"); - } - }, - 'b' => return w.printIntOptions(int_value, 2, .lower, options), - 'x' => return w.printIntOptions(int_value, 16, .lower, options), - 'X' => return w.printIntOptions(int_value, 16, .upper, options), - 'o' => return w.printIntOptions(int_value, 8, .lower, options), - 'B' => return w.printByteSize(int_value, .decimal, options), - 'D' => return w.printDuration(int_value, options), - else => invalidFmtError(fmt, value), - }, - 2 => { - if (fmt[0] == 'B' and fmt[1] == 'i') { - return w.printByteSize(int_value, .binary, options); - } else { - invalidFmtError(fmt, value); - } - }, - else => invalidFmtError(fmt, value), + const len = @typeInfo(@TypeOf(value)).vector.len; + if (max_depth == 0) return w.writeAll("{ ... }"); + try w.writeAll("{ "); + inline for (0..len) |i| { + try w.printValue(fmt, options, value[i], max_depth - 1); + if (i < len - 1) try w.writeAll(", "); } - comptime unreachable; + try w.writeAll(" }"); } -pub fn printAsciiChar(w: *Writer, c: u8, options: std.fmt.Options) Error!void { - return w.alignBufferOptions(@as(*const [1]u8, &c), options); -} - -pub fn printAscii(w: *Writer, bytes: []const u8, options: std.fmt.Options) Error!void { - return w.alignBufferOptions(bytes, options); -} - -pub fn printUnicodeCodepoint(w: *Writer, c: u21, options: std.fmt.Options) Error!void { - var buf: [4]u8 = undefined; - const len = std.unicode.utf8Encode(c, &buf) catch |err| switch (err) { - error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => l: { - buf[0..3].* = std.unicode.replacement_character_utf8; - break :l 3; +// A wrapper around `printIntAny` to avoid the generic explosion of this +// function by funneling smaller integer types through `isize` and `usize`. +pub inline fn printInt( + w: *Writer, + value: anytype, + base: u8, + case: std.fmt.Case, + options: std.fmt.Options, +) Error!void { + switch (@TypeOf(value)) { + isize, usize => {}, + comptime_int => { + if (comptime std.math.cast(usize, value)) |x| return printIntAny(w, x, base, case, options); + if (comptime std.math.cast(isize, value)) |x| return printIntAny(w, x, base, case, options); + const Int = std.math.IntFittingRange(value, value); + return printIntAny(w, @as(Int, value), base, case, options); }, - }; - return w.alignBufferOptions(buf[0..len], options); + else => switch (@typeInfo(@TypeOf(value)).int.signedness) { + .signed => if (std.math.cast(isize, value)) |x| return printIntAny(w, x, base, case, options), + .unsigned => if (std.math.cast(usize, value)) |x| return printIntAny(w, x, base, case, options), + }, + } + return printIntAny(w, value, base, case, options); } -pub fn printIntOptions( +/// In general, prefer `printInt` to avoid generic explosion. However this +/// function may be used when optimal codegen for a particular integer type is +/// desired. +pub fn printIntAny( w: *Writer, value: anytype, base: u8, @@ -1150,20 +1221,14 @@ pub fn printIntOptions( options: std.fmt.Options, ) Error!void { assert(base >= 2); - - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = std.math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - const value_info = @typeInfo(@TypeOf(int_value)).int; + const value_info = @typeInfo(@TypeOf(value)).int; // The type must have the same size as `base` or be wider in order for the // division to work const min_int_bits = comptime @max(value_info.bits, 8); const MinInt = std.meta.Int(.unsigned, min_int_bits); - const abs_value = @abs(int_value); + const abs_value = @abs(value); // The worst case in terms of space needed is base 2, plus 1 for the sign var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined; @@ -1210,38 +1275,49 @@ pub fn printIntOptions( return w.alignBufferOptions(buf[index..], options); } -pub fn printFloat( - w: *Writer, - comptime fmt: []const u8, - options: std.fmt.Options, - value: anytype, -) Error!void { - var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined; - - if (fmt.len > 1) invalidFmtError(fmt, value); - switch (if (fmt.len == 0) 'e' else fmt[0]) { - 'e' => { - const s = std.fmt.float.render(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return w.alignBufferOptions(s, options); - }, - 'd' => { - const s = std.fmt.float.render(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return w.alignBufferOptions(s, options); - }, - 'x' => { - var sub_bw: Writer = .fixed(&buf); - sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable; - return w.alignBufferOptions(sub_bw.buffered(), options); - }, - else => invalidFmtError(fmt, value), - } +pub fn printAsciiChar(w: *Writer, c: u8, options: std.fmt.Options) Error!void { + return w.alignBufferOptions(@as(*const [1]u8, &c), options); } -pub fn printFloatHexadecimal(w: *Writer, value: anytype, opt_precision: ?usize) Error!void { +pub fn printAscii(w: *Writer, bytes: []const u8, options: std.fmt.Options) Error!void { + return w.alignBufferOptions(bytes, options); +} + +pub fn printUnicodeCodepoint(w: *Writer, c: u21) Error!void { + var buf: [4]u8 = undefined; + const len = std.unicode.utf8Encode(c, &buf) catch |err| switch (err) { + error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => l: { + buf[0..3].* = std.unicode.replacement_character_utf8; + break :l 3; + }, + }; + return w.writeAll(buf[0..len]); +} + +pub fn printFloat( + w: *Writer, + value: anytype, + mode: std.fmt.float.Mode, + options: std.fmt.Options, +) Error!void { + var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined; + const s = std.fmt.float.render(&buf, value, .{ + .mode = mode, + .precision = options.precision, + }) catch |err| switch (err) { + error.BufferTooSmall => "(float)", + }; + return w.alignBufferOptions(s, options); +} + +pub fn printFloatHexOptions(w: *Writer, value: anytype, case: std.fmt.Case, options: std.fmt.Options) Error!void { + var buf: [50]u8 = undefined; // for aligning + var sub_writer: Writer = .fixed(&buf); + printFloatHex(&sub_writer, value, case, options.precision) catch unreachable; // buf is large enough + return w.alignBufferOptions(sub_writer.buffered(), options); +} + +pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void { if (std.math.signbit(value)) try w.writeByte('-'); if (std.math.isNan(value)) return w.writeAll("nan"); if (std.math.isInf(value)) return w.writeAll("inf"); @@ -1320,7 +1396,7 @@ pub fn printFloatHexadecimal(w: *Writer, value: anytype, opt_precision: ?usize) // +1 for the decimal part. var buf: [1 + mantissa_digits]u8 = undefined; - assert(std.fmt.printInt(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len); + assert(std.fmt.printInt(&buf, mantissa, 16, case, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len); try w.writeAll("0x"); try w.writeByte(buf[0]); @@ -1337,7 +1413,7 @@ pub fn printFloatHexadecimal(w: *Writer, value: anytype, opt_precision: ?usize) try w.splatByteAll('0', precision - trimmed.len); }; try w.writeAll("p"); - try w.printIntOptions(exponent - exponent_bias, 10, .lower, .{}); + try w.printInt(exponent - exponent_bias, 10, case, .{}); } pub const ByteSizeUnits = enum { @@ -1433,7 +1509,7 @@ pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void { }) |unit| { if (ns_remaining >= unit.ns) { const units = ns_remaining / unit.ns; - try w.printIntOptions(units, 10, .lower, .{}); + try w.printInt(units, 10, .lower, .{}); try w.writeByte(unit.sep); ns_remaining -= units * unit.ns; if (ns_remaining == 0) return; @@ -1447,13 +1523,13 @@ pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void { }) |unit| { const kunits = ns_remaining * 1000 / unit.ns; if (kunits >= 1000) { - try w.printIntOptions(kunits / 1000, 10, .lower, .{}); + try w.printInt(kunits / 1000, 10, .lower, .{}); const frac = kunits % 1000; if (frac > 0) { // Write up to 3 decimal places var decimal_buf = [_]u8{ '.', 0, 0, 0 }; var inner: Writer = .fixed(decimal_buf[1..]); - inner.printIntOptions(frac, 10, .lower, .{ .fill = '0', .width = 3 }) catch unreachable; + inner.printInt(frac, 10, .lower, .{ .fill = '0', .width = 3 }) catch unreachable; var end: usize = 4; while (end > 1) : (end -= 1) { if (decimal_buf[end - 1] != '0') break; @@ -1464,7 +1540,7 @@ pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void { } } - try w.printIntOptions(ns_remaining, 10, .lower, .{}); + try w.printInt(ns_remaining, 10, .lower, .{}); try w.writeAll("ns"); } @@ -1474,12 +1550,18 @@ pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void { pub fn printDuration(w: *Writer, nanoseconds: anytype, options: std.fmt.Options) Error!void { // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 var buf: [24]u8 = undefined; - var sub_bw: Writer = .fixed(&buf); - switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) { - .signed => sub_bw.printDurationSigned(nanoseconds) catch unreachable, - .unsigned => sub_bw.printDurationUnsigned(nanoseconds) catch unreachable, + var sub_writer: Writer = .fixed(&buf); + if (@TypeOf(nanoseconds) == comptime_int) { + if (nanoseconds >= 0) { + sub_writer.printDurationUnsigned(nanoseconds) catch unreachable; + } else { + sub_writer.printDurationSigned(nanoseconds) catch unreachable; + } + } else switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) { + .signed => sub_writer.printDurationSigned(nanoseconds) catch unreachable, + .unsigned => sub_writer.printDurationUnsigned(nanoseconds) catch unreachable, } - return w.alignBufferOptions(sub_bw.buffered(), options); + return w.alignBufferOptions(sub_writer.buffered(), options); } pub fn printHex(w: *Writer, bytes: []const u8, case: std.fmt.Case) Error!void { @@ -1749,7 +1831,7 @@ fn testDurationCaseSigned(expected: []const u8, input: i64) !void { try testing.expectEqualStrings(expected, w.buffered()); } -test printIntOptions { +test printInt { try testPrintIntCase("-1", @as(i1, -1), 10, .lower, .{}); try testPrintIntCase("-101111000110000101001110", @as(i32, -12345678), 2, .lower, .{}); @@ -1765,27 +1847,22 @@ test printIntOptions { try testPrintIntCase("+42", @as(i32, 42), 10, .lower, .{ .width = 3 }); try testPrintIntCase("-42", @as(i32, -42), 10, .lower, .{ .width = 3 }); -} -test "printInt with comptime_int" { - var buf: [20]u8 = undefined; - var w: Writer = .fixed(&buf); - try w.printInt("", .{}, @as(comptime_int, 123456789123456789)); - try std.testing.expectEqualStrings("123456789123456789", w.buffered()); + try testPrintIntCase("123456789123456789", @as(comptime_int, 123456789123456789), 10, .lower, .{}); } test "printFloat with comptime_float" { var buf: [20]u8 = undefined; var w: Writer = .fixed(&buf); - try w.printFloat("", .{}, @as(comptime_float, 1.0)); + try w.printFloat(@as(comptime_float, 1.0), .scientific, .{}); try std.testing.expectEqualStrings(w.buffered(), "1e0"); - try std.testing.expectFmt("1e0", "{}", .{1.0}); + try std.testing.expectFmt("1", "{}", .{1.0}); } fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { var buffer: [100]u8 = undefined; var w: Writer = .fixed(&buffer); - try w.printIntOptions(value, base, case, options); + try w.printInt(value, base, case, options); try testing.expectEqualStrings(expected, w.buffered()); } diff --git a/lib/std/json/dynamic_test.zig b/lib/std/json/dynamic_test.zig index 45cdc0d0c7..1362e3cfad 100644 --- a/lib/std/json/dynamic_test.zig +++ b/lib/std/json/dynamic_test.zig @@ -254,7 +254,7 @@ test "Value.jsonStringify" { \\ true, \\ 42, \\ 43, - \\ 4.2e1, + \\ 42, \\ "weeee", \\ [ \\ 1, @@ -266,7 +266,7 @@ test "Value.jsonStringify" { \\ } \\] ; - try testing.expectEqualSlices(u8, expected, fbs.getWritten()); + try testing.expectEqualStrings(expected, fbs.getWritten()); } test "parseFromValue(std.json.Value,...)" { diff --git a/lib/std/json/stringify.zig b/lib/std/json/stringify.zig index 0b575fc587..b3c208756c 100644 --- a/lib/std/json/stringify.zig +++ b/lib/std/json/stringify.zig @@ -469,7 +469,6 @@ pub fn WriteStream( /// * When option `emit_nonportable_numbers_as_strings` is true, if the value is outside the range `+-1<<53` (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number. /// * Zig floats -> JSON number or string. /// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number. - /// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00". /// * Zig `[]const u8`, `[]u8`, `*[N]u8`, `@Vector(N, u8)`, and similar -> JSON string. /// * See `StringifyOptions.emit_strings_as_arrays`. /// * If the content is not valid UTF-8, rendered as an array of numbers instead. diff --git a/lib/std/json/stringify_test.zig b/lib/std/json/stringify_test.zig index 122616b596..22dd504285 100644 --- a/lib/std/json/stringify_test.zig +++ b/lib/std/json/stringify_test.zig @@ -74,16 +74,16 @@ fn testBasicWriteStream(w: anytype, slice_stream: anytype) !void { \\{ \\ "object": { \\ "one": 1, - \\ "two": 2e0 + \\ "two": 2 \\ }, \\ "string": "This is a string", \\ "array": [ \\ "Another string", \\ 1, - \\ 3.5e0 + \\ 3.5 \\ ], \\ "int": 10, - \\ "float": 3.5e0 + \\ "float": 3.5 \\} ; try std.testing.expectEqualStrings(expected, result); @@ -123,12 +123,12 @@ test "stringify basic types" { try testStringify("null", @as(?u8, null), .{}); try testStringify("null", @as(?*u32, null), .{}); try testStringify("42", 42, .{}); - try testStringify("4.2e1", 42.0, .{}); + try testStringify("42", 42.0, .{}); try testStringify("42", @as(u8, 42), .{}); try testStringify("42", @as(u128, 42), .{}); try testStringify("9999999999999999", 9999999999999999, .{}); - try testStringify("4.2e1", @as(f32, 42), .{}); - try testStringify("4.2e1", @as(f64, 42), .{}); + try testStringify("42", @as(f32, 42), .{}); + try testStringify("42", @as(f64, 42), .{}); try testStringify("\"ItBroke\"", @as(anyerror, error.ItBroke), .{}); try testStringify("\"ItBroke\"", error.ItBroke, .{}); } diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 000b578dc0..c657aeeed3 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -2028,6 +2028,14 @@ pub const Mutable = struct { pub fn normalize(r: *Mutable, length: usize) void { r.len = llnormalize(r.limbs[0..length]); } + + pub fn format(self: Mutable, w: *std.io.Writer) std.io.Writer.Error!void { + return formatInteger(self, w, 10, .lower); + } + + pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void { + return self.toConst().formatInteger(w, base, case); + } }; /// A arbitrary-precision big integer, with a fixed set of immutable limbs. @@ -2321,7 +2329,7 @@ pub const Const = struct { /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn print(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void { + pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void { const available_len = 64; if (self.limbs.len > available_len) return w.writeAll("(BigInt)"); @@ -2337,20 +2345,6 @@ pub const Const = struct { return w.writeAll(buf[0..len]); } - const Format = struct { - int: Const, - base: u8, - case: std.fmt.Case, - - pub fn default(f: Format, w: *std.io.Writer) std.io.Writer.Error!void { - return print(f.int, w, f.base, f.case); - } - }; - - pub fn fmt(self: Const, base: u8, case: std.fmt.Case) std.fmt.Formatter(Format, Format.default) { - return .{ .data = .{ .int = self, .base = base, .case = case } }; - } - /// Converts self to a string in the requested base. /// Caller owns returned memory. /// Asserts that `base` is in the range [2, 36]. @@ -2918,16 +2912,16 @@ pub const Managed = struct { } /// To allow `std.fmt.format` to work with `Managed`. - pub fn format(self: Managed, w: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { - return self.toConst().format(w, f); + pub fn format(self: Managed, w: *std.io.Writer) std.io.Writer.Error!void { + return formatInteger(self, w, 10, .lower); } /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`, /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn fmt(self: Managed, base: u8, case: std.fmt.Case) std.fmt.Formatter(Const.Format, Const.Format.default) { - return .{ .data = .{ .int = self.toConst(), .base = base, .case = case } }; + pub fn formatInteger(self: Managed, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void { + return self.toConst().formatInteger(w, base, case); } /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| == diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 58f5a01a05..f09797352c 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -3813,8 +3813,8 @@ test "(BigInt) positive" { try a.pow(&a, 64 * @sizeOf(Limb) * 8); try b.sub(&a, &c); - try testing.expectFmt("(BigInt)", "{f}", .{a.fmt(10, .lower)}); - try testing.expectFmt("1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085903001302413467189726673216491511131602920781738033436090243804708340403154190335", "{f}", .{b.fmt(10, .lower)}); + try testing.expectFmt("(BigInt)", "{d}", .{a}); + try testing.expectFmt("1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085903001302413467189726673216491511131602920781738033436090243804708340403154190335", "{d}", .{b}); } test "(BigInt) negative" { @@ -3832,10 +3832,10 @@ test "(BigInt) negative" { a.negate(); try b.add(&a, &c); - const a_fmt = try std.fmt.allocPrint(testing.allocator, "{f}", .{a.fmt(10, .lower)}); + const a_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{a}); defer testing.allocator.free(a_fmt); - const b_fmt = try std.fmt.allocPrint(testing.allocator, "{f}", .{b.fmt(10, .lower)}); + const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b}); defer testing.allocator.free(b_fmt); try testing.expect(mem.eql(u8, a_fmt, "(BigInt)")); diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 5d7f16a2a0..be3c982d09 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -475,7 +475,7 @@ pub fn stringEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!vo ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte), else => { try w.writeAll("\\x"); - try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); + try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }); }, }; } @@ -492,7 +492,7 @@ pub fn charEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!void ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte), else => { try w.writeAll("\\x"); - try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); + try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }); }, }; } diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 4691b96933..b3e0311cdd 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -246,7 +246,7 @@ pub const Type = enum(u32) { _, pub const ptr_amdgpu_constant = - @field(Type, std.fmt.comptimePrint("ptr{f }", .{AddrSpace.amdgpu.constant})); + @field(Type, std.fmt.comptimePrint("ptr{f}", .{AddrSpace.amdgpu.constant.fmt(" ")})); pub const Tag = enum(u4) { simple, @@ -779,7 +779,7 @@ pub const Type = enum(u32) { } }, .integer => try w.print("i{d}", .{item.data}), - .pointer => try w.print("ptr{f }", .{@as(AddrSpace, @enumFromInt(item.data))}), + .pointer => try w.print("ptr{f}", .{@as(AddrSpace, @enumFromInt(item.data)).fmt(" ")}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); @@ -1242,7 +1242,7 @@ pub const Attribute = union(Kind) { .sret, .elementtype, => |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }), - .@"align" => |alignment| try w.print("{f }", .{alignment}), + .@"align" => |alignment| try w.print("{f}", .{alignment.fmt(" ")}), .dereferenceable, .dereferenceable_or_null, => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }), @@ -1853,10 +1853,31 @@ pub const ThreadLocal = enum(u3) { initialexec = 3, localexec = 4, - pub fn format(self: ThreadLocal, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - if (self == .default) return; - try w.print("{s}thread_local", .{prefix}); - if (self != .generaldynamic) try w.print("({s})", .{@tagName(self)}); + pub fn format(tl: ThreadLocal, w: *Writer) Writer.Error!void { + return Prefixed.format(.{ .thread_local = tl, .prefix = "" }, w); + } + + pub const Prefixed = struct { + thread_local: ThreadLocal, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + switch (p.thread_local) { + .default => return, + .generaldynamic => { + var vecs: [2][]const u8 = .{ p.prefix, "thread_local" }; + return w.writeVecAll(&vecs); + }, + else => { + var vecs: [4][]const u8 = .{ p.prefix, "thread_local(", @tagName(p.thread_local), ")" }; + return w.writeVecAll(&vecs); + }, + } + } + }; + + pub fn fmt(tl: ThreadLocal, prefix: []const u8) Prefixed { + return .{ .thread_local = tl, .prefix = prefix }; } }; @@ -1961,8 +1982,24 @@ pub const AddrSpace = enum(u24) { pub const funcref: AddrSpace = @enumFromInt(20); }; - pub fn format(self: AddrSpace, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - if (self != .default) try w.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); + pub fn format(addr_space: AddrSpace, w: *Writer) Writer.Error!void { + return Prefixed.format(.{ .addr_space = addr_space, .prefix = "" }, w); + } + + pub const Prefixed = struct { + addr_space: AddrSpace, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + switch (p.addr_space) { + .default => return, + else => return w.print("{s}addrspace({d})", .{ p.prefix, p.addr_space }), + } + } + }; + + pub fn fmt(addr_space: AddrSpace, prefix: []const u8) Prefixed { + return .{ .addr_space = addr_space, .prefix = prefix }; } }; @@ -1994,8 +2031,18 @@ pub const Alignment = enum(u6) { return if (self == .default) 0 else (@intFromEnum(self) + 1); } - pub fn format(self: Alignment, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - try w.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); + pub const Prefixed = struct { + alignment: Alignment, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + const byte_units = p.alignment.toByteUnits() orelse return; + return w.print("{s}align ({d})", .{ p.prefix, byte_units }); + } + }; + + pub fn fmt(alignment: Alignment, prefix: []const u8) Prefixed { + return .{ .alignment = alignment, .prefix = prefix }; } }; @@ -6978,8 +7025,27 @@ pub const MemoryAccessKind = enum(u1) { normal, @"volatile", - pub fn format(self: MemoryAccessKind, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - if (self != .normal) try w.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(memory_access_kind: MemoryAccessKind, w: *Writer) Writer.Error!void { + return Prefixed.format(.{ .memory_access_kind = memory_access_kind, .prefix = "" }, w); + } + + pub const Prefixed = struct { + memory_access_kind: MemoryAccessKind, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + switch (p.memory_access_kind) { + .normal => return, + .@"volatile" => { + var vecs: [2][]const u8 = .{ p.prefix, "volatile" }; + return w.writeVecAll(&vecs); + }, + } + } + }; + + pub fn fmt(memory_access_kind: MemoryAccessKind, prefix: []const u8) Prefixed { + return .{ .memory_access_kind = memory_access_kind, .prefix = prefix }; } }; @@ -6987,10 +7053,27 @@ pub const SyncScope = enum(u1) { singlethread, system, - pub fn format(self: SyncScope, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - if (self != .system) try w.print( - \\{s}syncscope("{s}") - , .{ prefix, @tagName(self) }); + pub fn format(sync_scope: SyncScope, w: *Writer) Writer.Error!void { + return Prefixed.format(.{ .sync_scope = sync_scope, .prefix = "" }, w); + } + + pub const Prefixed = struct { + sync_scope: SyncScope, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + switch (p.sync_scope) { + .system => return, + .singlethread => { + var vecs: [2][]const u8 = .{ p.prefix, "syncscope(\"singlethread\")" }; + return w.writeVecAll(&vecs); + }, + } + } + }; + + pub fn fmt(sync_scope: SyncScope, prefix: []const u8) Prefixed { + return .{ .sync_scope = sync_scope, .prefix = prefix }; } }; @@ -7003,8 +7086,27 @@ pub const AtomicOrdering = enum(u3) { acq_rel = 5, seq_cst = 6, - pub fn format(self: AtomicOrdering, w: *Writer, comptime prefix: []const u8) Writer.Error!void { - if (self != .none) try w.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(atomic_ordering: AtomicOrdering, w: *Writer) Writer.Error!void { + return Prefixed.format(.{ .atomic_ordering = atomic_ordering, .prefix = "" }, w); + } + + pub const Prefixed = struct { + atomic_ordering: AtomicOrdering, + prefix: []const u8, + + pub fn format(p: Prefixed, w: *Writer) Writer.Error!void { + switch (p.atomic_ordering) { + .none => return, + else => { + var vecs: [2][]const u8 = .{ p.prefix, @tagName(p.atomic_ordering) }; + return w.writeVecAll(&vecs); + }, + } + } + }; + + pub fn fmt(atomic_ordering: AtomicOrdering, prefix: []const u8) Prefixed { + return .{ .atomic_ordering = atomic_ordering, .prefix = prefix }; } }; @@ -8550,7 +8652,7 @@ pub fn init(options: Options) Allocator.Error!Builder { inline for (.{ 0, 4 }) |addr_space_index| { const addr_space: AddrSpace = @enumFromInt(addr_space_index); assert(self.ptrTypeAssumeCapacity(addr_space) == - @field(Type, std.fmt.comptimePrint("ptr{f }", .{addr_space}))); + @field(Type, std.fmt.comptimePrint("ptr{f}", .{addr_space.fmt(" ")}))); } } @@ -9469,7 +9571,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; try w.print( - \\{f} ={f}{f}{f}{f}{f }{f}{f }{f} {s} {f}{f}{f, }{f} + \\{f} ={f}{f}{f}{f}{f}{f}{f}{f} {s} {f}{f}{f}{f} \\ , .{ variable.global.fmt(self), @@ -9479,14 +9581,14 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void global.preemption, global.visibility, global.dll_storage_class, - variable.thread_local, + variable.thread_local.fmt(" "), global.unnamed_addr, - global.addr_space, + global.addr_space.fmt(" "), global.externally_initialized, @tagName(variable.mutability), global.type.fmt(self, .percent), variable.init.fmt(self, .{ .space = true }), - variable.alignment, + variable.alignment.fmt(", "), try metadata_formatter.fmt("!dbg ", global.dbg, null), }); } @@ -9500,7 +9602,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; try w.print( - \\{f} ={f}{f}{f}{f}{f }{f} alias {f}, {f}{f} + \\{f} ={f}{f}{f}{f}{f}{f} alias {f}, {f}{f} \\ , .{ alias.global.fmt(self), @@ -9508,7 +9610,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void global.preemption, global.visibility, global.dll_storage_class, - alias.thread_local, + alias.thread_local.fmt(" "), global.unnamed_addr, global.type.fmt(self, .percent), alias.aliasee.fmt(self, .{ .percent = true }), @@ -9564,15 +9666,15 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void try w.writeAll("..."); }, } - try w.print("){f}{f }", .{ global.unnamed_addr, global.addr_space }); + try w.print("){f}{f}", .{ global.unnamed_addr, global.addr_space.fmt(" ") }); if (function_attributes != .none) try w.print(" #{d}", .{ (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, }); { metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - try w.print("{f }{f}", .{ - function.alignment, + try w.print("{f}{f}", .{ + function.alignment.fmt(" "), try metadata_formatter.fmt(" !dbg ", global.dbg, null), }); } @@ -9709,7 +9811,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .@"alloca inalloca", => |tag| { const extra = function.extraData(Function.Instruction.Alloca, instruction.data); - try w.print(" %{f} = {s} {f}{f}{f, }{f, }", .{ + try w.print(" %{f} = {s} {f}{f}{f}{f}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.type.fmt(self, .percent), @@ -9720,24 +9822,24 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .comma = true, .percent = true, }), - extra.info.alignment, - extra.info.addr_space, + extra.info.alignment.fmt(", "), + extra.info.addr_space.fmt(", "), }); }, .arg => unreachable, .atomicrmw => |tag| { const extra = function.extraData(Function.Instruction.AtomicRmw, instruction.data); - try w.print(" %{f} = {s}{f } {s} {f}, {f}{f }{f }{f, }", .{ + try w.print(" %{f} = {t}{f} {t} {f}, {f}{f}{f}{f}", .{ instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.info.access_kind, - @tagName(extra.info.atomic_rmw_operation), + tag, + extra.info.access_kind.fmt(" "), + extra.info.atomic_rmw_operation, extra.ptr.fmt(function_index, self, .{ .percent = true }), extra.val.fmt(function_index, self, .{ .percent = true }), - extra.info.sync_scope, - extra.info.success_ordering, - extra.info.alignment, + extra.info.sync_scope.fmt(" "), + extra.info.success_ordering.fmt(" "), + extra.info.alignment.fmt(", "), }); }, .block => { @@ -9792,8 +9894,8 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void }), .none => unreachable, } - try w.print("{s}{f}{f}{f} {f} {f}(", .{ - @tagName(tag), + try w.print("{t}{f}{f}{f} {f} {f}(", .{ + tag, extra.data.info.call_conv, extra.data.attributes.ret(self).fmt(self, .{}), extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self), @@ -9831,17 +9933,17 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void => |tag| { const extra = function.extraData(Function.Instruction.CmpXchg, instruction.data); - try w.print(" %{f} = {s}{f } {f}, {f}, {f}{f }{f }{f }{f, }", .{ + try w.print(" %{f} = {t}{f} {f}, {f}, {f}{f}{f}{f}{f}", .{ instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.info.access_kind, + tag, + extra.info.access_kind.fmt(" "), extra.ptr.fmt(function_index, self, .{ .percent = true }), extra.cmp.fmt(function_index, self, .{ .percent = true }), extra.new.fmt(function_index, self, .{ .percent = true }), - extra.info.sync_scope, - extra.info.success_ordering, - extra.info.failure_ordering, - extra.info.alignment, + extra.info.sync_scope.fmt(" "), + extra.info.success_ordering.fmt(" "), + extra.info.failure_ordering.fmt(" "), + extra.info.alignment.fmt(", "), }); }, .extractelement => |tag| { @@ -9869,10 +9971,10 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void }, .fence => |tag| { const info: MemoryAccessInfo = @bitCast(instruction.data); - try w.print(" {s}{f }{f }", .{ - @tagName(tag), - info.sync_scope, - info.success_ordering, + try w.print(" {t}{f}{f}", .{ + tag, + info.sync_scope.fmt(" "), + info.success_ordering.fmt(" "), }); }, .fneg, @@ -9947,15 +10049,15 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .@"load atomic", => |tag| { const extra = function.extraData(Function.Instruction.Load, instruction.data); - try w.print(" %{f} = {s}{f } {f}, {f}{f }{f }{f, }", .{ + try w.print(" %{f} = {t}{f} {f}, {f}{f}{f}{f}", .{ instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.info.access_kind, + tag, + extra.info.access_kind.fmt(" "), extra.type.fmt(self, .percent), extra.ptr.fmt(function_index, self, .{ .percent = true }), - extra.info.sync_scope, - extra.info.success_ordering, - extra.info.alignment, + extra.info.sync_scope.fmt(" "), + extra.info.success_ordering.fmt(" "), + extra.info.alignment.fmt(", "), }); }, .phi, @@ -10015,14 +10117,14 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .@"store atomic", => |tag| { const extra = function.extraData(Function.Instruction.Store, instruction.data); - try w.print(" {s}{f } {f}, {f}{f }{f }{f, }", .{ - @tagName(tag), - extra.info.access_kind, + try w.print(" {t}{f} {f}, {f}{f}{f}{f}", .{ + tag, + extra.info.access_kind.fmt(" "), extra.val.fmt(function_index, self, .{ .percent = true }), extra.ptr.fmt(function_index, self, .{ .percent = true }), - extra.info.sync_scope, - extra.info.success_ordering, - extra.info.alignment, + extra.info.sync_scope.fmt(" "), + extra.info.success_ordering.fmt(" "), + extra.info.alignment.fmt(", "), }); }, .@"switch" => |tag| { diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index c25bf733e3..2b4fc642df 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -615,7 +615,7 @@ pub fn Serializer(Writer: type) type { /// Serialize an integer. pub fn int(self: *Self, val: anytype) Writer.Error!void { - //try self.writer.printIntOptions(val, 10, .lower, .{}); + //try self.writer.printInt(val, 10, .lower, .{}); try std.fmt.deprecatedFormat(self.writer, "{d}", .{val}); } diff --git a/src/Builtin.zig b/src/Builtin.zig index ef674cf889..b2cb603f53 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -200,8 +200,8 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { }), .windows => |windows| try buffer.print( \\ .windows = .{{ - \\ .min = {fc}, - \\ .max = {fc}, + \\ .min = {f}, + \\ .max = {f}, \\ }}}}, \\ , .{ windows.min, windows.max }), diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index e7ba4ec2b5..b9a1d4376a 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -227,9 +227,9 @@ pub const JobQueue = struct { } try buf.writer().print( - \\ pub const build_root = "{fq}"; + \\ pub const build_root = "{f}"; \\ - , .{fetch.package_root}); + , .{std.fmt.alt(fetch.package_root, .formatEscapeString)}); if (fetch.has_build_zig) { try buf.writer().print( @@ -1079,7 +1079,10 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re }); const notes_start = try eb.reserveNotes(notes_len); eb.extra.items[notes_start] = @intFromEnum(try eb.addErrorMessage(.{ - .msg = try eb.printString("try .url = \"{f;+/}#{f}\",", .{ uri, want_oid }), + .msg = try eb.printString("try .url = \"{f}#{f}\",", .{ + uri.fmt(.{ .scheme = true, .authority = true, .path = true }), + want_oid, + }), })); return error.FetchFailed; } diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig index 8dfcbb2453..4d2dae904f 100644 --- a/src/Package/Fetch/git.zig +++ b/src/Package/Fetch/git.zig @@ -662,13 +662,21 @@ pub const Session = struct { fn init(allocator: Allocator, uri: std.Uri) !Location { const scheme = try allocator.dupe(u8, uri.scheme); errdefer allocator.free(scheme); - const user = if (uri.user) |user| try std.fmt.allocPrint(allocator, "{fuser}", .{user}) else null; + const user = if (uri.user) |user| try std.fmt.allocPrint(allocator, "{f}", .{ + std.fmt.alt(user, .formatUser), + }) else null; errdefer if (user) |s| allocator.free(s); - const password = if (uri.password) |password| try std.fmt.allocPrint(allocator, "{fpassword}", .{password}) else null; + const password = if (uri.password) |password| try std.fmt.allocPrint(allocator, "{f}", .{ + std.fmt.alt(password, .formatPassword), + }) else null; errdefer if (password) |s| allocator.free(s); - const host = if (uri.host) |host| try std.fmt.allocPrint(allocator, "{fhost}", .{host}) else null; + const host = if (uri.host) |host| try std.fmt.allocPrint(allocator, "{f}", .{ + std.fmt.alt(host, .formatHost), + }) else null; errdefer if (host) |s| allocator.free(s); - const path = try std.fmt.allocPrint(allocator, "{fpath}", .{uri.path}); + const path = try std.fmt.allocPrint(allocator, "{f}", .{ + std.fmt.alt(uri.path, .formatPath), + }); errdefer allocator.free(path); // The query and fragment are not used as part of the base server URI. return .{ @@ -699,7 +707,9 @@ pub const Session = struct { fn getCapabilities(session: *Session, http_headers_buffer: []u8) !CapabilityIterator { var info_refs_uri = session.location.uri; { - const session_uri_path = try std.fmt.allocPrint(session.allocator, "{fpath}", .{session.location.uri.path}); + const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{ + std.fmt.alt(session.location.uri.path, .formatPath), + }); defer session.allocator.free(session_uri_path); info_refs_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "info/refs" }) }; } @@ -723,7 +733,9 @@ pub const Session = struct { if (request.response.status != .ok) return error.ProtocolError; const any_redirects_occurred = request.redirect_behavior.remaining() < max_redirects; if (any_redirects_occurred) { - const request_uri_path = try std.fmt.allocPrint(session.allocator, "{fpath}", .{request.uri.path}); + const request_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{ + std.fmt.alt(request.uri.path, .formatPath), + }); defer session.allocator.free(request_uri_path); if (!mem.endsWith(u8, request_uri_path, "/info/refs")) return error.UnparseableRedirect; var new_uri = request.uri; @@ -810,7 +822,9 @@ pub const Session = struct { pub fn listRefs(session: Session, options: ListRefsOptions) !RefIterator { var upload_pack_uri = session.location.uri; { - const session_uri_path = try std.fmt.allocPrint(session.allocator, "{fpath}", .{session.location.uri.path}); + const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{ + std.fmt.alt(session.location.uri.path, .formatPath), + }); defer session.allocator.free(session_uri_path); upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "git-upload-pack" }) }; } @@ -925,7 +939,9 @@ pub const Session = struct { ) !FetchStream { var upload_pack_uri = session.location.uri; { - const session_uri_path = try std.fmt.allocPrint(session.allocator, "{fpath}", .{session.location.uri.path}); + const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{ + std.fmt.alt(session.location.uri.path, .formatPath), + }); defer session.allocator.free(session_uri_path); upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "git-upload-pack" }) }; } diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index b55bab127b..8c70a5b784 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -492,7 +492,7 @@ fn lowerInt( if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) { return self.fail( node, - "type '{f}' cannot represent integer value '{f}'", + "type '{f}' cannot represent integer value '{d}'", .{ res_ty.fmt(self.sema.pt), val }, ); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index f0fdc3a98a..49baf7acad 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1151,7 +1151,7 @@ fn gen(func: *Func) !void { func.ret_mcv.long.address().offset(-func.ret_mcv.short.indirect.off), ); func.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; - tracking_log.debug("spill {} to {f}", .{ func.ret_mcv.long, frame_index }); + tracking_log.debug("spill {} to {}", .{ func.ret_mcv.long, frame_index }); }, else => unreachable, } @@ -1987,7 +1987,7 @@ fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex { } const frame_index: FrameIndex = @enumFromInt(func.frame_allocs.len); try func.frame_allocs.append(func.gpa, alloc); - log.debug("allocated frame {f}", .{frame_index}); + log.debug("allocated frame {}", .{frame_index}); return frame_index; } diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 2f79da7116..94c64dfc98 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -249,6 +249,12 @@ pub const FrameIndex = enum(u32) { spill_frame, /// Other indices are used for local variable stack slots _, + + pub const named_count = @typeInfo(FrameIndex).@"enum".fields.len; + + pub fn isNamed(fi: FrameIndex) bool { + return @intFromEnum(fi) < named_count; + } }; /// A linker symbol not yet allocated in VM. diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 177d6b7b49..486497a365 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -525,47 +525,47 @@ pub const MCValue = union(enum) { }; } - pub fn format(mcv: MCValue, bw: *Writer) Writer.Error!void { + pub fn format(mcv: MCValue, w: *Writer) Writer.Error!void { switch (mcv) { - .none, .unreach, .dead, .undef => try bw.print("({s})", .{@tagName(mcv)}), - .immediate => |pl| try bw.print("0x{x}", .{pl}), - .memory => |pl| try bw.print("[ds:0x{x}]", .{pl}), - inline .eflags, .register => |pl| try bw.print("{s}", .{@tagName(pl)}), - .register_pair => |pl| try bw.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), - .register_triple => |pl| try bw.print("{s}:{s}:{s}", .{ + .none, .unreach, .dead, .undef => try w.print("({s})", .{@tagName(mcv)}), + .immediate => |pl| try w.print("0x{x}", .{pl}), + .memory => |pl| try w.print("[ds:0x{x}]", .{pl}), + inline .eflags, .register => |pl| try w.print("{s}", .{@tagName(pl)}), + .register_pair => |pl| try w.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), + .register_triple => |pl| try w.print("{s}:{s}:{s}", .{ @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), }), - .register_quadruple => |pl| try bw.print("{s}:{s}:{s}:{s}", .{ + .register_quadruple => |pl| try w.print("{s}:{s}:{s}:{s}", .{ @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), }), - .register_offset => |pl| try bw.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), - .register_overflow => |pl| try bw.print("{s}:{s}", .{ + .register_offset => |pl| try w.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), + .register_overflow => |pl| try w.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg), }), - .register_mask => |pl| try bw.print("mask({s},{f}):{c}{s}", .{ + .register_mask => |pl| try w.print("mask({s},{f}):{c}{s}", .{ @tagName(pl.info.kind), pl.info.scalar, @as(u8, if (pl.info.inverted) '!' else ' '), @tagName(pl.reg), }), - .indirect => |pl| try bw.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), - .indirect_load_frame => |pl| try bw.print("[[{f} + 0x{x}]]", .{ pl.index, pl.off }), - .load_frame => |pl| try bw.print("[{f} + 0x{x}]", .{ pl.index, pl.off }), - .lea_frame => |pl| try bw.print("{f} + 0x{x}", .{ pl.index, pl.off }), - .load_nav => |pl| try bw.print("[nav:{d}]", .{@intFromEnum(pl)}), - .lea_nav => |pl| try bw.print("nav:{d}", .{@intFromEnum(pl)}), - .load_uav => |pl| try bw.print("[uav:{d}]", .{@intFromEnum(pl.val)}), - .lea_uav => |pl| try bw.print("uav:{d}", .{@intFromEnum(pl.val)}), - .load_lazy_sym => |pl| try bw.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), - .lea_lazy_sym => |pl| try bw.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), - .load_extern_func => |pl| try bw.print("[extern:{d}]", .{@intFromEnum(pl)}), - .lea_extern_func => |pl| try bw.print("extern:{d}", .{@intFromEnum(pl)}), - .elementwise_args => |pl| try bw.print("elementwise:{d}:[{f} + 0x{x}]", .{ + .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), + .indirect_load_frame => |pl| try w.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }), + .load_frame => |pl| try w.print("[{} + 0x{x}]", .{ pl.index, pl.off }), + .lea_frame => |pl| try w.print("{} + 0x{x}", .{ pl.index, pl.off }), + .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}), + .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}), + .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}), + .lea_uav => |pl| try w.print("uav:{d}", .{@intFromEnum(pl.val)}), + .load_lazy_sym => |pl| try w.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}), + .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}), + .elementwise_args => |pl| try w.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off, }), - .reserved_frame => |pl| try bw.print("(dead:{f})", .{pl}), - .air_ref => |pl| try bw.print("(air:0x{x})", .{@intFromEnum(pl)}), + .reserved_frame => |pl| try w.print("(dead:{})", .{pl}), + .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}), } } }; @@ -2026,7 +2026,7 @@ fn gen( .{}, ); self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; - tracking_log.debug("spill {f} to {f}", .{ self.ret_mcv.long, frame_index }); + tracking_log.debug("spill {f} to {}", .{ self.ret_mcv.long, frame_index }); }, else => unreachable, } diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 2e9b1f7f21..16361acb4d 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -721,6 +721,12 @@ pub const FrameIndex = enum(u32) { call_frame, // Other indices are used for local variable stack slots _, + + pub const named_count = @typeInfo(FrameIndex).@"enum".fields.len; + + pub fn isNamed(fi: FrameIndex) bool { + return @intFromEnum(fi) < named_count; + } }; pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 59938990f6..43d23af5fc 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -259,7 +259,7 @@ pub const Instruction = struct { switch (sib.base) { .none => any = false, .reg => |reg| try w.print("{s}", .{@tagName(reg)}), - .frame => |frame_index| try w.print("{f}", .{frame_index}), + .frame => |frame_index| try w.print("{}", .{frame_index}), .table => try w.print("Table", .{}), .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}), .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}), diff --git a/src/link.zig b/src/link.zig index 41b184d792..0fbd4b28cf 100644 --- a/src/link.zig +++ b/src/link.zig @@ -838,8 +838,10 @@ pub const File = struct { const cached_pp_file_path = the_key.status.success.object_path; cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{}) catch |err| { const diags = &base.comp.link_diags; - return diags.fail("failed to copy '{f'}' to '{f'}': {s}", .{ - @as(Path, cached_pp_file_path), @as(Path, emit), @errorName(err), + return diags.fail("failed to copy '{f}' to '{f}': {s}", .{ + std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar), + std.fmt.alt(@as(Path, emit), .formatEscapeChar), + @errorName(err), }); }; return; @@ -2086,14 +2088,14 @@ fn resolvePathInputLib( }) { var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => return .no_match, - else => |e| fatal("unable to search for {s} library '{f'}': {s}", .{ - @tagName(link_mode), test_path, @errorName(e), + else => |e| fatal("unable to search for {s} library '{f}': {s}", .{ + @tagName(link_mode), std.fmt.alt(test_path, .formatEscapeChar), @errorName(e), }), }; errdefer file.close(); try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); - const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f'}': {s}", .{ - test_path, @errorName(err), + const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f}': {s}", .{ + std.fmt.alt(test_path, .formatEscapeChar), @errorName(err), }); const buf = ld_script_bytes.items[0..n]; if (mem.startsWith(u8, buf, std.elf.MAGIC) or mem.startsWith(u8, buf, std.elf.ARMAG)) { diff --git a/src/link/C.zig b/src/link/C.zig index 6f32857c1e..5ffb0fa986 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -503,8 +503,8 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P var fw = file.writer(&.{}); var w = &fw.interface; w.writeVecAll(f.all_buffers.items) catch |err| switch (err) { - error.WriteFailed => return diags.fail("failed to write to '{f'}': {s}", .{ - self.base.emit, @errorName(fw.err.?), + error.WriteFailed => return diags.fail("failed to write to '{f}': {s}", .{ + std.fmt.alt(self.base.emit, .formatEscapeChar), @errorName(fw.err.?), }), }; } diff --git a/src/main.zig b/src/main.zig index 99cdf887f4..f639630604 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6964,7 +6964,9 @@ fn cmdFetch( std.log.info("resolved ref '{s}' to commit {s}", .{ target_ref, latest_commit_hex }); // include the original refspec in a query parameter, could be used to check for updates - uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={f%}", .{fragment}) }; + uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={f}", .{ + std.fmt.alt(fragment, .formatEscaped), + }) }; } else { std.log.info("resolved to commit {s}", .{latest_commit_hex}); } diff --git a/src/print_value.zig b/src/print_value.zig index ae9ceb1a16..e0a489ee40 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -77,7 +77,7 @@ pub fn print( .func => |func| try writer.print("(function '{f}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}), .int => |int| switch (int.storage) { inline .u64, .i64 => |x| try writer.print("{d}", .{x}), - .big_int => |x| try writer.print("{fd}", .{x}), + .big_int => |x| try writer.print("{d}", .{x}), .lazy_align => |ty| if (opt_sema != null) { const a = try Type.fromInterned(ty).abiAlignmentSema(pt); try writer.print("{d}", .{a.toByteUnits() orelse 0});