Line data Source code
1 : // Copyright (C) 2025-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 : /* DO NOT INCLUDE ANYWHERE - this is automatically included
20 : * by rust-parse-impl.h
21 : * This is also the reason why there are no include guards. */
22 :
23 : #include "rust-parse.h"
24 :
25 : namespace Rust {
26 :
27 : // "Unexpected token" panic mode - flags gcc error at unexpected token
28 : // TODO: seems to be unused, remove?
29 : template <typename ManagedTokenSource>
30 : void
31 0 : Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
32 : {
33 0 : Error error (t->get_locus (), "unexpected token %qs",
34 : t->get_token_description ());
35 0 : add_error (std::move (error));
36 0 : }
37 :
38 : /* Crappy "error recovery" performed after error by skipping tokens until a
39 : * semi-colon is found */
40 : template <typename ManagedTokenSource>
41 : void
42 25 : Parser<ManagedTokenSource>::skip_after_semicolon ()
43 : {
44 25 : const_TokenPtr t = lexer.peek_token ();
45 :
46 34 : while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
47 : {
48 9 : lexer.skip_token ();
49 9 : t = lexer.peek_token ();
50 : }
51 :
52 25 : if (t->get_id () == SEMICOLON)
53 4 : lexer.skip_token ();
54 25 : }
55 :
56 : /* Skips the current token */
57 : template <typename ManagedTokenSource>
58 : void
59 5562 : Parser<ManagedTokenSource>::skip_token ()
60 : {
61 1534 : lexer.skip_token ();
62 1369 : }
63 :
64 : /* Checks if current token has inputted id - skips it and returns true if so,
65 : * diagnoses an error and returns false otherwise. */
66 : template <typename ManagedTokenSource>
67 : bool
68 296567 : Parser<ManagedTokenSource>::skip_token (TokenId token_id)
69 : {
70 296567 : return expect_token (token_id) != const_TokenPtr ();
71 : }
72 :
73 : /* Checks if current token is similar to inputted token - skips it and returns
74 : * true if so, diagnoses an error and returns false otherwise. */
75 : template <typename ManagedTokenSource>
76 : bool
77 2692 : Parser<ManagedTokenSource>::skip_token (const_TokenPtr token)
78 : {
79 8019 : return expect_token (token) != const_TokenPtr ();
80 : }
81 :
82 : /* Checks if current token has inputted id - skips it and returns true if so,
83 : * returns false otherwise without diagnosing an error */
84 : template <typename ManagedTokenSource>
85 : bool
86 47112 : Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
87 : {
88 94224 : if (lexer.peek_token ()->get_id () != token_id)
89 : return false;
90 : else
91 1101 : return skip_token (token_id);
92 : }
93 :
94 : /* Checks the current token - if id is same as expected, skips and returns it,
95 : * otherwise diagnoses error and returns null. */
96 : template <typename ManagedTokenSource>
97 : const_TokenPtr
98 334794 : Parser<ManagedTokenSource>::expect_token (TokenId token_id)
99 : {
100 334794 : const_TokenPtr t = lexer.peek_token ();
101 334794 : if (t->get_id () == token_id)
102 : {
103 333108 : lexer.skip_token ();
104 333108 : return t;
105 : }
106 : else
107 : {
108 1686 : Error error (t->get_locus (), "expecting %qs but %qs found",
109 : get_token_description (token_id),
110 : t->get_token_description ());
111 1686 : add_error (std::move (error));
112 :
113 1686 : return const_TokenPtr ();
114 1686 : }
115 334794 : }
116 :
117 : /* Checks the current token - if same as expected, skips and returns it,
118 : * otherwise diagnoses error and returns null. */
119 : template <typename ManagedTokenSource>
120 : const_TokenPtr
121 2692 : Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect)
122 : {
123 2692 : const_TokenPtr t = lexer.peek_token ();
124 2692 : if (t->get_id () == token_expect->get_id ()
125 2692 : && (!t->should_have_str () || t->get_str () == token_expect->get_str ()))
126 : {
127 2635 : lexer.skip_token ();
128 2635 : return t;
129 : }
130 : else
131 : {
132 57 : Error error (t->get_locus (), "expecting %qs but %qs found",
133 : token_expect->get_token_description (),
134 : t->get_token_description ());
135 57 : add_error (std::move (error));
136 :
137 57 : return const_TokenPtr ();
138 57 : }
139 2692 : }
140 :
141 : // Skips all tokens until EOF or }. Don't use.
142 : template <typename ManagedTokenSource>
143 : void
144 0 : Parser<ManagedTokenSource>::skip_after_end ()
145 : {
146 0 : const_TokenPtr t = lexer.peek_token ();
147 :
148 0 : while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
149 : {
150 0 : lexer.skip_token ();
151 0 : t = lexer.peek_token ();
152 : }
153 :
154 0 : if (t->get_id () == RIGHT_CURLY)
155 : {
156 0 : lexer.skip_token ();
157 : }
158 0 : }
159 :
160 : /* A slightly more aware error-handler that skips all tokens until it reaches
161 : * the end of the block scope (i.e. when left curly brackets = right curly
162 : * brackets). Note: assumes currently in the middle of a block. Use
163 : * skip_after_next_block to skip based on the assumption that the block
164 : * has not been entered yet. */
165 : template <typename ManagedTokenSource>
166 : void
167 34 : Parser<ManagedTokenSource>::skip_after_end_block ()
168 : {
169 34 : const_TokenPtr t = lexer.peek_token ();
170 34 : int curly_count = 1;
171 :
172 112 : while (curly_count > 0 && t->get_id () != END_OF_FILE)
173 : {
174 78 : switch (t->get_id ())
175 : {
176 6 : case LEFT_CURLY:
177 6 : curly_count++;
178 6 : break;
179 18 : case RIGHT_CURLY:
180 18 : curly_count--;
181 18 : break;
182 : default:
183 : break;
184 : }
185 78 : lexer.skip_token ();
186 78 : t = lexer.peek_token ();
187 : }
188 34 : }
189 :
190 : /* Skips tokens until the end of the next block. i.e. assumes that the block
191 : * has not been entered yet. */
192 : template <typename ManagedTokenSource>
193 : void
194 1 : Parser<ManagedTokenSource>::skip_after_next_block ()
195 : {
196 1 : const_TokenPtr t = lexer.peek_token ();
197 :
198 : // initial loop - skip until EOF if no left curlies encountered
199 1 : while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
200 : {
201 0 : lexer.skip_token ();
202 :
203 0 : t = lexer.peek_token ();
204 : }
205 :
206 : // if next token is left, skip it and then skip after the block ends
207 1 : if (t->get_id () == LEFT_CURLY)
208 : {
209 1 : lexer.skip_token ();
210 :
211 1 : skip_after_end_block ();
212 : }
213 : // otherwise, do nothing as EOF
214 1 : }
215 :
216 : /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
217 : * (as designed for attribute body use) */
218 : template <typename ManagedTokenSource>
219 : void
220 0 : Parser<ManagedTokenSource>::skip_after_end_attribute ()
221 : {
222 0 : const_TokenPtr t = lexer.peek_token ();
223 :
224 0 : while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE)
225 : {
226 0 : lexer.skip_token ();
227 0 : t = lexer.peek_token ();
228 : }
229 :
230 : // Don't skip the RIGHT_SQUARE token
231 0 : }
232 :
233 : // Returns true if the next token is END, ELSE, or EOF;
234 : template <typename ManagedTokenSource>
235 : bool
236 0 : Parser<ManagedTokenSource>::done_end_or_else ()
237 : {
238 0 : const_TokenPtr t = lexer.peek_token ();
239 0 : return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
240 0 : || t->get_id () == END_OF_FILE);
241 0 : }
242 :
243 : // Returns true if the next token is END or EOF.
244 : template <typename ManagedTokenSource>
245 : bool
246 0 : Parser<ManagedTokenSource>::done_end ()
247 : {
248 0 : const_TokenPtr t = lexer.peek_token ();
249 0 : return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
250 0 : }
251 :
252 : } // namespace Rust
|