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 : :
24 : : namespace Rust {
25 : : // Hackily defined way to get token description for enum value using x-macros
26 : : const char *
27 : 255851 : get_token_description (TokenId id)
28 : : {
29 : 255851 : switch (id)
30 : : {
31 : : #define RS_TOKEN(name, descr) \
32 : : case name: \
33 : : return descr;
34 : : #define RS_TOKEN_KEYWORD_2015(x, y) RS_TOKEN (x, y)
35 : : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
36 : 255851 : RS_TOKEN_LIST
37 : : #undef RS_TOKEN_KEYWORD_2015
38 : : #undef RS_TOKEN_KEYWORD_2018
39 : : #undef RS_TOKEN
40 : 0 : default:
41 : 0 : rust_unreachable ();
42 : : }
43 : : }
44 : :
45 : : /* Hackily defined way to get token description as a string for enum value using
46 : : * x-macros */
47 : : const char *
48 : 2 : token_id_to_str (TokenId id)
49 : : {
50 : 2 : switch (id)
51 : : {
52 : : #define RS_TOKEN(name, _) \
53 : : case name: \
54 : : return #name;
55 : : #define RS_TOKEN_KEYWORD_2015(x, y) RS_TOKEN (x, y)
56 : : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
57 : 2 : RS_TOKEN_LIST
58 : : #undef RS_TOKEN_KEYWORD_2015
59 : : #undef RS_TOKEN_KEYWORD_2018
60 : : #undef RS_TOKEN
61 : 0 : default:
62 : 0 : rust_unreachable ();
63 : : }
64 : : }
65 : :
66 : : /* checks if a token is a keyword */
67 : : bool
68 : 343757 : token_id_is_keyword (TokenId id)
69 : : {
70 : 343757 : switch (id)
71 : : {
72 : : #define RS_TOKEN_KEYWORD_2015(name, _) case name:
73 : : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
74 : : #define RS_TOKEN(a, b)
75 : : RS_TOKEN_LIST return true;
76 : : #undef RS_TOKEN_KEYWORD_2015
77 : : #undef RS_TOKEN_KEYWORD_2018
78 : : #undef RS_TOKEN
79 : 343739 : default:
80 : 343739 : return false;
81 : : }
82 : : }
83 : :
84 : : /* gets the string associated with a keyword */
85 : : const std::string &
86 : 10 : token_id_keyword_string (TokenId id)
87 : : {
88 : 10 : switch (id)
89 : : {
90 : : #define RS_TOKEN_KEYWORD_2015(id, str_ptr) \
91 : : case id: { \
92 : : static const std::string str (str_ptr); \
93 : : return str; \
94 : : } \
95 : : rust_unreachable ();
96 : : #define RS_TOKEN_KEYWORD_2018 RS_TOKEN_KEYWORD_2015
97 : : #define RS_TOKEN(a, b)
98 : 5126 : RS_TOKEN_LIST
99 : : #undef RS_TOKEN_KEYWORD_2015
100 : : #undef RS_TOKEN_KEYWORD_2018
101 : : #undef RS_TOKEN
102 : 0 : default:
103 : 0 : rust_unreachable ();
104 : : }
105 : : }
106 : :
107 : : const char *
108 : 92 : get_type_hint_string (PrimitiveCoreType type)
109 : : {
110 : 92 : switch (type)
111 : : {
112 : : case CORETYPE_BOOL:
113 : : return "bool";
114 : 0 : case CORETYPE_CHAR:
115 : 0 : return "char";
116 : 0 : case CORETYPE_STR:
117 : 0 : return "str";
118 : : // case CORETYPE_INT:
119 : 0 : case CORETYPE_ISIZE:
120 : 0 : return "isize";
121 : : // case CORETYPE_UINT:
122 : 36 : case CORETYPE_USIZE:
123 : 36 : return "usize";
124 : 48 : case CORETYPE_F32:
125 : 48 : return "f32";
126 : 0 : case CORETYPE_F64:
127 : 0 : return "f64";
128 : 0 : case CORETYPE_I8:
129 : 0 : return "i8";
130 : 0 : case CORETYPE_I16:
131 : 0 : return "i16";
132 : 2 : case CORETYPE_I32:
133 : 2 : return "i32";
134 : 0 : case CORETYPE_I64:
135 : 0 : return "i64";
136 : 0 : case CORETYPE_I128:
137 : 0 : return "i128";
138 : 2 : case CORETYPE_U8:
139 : 2 : return "u8";
140 : 4 : case CORETYPE_U16:
141 : 4 : return "u16";
142 : 0 : case CORETYPE_U32:
143 : 0 : return "u32";
144 : 0 : case CORETYPE_U64:
145 : 0 : return "u64";
146 : 0 : case CORETYPE_U128:
147 : 0 : return "u128";
148 : 0 : case CORETYPE_PURE_DECIMAL:
149 : 0 : return "pure_decimal";
150 : 0 : case CORETYPE_UNKNOWN:
151 : 0 : default:
152 : 0 : return "unknown";
153 : : }
154 : : }
155 : :
156 : : const char *
157 : 92 : Token::get_type_hint_str () const
158 : : {
159 : 92 : return get_type_hint_string (type_hint);
160 : : }
161 : :
162 : : std::string
163 : 191299 : nfc_normalize_token_string (location_t loc, TokenId id, const std::string &str)
164 : : {
165 : 191299 : if (id == IDENTIFIER || id == LIFETIME)
166 : : {
167 : 162868 : tl::optional<Utf8String> ustring = Utf8String::make_utf8_string (str);
168 : 162868 : if (ustring.has_value ())
169 : 162868 : return ustring.value ().nfc_normalize ().as_string ();
170 : : else
171 : 0 : rust_internal_error_at (loc,
172 : : "identifier '%s' is not a valid UTF-8 string",
173 : : str.c_str ());
174 : 162868 : }
175 : : else
176 : 28431 : return str;
177 : : }
178 : :
179 : : const std::string &
180 : 340471 : Token::get_str () const
181 : : {
182 : 340471 : if (token_id_is_keyword (token_id))
183 : 10 : return token_id_keyword_string (token_id);
184 : :
185 : : // FIXME: attempt to return null again
186 : : // gcc_assert(str != NULL);
187 : :
188 : : // HACK: allow referencing an empty string
189 : 345577 : static const std::string empty = "";
190 : :
191 : 340461 : if (str == NULL)
192 : : {
193 : 0 : rust_error_at (get_locus (),
194 : : "attempted to get string for %qs, which has no string. "
195 : : "returning empty string instead",
196 : : get_token_description ());
197 : 0 : return empty;
198 : : }
199 : : return *str;
200 : : }
201 : :
202 : : namespace {
203 : : enum class Context
204 : : {
205 : : String,
206 : : Char
207 : : };
208 : :
209 : : const std::map<char, std::string> matches = {
210 : : {'\t', "\\t"}, {'\n', "\\n"}, {'\r', "\\r"},
211 : : {'\0', "\\0"}, {'\\', "\\\\"}, {'\v', "\\v"},
212 : : };
213 : :
214 : : std::string
215 : 3366 : escape_special_chars (const std::string &source, Context ctx)
216 : : {
217 : 3366 : std::stringstream stream;
218 : 3366 : decltype (matches)::const_iterator result;
219 : 27627 : for (char c : source)
220 : : {
221 : : // FIXME: #2411 Also replace escaped unicode values and \x digits
222 : 24261 : if ((result = matches.find (c)) != matches.end ())
223 : 120 : stream << result->second;
224 : 24141 : else if (c == '\'' && ctx == Context::Char)
225 : 0 : stream << "\\'";
226 : 24141 : else if (c == '"' && ctx == Context::String)
227 : 16 : stream << "\\\"";
228 : : else
229 : 24125 : stream << c;
230 : : }
231 : :
232 : 3366 : return stream.str ();
233 : 3366 : }
234 : :
235 : : } // namespace
236 : :
237 : : std::string
238 : 78696 : Token::as_string () const
239 : : {
240 : 78696 : if (should_have_str ())
241 : : {
242 : 23271 : switch (get_id ())
243 : : {
244 : 3265 : case STRING_LITERAL:
245 : 6530 : return "\"" + escape_special_chars (get_str (), Context::String)
246 : 3265 : + "\"";
247 : 16 : case BYTE_STRING_LITERAL:
248 : 32 : return "b\"" + escape_special_chars (get_str (), Context::String)
249 : 16 : + "\"";
250 : 0 : case RAW_STRING_LITERAL:
251 : 0 : return "r\"" + escape_special_chars (get_str (), Context::String)
252 : 0 : + "\"";
253 : 56 : case CHAR_LITERAL:
254 : 112 : return "'" + escape_special_chars (get_str (), Context::Char) + "'";
255 : 29 : case BYTE_CHAR_LITERAL:
256 : 58 : return "b'" + escape_special_chars (get_str (), Context::Char) + "'";
257 : 921 : case LIFETIME:
258 : 921 : return "'" + get_str ();
259 : : case SCOPE_RESOLUTION:
260 : : return "::";
261 : 1632 : case INT_LITERAL:
262 : 1632 : if (get_type_hint () == CORETYPE_UNKNOWN)
263 : 1540 : return get_str ();
264 : : else
265 : 92 : return get_str () + get_type_hint_str ();
266 : 16 : case FLOAT_LITERAL:
267 : 16 : if (get_type_hint () == CORETYPE_UNKNOWN)
268 : 16 : return get_str ();
269 : : else
270 : 0 : return get_str () + get_type_hint_str ();
271 : 17336 : default:
272 : 17336 : return get_str ();
273 : : }
274 : : }
275 : : else
276 : : {
277 : 55425 : return get_token_description ();
278 : : }
279 : : }
280 : : } // namespace Rust
|