Branch data Line data Source code
1 : : // Copyright (C) 2020-2023 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 : : #ifndef RUST_LEX_H
20 : : #define RUST_LEX_H
21 : :
22 : : #include "rust-linemap.h"
23 : : #include "rust-buffered-queue.h"
24 : : #include "rust-token.h"
25 : : #include "rust-optional.h"
26 : :
27 : : namespace Rust {
28 : : // Simple wrapper for FILE* that simplifies destruction.
29 : : struct RAIIFile
30 : : {
31 : : private:
32 : : FILE *file;
33 : : const char *filename;
34 : :
35 : 9958 : void close ()
36 : : {
37 : 9958 : if (file != nullptr && file != stdin)
38 : 3296 : fclose (file);
39 : 9958 : }
40 : :
41 : 3299 : static bool allowed_filetype (const struct stat &statbuf)
42 : : {
43 : : // The file could be either
44 : : // - a regular file
45 : : // - a char device (/dev/null...)
46 : 3299 : return S_ISREG (statbuf.st_mode) || S_ISCHR (statbuf.st_mode);
47 : : }
48 : :
49 : : public:
50 : 3306 : RAIIFile (const char *filename) : filename (filename)
51 : : {
52 : 3306 : if (strcmp (filename, "-") == 0)
53 : : {
54 : 0 : file = stdin;
55 : : }
56 : : else
57 : : {
58 : 3306 : struct stat statbuf;
59 : 3306 : if (!(file = fopen (filename, "r")))
60 : : {
61 : 7 : return;
62 : : }
63 : :
64 : 3299 : if (-1 == fstat (fileno (file), &statbuf)
65 : 3299 : || !allowed_filetype (statbuf))
66 : : {
67 : 2 : fclose (file);
68 : 2 : file = nullptr;
69 : 2 : errno = EISDIR;
70 : : }
71 : : }
72 : : }
73 : :
74 : : /**
75 : : * Create a RAIIFile from an existing instance of FILE*
76 : : */
77 : 98 : RAIIFile (FILE *raw, const char *filename = nullptr)
78 : 98 : : file (raw), filename (filename)
79 : : {}
80 : :
81 : : RAIIFile (const RAIIFile &other) = delete;
82 : : RAIIFile &operator= (const RAIIFile &other) = delete;
83 : :
84 : : // have to specify setting file to nullptr, otherwise unintended fclose occurs
85 : 6556 : RAIIFile (RAIIFile &&other) : file (other.file), filename (other.filename)
86 : : {
87 : 6556 : other.file = nullptr;
88 : : }
89 : :
90 : : RAIIFile &operator= (RAIIFile &&other)
91 : : {
92 : : close ();
93 : : file = other.file;
94 : : filename = other.filename;
95 : : other.file = nullptr;
96 : :
97 : : return *this;
98 : : }
99 : :
100 : 98 : static RAIIFile create_error () { return RAIIFile (nullptr, nullptr); }
101 : :
102 : 9958 : ~RAIIFile () { close (); }
103 : :
104 : 3299 : FILE *get_raw () { return file; }
105 : 63 : const char *get_filename () { return filename; }
106 : :
107 : 3285 : bool ok () const { return file; }
108 : : };
109 : :
110 : : class Lexer
111 : : {
112 : : private:
113 : : // Request new Location for current column in line_table
114 : : Location get_current_location ();
115 : :
116 : : // Skips the current input char.
117 : : void skip_input ();
118 : : // Advances current input char to n + 1 chars ahead of current position.
119 : : void skip_input (int n);
120 : :
121 : : // Returns char n chars ahead of current position.
122 : : int peek_input ();
123 : : // Peeks the current char.
124 : : int peek_input (int n);
125 : :
126 : : // Classifies keyword (i.e. gets id for keyword).
127 : : TokenId classify_keyword (const std::string &str);
128 : :
129 : : // Builds a token from the input queue.
130 : : TokenPtr build_token ();
131 : :
132 : : std::tuple<std::string, int, bool> parse_in_decimal ();
133 : : std::pair<std::string, int> parse_in_exponent_part ();
134 : : std::pair<PrimitiveCoreType, int> parse_in_type_suffix ();
135 : : std::tuple<char, int, bool> parse_escape (char opening_char);
136 : : std::tuple<Codepoint, int, bool> parse_utf8_escape ();
137 : : int parse_partial_string_continue ();
138 : : std::pair<long, int> parse_partial_hex_escape ();
139 : : std::pair<Codepoint, int> parse_partial_unicode_escape ();
140 : :
141 : : int get_input_codepoint_length ();
142 : : int test_get_input_codepoint_n_length (int n_start_offset);
143 : : Codepoint peek_codepoint_input ();
144 : : Codepoint test_peek_codepoint_input (int n);
145 : : void skip_codepoint_input ();
146 : : void skip_broken_string_input (int current_char);
147 : :
148 : : TokenPtr parse_byte_char (Location loc);
149 : : TokenPtr parse_byte_string (Location loc);
150 : : TokenPtr parse_raw_byte_string (Location loc);
151 : : TokenPtr parse_raw_identifier (Location loc);
152 : : TokenPtr parse_string (Location loc);
153 : : TokenPtr maybe_parse_raw_string (Location loc);
154 : : TokenPtr parse_raw_string (Location loc, int initial_hash_count);
155 : : TokenPtr parse_non_decimal_int_literals (Location loc);
156 : : TokenPtr parse_decimal_int_or_float (Location loc);
157 : : TokenPtr parse_char_or_lifetime (Location loc);
158 : : TokenPtr parse_identifier_or_keyword (Location loc);
159 : :
160 : : template <typename IsDigitFunc>
161 : : TokenPtr parse_non_decimal_int_literal (Location loc,
162 : : IsDigitFunc is_digit_func,
163 : : std::string existent_str, int base);
164 : :
165 : : public:
166 : : // Construct lexer with input file and filename provided
167 : : Lexer (const char *filename, RAIIFile input, Linemap *linemap,
168 : : Optional<std::ofstream &> dump_lex_opt
169 : : = Optional<std::ofstream &>::none ());
170 : :
171 : : // Lex the contents of a string instead of a file
172 : : Lexer (const std::string &input);
173 : :
174 : : // dtor
175 : : ~Lexer ();
176 : :
177 : : // don't allow copy semantics (for now, at least)
178 : : Lexer (const Lexer &other) = delete;
179 : : Lexer &operator= (const Lexer &other) = delete;
180 : :
181 : : // enable move semantics
182 : : Lexer (Lexer &&other) = default;
183 : : Lexer &operator= (Lexer &&other) = default;
184 : :
185 : : // Returns token n tokens ahead of current position.
186 : 46645 : const_TokenPtr peek_token (int n) { return token_queue.peek (n); }
187 : : // Peeks the current token.
188 : 1282784 : const_TokenPtr peek_token () { return peek_token (0); }
189 : :
190 : : // Advances current token to n + 1 tokens ahead of current position.
191 : : void skip_token (int n);
192 : : // Skips the current token.
193 : 303703 : void skip_token () { skip_token (0); }
194 : :
195 : : // Dumps and advances by n + 1 tokens.
196 : : void dump_and_skip (int n);
197 : :
198 : : // Replaces the current token with a specified token.
199 : : void replace_current_token (TokenPtr replacement);
200 : : // FIXME: don't use anymore
201 : :
202 : : /* Splits the current token into two. Intended for use with nested generics
203 : : * closes (i.e. T<U<X>> where >> is wrongly lexed as one token). Note that
204 : : * this will only work with "simple" tokens like punctuation. */
205 : : void split_current_token (TokenId new_left, TokenId new_right);
206 : :
207 : 0 : Linemap *get_line_map () { return line_map; }
208 : 63 : std::string get_filename () { return std::string (input.get_filename ()); }
209 : :
210 : : private:
211 : : void start_line (int current_line, int current_column);
212 : :
213 : : // File for use as input.
214 : : RAIIFile input;
215 : : // TODO is this actually required? could just have file storage in InputSource
216 : :
217 : : // Current line number.
218 : : int current_line;
219 : : // Current column number.
220 : : int current_column;
221 : : // Current character.
222 : : int current_char;
223 : : // Line map.
224 : : Linemap *line_map;
225 : :
226 : : /* Max column number that can be quickly allocated - higher may require
227 : : * allocating new linemap */
228 : : static const int max_column_hint = 80;
229 : :
230 : : Optional<std::ofstream &> dump_lex_out;
231 : :
232 : : // Input source wrapper thing.
233 : 3376 : class InputSource
234 : : {
235 : : public:
236 : : virtual ~InputSource () {}
237 : :
238 : : // Overload operator () to return next char from input stream.
239 : : virtual int next () = 0;
240 : : };
241 : :
242 : : class FileInputSource : public InputSource
243 : : {
244 : : private:
245 : : // Input source file.
246 : : FILE *input;
247 : :
248 : : public:
249 : : // Create new input source from file.
250 : 3278 : FileInputSource (FILE *input) : input (input) {}
251 : :
252 : 1331497 : int next () override { return fgetc (input); }
253 : : };
254 : :
255 : : class BufferInputSource : public InputSource
256 : : {
257 : : private:
258 : : const std::string &buffer;
259 : : size_t offs;
260 : :
261 : : public:
262 : : // Create new input source from file.
263 : 98 : BufferInputSource (const std::string &b, size_t offset)
264 : 98 : : buffer (b), offs (offset)
265 : : {}
266 : :
267 : 1959 : int next () override
268 : : {
269 : 1959 : if (offs >= buffer.size ())
270 : : return EOF;
271 : :
272 : 1863 : return buffer.at (offs++);
273 : : }
274 : : };
275 : :
276 : : // The input source for the lexer.
277 : : // InputSource input_source;
278 : : // Input file queue.
279 : : std::unique_ptr<InputSource> raw_input_source;
280 : : buffered_queue<int, InputSource &> input_queue;
281 : :
282 : : // Token source wrapper thing.
283 : : struct TokenSource
284 : : {
285 : : // The lexer object that will use this TokenSource.
286 : : Lexer *lexer;
287 : :
288 : : // Create a new TokenSource with given lexer.
289 : 3278 : TokenSource (Lexer *parLexer) : lexer (parLexer) {}
290 : :
291 : : // Overload operator () to build token in lexer.
292 : 309477 : TokenPtr next () { return lexer->build_token (); }
293 : : };
294 : :
295 : : // The token source for the lexer.
296 : : // TokenSource token_source;
297 : : // Token stream queue.
298 : : buffered_queue<std::shared_ptr<Token>, TokenSource> token_queue;
299 : : };
300 : :
301 : : } // namespace Rust
302 : :
303 : : #endif
|