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.
This commit is contained in:
Andrew Kelley 2021-02-27 00:26:25 -07:00
parent 0816981561
commit 3f844cba0b

View File

@ -12,7 +12,7 @@ pub fn formatId(
return writer.writeAll(bytes);
}
try writer.writeAll("@\"");
try formatEscapes(bytes, fmt, options, writer);
try formatEscapes(bytes, "", options, writer);
try writer.writeByte('"');
}
@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool {
return std.zig.Token.getKeyword(bytes) == null;
}
/// Print the string as escaped contents of a double quoted or single-quoted string.
/// Format `{}` treats contents as a double-quoted string.
/// Format `{'}` treats contents as a single-quoted string.
pub fn formatEscapes(
bytes: []const u8,
comptime fmt: []const u8,
@ -43,8 +46,24 @@ pub fn formatEscapes(
'\r' => try writer.writeAll("\\r"),
'\t' => try writer.writeAll("\\t"),
'\\' => try writer.writeAll("\\\\"),
'"' => try writer.writeAll("\\\""),
'\'' => try writer.writeAll("\\'"),
'"' => {
if (fmt.len == 1 and fmt[0] == '\'') {
try writer.writeByte('"');
} else if (fmt.len == 0) {
try writer.writeAll("\\\"");
} else {
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
}
},
'\'' => {
if (fmt.len == 1 and fmt[0] == '\'') {
try writer.writeAll("\\'");
} else if (fmt.len == 0) {
try writer.writeByte('\'');
} else {
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
}
},
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
// Use hex escapes for rest any unprintable characters.
else => {
@ -54,7 +73,10 @@ pub fn formatEscapes(
};
}
/// Return a Formatter for Zig Escapes
/// Return a Formatter for Zig Escapes of a double quoted string.
/// The format specifier must be one of:
/// * `{}` treats contents as a double-quoted string.
/// * `{'}` treats contents as a single-quoted string.
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) {
return .{ .data = bytes };
}
@ -67,6 +89,9 @@ test "escape invalid identifiers" {
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
try expectFmt(
\\" \\ hi \x07 \x11 \" derp \'"
\\" \\ hi \x07 \x11 " derp \'"
, "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
try expectFmt(
\\" \\ hi \x07 \x11 \" derp '"
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
}