From c3dadfa95b01d140460eb3d3d47d13859302f298 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Sun, 17 Jan 2021 19:22:48 -0800 Subject: [PATCH] translate-c: Add Wide, UTF-16, and UTF-32 character literals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for L'', u'', and U''. 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. --- src/translate_c.zig | 18 ++++++++++-------- test/run_translated_c.zig | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index ff9e1e5d0d2781b13101385d470ff46b8b154799..388fa8841ea5c2519b7b63a5b7a070d907b4bc98 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -2942,9 +2942,9 @@ fn transCharLiteral( suppress_as: SuppressCast, ) TransError!*ast.Node { const kind = stmt.getKind(); + const val = stmt.getValue(); const int_lit_node = switch (kind) { .Ascii, .UTF8 => blk: { - const val = stmt.getValue(); if (kind == .Ascii) { // C has a somewhat obscure feature called multi-character character // constant @@ -2960,13 +2960,15 @@ fn transCharLiteral( }; break :blk &node.base; }, - .UTF16, .UTF32, .Wide => return revertAndWarn( - rp, - error.UnsupportedTranslation, - @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), - "TODO: support character literal kind {}", - .{kind}, - ), + .Wide, .UTF16, .UTF32 => blk: { + const token = try appendTokenFmt(rp.c, .CharLiteral, "'\\u{{{x}}}'", .{val}); + const node = try rp.c.arena.create(ast.Node.OneToken); + node.* = .{ + .base = .{ .tag = .CharLiteral }, + .token = token, + }; + break :blk &node.base; + }, }; if (suppress_as == .no_as) { return maybeSuppressResult(rp, scope, result_used, int_lit_node); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index f719d0fe4094a4f40d0795a29b71bc2a2e36f4e6..13952742517de1ca95719d0c193caa4cc04a4273 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -719,4 +719,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("Wide, UTF-16, and UTF-32 character literals", + \\#include + \\#include + \\int main() { + \\ wchar_t wc = L'™'; + \\ int utf16_char = u'™'; + \\ int utf32_char = U'💯'; + \\ if (wc != 8482) abort(); + \\ if (utf16_char != 8482) abort(); + \\ if (utf32_char != 128175) abort(); + \\ unsigned char c = wc; + \\ if (c != 0x22) abort(); + \\ c = utf32_char; + \\ if (c != 0xaf) abort(); + \\ return 0; + \\} + , ""); } -- 2.54.0