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(...@@ -2942,9 +2942,9 @@ fn transCharLiteral(
2942 suppress_as: SuppressCast,2942 suppress_as: SuppressCast,
2943) TransError!*ast.Node {2943) TransError!*ast.Node {
2944 const kind = stmt.getKind();2944 const kind = stmt.getKind();
2945 const val = stmt.getValue();
2945 const int_lit_node = switch (kind) {2946 const int_lit_node = switch (kind) {
2946 .Ascii, .UTF8 => blk: {2947 .Ascii, .UTF8 => blk: {
2947 const val = stmt.getValue();
2948 if (kind == .Ascii) {2948 if (kind == .Ascii) {
2949 // C has a somewhat obscure feature called multi-character character2949 // C has a somewhat obscure feature called multi-character character
2950 // constant2950 // constant
...@@ -2960,13 +2960,15 @@ fn transCharLiteral(...@@ -2960,13 +2960,15 @@ fn transCharLiteral(
2960 };2960 };
2961 break :blk &node.base;2961 break :blk &node.base;
2962 },2962 },
2963 .UTF16, .UTF32, .Wide => return revertAndWarn(2963 .Wide, .UTF16, .UTF32 => blk: {
2964 rp,2964 const token = try appendTokenFmt(rp.c, .CharLiteral, "'\\u{{{x}}}'", .{val});
2965 error.UnsupportedTranslation,2965 const node = try rp.c.arena.create(ast.Node.OneToken);
2966 @ptrCast(*const clang.Stmt, stmt).getBeginLoc(),2966 node.* = .{
2967 "TODO: support character literal kind {}",2967 .base = .{ .tag = .CharLiteral },
2968 .{kind},2968 .token = token,
2969 ),2969 };
2970 break :blk &node.base;
2971 },
2970 };2972 };
2971 if (suppress_as == .no_as) {2973 if (suppress_as == .no_as) {
2972 return maybeSuppressResult(rp, scope, result_used, int_lit_node);2974 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 {...@@ -719,4 +719,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
719 \\ return 0;719 \\ return 0;
720 \\}720 \\}
721 , "");721 , "");
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 , "");
722}740}