aboutsummaryrefslogtreecommitdiff
path: root/lib/std/fmt.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-02-11 23:45:40 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-02-11 23:45:40 -0700
commitb4e344bcf859f2df89637e0825a2e0e57d092ef6 (patch)
tree44465c5c3eadcfdc57f0a0a3eb5cffff9107bd7f /lib/std/fmt.zig
parent3d0f4b90305bc1815ccc86613cb3da715e9b62c0 (diff)
parentd3565ed6b48c9c66128f181e7b90b5348504cb3f (diff)
downloadzig-b4e344bcf859f2df89637e0825a2e0e57d092ef6.tar.gz
zig-b4e344bcf859f2df89637e0825a2e0e57d092ef6.zip
Merge remote-tracking branch 'origin/master' into ast-memory-layout
Conflicts: * lib/std/zig/ast.zig * lib/std/zig/parse.zig * lib/std/zig/parser_test.zig * lib/std/zig/render.zig * src/Module.zig * src/zir.zig I resolved some of the conflicts by reverting a small portion of @tadeokondrak's stage2 logic here regarding `callconv(.Inline)`. It will need to get reworked as part of this branch.
Diffstat (limited to 'lib/std/fmt.zig')
-rw-r--r--lib/std/fmt.zig98
1 files changed, 59 insertions, 39 deletions
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 196e95f838..c1b24cc6da 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -69,6 +69,7 @@ pub const FormatOptions = struct {
/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
/// - `*`: output the address of the value instead of the value itself.
+/// - `any`: output a value of any type using its default format
///
/// If a formatted user type contains a function of the type
/// ```
@@ -387,17 +388,32 @@ pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @T
return;
}
},
- .Array => |info| {
- try writer.writeAll(@typeName(info.child) ++ "@");
- try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
- return;
- },
else => {},
}
@compileError("Cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
}
+// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
+const ANY = "any";
+
+fn defaultSpec(comptime T: type) [:0]const u8 {
+ switch (@typeInfo(T)) {
+ .Array => |_| return ANY,
+ .Pointer => |ptr_info| switch (ptr_info.size) {
+ .One => switch (@typeInfo(ptr_info.child)) {
+ .Array => |_| return "*",
+ else => {},
+ },
+ .Many, .C => return "*",
+ .Slice => return ANY,
+ },
+ .Optional => |info| return defaultSpec(info.child),
+ else => {},
+ }
+ return "";
+}
+
pub fn formatType(
value: anytype,
comptime fmt: []const u8,
@@ -405,18 +421,19 @@ pub fn formatType(
writer: anytype,
max_depth: usize,
) @TypeOf(writer).Error!void {
- if (comptime std.mem.eql(u8, fmt, "*")) {
+ const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY)) defaultSpec(@TypeOf(value)) else fmt;
+ if (comptime std.mem.eql(u8, actual_fmt, "*")) {
return formatAddress(value, options, writer);
}
const T = @TypeOf(value);
if (comptime std.meta.trait.hasFn("format")(T)) {
- return try value.format(fmt, options, writer);
+ return try value.format(actual_fmt, options, writer);
}
switch (@typeInfo(T)) {
.ComptimeInt, .Int, .ComptimeFloat, .Float => {
- return formatValue(value, fmt, options, writer);
+ return formatValue(value, actual_fmt, options, writer);
},
.Void => {
return formatBuf("void", options, writer);
@@ -426,16 +443,16 @@ pub fn formatType(
},
.Optional => {
if (value) |payload| {
- return formatType(payload, fmt, options, writer, max_depth);
+ return formatType(payload, actual_fmt, options, writer, max_depth);
} else {
return formatBuf("null", options, writer);
}
},
.ErrorUnion => {
if (value) |payload| {
- return formatType(payload, fmt, options, writer, max_depth);
+ return formatType(payload, actual_fmt, options, writer, max_depth);
} else |err| {
- return formatType(err, fmt, options, writer, max_depth);
+ return formatType(err, actual_fmt, options, writer, max_depth);
}
},
.ErrorSet => {
@@ -461,7 +478,7 @@ pub fn formatType(
}
try writer.writeAll("(");
- try formatType(@enumToInt(value), fmt, options, writer, max_depth);
+ try formatType(@enumToInt(value), actual_fmt, options, writer, max_depth);
try writer.writeAll(")");
},
.Union => |info| {
@@ -475,7 +492,7 @@ pub fn formatType(
try writer.writeAll(" = ");
inline for (info.fields) |u_field| {
if (value == @field(UnionTagType, u_field.name)) {
- try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
+ try formatType(@field(value, u_field.name), ANY, options, writer, max_depth - 1);
}
}
try writer.writeAll(" }");
@@ -497,48 +514,54 @@ pub fn formatType(
}
try writer.writeAll(f.name);
try writer.writeAll(" = ");
- try formatType(@field(value, f.name), fmt, options, writer, max_depth - 1);
+ try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
}
try writer.writeAll(" }");
},
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => switch (@typeInfo(ptr_info.child)) {
.Array => |info| {
+ if (actual_fmt.len == 0)
+ @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");
if (info.child == u8) {
- if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
- return formatText(value, fmt, options, writer);
+ if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
+ return formatText(value, actual_fmt, options, writer);
}
}
- return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
+ @compileError("Unknown format string: '" ++ actual_fmt ++ "'");
},
.Enum, .Union, .Struct => {
- return formatType(value.*, fmt, options, writer, max_depth);
+ return formatType(value.*, actual_fmt, options, writer, max_depth);
},
else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) }),
},
.Many, .C => {
+ if (actual_fmt.len == 0)
+ @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
if (ptr_info.sentinel) |sentinel| {
- return formatType(mem.span(value), fmt, options, writer, max_depth);
+ return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
}
if (ptr_info.child == u8) {
- if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
- return formatText(mem.span(value), fmt, options, writer);
+ if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
+ return formatText(mem.span(value), actual_fmt, options, writer);
}
}
- return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
+ @compileError("Unknown format string: '" ++ actual_fmt ++ "'");
},
.Slice => {
+ if (actual_fmt.len == 0)
+ @compileError("cannot format slice without a specifier (i.e. {s} or {any})");
if (max_depth == 0) {
return writer.writeAll("{ ... }");
}
if (ptr_info.child == u8) {
- if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
- return formatText(value, fmt, options, writer);
+ if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
+ return formatText(value, actual_fmt, options, writer);
}
}
try writer.writeAll("{ ");
for (value) |elem, i| {
- try formatType(elem, fmt, options, writer, max_depth - 1);
+ try formatType(elem, actual_fmt, options, writer, max_depth - 1);
if (i != value.len - 1) {
try writer.writeAll(", ");
}
@@ -547,17 +570,19 @@ pub fn formatType(
},
},
.Array => |info| {
+ if (actual_fmt.len == 0)
+ @compileError("cannot format array without a specifier (i.e. {s} or {any})");
if (max_depth == 0) {
return writer.writeAll("{ ... }");
}
if (info.child == u8) {
- if (fmt.len > 0 and comptime mem.indexOfScalar(u8, "sxXeEzZ", fmt[0]) != null) {
- return formatText(&value, fmt, options, writer);
+ if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {
+ return formatText(&value, actual_fmt, options, writer);
}
}
try writer.writeAll("{ ");
for (value) |elem, i| {
- try formatType(elem, fmt, options, writer, max_depth - 1);
+ try formatType(elem, actual_fmt, options, writer, max_depth - 1);
if (i < value.len - 1) {
try writer.writeAll(", ");
}
@@ -568,7 +593,7 @@ pub fn formatType(
try writer.writeAll("{ ");
var i: usize = 0;
while (i < info.len) : (i += 1) {
- try formatValue(value[i], fmt, options, writer);
+ try formatValue(value[i], actual_fmt, options, writer);
if (i < info.len - 1) {
try writer.writeAll(", ");
}
@@ -634,12 +659,7 @@ pub fn formatIntValue(
@compileError("Cannot print integer that is larger than 8 bits as a ascii");
}
} else if (comptime std.mem.eql(u8, fmt, "Z")) {
- if (@typeInfo(@TypeOf(int_value)).Int.bits <= 8) {
- const c: u8 = int_value;
- return formatZigEscapes(@as(*const [1]u8, &c), options, writer);
- } else {
- @compileError("Cannot escape character with more than 8 bits");
- }
+ @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
} else if (comptime std.mem.eql(u8, fmt, "u")) {
if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) {
return formatUnicodeCodepoint(@as(u21, int_value), options, writer);
@@ -659,7 +679,7 @@ pub fn formatIntValue(
radix = 8;
uppercase = false;
} else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
+ @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
}
return formatInt(int_value, radix, uppercase, options, writer);
@@ -686,7 +706,7 @@ fn formatFloatValue(
else => |e| return e,
};
} else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
+ @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
}
return formatBuf(buf_stream.getWritten(), options, writer);
@@ -720,7 +740,7 @@ pub fn formatText(
} else if (comptime std.mem.eql(u8, fmt, "Z")) {
@compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
} else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
+ @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
}
}
@@ -1673,7 +1693,7 @@ test "slice" {
{
var int_slice = [_]u32{ 1, 4096, 391891, 1111111111 };
var runtime_zero: usize = 0;
- try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {}", .{int_slice[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..]});