authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-01-17 19:22:48-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-18 11:05:51-08:00
logc3dadfa95b01d140460eb3d3d47d13859302f298
tree8d0135b3319b548b44e7f6ab1c9ba73d45a16788
parent384ccaa27a979f406f41e1617d3c9ef015517fda

translate-c: Add Wide, UTF-16, and UTF-32 character literals

Add support for L'<wchar_t>', u'<char16_t>', and U'<char32_t>'. Currently this just translates wide char literals to \u{NNNNNN} escape codes (e.g. U'💯' -> '\u{1f4af}') Another approach would be to emit UTF-8 encoded character literals directly, but in my opinion this approaches Unicode-complete because it would require knowledge of which Unicode codepoints have graphical representations for the emitted source to be readable. We could also just emit integer literals, but the current method makes it clear that we have translated a wide character literal and not just an integer constant.

2 files changed, 28 insertions(+), 8 deletions(-)

src/translate_c.zig+10-8
......@@ -2942,9 +2942,9 @@ fn transCharLiteral(
29422942 suppress_as: SuppressCast,
29432943) TransError!*ast.Node {
29442944 const kind = stmt.getKind();
2945 const val = stmt.getValue();
29452946 const int_lit_node = switch (kind) {
29462947 .Ascii, .UTF8 => blk: {
2947 const val = stmt.getValue();
29482948 if (kind == .Ascii) {
29492949 // C has a somewhat obscure feature called multi-character character
29502950 // constant
......@@ -2960,13 +2960,15 @@ fn transCharLiteral(
29602960 };
29612961 break :blk &node.base;
29622962 },
2963 .UTF16, .UTF32, .Wide => return revertAndWarn(
2964 rp,
2965 error.UnsupportedTranslation,
2966 @ptrCast(*const clang.Stmt, stmt).getBeginLoc(),
2967 "TODO: support character literal kind {}",
2968 .{kind},
2969 ),
2963 .Wide, .UTF16, .UTF32 => blk: {
2964 const token = try appendTokenFmt(rp.c, .CharLiteral, "'\\u{{{x}}}'", .{val});
2965 const node = try rp.c.arena.create(ast.Node.OneToken);
2966 node.* = .{
2967 .base = .{ .tag = .CharLiteral },
2968 .token = token,
2969 };
2970 break :blk &node.base;
2971 },
29702972 };
29712973 if (suppress_as == .no_as) {
29722974 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
test/run_translated_c.zig+18
......@@ -719,4 +719,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
719719 \\ return 0;
720720 \\}
721721 , "");
722
723 cases.add("Wide, UTF-16, and UTF-32 character literals",
724 \\#include <wchar.h>
725 \\#include <stdlib.h>
726 \\int main() {
727 \\ wchar_t wc = L'™';
728 \\ int utf16_char = u'™';
729 \\ int utf32_char = U'💯';
730 \\ if (wc != 8482) abort();
731 \\ if (utf16_char != 8482) abort();
732 \\ if (utf32_char != 128175) abort();
733 \\ unsigned char c = wc;
734 \\ if (c != 0x22) abort();
735 \\ c = utf32_char;
736 \\ if (c != 0xaf) abort();
737 \\ return 0;
738 \\}
739 , "");
722740}