| author | |
| committer | |
| log | c3dadfa95b01d140460eb3d3d47d13859302f298 |
| tree | 8d0135b3319b548b44e7f6ab1c9ba73d45a16788 |
| parent | 384ccaa27a979f406f41e1617d3c9ef015517fda |
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 character | 2949 | // C has a somewhat obscure feature called multi-character character |
| 2950 | // constant | 2950 | // 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 | } |