From 3f844cba0b601186bb20efa6090e944b9267f538 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 27 Feb 2021 00:26:25 -0700 Subject: [PATCH] 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. --- lib/std/zig/fmt.zig | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/std/zig/fmt.zig b/lib/std/zig/fmt.zig index 2ca5279263..56f480dc3e 100644 --- a/lib/std/zig/fmt.zig +++ b/lib/std/zig/fmt.zig @@ -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 '")}); }