authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-10-21 09:43:04+02:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-10-21 09:43:04+02:00
log8f0c6ce407f96d04e9f4b7b66b2ce18134775969
treee039a597c7095989eef6f6304f700632f336ce0e
parent3c08167cb766f8d00fc5a219e382abba12e57ede
parentb77411310c94db7f6f1678e189f9d8954828b78c

Merge pull request 'Allow \u escape sequences to encode surrogate code points' (#36965) from squeek502/zig:surrogates into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36965

3 files changed, 18 insertions(+), 9 deletions(-)

doc/langref.html.in+11-2
......@@ -755,12 +755,21 @@
755755 </tr>
756756 <tr>
757757 <th scope="row"><code>\u{NNNNNN}</code></th>
758 <td>hexadecimal Unicode scalar value UTF-8 encoded (1 or more digits)</td>
758 <td>hexadecimal Unicode code point (1 or more digits)</td>
759759 </tr>
760760 </tbody>
761761 </table>
762762 </div>
763 <p>Note that the maximum valid Unicode scalar value is {#syntax#}0x10ffff{#endsyntax#}.</p>
763 <p>
764 Note that the highest Unicode code point is {#syntax#}0x10ffff{#endsyntax#}. Character
765 literals are integers ({#syntax#}'A'{#endsyntax#} = {#syntax#}65{#endsyntax#} and
766 {#syntax#}'\u{10000}'{#endsyntax#} = {#syntax#}0x10000{#endsyntax#} = {#syntax#}65536{#endsyntax#}),
767 and <code>\u</code> escapes in string literals are encoded as UTF-8
768 ({#syntax#}"A"{#endsyntax#} = {#syntax#}"\u{41}"{#endsyntax#} = {#syntax#}"\x41"{#endsyntax#}
769 and {#syntax#}"\u{10000}"{#endsyntax#} = {#syntax#}"\xF0\x90\x80\x80"{#endsyntax#}).
770 <code>\u</code> escapes can be used for surrogate code points, which are not Unicode
771 scalar values or technically allowed in UTF-8 as defined by the Unicode standard, but can be useful in practice.
772 </p>
764773 {#header_close#}
765774 {#header_open|Multiline String Literals#}
766775 <p>
lib/compiler/Maker/Package/Manifest.zig+1-1
......@@ -544,7 +544,7 @@ const Parse = struct {
544544 try p.appendErrorOff(
545545 token,
546546 offset + @as(u32, @intCast(bad_index)),
547 "unicode escape does not correspond to a valid unicode scalar value",
547 "unicode escape does not correspond to a unicode code point",
548548 .{},
549549 );
550550 },
lib/std/zig/string_literal.zig+6-6
......@@ -1,6 +1,5 @@
11const std = @import("../std.zig");
22const assert = std.debug.assert;
3const utf8Encode = std.unicode.utf8Encode;
43const Writer = std.Io.Writer;
54
65pub const ParseError = error{
......@@ -63,7 +62,7 @@ pub const Error = union(enum) {
6362 .{self.raw_string[bad_index]},
6463 ),
6564 .invalid_unicode_codepoint => try writer.writeAll(
66 "unicode escape does not correspond to a valid unicode scalar value",
65 "unicode escape does not correspond to a unicode code point",
6766 ),
6867 .expected_lbrace => |bad_index| try writer.print(
6968 "expected '{{', found '{c}'",
......@@ -334,8 +333,8 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result {
334333 .success => |codepoint| {
335334 if (bytes[escape_char_index] == 'u') {
336335 var buf: [4]u8 = undefined;
337 const len = utf8Encode(codepoint, &buf) catch {
338 return .{ .failure = .{ .invalid_unicode_codepoint = escape_char_index + 1 } };
336 const len = std.unicode.wtf8Encode(codepoint, &buf) catch |err| switch (err) {
337 error.CodepointTooLarge => unreachable, // Checked in `parseEscapeSequence`.
339338 };
340339 try writer.writeAll(buf[0..len]);
341340 } else {
......@@ -383,6 +382,7 @@ test parseAlloc {
383382 try expect(eql(u8, "\x12foo", try parseAlloc(alloc, "\"\\x12foo\"")));
384383 try expect(eql(u8, "bytes\u{1234}foo", try parseAlloc(alloc, "\"bytes\\u{1234}foo\"")));
385384 try expect(eql(u8, "foo", try parseAlloc(alloc, "\"foo\"")));
386 try expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\x6f\x6f\"")));
387 try expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\u{1f4af}\"")));
385 try expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\\x6f\\x6f\"")));
386 try expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\\u{1f4af}\"")));
387 try expect(eql(u8, "\xed\xa0\x80", try parseAlloc(alloc, "\"\\u{d800}\"")));
388388}