Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 253908 : get_token_description (TokenId id)
29 : : {
30 : 253908 : 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 : 253908 : 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 : 1 : token_id_to_str (TokenId id)
50 : : {
51 : 1 : 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 : 1 : 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 : 372086 : token_id_is_keyword (TokenId id)
70 : : {
71 : 372086 : 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 : 372074 : default:
81 : 372074 : return false;
82 : : }
83 : : }
84 : :
85 : : /* gets the string associated with a keyword */
86 : : const std::string &
87 : 7 : token_id_keyword_string (TokenId id)
88 : : {
89 : 7 : 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 : 4407 : 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 : 80 : get_type_hint_string (PrimitiveCoreType type)
111 : : {
112 : 80 : 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 : 0 : case CORETYPE_ISIZE:
122 : 0 : return "isize";
123 : : // case CORETYPE_UINT:
124 : 32 : case CORETYPE_USIZE:
125 : 32 : return "usize";
126 : 42 : case CORETYPE_F32:
127 : 42 : return "f32";
128 : 0 : case CORETYPE_F64:
129 : 0 : return "f64";
130 : 0 : case CORETYPE_I8:
131 : 0 : return "i8";
132 : 0 : case CORETYPE_I16:
133 : 0 : return "i16";
134 : 1 : case CORETYPE_I32:
135 : 1 : return "i32";
136 : 0 : case CORETYPE_I64:
137 : 0 : return "i64";
138 : 0 : case CORETYPE_I128:
139 : 0 : return "i128";
140 : 2 : case CORETYPE_U8:
141 : 2 : return "u8";
142 : 2 : case CORETYPE_U16:
143 : 2 : return "u16";
144 : 1 : case CORETYPE_U32:
145 : 1 : return "u32";
146 : 0 : case CORETYPE_U64:
147 : 0 : return "u64";
148 : 0 : case CORETYPE_U128:
149 : 0 : return "u128";
150 : 0 : case CORETYPE_PURE_DECIMAL:
151 : 0 : return "pure_decimal";
152 : 0 : case CORETYPE_UNKNOWN:
153 : 0 : default:
154 : 0 : return "unknown";
155 : : }
156 : : }
157 : :
158 : : const char *
159 : 80 : Token::get_type_hint_str () const
160 : : {
161 : 80 : return get_type_hint_string (type_hint);
162 : : }
163 : :
164 : : std::string
165 : 223486 : nfc_normalize_token_string (location_t loc, TokenId id, const std::string &str)
166 : : {
167 : 223486 : if (id == IDENTIFIER || id == LIFETIME)
168 : : {
169 : 183725 : tl::optional<Utf8String> ustring = Utf8String::make_utf8_string (str);
170 : 183725 : if (ustring.has_value ())
171 : 183725 : 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 : 183725 : }
177 : : else
178 : 39761 : return str;
179 : : }
180 : :
181 : : const std::string &
182 : 370030 : Token::get_str () const
183 : : {
184 : 370030 : if (token_id_is_keyword (token_id))
185 : 7 : return token_id_keyword_string (token_id);
186 : :
187 : : // FIXME: attempt to return null again
188 : : // gcc_assert(str != NULL);
189 : :
190 : : // HACK: allow referencing an empty string
191 : 374423 : static const std::string empty = "";
192 : :
193 : 370023 : if (str == NULL)
194 : : {
195 : 0 : rust_error_at (get_locus (),
196 : : "attempted to get string for %qs, which has no string. "
197 : : "returning empty string instead",
198 : : get_token_description ());
199 : 0 : return empty;
200 : : }
201 : : return *str;
202 : : }
203 : :
204 : : namespace {
205 : : enum class Context
206 : : {
207 : : String,
208 : : Char
209 : : };
210 : :
211 : : const std::map<char, std::string> matches = {
212 : : {'\t', "\\t"}, {'\n', "\\n"}, {'\r', "\\r"},
213 : : {'\0', "\\0"}, {'\\', "\\\\"}, {'\v', "\\v"},
214 : : };
215 : :
216 : : std::string
217 : 3036 : escape_special_chars (const std::string &source, Context ctx)
218 : : {
219 : 3036 : std::stringstream stream;
220 : 3036 : decltype (matches)::const_iterator result;
221 : 25531 : for (char c : source)
222 : : {
223 : : // FIXME: #2411 Also replace escaped unicode values and \x digits
224 : 22495 : if ((result = matches.find (c)) != matches.end ())
225 : 116 : stream << result->second;
226 : 22379 : else if (c == '\'' && ctx == Context::Char)
227 : 0 : stream << "\\'";
228 : 22379 : else if (c == '"' && ctx == Context::String)
229 : 16 : stream << "\\\"";
230 : : else
231 : 22363 : stream << c;
232 : : }
233 : :
234 : 3036 : return stream.str ();
235 : 3036 : }
236 : :
237 : : } // namespace
238 : :
239 : : TokenPtr
240 : 0 : Token::make_identifier (const Identifier &ident)
241 : : {
242 : 0 : std::string str = ident;
243 : 0 : return make_identifier (ident.get_locus (), std::move (str));
244 : 0 : }
245 : :
246 : : std::string
247 : 72871 : Token::as_string () const
248 : : {
249 : 72871 : if (should_have_str ())
250 : : {
251 : 21749 : switch (get_id ())
252 : : {
253 : 2945 : case STRING_LITERAL:
254 : 5890 : return "\"" + escape_special_chars (get_str (), Context::String)
255 : 2945 : + "\"";
256 : 14 : case BYTE_STRING_LITERAL:
257 : 28 : return "b\"" + escape_special_chars (get_str (), Context::String)
258 : 14 : + "\"";
259 : 0 : case RAW_STRING_LITERAL:
260 : 0 : return "r\"" + escape_special_chars (get_str (), Context::String)
261 : 0 : + "\"";
262 : 49 : case CHAR_LITERAL:
263 : 98 : return "'" + escape_special_chars (get_str (), Context::Char) + "'";
264 : 28 : case BYTE_CHAR_LITERAL:
265 : 56 : return "b'" + escape_special_chars (get_str (), Context::Char) + "'";
266 : 937 : case LIFETIME:
267 : 937 : return "'" + get_str ();
268 : : case SCOPE_RESOLUTION:
269 : : return "::";
270 : 1456 : case INT_LITERAL:
271 : 1456 : if (get_type_hint () == CORETYPE_UNKNOWN)
272 : 1376 : return get_str ();
273 : : else
274 : 80 : return get_str () + get_type_hint_str ();
275 : 16 : case FLOAT_LITERAL:
276 : 16 : if (get_type_hint () == CORETYPE_UNKNOWN)
277 : 16 : return get_str ();
278 : : else
279 : 0 : return get_str () + get_type_hint_str ();
280 : 16304 : default:
281 : 16304 : return get_str ();
282 : : }
283 : : }
284 : : else
285 : : {
286 : 51122 : return get_token_description ();
287 : : }
288 : : }
289 : : } // namespace Rust
|