Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-system.h"
20 : #include "rust-token.h"
21 : #include "rust-diagnostics.h"
22 : #include "rust-unicode.h"
23 : #include "rust-ast.h"
24 :
25 : namespace Rust {
26 : // Hackily defined way to get token description for enum value using x-macros
27 : const char *
28 18758541 : get_token_description (TokenId id)
29 : {
30 18758541 : switch (id)
31 : {
32 : #define RS_TOKEN(name, descr) \
33 : case name: \
34 : return descr;
35 : #define RS_TOKEN_KEYWORD_2015(x, y) RS_TOKEN (x, y)
36 : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
37 18758541 : RS_TOKEN_LIST
38 : #undef RS_TOKEN_KEYWORD_2015
39 : #undef RS_TOKEN_KEYWORD_2018
40 : #undef RS_TOKEN
41 0 : default:
42 0 : rust_unreachable ();
43 : }
44 : }
45 :
46 : /* Hackily defined way to get token description as a string for enum value using
47 : * x-macros */
48 : const char *
49 56 : token_id_to_str (TokenId id)
50 : {
51 56 : switch (id)
52 : {
53 : #define RS_TOKEN(name, _) \
54 : case name: \
55 : return #name;
56 : #define RS_TOKEN_KEYWORD_2015(x, y) RS_TOKEN (x, y)
57 : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
58 56 : RS_TOKEN_LIST
59 : #undef RS_TOKEN_KEYWORD_2015
60 : #undef RS_TOKEN_KEYWORD_2018
61 : #undef RS_TOKEN
62 0 : default:
63 0 : rust_unreachable ();
64 : }
65 : }
66 :
67 : /* checks if a token is a keyword */
68 : bool
69 15821124 : token_id_is_keyword (TokenId id)
70 : {
71 15821124 : switch (id)
72 : {
73 : #define RS_TOKEN_KEYWORD_2015(name, _) case name:
74 : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
75 : #define RS_TOKEN(a, b)
76 : RS_TOKEN_LIST return true;
77 : #undef RS_TOKEN_KEYWORD_2015
78 : #undef RS_TOKEN_KEYWORD_2018
79 : #undef RS_TOKEN
80 15819044 : default:
81 15819044 : return false;
82 : }
83 : }
84 :
85 : /* gets the string associated with a keyword */
86 : const std::string &
87 1347 : token_id_keyword_string (TokenId id)
88 : {
89 1347 : switch (id)
90 : {
91 : #define RS_TOKEN_KEYWORD_2015(id, str_ptr) \
92 : case id: \
93 : { \
94 : static const std::string str (str_ptr); \
95 : return str; \
96 : } \
97 : rust_unreachable ();
98 : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
99 : #define RS_TOKEN(a, b)
100 1347 : RS_TOKEN_LIST
101 : #undef RS_TOKEN_KEYWORD_2015
102 : #undef RS_TOKEN_KEYWORD_2018
103 : #undef RS_TOKEN
104 0 : default:
105 0 : rust_unreachable ();
106 : }
107 : }
108 :
109 : const char *
110 1911 : get_type_hint_string (PrimitiveCoreType type)
111 : {
112 1911 : switch (type)
113 : {
114 : case CORETYPE_BOOL:
115 : return "bool";
116 0 : case CORETYPE_CHAR:
117 0 : return "char";
118 0 : case CORETYPE_STR:
119 0 : return "str";
120 : // case CORETYPE_INT:
121 1 : case CORETYPE_ISIZE:
122 1 : return "isize";
123 : // case CORETYPE_UINT:
124 32 : case CORETYPE_USIZE:
125 32 : return "usize";
126 487 : case CORETYPE_F32:
127 487 : return "f32";
128 222 : case CORETYPE_F64:
129 222 : return "f64";
130 93 : case CORETYPE_I8:
131 93 : return "i8";
132 86 : case CORETYPE_I16:
133 86 : return "i16";
134 250 : case CORETYPE_I32:
135 250 : return "i32";
136 87 : case CORETYPE_I64:
137 87 : return "i64";
138 14 : case CORETYPE_I128:
139 14 : return "i128";
140 133 : case CORETYPE_U8:
141 133 : return "u8";
142 130 : case CORETYPE_U16:
143 130 : return "u16";
144 220 : case CORETYPE_U32:
145 220 : return "u32";
146 120 : case CORETYPE_U64:
147 120 : return "u64";
148 17 : case CORETYPE_U128:
149 17 : return "u128";
150 0 : case CORETYPE_PURE_DECIMAL:
151 0 : return "pure_decimal";
152 19 : case CORETYPE_UNKNOWN:
153 19 : default:
154 19 : return "unknown";
155 : }
156 : }
157 :
158 : const char *
159 1911 : Token::get_type_hint_str () const
160 : {
161 1911 : return get_type_hint_string (type_hint);
162 : }
163 :
164 : std::string
165 724928 : nfc_normalize_token_string (location_t loc, TokenId id, const std::string &str)
166 : {
167 724928 : if (id == IDENTIFIER || id == LIFETIME)
168 : {
169 610159 : tl::optional<Utf8String> ustring = Utf8String::make_utf8_string (str);
170 610159 : if (ustring.has_value ())
171 610159 : return ustring.value ().nfc_normalize ().as_string ();
172 : else
173 0 : rust_internal_error_at (loc,
174 : "identifier '%s' is not a valid UTF-8 string",
175 : str.c_str ());
176 610159 : }
177 : else
178 114769 : return str;
179 : }
180 :
181 : namespace {
182 : enum class Context
183 : {
184 : String,
185 : Char
186 : };
187 :
188 : const std::map<char, std::string> matches = {
189 : {'\t', "\\t"}, {'\n', "\\n"}, {'\r', "\\r"},
190 : {'\0', "\\0"}, {'\\', "\\\\"}, {'\v', "\\v"},
191 : };
192 :
193 : std::string
194 20402 : escape_special_chars (const std::string &source, Context ctx)
195 : {
196 20402 : std::stringstream stream;
197 20402 : decltype (matches)::const_iterator result;
198 260764 : for (char c : source)
199 : {
200 : // FIXME: #2411 Also replace escaped unicode values and \x digits
201 240362 : if ((result = matches.find (c)) != matches.end ())
202 2917 : stream << result->second;
203 237445 : else if (c == '\'' && ctx == Context::Char)
204 14 : stream << "\\'";
205 237431 : else if (c == '"' && ctx == Context::String)
206 22 : stream << "\\\"";
207 : else
208 237409 : stream << c;
209 : }
210 :
211 20402 : return stream.str ();
212 20402 : }
213 :
214 : } // namespace
215 :
216 : TokenPtr
217 548 : Token::make_identifier (const Identifier &ident)
218 : {
219 548 : std::string str = ident;
220 548 : return make_identifier (ident.get_locus (), std::move (str));
221 548 : }
222 :
223 : std::string
224 897219 : Token::as_string () const
225 : {
226 897219 : if (should_have_str ())
227 : {
228 278775 : switch (get_id ())
229 : {
230 19775 : case STRING_LITERAL:
231 39550 : return "\"" + escape_special_chars (get_str (), Context::String)
232 19775 : + "\"";
233 35 : case BYTE_STRING_LITERAL:
234 70 : return "b\"" + escape_special_chars (get_str (), Context::String)
235 35 : + "\"";
236 1 : case RAW_STRING_LITERAL:
237 2 : return "r\"" + escape_special_chars (get_str (), Context::String)
238 1 : + "\"";
239 183 : case CHAR_LITERAL:
240 366 : return "'" + escape_special_chars (get_str (), Context::Char) + "'";
241 408 : case BYTE_CHAR_LITERAL:
242 816 : return "b'" + escape_special_chars (get_str (), Context::Char) + "'";
243 9534 : case LIFETIME:
244 9534 : return "'" + get_str ();
245 0 : case SCOPE_RESOLUTION:
246 0 : return "::";
247 17589 : case INT_LITERAL:
248 17589 : if (get_type_hint () == CORETYPE_UNKNOWN)
249 15745 : return get_str ();
250 : else
251 : /* FIXME: This is a workaround for an overzealous -Wrestrict,
252 : #125404 - we should remove it once it is fixed
253 :
254 : return get_str () + get_type_hint_str ();
255 : */
256 : {
257 1844 : std::string s = get_str ();
258 1844 : s += get_type_hint_str ();
259 1844 : return s;
260 1844 : }
261 329 : case FLOAT_LITERAL:
262 329 : if (get_type_hint () == CORETYPE_UNKNOWN)
263 281 : return get_str ();
264 : else
265 : /* FIXME: This is a workaround for an overzealous -Wrestrict,
266 : #125404 - we should remove it once it is fixed
267 :
268 : return get_str () + get_type_hint_str ();
269 : */
270 : {
271 48 : std::string s = get_str ();
272 48 : s += get_type_hint_str ();
273 48 : return s;
274 48 : }
275 :
276 230921 : default:
277 230921 : return get_str ();
278 : }
279 : }
280 : else
281 : {
282 618444 : return get_token_description ();
283 : }
284 : }
285 : } // namespace Rust
|