Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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 "optional.h"
26 : : #include "selftest.h"
27 : : #include "rust-input-source.h"
28 : :
29 : : namespace Rust {
30 : : // Simple wrapper for FILE* that simplifies destruction.
31 : : struct RAIIFile
32 : : {
33 : : private:
34 : : FILE *file;
35 : : const char *filename;
36 : :
37 : 11416 : void close ()
38 : : {
39 : 11416 : if (file != nullptr && file != stdin)
40 : 3783 : fclose (file);
41 : 11416 : }
42 : :
43 : 3789 : static bool allowed_filetype (const struct stat &statbuf)
44 : : {
45 : : // The file could be either
46 : : // - a regular file
47 : : // - a char device (/dev/null...)
48 : 3789 : return S_ISREG (statbuf.st_mode) || S_ISCHR (statbuf.st_mode);
49 : : }
50 : :
51 : : public:
52 : 3798 : RAIIFile (const char *filename) : filename (filename)
53 : : {
54 : 3798 : if (strcmp (filename, "-") == 0)
55 : : {
56 : 0 : file = stdin;
57 : : }
58 : : else
59 : : {
60 : 3798 : struct stat statbuf;
61 : 3798 : if (!(file = fopen (filename, "r")))
62 : : {
63 : 9 : return;
64 : : }
65 : :
66 : 3789 : if (-1 == fstat (fileno (file), &statbuf)
67 : 3789 : || !allowed_filetype (statbuf))
68 : : {
69 : 2 : fclose (file);
70 : 2 : file = nullptr;
71 : 2 : errno = EISDIR;
72 : : }
73 : : }
74 : : }
75 : :
76 : : /**
77 : : * Create a RAIIFile from an existing instance of FILE*
78 : : */
79 : 92 : RAIIFile (FILE *raw, const char *filename = nullptr)
80 : 92 : : file (raw), filename (filename)
81 : : {}
82 : :
83 : : RAIIFile (const RAIIFile &other) = delete;
84 : : RAIIFile &operator= (const RAIIFile &other) = delete;
85 : :
86 : : // have to specify setting file to nullptr, otherwise unintended fclose occurs
87 : 7534 : RAIIFile (RAIIFile &&other) : file (other.file), filename (other.filename)
88 : : {
89 : 7534 : other.file = nullptr;
90 : : }
91 : :
92 : : RAIIFile &operator= (RAIIFile &&other)
93 : : {
94 : : close ();
95 : : file = other.file;
96 : : filename = other.filename;
97 : : other.file = nullptr;
98 : :
99 : : return *this;
100 : : }
101 : :
102 : 92 : static RAIIFile create_error () { return RAIIFile (nullptr, nullptr); }
103 : :
104 : 11416 : ~RAIIFile () { close (); }
105 : :
106 : 3791 : FILE *get_raw () { return file; }
107 : 460 : const char *get_filename () { return filename; }
108 : :
109 : 3774 : bool ok () const { return file; }
110 : : };
111 : :
112 : : class Lexer
113 : : {
114 : : private:
115 : : // Request new Location for current column in line_table
116 : : location_t get_current_location ();
117 : :
118 : : // Skips the current input char.
119 : : void skip_input ();
120 : : // Advances current input char to n + 1 chars ahead of current position.
121 : : void skip_input (int n);
122 : :
123 : : // Peeks the current char.
124 : : Codepoint peek_input ();
125 : : // Returns char n bytes ahead of current position.
126 : : Codepoint peek_input (int n);
127 : :
128 : : // Classifies keyword (i.e. gets id for keyword).
129 : : TokenId classify_keyword (const std::string &str);
130 : :
131 : : std::tuple<std::string, int, bool> parse_in_decimal ();
132 : : std::pair<std::string, int> parse_in_exponent_part ();
133 : : std::pair<PrimitiveCoreType, int> parse_in_type_suffix ();
134 : : std::tuple<char, int, bool> parse_escape (char opening_char);
135 : : std::tuple<Codepoint, int, bool> parse_utf8_escape ();
136 : : int parse_partial_string_continue ();
137 : : std::pair<long, int> parse_partial_hex_escape ();
138 : : std::pair<Codepoint, int> parse_partial_unicode_escape ();
139 : :
140 : : void skip_broken_string_input (Codepoint current_char);
141 : :
142 : : TokenPtr parse_byte_char (location_t loc);
143 : : TokenPtr parse_byte_string (location_t loc);
144 : : TokenPtr parse_raw_byte_string (location_t loc);
145 : : TokenPtr parse_raw_identifier (location_t loc);
146 : : TokenPtr parse_string (location_t loc);
147 : : TokenPtr maybe_parse_raw_string (location_t loc);
148 : : TokenPtr parse_raw_string (location_t loc, int initial_hash_count);
149 : : TokenPtr parse_non_decimal_int_literals (location_t loc);
150 : : TokenPtr parse_decimal_int_or_float (location_t loc);
151 : : TokenPtr parse_char_or_lifetime (location_t loc);
152 : : TokenPtr parse_identifier_or_keyword (location_t loc);
153 : :
154 : : template <typename IsDigitFunc>
155 : : TokenPtr parse_non_decimal_int_literal (location_t loc,
156 : : IsDigitFunc is_digit_func,
157 : : std::string existent_str, int base);
158 : :
159 : : public:
160 : : // Construct lexer with input file and filename provided
161 : : Lexer (const char *filename, RAIIFile input, Linemap *linemap,
162 : 50 : tl::optional<std::ofstream &> dump_lex_opt = tl::nullopt);
163 : :
164 : : // Lex the contents of a string instead of a file
165 : : Lexer (const std::string &input, Linemap *linemap);
166 : :
167 : : // dtor
168 : : ~Lexer ();
169 : :
170 : : // don't allow copy semantics (for now, at least)
171 : : Lexer (const Lexer &other) = delete;
172 : : Lexer &operator= (const Lexer &other) = delete;
173 : :
174 : : // enable move semantics
175 : : Lexer (Lexer &&other) = default;
176 : : Lexer &operator= (Lexer &&other) = default;
177 : :
178 : : bool input_source_is_valid_utf8 ();
179 : :
180 : : // Returns token n tokens ahead of current position.
181 : 126571 : const_TokenPtr peek_token (int n) { return token_queue.peek (n); }
182 : : // Peeks the current token.
183 : 1638821 : const_TokenPtr peek_token () { return peek_token (0); }
184 : :
185 : : // Builds a token from the input queue.
186 : : TokenPtr build_token ();
187 : :
188 : : // Advances current token to n + 1 tokens ahead of current position.
189 : : void skip_token (int n);
190 : : // Skips the current token.
191 : 373455 : void skip_token () { skip_token (0); }
192 : :
193 : : // Dumps and advances by n + 1 tokens.
194 : : void dump_and_skip (int n);
195 : :
196 : : // Replaces the current token with a specified token.
197 : : void replace_current_token (TokenPtr replacement);
198 : : // FIXME: don't use anymore
199 : :
200 : : /* Splits the current token into two. Intended for use with nested generics
201 : : * closes (i.e. T<U<X>> where >> is wrongly lexed as one token). Note that
202 : : * this will only work with "simple" tokens like punctuation. */
203 : : void split_current_token (TokenId new_left, TokenId new_right);
204 : :
205 : : void split_current_token (std::vector<TokenPtr> new_tokens);
206 : :
207 : : Linemap *get_line_map () { return line_map; }
208 : 460 : 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 : : Codepoint 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 : : tl::optional<std::ofstream &> dump_lex_out;
231 : :
232 : : // The input source for the lexer.
233 : : // InputSource input_source;
234 : : // Input file queue.
235 : : std::unique_ptr<InputSource> raw_input_source;
236 : : buffered_queue<Codepoint, std::reference_wrapper<InputSource>> input_queue;
237 : :
238 : : // Token source wrapper thing.
239 : : struct TokenSource
240 : : {
241 : : // The lexer object that will use this TokenSource.
242 : : Lexer *lexer;
243 : :
244 : : // Create a new TokenSource with given lexer.
245 : 3767 : TokenSource (Lexer *parLexer) : lexer (parLexer) {}
246 : :
247 : : // Used to mimic std::reference_wrapper that is used for InputSource.
248 : : TokenSource &get () { return *this; }
249 : :
250 : : // Overload operator () to build token in lexer.
251 : 380052 : TokenPtr next () { return lexer->build_token (); }
252 : : };
253 : :
254 : : // The token source for the lexer.
255 : : // TokenSource token_source;
256 : : // Token stream queue.
257 : : buffered_queue<std::shared_ptr<Token>, TokenSource> token_queue;
258 : : };
259 : :
260 : : } // namespace Rust
261 : :
262 : : #if CHECKING_P
263 : :
264 : : namespace selftest {
265 : : void
266 : : rust_input_source_test ();
267 : :
268 : : } // namespace selftest
269 : :
270 : : #endif // CHECKING_P
271 : :
272 : : #endif
|