authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-27 00:26:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-27 00:27:53-07:00
log3f844cba0b601186bb20efa6090e944b9267f538
tree1fe8a2020b0bf8293bfbea43a8a6835eeac4eb8e
parent081698156141ba16a168d9448b9883c0f5a3edd0

std.zig.fmt escaped string formatting recognizes single quote style

This introduces {'} to indicate escape for a single-quoted string, and {} to indicate escape for a double quoted string. Without this, there would be unnecessary \' inside double quoted strings, and unnecessary \" inside single quoted strings. Motivated by the llvm12 branch, in the new tool I am writing for updating target CPU features.

1 files changed, 30 insertions(+), 5 deletions(-)

lib/std/zig/fmt.zig+30-5
......@@ -12,7 +12,7 @@ pub fn formatId(
1212 return writer.writeAll(bytes);
1313 }
1414 try writer.writeAll("@\"");
15 try formatEscapes(bytes, fmt, options, writer);
15 try formatEscapes(bytes, "", options, writer);
1616 try writer.writeByte('"');
1717}
1818
......@@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool {
3232 return std.zig.Token.getKeyword(bytes) == null;
3333}
3434
35/// Print the string as escaped contents of a double quoted or single-quoted string.
36/// Format `{}` treats contents as a double-quoted string.
37/// Format `{'}` treats contents as a single-quoted string.
3538pub fn formatEscapes(
3639 bytes: []const u8,
3740 comptime fmt: []const u8,
......@@ -43,8 +46,24 @@ pub fn formatEscapes(
4346 '\r' => try writer.writeAll("\\r"),
4447 '\t' => try writer.writeAll("\\t"),
4548 '\\' => try writer.writeAll("\\\\"),
46 '"' => try writer.writeAll("\\\""),
47 '\'' => try writer.writeAll("\\'"),
49 '"' => {
50 if (fmt.len == 1 and fmt[0] == '\'') {
51 try writer.writeByte('"');
52 } else if (fmt.len == 0) {
53 try writer.writeAll("\\\"");
54 } else {
55 @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
56 }
57 },
58 '\'' => {
59 if (fmt.len == 1 and fmt[0] == '\'') {
60 try writer.writeAll("\\'");
61 } else if (fmt.len == 0) {
62 try writer.writeByte('\'');
63 } else {
64 @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
65 }
66 },
4867 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
4968 // Use hex escapes for rest any unprintable characters.
5069 else => {
......@@ -54,7 +73,10 @@ pub fn formatEscapes(
5473 };
5574}
5675
57/// Return a Formatter for Zig Escapes
76/// Return a Formatter for Zig Escapes of a double quoted string.
77/// The format specifier must be one of:
78/// * `{}` treats contents as a double-quoted string.
79/// * `{'}` treats contents as a single-quoted string.
5880pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) {
5981 return .{ .data = bytes };
6082}
......@@ -67,6 +89,9 @@ test "escape invalid identifiers" {
6789 try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
6890 try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
6991 try expectFmt(
70 \\" \\ hi \x07 \x11 \" derp \'"
92 \\" \\ hi \x07 \x11 " derp \'"
93 , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
94 try expectFmt(
95 \\" \\ hi \x07 \x11 \" derp '"
7196 , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
7297}