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 : : /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before
20 : : * Parser was template). Separated from rust-parse.h for readability. */
21 : :
22 : : /* DO NOT INCLUDE ANYWHERE - this is automatically included
23 : : * by rust-parse-impl-*.cc
24 : : * This is also the reason why there are no include guards. */
25 : :
26 : : #include "expected.h"
27 : : #include "rust-ast.h"
28 : : #include "rust-common.h"
29 : : #include "rust-expr.h"
30 : : #include "rust-item.h"
31 : : #include "rust-common.h"
32 : : #include "rust-parse.h"
33 : : #include "rust-token.h"
34 : : #define INCLUDE_ALGORITHM
35 : : #include "rust-diagnostics.h"
36 : : #include "rust-dir-owner.h"
37 : : #include "rust-attribute-values.h"
38 : : #include "rust-keyword-values.h"
39 : : #include "rust-edition.h"
40 : :
41 : : #include "optional.h"
42 : :
43 : : namespace Rust {
44 : : // Left binding powers of operations.
45 : : enum binding_powers
46 : : {
47 : : // Highest priority
48 : : LBP_HIGHEST = 100,
49 : :
50 : : LBP_PATH = 95,
51 : :
52 : : LBP_METHOD_CALL = 90,
53 : :
54 : : LBP_FIELD_EXPR = 85,
55 : :
56 : : LBP_FUNCTION_CALL = 80,
57 : : LBP_ARRAY_REF = LBP_FUNCTION_CALL,
58 : :
59 : : LBP_QUESTION_MARK = 75, // unary postfix - counts as left
60 : :
61 : : LBP_UNARY_PLUS = 70, // Used only when the null denotation is +
62 : : LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is -
63 : : LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix
64 : : LBP_UNARY_EXCLAM = LBP_UNARY_PLUS,
65 : : LBP_UNARY_AMP = LBP_UNARY_PLUS,
66 : : LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS,
67 : :
68 : : LBP_AS = 65,
69 : :
70 : : LBP_MUL = 60,
71 : : LBP_DIV = LBP_MUL,
72 : : LBP_MOD = LBP_MUL,
73 : :
74 : : LBP_PLUS = 55,
75 : : LBP_MINUS = LBP_PLUS,
76 : :
77 : : LBP_L_SHIFT = 50,
78 : : LBP_R_SHIFT = LBP_L_SHIFT,
79 : :
80 : : LBP_AMP = 45,
81 : :
82 : : LBP_CARET = 40,
83 : :
84 : : LBP_PIPE = 35,
85 : :
86 : : LBP_EQUAL = 30,
87 : : LBP_NOT_EQUAL = LBP_EQUAL,
88 : : LBP_SMALLER_THAN = LBP_EQUAL,
89 : : LBP_SMALLER_EQUAL = LBP_EQUAL,
90 : : LBP_GREATER_THAN = LBP_EQUAL,
91 : : LBP_GREATER_EQUAL = LBP_EQUAL,
92 : :
93 : : LBP_LOGICAL_AND = 25,
94 : :
95 : : LBP_LOGICAL_OR = 20,
96 : :
97 : : LBP_DOT_DOT = 15,
98 : : LBP_DOT_DOT_EQ = LBP_DOT_DOT,
99 : :
100 : : // TODO: note all these assig operators are RIGHT associative!
101 : : LBP_ASSIG = 10,
102 : : LBP_PLUS_ASSIG = LBP_ASSIG,
103 : : LBP_MINUS_ASSIG = LBP_ASSIG,
104 : : LBP_MULT_ASSIG = LBP_ASSIG,
105 : : LBP_DIV_ASSIG = LBP_ASSIG,
106 : : LBP_MOD_ASSIG = LBP_ASSIG,
107 : : LBP_AMP_ASSIG = LBP_ASSIG,
108 : : LBP_PIPE_ASSIG = LBP_ASSIG,
109 : : LBP_CARET_ASSIG = LBP_ASSIG,
110 : : LBP_L_SHIFT_ASSIG = LBP_ASSIG,
111 : : LBP_R_SHIFT_ASSIG = LBP_ASSIG,
112 : :
113 : : // return, break, and closures as lowest priority?
114 : : LBP_RETURN = 5,
115 : : LBP_BREAK = LBP_RETURN,
116 : : LBP_CLOSURE = LBP_RETURN, // unary prefix operators
117 : :
118 : : #if 0
119 : : // rust precedences
120 : : // used for closures
121 : : PREC_CLOSURE = -40,
122 : : // used for break, continue, return, and yield
123 : : PREC_JUMP = -30,
124 : : // used for range (although weird comment in rustc about this)
125 : : PREC_RANGE = -10,
126 : : // used for binary operators mentioned below - also cast, colon (type),
127 : : // assign, assign_op
128 : : PREC_BINOP = FROM_ASSOC_OP,
129 : : // used for box, address_of, let, unary (again, weird comment on let)
130 : : PREC_PREFIX = 50,
131 : : // used for await, call, method call, field, index, try,
132 : : // inline asm, macro invocation
133 : : PREC_POSTFIX = 60,
134 : : // used for array, repeat, tuple, literal, path, paren, if,
135 : : // while, for, 'loop', match, block, try block, async, struct
136 : : PREC_PAREN = 99,
137 : : PREC_FORCE_PAREN = 100,
138 : : #endif
139 : :
140 : : // lowest priority
141 : : LBP_LOWEST = 0
142 : : };
143 : :
144 : : /* Returns whether the token can start a type (i.e. there is a valid type
145 : : * beginning with the token). */
146 : : inline bool
147 : 815 : can_tok_start_type (TokenId id)
148 : : {
149 : 815 : switch (id)
150 : : {
151 : : case EXCLAM:
152 : : case LEFT_SQUARE:
153 : : case LEFT_ANGLE:
154 : : case UNDERSCORE:
155 : : case ASTERISK:
156 : : case AMP:
157 : : case LIFETIME:
158 : : case IDENTIFIER:
159 : : case SUPER:
160 : : case SELF:
161 : : case SELF_ALIAS:
162 : : case CRATE:
163 : : case DOLLAR_SIGN:
164 : : case SCOPE_RESOLUTION:
165 : : case LEFT_PAREN:
166 : : case FOR:
167 : : case ASYNC:
168 : : case CONST:
169 : : case UNSAFE:
170 : : case EXTERN_KW:
171 : : case FN_KW:
172 : : case IMPL:
173 : : case DYN:
174 : : case QUESTION_MARK:
175 : : return true;
176 : 395 : default:
177 : 395 : return false;
178 : : }
179 : : }
180 : :
181 : : /* Returns whether the token id is (or is likely to be) a right angle bracket.
182 : : * i.e. '>', '>>', '>=' and '>>=' tokens. */
183 : : inline bool
184 : 79979 : is_right_angle_tok (TokenId id)
185 : : {
186 : 79979 : switch (id)
187 : : {
188 : : case RIGHT_ANGLE:
189 : : case RIGHT_SHIFT:
190 : : case GREATER_OR_EQUAL:
191 : : case RIGHT_SHIFT_EQ:
192 : : return true;
193 : 52469 : default:
194 : 13026 : return false;
195 : : }
196 : : }
197 : :
198 : : /* HACK-y special handling for skipping a right angle token at the end of
199 : : * generic arguments.
200 : : * Currently, this replaces the "current token" with one that is identical
201 : : * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
202 : : * for several reasons - it modifies the token stream to something that
203 : : * actually doesn't make syntactic sense, it may not worked if the token
204 : : * has already been skipped, etc. It was done because it would not
205 : : * actually require inserting new items into the token stream (which I
206 : : * thought would take more work to not mess up) and because I wasn't sure
207 : : * if the "already seen right angle" flag in the parser would work
208 : : * correctly.
209 : : * Those two other approaches listed are in my opinion actually better
210 : : * long-term - insertion is probably best as it reflects syntactically
211 : : * what occurs. On the other hand, I need to do a code audit to make sure
212 : : * that insertion doesn't mess anything up. So that's a FIXME. */
213 : : template <typename ManagedTokenSource>
214 : : bool
215 : 26947 : Parser<ManagedTokenSource>::skip_generics_right_angle ()
216 : : {
217 : : /* OK, new great idea. Have a lexer method called
218 : : * "split_current_token(TokenType newLeft, TokenType newRight)", which is
219 : : * called here with whatever arguments are appropriate. That lexer method
220 : : * handles "replacing" the current token with the "newLeft" and "inserting"
221 : : * the next token with the "newRight" (and creating a location, etc. for it)
222 : : */
223 : :
224 : : /* HACK: special handling for right shift '>>', greater or equal '>=', and
225 : : * right shift assig */
226 : : // '>>='
227 : 26947 : const_TokenPtr tok = lexer.peek_token ();
228 : 26947 : switch (tok->get_id ())
229 : : {
230 : 23260 : case RIGHT_ANGLE:
231 : : // this is good - skip token
232 : 23260 : lexer.skip_token ();
233 : 23260 : return true;
234 : 3686 : case RIGHT_SHIFT:
235 : : {
236 : : // new implementation that should be better
237 : 3686 : lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
238 : 3686 : lexer.skip_token ();
239 : 3686 : return true;
240 : : }
241 : 0 : case GREATER_OR_EQUAL:
242 : : {
243 : : // new implementation that should be better
244 : 0 : lexer.split_current_token (RIGHT_ANGLE, EQUAL);
245 : 0 : lexer.skip_token ();
246 : 0 : return true;
247 : : }
248 : 0 : case RIGHT_SHIFT_EQ:
249 : : {
250 : : // new implementation that should be better
251 : 0 : lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
252 : 0 : lexer.skip_token ();
253 : 0 : return true;
254 : : }
255 : 1 : default:
256 : 1 : add_error (Error (tok->get_locus (),
257 : : "expected %<>%> at end of generic argument - found %qs",
258 : : tok->get_token_description ()));
259 : 1 : return false;
260 : : }
261 : 26947 : }
262 : :
263 : : /* Gets left binding power for specified token.
264 : : * Not suitable for use at the moment or possibly ever because binding power
265 : : * cannot be purely determined from operator token with Rust grammar - e.g.
266 : : * method call and field access have
267 : : * different left binding powers but the same operator token. */
268 : : template <typename ManagedTokenSource>
269 : : int
270 : 840238 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
271 : : {
272 : : // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
273 : 840238 : switch (token->get_id ())
274 : : {
275 : : /* TODO: issue here - distinguish between method calls and field access
276 : : * somehow? Also would have to distinguish between paths and function
277 : : * calls (:: operator), maybe more stuff. */
278 : : /* Current plan for tackling LBP - don't do it based on token, use
279 : : * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
280 : : * and handle other expressions without it. rustc only considers
281 : : * arithmetic, logical/relational, 'as',
282 : : * '?=', ranges, colons, and assignment to have operator precedence and
283 : : * associativity rules applicable. It then has
284 : : * a separate "ExprPrecedence" that also includes binary operators. */
285 : :
286 : : // TODO: handle operator overloading - have a function replace the
287 : : // operator?
288 : :
289 : : /*case DOT:
290 : : return LBP_DOT;*/
291 : :
292 : 0 : case SCOPE_RESOLUTION:
293 : 0 : rust_debug (
294 : : "possible error - looked up LBP of scope resolution operator. should "
295 : : "be handled elsewhere.");
296 : 0 : return LBP_PATH;
297 : :
298 : : /* Resolved by lookahead HACK that should work with current code. If next
299 : : * token is identifier and token after that isn't parenthesised expression
300 : : * list, it is a field reference. */
301 : 46259 : case DOT:
302 : 92518 : if (lexer.peek_token (1)->get_id () == IDENTIFIER
303 : 83573 : && lexer.peek_token (2)->get_id () != LEFT_PAREN)
304 : : {
305 : : return LBP_FIELD_EXPR;
306 : : }
307 : : return LBP_METHOD_CALL;
308 : :
309 : : case LEFT_PAREN:
310 : : return LBP_FUNCTION_CALL;
311 : :
312 : : case LEFT_SQUARE:
313 : : return LBP_ARRAY_REF;
314 : :
315 : : // postfix question mark (i.e. error propagation expression)
316 : 203 : case QUESTION_MARK:
317 : 203 : return LBP_QUESTION_MARK;
318 : :
319 : 9989 : case AS:
320 : 9989 : return LBP_AS;
321 : :
322 : : case ASTERISK:
323 : : return LBP_MUL;
324 : : case DIV:
325 : : return LBP_DIV;
326 : : case PERCENT:
327 : : return LBP_MOD;
328 : :
329 : : case PLUS:
330 : : return LBP_PLUS;
331 : : case MINUS:
332 : : return LBP_MINUS;
333 : :
334 : : case LEFT_SHIFT:
335 : : return LBP_L_SHIFT;
336 : : case RIGHT_SHIFT:
337 : : return LBP_R_SHIFT;
338 : :
339 : : // binary & operator
340 : 4373 : case AMP:
341 : 4373 : return LBP_AMP;
342 : :
343 : : // binary ^ operator
344 : 159 : case CARET:
345 : 159 : return LBP_CARET;
346 : :
347 : : // binary | operator
348 : 3228 : case PIPE:
349 : 3228 : return LBP_PIPE;
350 : :
351 : : case EQUAL_EQUAL:
352 : : return LBP_EQUAL;
353 : : case NOT_EQUAL:
354 : : return LBP_NOT_EQUAL;
355 : : case RIGHT_ANGLE:
356 : : return LBP_GREATER_THAN;
357 : : case GREATER_OR_EQUAL:
358 : : return LBP_GREATER_EQUAL;
359 : : case LEFT_ANGLE:
360 : : return LBP_SMALLER_THAN;
361 : : case LESS_OR_EQUAL:
362 : : return LBP_SMALLER_EQUAL;
363 : :
364 : 1242 : case LOGICAL_AND:
365 : 1242 : return LBP_LOGICAL_AND;
366 : :
367 : 510 : case OR:
368 : 510 : return LBP_LOGICAL_OR;
369 : :
370 : : case DOT_DOT:
371 : : return LBP_DOT_DOT;
372 : :
373 : : case DOT_DOT_EQ:
374 : : return LBP_DOT_DOT_EQ;
375 : :
376 : : case EQUAL:
377 : : return LBP_ASSIG;
378 : : case PLUS_EQ:
379 : : return LBP_PLUS_ASSIG;
380 : : case MINUS_EQ:
381 : : return LBP_MINUS_ASSIG;
382 : : case ASTERISK_EQ:
383 : : return LBP_MULT_ASSIG;
384 : : case DIV_EQ:
385 : : return LBP_DIV_ASSIG;
386 : : case PERCENT_EQ:
387 : : return LBP_MOD_ASSIG;
388 : : case AMP_EQ:
389 : : return LBP_AMP_ASSIG;
390 : : case PIPE_EQ:
391 : : return LBP_PIPE_ASSIG;
392 : : case CARET_EQ:
393 : : return LBP_CARET_ASSIG;
394 : : case LEFT_SHIFT_EQ:
395 : : return LBP_L_SHIFT_ASSIG;
396 : : case RIGHT_SHIFT_EQ:
397 : : return LBP_R_SHIFT_ASSIG;
398 : :
399 : : /* HACK: float literal due to lexer misidentifying a dot then an integer as
400 : : * a float */
401 : : case FLOAT_LITERAL:
402 : : return LBP_FIELD_EXPR;
403 : : // field expr is same as tuple expr in precedence, i imagine
404 : : // TODO: is this needed anymore? lexer shouldn't do that anymore
405 : :
406 : : // anything that can't appear in an infix position is given lowest priority
407 : 737939 : default:
408 : 737939 : return LBP_LOWEST;
409 : : }
410 : : }
411 : :
412 : : // Returns true when current token is EOF.
413 : : template <typename ManagedTokenSource>
414 : : bool
415 : 0 : Parser<ManagedTokenSource>::done_end_of_file ()
416 : : {
417 : 0 : return lexer.peek_token ()->get_id () == END_OF_FILE;
418 : : }
419 : :
420 : : // Parses a sequence of items within a module or the implicit top-level module
421 : : // in a crate
422 : : template <typename ManagedTokenSource>
423 : : std::vector<std::unique_ptr<AST::Item>>
424 : 4861 : Parser<ManagedTokenSource>::parse_items ()
425 : : {
426 : 4861 : std::vector<std::unique_ptr<AST::Item>> items;
427 : :
428 : 4861 : const_TokenPtr t = lexer.peek_token ();
429 : 28576 : while (t->get_id () != END_OF_FILE)
430 : : {
431 : 23786 : std::unique_ptr<AST::Item> item = parse_item (false);
432 : 23786 : if (item == nullptr)
433 : : {
434 : : // TODO: should all items be cleared?
435 : 71 : items = std::vector<std::unique_ptr<AST::Item>> ();
436 : : break;
437 : : }
438 : :
439 : 23715 : items.push_back (std::move (item));
440 : :
441 : 23715 : t = lexer.peek_token ();
442 : : }
443 : :
444 : 4861 : return items;
445 : 4861 : }
446 : :
447 : : // Parses a crate (compilation unit) - entry point
448 : : template <typename ManagedTokenSource>
449 : : std::unique_ptr<AST::Crate>
450 : 4608 : Parser<ManagedTokenSource>::parse_crate ()
451 : : {
452 : : // parse inner attributes
453 : 4608 : AST::AttrVec inner_attrs = parse_inner_attributes ();
454 : :
455 : : // parse items
456 : 4608 : std::vector<std::unique_ptr<AST::Item>> items = parse_items ();
457 : :
458 : : // emit all errors
459 : 4737 : for (const auto &error : error_table)
460 : 129 : error.emit ();
461 : :
462 : : return std::unique_ptr<AST::Crate> (
463 : 4608 : new AST::Crate (std::move (items), std::move (inner_attrs)));
464 : 4608 : }
465 : :
466 : : // Parse a contiguous block of inner attributes.
467 : : template <typename ManagedTokenSource>
468 : : AST::AttrVec
469 : 174690 : Parser<ManagedTokenSource>::parse_inner_attributes ()
470 : : {
471 : 174690 : AST::AttrVec inner_attributes;
472 : :
473 : : // only try to parse it if it starts with "#!" not only "#"
474 : 84844 : while ((lexer.peek_token ()->get_id () == HASH
475 : 112397 : && lexer.peek_token (1)->get_id () == EXCLAM)
476 : 544287 : || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
477 : : {
478 : 5047 : AST::Attribute inner_attr = parse_inner_attribute ();
479 : :
480 : : /* Ensure only valid inner attributes are added to the inner_attributes
481 : : * list */
482 : 5047 : if (!inner_attr.is_empty ())
483 : : {
484 : 5047 : inner_attributes.push_back (std::move (inner_attr));
485 : : }
486 : : else
487 : : {
488 : : /* If no more valid inner attributes, break out of loop (only
489 : : * contiguous inner attributes parsed). */
490 : : break;
491 : : }
492 : : }
493 : :
494 : 174690 : inner_attributes.shrink_to_fit ();
495 : 174690 : return inner_attributes;
496 : : }
497 : :
498 : : // Parse a inner or outer doc comment into an doc attribute
499 : : template <typename ManagedTokenSource>
500 : : std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
501 : 53771 : Parser<ManagedTokenSource>::parse_doc_comment ()
502 : : {
503 : 53771 : const_TokenPtr token = lexer.peek_token ();
504 : 53771 : location_t locus = token->get_locus ();
505 : 53771 : AST::SimplePathSegment segment (Values::Attributes::DOC, locus);
506 : 53771 : std::vector<AST::SimplePathSegment> segments;
507 : 53771 : segments.push_back (std::move (segment));
508 : 53771 : AST::SimplePath attr_path (std::move (segments), false, locus);
509 : 107542 : AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING,
510 : : PrimitiveCoreType::CORETYPE_STR, {}, locus);
511 : 53771 : std::unique_ptr<AST::AttrInput> attr_input (
512 : 53771 : new AST::AttrInputLiteral (std::move (lit_expr)));
513 : 53771 : lexer.skip_token ();
514 : 107542 : return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
515 : 53771 : }
516 : :
517 : : // Parse a single inner attribute.
518 : : template <typename ManagedTokenSource>
519 : : AST::Attribute
520 : 5047 : Parser<ManagedTokenSource>::parse_inner_attribute ()
521 : : {
522 : 10094 : if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
523 : : {
524 : 2648 : auto values = parse_doc_comment ();
525 : 2648 : auto path = std::move (std::get<0> (values));
526 : 2648 : auto input = std::move (std::get<1> (values));
527 : 2648 : auto loc = std::get<2> (values);
528 : 2648 : return AST::Attribute (std::move (path), std::move (input), loc, true);
529 : 5296 : }
530 : :
531 : 4798 : if (lexer.peek_token ()->get_id () != HASH)
532 : : {
533 : 0 : Error error (lexer.peek_token ()->get_locus (),
534 : : "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
535 : : "was invoked");
536 : 0 : add_error (std::move (error));
537 : :
538 : 0 : return AST::Attribute::create_empty ();
539 : 0 : }
540 : 2399 : lexer.skip_token ();
541 : :
542 : 4798 : if (lexer.peek_token ()->get_id () != EXCLAM)
543 : : {
544 : 0 : Error error (lexer.peek_token ()->get_locus (),
545 : : "expected %<!%> or %<[%> for inner attribute");
546 : 0 : add_error (std::move (error));
547 : :
548 : 0 : return AST::Attribute::create_empty ();
549 : 0 : }
550 : 2399 : lexer.skip_token ();
551 : :
552 : 2399 : if (!skip_token (LEFT_SQUARE))
553 : 0 : return AST::Attribute::create_empty ();
554 : :
555 : 2399 : auto values = parse_attribute_body ();
556 : :
557 : 2399 : auto path = std::move (std::get<0> (values));
558 : 2399 : auto input = std::move (std::get<1> (values));
559 : 2399 : auto loc = std::get<2> (values);
560 : 2399 : auto actual_attribute
561 : 2399 : = AST::Attribute (std::move (path), std::move (input), loc, true);
562 : :
563 : 2399 : if (!skip_token (RIGHT_SQUARE))
564 : 0 : return AST::Attribute::create_empty ();
565 : :
566 : 2399 : return actual_attribute;
567 : 4798 : }
568 : :
569 : : // Parses the body of an attribute (inner or outer).
570 : : template <typename ManagedTokenSource>
571 : : std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
572 : 44823 : Parser<ManagedTokenSource>::parse_attribute_body ()
573 : : {
574 : 44823 : location_t locus = lexer.peek_token ()->get_locus ();
575 : :
576 : 44823 : AST::SimplePath attr_path = parse_simple_path ();
577 : : // ensure path is valid to parse attribute input
578 : 44823 : if (attr_path.is_empty ())
579 : : {
580 : 0 : Error error (lexer.peek_token ()->get_locus (),
581 : : "empty simple path in attribute");
582 : 0 : add_error (std::move (error));
583 : :
584 : : // Skip past potential further info in attribute (i.e. attr_input)
585 : 0 : skip_after_end_attribute ();
586 : 0 : return std::make_tuple (std::move (attr_path), nullptr, UNDEF_LOCATION);
587 : 0 : }
588 : :
589 : 44823 : std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input ();
590 : : // AttrInput is allowed to be null, so no checks here
591 : :
592 : 44823 : return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
593 : 44823 : }
594 : :
595 : : /* Determines whether token is a valid simple path segment. This does not
596 : : * include scope resolution operators. */
597 : : inline bool
598 : 62720 : is_simple_path_segment (TokenId id)
599 : : {
600 : 62720 : switch (id)
601 : : {
602 : : case IDENTIFIER:
603 : : case SUPER:
604 : : case SELF:
605 : : case CRATE:
606 : : return true;
607 : : case DOLLAR_SIGN:
608 : : // assume that dollar sign leads to $crate
609 : : return true;
610 : 5966 : default:
611 : 5966 : return false;
612 : : }
613 : : }
614 : :
615 : : // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
616 : : template <typename ManagedTokenSource>
617 : : AST::SimplePath
618 : 55670 : Parser<ManagedTokenSource>::parse_simple_path ()
619 : : {
620 : 55670 : bool has_opening_scope_resolution = false;
621 : 55670 : location_t locus = UNKNOWN_LOCATION;
622 : :
623 : : // don't parse anything if not a path upfront
624 : 111340 : if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
625 : 55968 : && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
626 : 242 : return AST::SimplePath::create_empty ();
627 : :
628 : : /* Checks for opening scope resolution (i.e. global scope fully-qualified
629 : : * path) */
630 : 110856 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
631 : : {
632 : 0 : has_opening_scope_resolution = true;
633 : :
634 : 0 : locus = lexer.peek_token ()->get_locus ();
635 : :
636 : 0 : lexer.skip_token ();
637 : : }
638 : :
639 : : // Parse single required simple path segment
640 : 55428 : AST::SimplePathSegment segment = parse_simple_path_segment ();
641 : :
642 : : // get location if not gotten already
643 : 55428 : if (locus == UNKNOWN_LOCATION)
644 : 55428 : locus = segment.get_locus ();
645 : :
646 : 55428 : std::vector<AST::SimplePathSegment> segments;
647 : :
648 : : // Return empty vector if first, actually required segment is an error
649 : 55428 : if (segment.is_error ())
650 : 56 : return AST::SimplePath::create_empty ();
651 : :
652 : 55372 : segments.push_back (std::move (segment));
653 : :
654 : : // Parse all other simple path segments
655 : 117208 : while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
656 : : {
657 : 3522 : AST::SimplePathSegment new_segment = parse_simple_path_segment (1);
658 : :
659 : : // Return path as currently constructed if segment in error state.
660 : 3522 : if (new_segment.is_error ())
661 : : break;
662 : :
663 : 2942 : segments.push_back (std::move (new_segment));
664 : : }
665 : :
666 : : // DEBUG: check for any empty segments
667 : 113686 : for (const auto &seg : segments)
668 : : {
669 : 58314 : if (seg.is_error ())
670 : : {
671 : 0 : rust_debug (
672 : : "when parsing simple path, somehow empty path segment was "
673 : : "not filtered out. Path begins with '%s'",
674 : : segments.at (0).as_string ().c_str ());
675 : : }
676 : : }
677 : :
678 : 55372 : return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
679 : 55372 : locus);
680 : : /* TODO: now that is_simple_path_segment exists, could probably start
681 : : * actually making errors upon parse failure of segments and whatever */
682 : 55428 : }
683 : :
684 : : /* Parses a single SimplePathSegment (does not handle the scope resolution
685 : : * operators)
686 : : * Starts parsing at an offset of base_peek */
687 : : template <typename ManagedTokenSource>
688 : : AST::SimplePathSegment
689 : 58950 : Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
690 : : {
691 : : using namespace Values;
692 : 58950 : const_TokenPtr t = lexer.peek_token (base_peek);
693 : 58950 : switch (t->get_id ())
694 : : {
695 : 57227 : case IDENTIFIER:
696 : 57227 : lexer.skip_token (base_peek);
697 : :
698 : 114454 : return AST::SimplePathSegment (t->get_str (), t->get_locus ());
699 : 365 : case SUPER:
700 : 365 : lexer.skip_token (base_peek);
701 : :
702 : 365 : return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
703 : 237 : case SELF:
704 : 237 : lexer.skip_token (base_peek);
705 : :
706 : 237 : return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
707 : 485 : case CRATE:
708 : 485 : lexer.skip_token (base_peek);
709 : :
710 : 485 : return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ());
711 : 0 : case DOLLAR_SIGN:
712 : 0 : if (lexer.peek_token (base_peek + 1)->get_id () == CRATE)
713 : : {
714 : 0 : lexer.skip_token (base_peek + 1);
715 : :
716 : 0 : return AST::SimplePathSegment ("$crate", t->get_locus ());
717 : : }
718 : : gcc_fallthrough ();
719 : : default:
720 : : // do nothing but inactivates warning from gcc when compiling
721 : : /* could put the rust_error_at thing here but fallthrough (from failing
722 : : * $crate condition) isn't completely obvious if it is. */
723 : :
724 : : // test prevent error
725 : 636 : return AST::SimplePathSegment::create_error ();
726 : : }
727 : : rust_unreachable ();
728 : : /*rust_error_at(
729 : : t->get_locus(), "invalid token '%s' in simple path segment",
730 : : t->get_token_description());*/
731 : : // this is not necessarily an error, e.g. end of path
732 : : // return AST::SimplePathSegment::create_error();
733 : 58950 : }
734 : :
735 : : // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
736 : : template <typename ManagedTokenSource>
737 : : AST::PathIdentSegment
738 : 544675 : Parser<ManagedTokenSource>::parse_path_ident_segment ()
739 : : {
740 : 544675 : const_TokenPtr t = lexer.peek_token ();
741 : 544675 : switch (t->get_id ())
742 : : {
743 : 510085 : case IDENTIFIER:
744 : 510085 : lexer.skip_token ();
745 : :
746 : 1020170 : return AST::PathIdentSegment (t->get_str (), t->get_locus ());
747 : 41 : case SUPER:
748 : 41 : lexer.skip_token ();
749 : :
750 : 41 : return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
751 : 20050 : case SELF:
752 : 20050 : lexer.skip_token ();
753 : :
754 : 20050 : return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
755 : 13467 : case SELF_ALIAS:
756 : 13467 : lexer.skip_token ();
757 : :
758 : 26934 : return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
759 : 26934 : t->get_locus ());
760 : 817 : case CRATE:
761 : 817 : lexer.skip_token ();
762 : :
763 : 817 : return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ());
764 : 4 : case DOLLAR_SIGN:
765 : 8 : if (lexer.peek_token (1)->get_id () == CRATE)
766 : : {
767 : 0 : lexer.skip_token (1);
768 : :
769 : 0 : return AST::PathIdentSegment ("$crate", t->get_locus ());
770 : : }
771 : : gcc_fallthrough ();
772 : : default:
773 : : /* do nothing but inactivates warning from gcc when compiling
774 : : * could put the error_at thing here but fallthrough (from failing $crate
775 : : * condition) isn't completely obvious if it is. */
776 : :
777 : : // test prevent error
778 : 215 : return AST::PathIdentSegment::create_error ();
779 : : }
780 : : rust_unreachable ();
781 : : // not necessarily an error
782 : 544675 : }
783 : :
784 : : // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
785 : : template <typename ManagedTokenSource>
786 : : std::unique_ptr<AST::AttrInput>
787 : 44823 : Parser<ManagedTokenSource>::parse_attr_input ()
788 : : {
789 : 44823 : const_TokenPtr t = lexer.peek_token ();
790 : 44823 : switch (t->get_id ())
791 : : {
792 : 25713 : case LEFT_PAREN:
793 : : case LEFT_SQUARE:
794 : : case LEFT_CURLY:
795 : : {
796 : : // must be a delimited token tree, so parse that
797 : 25713 : std::unique_ptr<AST::AttrInput> input_tree (
798 : 25713 : new AST::DelimTokenTree (parse_delim_token_tree ()));
799 : :
800 : : // TODO: potential checks on DelimTokenTree before returning
801 : :
802 : : return input_tree;
803 : : }
804 : 6752 : case EQUAL:
805 : : {
806 : : // = LiteralExpr
807 : 6752 : lexer.skip_token ();
808 : :
809 : 6752 : t = lexer.peek_token ();
810 : :
811 : : // attempt to parse macro
812 : : // TODO: macros may/may not be allowed in attributes
813 : : // this is needed for "#[doc = include_str!(...)]"
814 : 6752 : if (is_simple_path_segment (t->get_id ()))
815 : : {
816 : 1326 : std::unique_ptr<AST::MacroInvocation> invoke
817 : 1326 : = parse_macro_invocation ({});
818 : :
819 : 1326 : if (!invoke)
820 : 0 : return nullptr;
821 : :
822 : : return std::unique_ptr<AST::AttrInput> (
823 : 1326 : new AST::AttrInputMacro (std::move (invoke)));
824 : 1326 : }
825 : :
826 : : /* Ensure token is a "literal expression" (literally only a literal
827 : : * token of any type) */
828 : 5426 : if (!t->is_literal ())
829 : : {
830 : 0 : Error error (
831 : : t->get_locus (),
832 : : "unknown token %qs in attribute body - literal expected",
833 : : t->get_token_description ());
834 : 0 : add_error (std::move (error));
835 : :
836 : 0 : skip_after_end_attribute ();
837 : 0 : return nullptr;
838 : 0 : }
839 : :
840 : 5426 : AST::Literal::LitType lit_type = AST::Literal::STRING;
841 : : // Crappy mapping of token type to literal type
842 : 5426 : switch (t->get_id ())
843 : : {
844 : : case INT_LITERAL:
845 : : lit_type = AST::Literal::INT;
846 : : break;
847 : : case FLOAT_LITERAL:
848 : : lit_type = AST::Literal::FLOAT;
849 : : break;
850 : : case CHAR_LITERAL:
851 : : lit_type = AST::Literal::CHAR;
852 : : break;
853 : : case BYTE_CHAR_LITERAL:
854 : : lit_type = AST::Literal::BYTE;
855 : : break;
856 : : case BYTE_STRING_LITERAL:
857 : : lit_type = AST::Literal::BYTE_STRING;
858 : : break;
859 : : case RAW_STRING_LITERAL:
860 : : lit_type = AST::Literal::RAW_STRING;
861 : : break;
862 : : case STRING_LITERAL:
863 : : default:
864 : : lit_type = AST::Literal::STRING;
865 : : break; // TODO: raw string? don't eliminate it from lexer?
866 : : }
867 : :
868 : : // create actual LiteralExpr
869 : 16278 : AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (),
870 : : {}, t->get_locus ());
871 : 5426 : lexer.skip_token ();
872 : :
873 : 5426 : std::unique_ptr<AST::AttrInput> attr_input_lit (
874 : 5426 : new AST::AttrInputLiteral (std::move (lit_expr)));
875 : :
876 : : // do checks or whatever? none required, really
877 : :
878 : : // FIXME: shouldn't a skip token be required here?
879 : :
880 : 5426 : return attr_input_lit;
881 : 5426 : }
882 : : break;
883 : 12358 : case RIGHT_PAREN:
884 : : case RIGHT_SQUARE:
885 : : case RIGHT_CURLY:
886 : : case END_OF_FILE:
887 : : // means AttrInput is missing, which is allowed
888 : 12358 : return nullptr;
889 : 0 : default:
890 : 0 : add_error (
891 : 0 : Error (t->get_locus (),
892 : : "unknown token %qs in attribute body - attribute input or "
893 : : "none expected",
894 : : t->get_token_description ()));
895 : :
896 : 0 : skip_after_end_attribute ();
897 : 0 : return nullptr;
898 : : }
899 : : rust_unreachable ();
900 : : // TODO: find out how to stop gcc error on "no return value"
901 : 44823 : }
902 : :
903 : : /* Returns true if the token id matches the delimiter type. Note that this only
904 : : * operates for END delimiter tokens. */
905 : : inline bool
906 : 1053191 : token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
907 : : {
908 : 1053191 : return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
909 : 815900 : || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
910 : 1847113 : || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
911 : : }
912 : :
913 : : /* Returns true if the likely result of parsing the next few tokens is a path.
914 : : * Not guaranteed, though, especially in the case of syntax errors. */
915 : : inline bool
916 : : is_likely_path_next (TokenId next_token_id)
917 : : {
918 : : switch (next_token_id)
919 : : {
920 : : case IDENTIFIER:
921 : : case SUPER:
922 : : case SELF:
923 : : case SELF_ALIAS:
924 : : case CRATE:
925 : : // maybe - maybe do extra check. But then requires another TokenId.
926 : : case DOLLAR_SIGN:
927 : : case SCOPE_RESOLUTION:
928 : : return true;
929 : : default:
930 : : return false;
931 : : }
932 : : }
933 : :
934 : : // Parses a delimited token tree
935 : : template <typename ManagedTokenSource>
936 : : AST::DelimTokenTree
937 : 134788 : Parser<ManagedTokenSource>::parse_delim_token_tree ()
938 : : {
939 : 134788 : const_TokenPtr t = lexer.peek_token ();
940 : 134788 : lexer.skip_token ();
941 : 134788 : location_t initial_loc = t->get_locus ();
942 : :
943 : : // save delim type to ensure it is reused later
944 : 134788 : AST::DelimType delim_type = AST::PARENS;
945 : :
946 : : // Map tokens to DelimType
947 : 134788 : switch (t->get_id ())
948 : : {
949 : : case LEFT_PAREN:
950 : : delim_type = AST::PARENS;
951 : : break;
952 : 10924 : case LEFT_SQUARE:
953 : 10924 : delim_type = AST::SQUARE;
954 : 10924 : break;
955 : 8562 : case LEFT_CURLY:
956 : 8562 : delim_type = AST::CURLY;
957 : 8562 : break;
958 : 0 : default:
959 : 0 : add_error (Error (t->get_locus (),
960 : : "unexpected token %qs - expecting delimiters (for a "
961 : : "delimited token tree)",
962 : : t->get_token_description ()));
963 : :
964 : 0 : return AST::DelimTokenTree::create_empty ();
965 : : }
966 : :
967 : : // parse actual token tree vector - 0 or more
968 : 134788 : std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
969 : 134788 : auto delim_open
970 : 134788 : = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
971 : 134788 : token_trees_in_tree.push_back (std::move (delim_open));
972 : :
973 : : // repeat loop until finding the matching delimiter
974 : 134788 : t = lexer.peek_token ();
975 : 838267 : while (!token_id_matches_delims (t->get_id (), delim_type)
976 : 838266 : && t->get_id () != END_OF_FILE)
977 : : {
978 : 703479 : std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree ();
979 : :
980 : 703479 : if (tok_tree == nullptr)
981 : 1 : return AST::DelimTokenTree::create_empty ();
982 : :
983 : 703478 : token_trees_in_tree.push_back (std::move (tok_tree));
984 : :
985 : : // lexer.skip_token();
986 : 703478 : t = lexer.peek_token ();
987 : : }
988 : 134787 : auto delim_close
989 : 134787 : = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
990 : 134787 : token_trees_in_tree.push_back (std::move (delim_close));
991 : :
992 : 134787 : AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
993 : : initial_loc);
994 : :
995 : : // parse end delimiters
996 : 134787 : t = lexer.peek_token ();
997 : :
998 : 134787 : if (token_id_matches_delims (t->get_id (), delim_type))
999 : : {
1000 : : // tokens match opening delimiter, so skip.
1001 : 134779 : lexer.skip_token ();
1002 : :
1003 : : // DEBUG
1004 : 269558 : rust_debug ("finished parsing new delim token tree - peeked token is now "
1005 : : "'%s' while t is '%s'",
1006 : : lexer.peek_token ()->get_token_description (),
1007 : : t->get_token_description ());
1008 : :
1009 : 134779 : return token_tree;
1010 : : }
1011 : : else
1012 : : {
1013 : : // tokens don't match opening delimiters, so produce error
1014 : 9 : Error error (t->get_locus (),
1015 : : "unexpected token %qs - expecting closing delimiter %qs "
1016 : : "(for a delimited token tree)",
1017 : : t->get_token_description (),
1018 : : (delim_type == AST::PARENS
1019 : : ? ")"
1020 : : : (delim_type == AST::SQUARE ? "]" : "}")));
1021 : 8 : add_error (std::move (error));
1022 : :
1023 : : /* return empty token tree despite possibly parsing valid token tree -
1024 : : * TODO is this a good idea? */
1025 : 8 : return AST::DelimTokenTree::create_empty ();
1026 : 8 : }
1027 : 134788 : }
1028 : :
1029 : : // Parses an identifier/keyword as a Token
1030 : : template <typename ManagedTokenSource>
1031 : : std::unique_ptr<AST::Token>
1032 : 13336 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
1033 : : {
1034 : 13336 : const_TokenPtr t = lexer.peek_token ();
1035 : :
1036 : 13336 : if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
1037 : : {
1038 : 13333 : lexer.skip_token ();
1039 : 13333 : return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1040 : : }
1041 : : else
1042 : : {
1043 : 3 : add_error (Error (t->get_locus (), "expected keyword or identifier"));
1044 : 3 : return nullptr;
1045 : : }
1046 : 13336 : }
1047 : :
1048 : : /* Parses a TokenTree syntactical production. This is either a delimited token
1049 : : * tree or a non-delimiter token. */
1050 : : template <typename ManagedTokenSource>
1051 : : std::unique_ptr<AST::TokenTree>
1052 : 780632 : Parser<ManagedTokenSource>::parse_token_tree ()
1053 : : {
1054 : 780632 : const_TokenPtr t = lexer.peek_token ();
1055 : :
1056 : 780632 : switch (t->get_id ())
1057 : : {
1058 : 52759 : case LEFT_PAREN:
1059 : : case LEFT_SQUARE:
1060 : : case LEFT_CURLY:
1061 : : // Parse delimited token tree
1062 : : // TODO: use move rather than copy constructor
1063 : 52759 : return std::unique_ptr<AST::DelimTokenTree> (
1064 : 52759 : new AST::DelimTokenTree (parse_delim_token_tree ()));
1065 : 2 : case RIGHT_PAREN:
1066 : : case RIGHT_SQUARE:
1067 : : case RIGHT_CURLY:
1068 : : // error - should not be called when this a token
1069 : 2 : add_error (Error (t->get_locus (), "unexpected closing delimiter %qs",
1070 : : t->get_token_description ()));
1071 : :
1072 : 4 : add_error (Error (Error::Kind::Hint, t->get_locus (),
1073 : 2 : "token tree requires either paired delimiters or "
1074 : : "non-delimiter tokens"));
1075 : :
1076 : 2 : lexer.skip_token ();
1077 : 2 : return nullptr;
1078 : 727871 : default:
1079 : : // parse token itself as TokenTree
1080 : 727871 : lexer.skip_token ();
1081 : 727871 : return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1082 : : }
1083 : 780632 : }
1084 : :
1085 : : template <typename ManagedTokenSource>
1086 : : bool
1087 : 5175 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
1088 : : {
1089 : 5175 : auto macro_name = lexer.peek_token (2)->get_id ();
1090 : :
1091 : 5175 : bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
1092 : :
1093 : 5175 : return t->get_str () == Values::WeakKeywords::MACRO_RULES
1094 : 6295 : && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
1095 : : }
1096 : :
1097 : : // Parses a single item
1098 : : template <typename ManagedTokenSource>
1099 : : std::unique_ptr<AST::Item>
1100 : 39477 : Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
1101 : : {
1102 : : // has a "called_from_statement" parameter for better error message handling
1103 : :
1104 : : // parse outer attributes for item
1105 : 39477 : AST::AttrVec outer_attrs = parse_outer_attributes ();
1106 : 39477 : const_TokenPtr t = lexer.peek_token ();
1107 : :
1108 : 39477 : switch (t->get_id ())
1109 : : {
1110 : 7 : case END_OF_FILE:
1111 : : // not necessarily an error, unless we just read outer
1112 : : // attributes which needs to be attached
1113 : 7 : if (!outer_attrs.empty ())
1114 : : {
1115 : 0 : Rust::AST::Attribute attr = outer_attrs.back ();
1116 : 0 : Error error (attr.get_locus (),
1117 : : "expected item after outer attribute or doc comment");
1118 : 0 : add_error (std::move (error));
1119 : 0 : }
1120 : 7 : return nullptr;
1121 : :
1122 : 34468 : case ASYNC:
1123 : : case PUB:
1124 : : case MOD:
1125 : : case EXTERN_KW:
1126 : : case USE:
1127 : : case FN_KW:
1128 : : case TYPE:
1129 : : case STRUCT_KW:
1130 : : case ENUM_KW:
1131 : : case CONST:
1132 : : case STATIC_KW:
1133 : : case AUTO:
1134 : : case TRAIT:
1135 : : case IMPL:
1136 : : case MACRO:
1137 : : /* TODO: implement union keyword but not really because of
1138 : : * context-dependence crappy hack way to parse a union written below to
1139 : : * separate it from the good code. */
1140 : : // case UNION:
1141 : : case UNSAFE: // maybe - unsafe traits are a thing
1142 : : // if any of these (should be all possible VisItem prefixes), parse a
1143 : : // VisItem
1144 : 34468 : return parse_vis_item (std::move (outer_attrs));
1145 : : break;
1146 : 3 : case SUPER:
1147 : : case SELF:
1148 : : case CRATE:
1149 : : case DOLLAR_SIGN:
1150 : : // almost certainly macro invocation semi
1151 : 6 : return parse_macro_invocation_semi (std::move (outer_attrs));
1152 : : break;
1153 : : // crappy hack to do union "keyword"
1154 : 4999 : case IDENTIFIER:
1155 : : // TODO: ensure std::string and literal comparison works
1156 : 6863 : if (t->get_str () == Values::WeakKeywords::UNION
1157 : 5062 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
1158 : : {
1159 : 63 : return parse_vis_item (std::move (outer_attrs));
1160 : : // or should this go straight to parsing union?
1161 : : }
1162 : 6737 : else if (t->get_str () == Values::WeakKeywords::DEFAULT
1163 : 4938 : && lexer.peek_token (1)->get_id () != EXCLAM)
1164 : : {
1165 : 1 : add_error (Error (t->get_locus (),
1166 : : "%qs is only allowed on items within %qs blocks",
1167 : : "default", "impl"));
1168 : 1 : return nullptr;
1169 : : }
1170 : 9870 : else if (is_macro_rules_def (t))
1171 : : {
1172 : : // macro_rules! macro item
1173 : 1116 : return parse_macro_rules_def (std::move (outer_attrs));
1174 : : }
1175 : 7638 : else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
1176 : 7637 : || lexer.peek_token (1)->get_id () == EXCLAM)
1177 : : {
1178 : : /* path (probably) or macro invocation, so probably a macro invocation
1179 : : * semi */
1180 : 7631 : return parse_macro_invocation_semi (std::move (outer_attrs));
1181 : : }
1182 : : gcc_fallthrough ();
1183 : : default:
1184 : : // otherwise unrecognised
1185 : 6 : add_error (Error (t->get_locus (),
1186 : : "unrecognised token %qs for start of %s",
1187 : : t->get_token_description (),
1188 : : called_from_statement ? "statement" : "item"));
1189 : :
1190 : : // skip somewhere?
1191 : 3 : return nullptr;
1192 : : break;
1193 : : }
1194 : 39477 : }
1195 : :
1196 : : // Parses a contiguous block of outer attributes.
1197 : : template <typename ManagedTokenSource>
1198 : : AST::AttrVec
1199 : 290078 : Parser<ManagedTokenSource>::parse_outer_attributes ()
1200 : : {
1201 : 290078 : AST::AttrVec outer_attributes;
1202 : :
1203 : 295803 : while (lexer.peek_token ()->get_id ()
1204 : : == HASH /* Can also be #!, which catches errors. */
1205 : 723026 : || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT
1206 : 1394929 : || lexer.peek_token ()->get_id ()
1207 : : == INNER_DOC_COMMENT) /* For error handling. */
1208 : : {
1209 : 91763 : AST::Attribute outer_attr = parse_outer_attribute ();
1210 : :
1211 : : /* Ensure only valid outer attributes are added to the outer_attributes
1212 : : * list */
1213 : 91763 : if (!outer_attr.is_empty ())
1214 : : {
1215 : 91754 : outer_attributes.push_back (std::move (outer_attr));
1216 : : }
1217 : : else
1218 : : {
1219 : : /* If no more valid outer attributes, break out of loop (only
1220 : : * contiguous outer attributes parsed). */
1221 : : break;
1222 : : }
1223 : : }
1224 : :
1225 : 290078 : outer_attributes.shrink_to_fit ();
1226 : 290078 : return outer_attributes;
1227 : :
1228 : : /* TODO: this shares basically all code with parse_inner_attributes except
1229 : : * function call - find way of making it more modular? function pointer? */
1230 : : }
1231 : :
1232 : : // Parse a single outer attribute.
1233 : : template <typename ManagedTokenSource>
1234 : : AST::Attribute
1235 : 91763 : Parser<ManagedTokenSource>::parse_outer_attribute ()
1236 : : {
1237 : 183526 : if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
1238 : : {
1239 : 51123 : auto values = parse_doc_comment ();
1240 : 51123 : auto path = std::move (std::get<0> (values));
1241 : 51123 : auto input = std::move (std::get<1> (values));
1242 : 51123 : auto loc = std::get<2> (values);
1243 : 51123 : return AST::Attribute (std::move (path), std::move (input), loc, false);
1244 : 102246 : }
1245 : :
1246 : 81280 : if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
1247 : : {
1248 : 2 : Error error (
1249 : 2 : lexer.peek_token ()->get_locus (), ErrorCode::E0753,
1250 : : "expected outer doc comment, inner doc (%<//!%> or %</*!%>) only "
1251 : : "allowed at start of item "
1252 : : "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
1253 : 2 : add_error (std::move (error));
1254 : 2 : lexer.skip_token ();
1255 : 2 : return AST::Attribute::create_empty ();
1256 : 2 : }
1257 : :
1258 : : /* OuterAttribute -> '#' '[' Attr ']' */
1259 : :
1260 : 81276 : if (lexer.peek_token ()->get_id () != HASH)
1261 : 0 : return AST::Attribute::create_empty ();
1262 : :
1263 : 40638 : lexer.skip_token ();
1264 : :
1265 : 40638 : TokenId id = lexer.peek_token ()->get_id ();
1266 : 40638 : if (id != LEFT_SQUARE)
1267 : : {
1268 : 0 : if (id == EXCLAM)
1269 : : {
1270 : : // this is inner attribute syntax, so throw error
1271 : : // inner attributes were either already parsed or not allowed here.
1272 : 0 : Error error (
1273 : 0 : lexer.peek_token ()->get_locus (),
1274 : : "token %<!%> found, indicating inner attribute definition. Inner "
1275 : : "attributes are not possible at this location");
1276 : 0 : add_error (std::move (error));
1277 : 0 : }
1278 : 0 : return AST::Attribute::create_empty ();
1279 : : }
1280 : :
1281 : 40638 : lexer.skip_token ();
1282 : :
1283 : 40638 : auto values = parse_attribute_body ();
1284 : 40638 : auto path = std::move (std::get<0> (values));
1285 : 40638 : auto input = std::move (std::get<1> (values));
1286 : 40638 : auto loc = std::get<2> (values);
1287 : 40638 : auto actual_attribute
1288 : 40638 : = AST::Attribute (std::move (path), std::move (input), loc, false);
1289 : :
1290 : 81276 : if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
1291 : 7 : return AST::Attribute::create_empty ();
1292 : :
1293 : 40631 : lexer.skip_token ();
1294 : :
1295 : 40631 : return actual_attribute;
1296 : 81276 : }
1297 : :
1298 : : // Parses a VisItem (item that can have non-default visibility).
1299 : : template <typename ManagedTokenSource>
1300 : : std::unique_ptr<AST::VisItem>
1301 : 35572 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
1302 : : {
1303 : : // parse visibility, which may or may not exist
1304 : 35572 : AST::Visibility vis = parse_visibility ();
1305 : :
1306 : : // select VisItem to create depending on keyword
1307 : 35572 : const_TokenPtr t = lexer.peek_token ();
1308 : :
1309 : 35572 : switch (t->get_id ())
1310 : : {
1311 : 1605 : case MOD:
1312 : 1605 : return parse_module (std::move (vis), std::move (outer_attrs));
1313 : 1551 : case EXTERN_KW:
1314 : : // lookahead to resolve syntactical production
1315 : 1551 : t = lexer.peek_token (1);
1316 : :
1317 : 1551 : switch (t->get_id ())
1318 : : {
1319 : 27 : case CRATE:
1320 : 27 : return parse_extern_crate (std::move (vis), std::move (outer_attrs));
1321 : 0 : case FN_KW: // extern function
1322 : 0 : return parse_function (std::move (vis), std::move (outer_attrs));
1323 : 0 : case LEFT_CURLY: // extern block
1324 : 0 : return parse_extern_block (std::move (vis), std::move (outer_attrs));
1325 : 1524 : case STRING_LITERAL: // for specifying extern ABI
1326 : : // could be extern block or extern function, so more lookahead
1327 : 1524 : t = lexer.peek_token (2);
1328 : :
1329 : 1524 : switch (t->get_id ())
1330 : : {
1331 : 2 : case FN_KW:
1332 : 2 : return parse_function (std::move (vis), std::move (outer_attrs));
1333 : 1522 : case LEFT_CURLY:
1334 : 1522 : return parse_extern_block (std::move (vis),
1335 : 1522 : std::move (outer_attrs));
1336 : 0 : default:
1337 : 0 : add_error (
1338 : 0 : Error (t->get_locus (),
1339 : : "unexpected token %qs in some sort of extern production",
1340 : : t->get_token_description ()));
1341 : :
1342 : 0 : lexer.skip_token (2); // TODO: is this right thing to do?
1343 : 0 : return nullptr;
1344 : : }
1345 : 0 : default:
1346 : 0 : add_error (
1347 : 0 : Error (t->get_locus (),
1348 : : "unexpected token %qs in some sort of extern production",
1349 : : t->get_token_description ()));
1350 : :
1351 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
1352 : 0 : return nullptr;
1353 : : }
1354 : 1495 : case USE:
1355 : 1495 : return parse_use_decl (std::move (vis), std::move (outer_attrs));
1356 : 6600 : case FN_KW:
1357 : 6600 : return parse_function (std::move (vis), std::move (outer_attrs));
1358 : 73 : case TYPE:
1359 : 73 : return parse_type_alias (std::move (vis), std::move (outer_attrs));
1360 : 3319 : case STRUCT_KW:
1361 : 3319 : return parse_struct (std::move (vis), std::move (outer_attrs));
1362 : 573 : case ENUM_KW:
1363 : 573 : return parse_enum (std::move (vis), std::move (outer_attrs));
1364 : : // TODO: implement union keyword but not really because of
1365 : : // context-dependence case UNION: crappy hack to do union "keyword"
1366 : 109 : case IDENTIFIER:
1367 : 218 : if (t->get_str () == Values::WeakKeywords::UNION
1368 : 218 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
1369 : : {
1370 : 109 : return parse_union (std::move (vis), std::move (outer_attrs));
1371 : : // or should item switch go straight to parsing union?
1372 : : }
1373 : : else
1374 : : {
1375 : : break;
1376 : : }
1377 : 1129 : case CONST:
1378 : : // lookahead to resolve syntactical production
1379 : 1129 : t = lexer.peek_token (1);
1380 : :
1381 : 1129 : switch (t->get_id ())
1382 : : {
1383 : 1023 : case IDENTIFIER:
1384 : : case UNDERSCORE:
1385 : 1023 : return parse_const_item (std::move (vis), std::move (outer_attrs));
1386 : 1 : case ASYNC:
1387 : 1 : return parse_async_item (std::move (vis), std::move (outer_attrs));
1388 : 105 : case UNSAFE:
1389 : : case EXTERN_KW:
1390 : : case FN_KW:
1391 : 105 : return parse_function (std::move (vis), std::move (outer_attrs));
1392 : 0 : default:
1393 : 0 : add_error (
1394 : 0 : Error (t->get_locus (),
1395 : : "unexpected token %qs in some sort of const production",
1396 : : t->get_token_description ()));
1397 : :
1398 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
1399 : 0 : return nullptr;
1400 : : }
1401 : : // for async functions
1402 : 2 : case ASYNC:
1403 : 2 : return parse_async_item (std::move (vis), std::move (outer_attrs));
1404 : :
1405 : 93 : case STATIC_KW:
1406 : 93 : return parse_static_item (std::move (vis), std::move (outer_attrs));
1407 : 3821 : case AUTO:
1408 : : case TRAIT:
1409 : 3821 : return parse_trait (std::move (vis), std::move (outer_attrs));
1410 : 11210 : case IMPL:
1411 : 11210 : return parse_impl (std::move (vis), std::move (outer_attrs));
1412 : 3927 : case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
1413 : : // lookahead to resolve syntactical production
1414 : 3927 : t = lexer.peek_token (1);
1415 : :
1416 : 3927 : switch (t->get_id ())
1417 : : {
1418 : 72 : case AUTO:
1419 : : case TRAIT:
1420 : 72 : return parse_trait (std::move (vis), std::move (outer_attrs));
1421 : 3635 : case EXTERN_KW:
1422 : : case FN_KW:
1423 : 3635 : return parse_function (std::move (vis), std::move (outer_attrs));
1424 : 219 : case IMPL:
1425 : 219 : return parse_impl (std::move (vis), std::move (outer_attrs));
1426 : 1 : case MOD:
1427 : 1 : return parse_module (std::move (vis), std::move (outer_attrs));
1428 : 0 : default:
1429 : 0 : add_error (
1430 : 0 : Error (t->get_locus (),
1431 : : "unexpected token %qs in some sort of unsafe production",
1432 : : t->get_token_description ()));
1433 : :
1434 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
1435 : 0 : return nullptr;
1436 : : }
1437 : 64 : case MACRO:
1438 : 64 : return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
1439 : : default:
1440 : : // otherwise vis item clearly doesn't exist, which is not an error
1441 : : // has a catch-all post-switch return to allow other breaks to occur
1442 : : break;
1443 : : }
1444 : 1 : return nullptr;
1445 : 35572 : }
1446 : :
1447 : : template <typename ManagedTokenSource>
1448 : : std::unique_ptr<AST::Function>
1449 : 4 : Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
1450 : : AST::AttrVec outer_attrs)
1451 : : {
1452 : 4 : auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
1453 : 4 : const_TokenPtr t = lexer.peek_token (offset);
1454 : :
1455 : 4 : if (get_rust_edition () == Edition::E2015)
1456 : : {
1457 : 1 : add_error (Error (t->get_locus (), ErrorCode::E0670,
1458 : : "%<async fn%> is not permitted in Rust 2015"));
1459 : 1 : add_error (
1460 : 2 : Error::Hint (t->get_locus (),
1461 : : "to use %<async fn%>, switch to Rust 2018 or later"));
1462 : : }
1463 : :
1464 : 4 : t = lexer.peek_token (offset + 1);
1465 : :
1466 : 4 : switch (t->get_id ())
1467 : : {
1468 : 4 : case UNSAFE:
1469 : : case FN_KW:
1470 : 4 : return parse_function (std::move (vis), std::move (outer_attrs));
1471 : :
1472 : 0 : default:
1473 : 0 : add_error (
1474 : 0 : Error (t->get_locus (), "expected item, found keyword %<async%>"));
1475 : :
1476 : 0 : lexer.skip_token (1);
1477 : 0 : return nullptr;
1478 : : }
1479 : 4 : }
1480 : :
1481 : : // Parses a macro rules definition syntax extension whatever thing.
1482 : : template <typename ManagedTokenSource>
1483 : : std::unique_ptr<AST::MacroRulesDefinition>
1484 : 1634 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
1485 : : {
1486 : : // ensure that first token is identifier saying "macro_rules"
1487 : 1634 : const_TokenPtr t = lexer.peek_token ();
1488 : 1634 : if (t->get_id () != IDENTIFIER
1489 : 1634 : || t->get_str () != Values::WeakKeywords::MACRO_RULES)
1490 : : {
1491 : 0 : Error error (
1492 : : t->get_locus (),
1493 : : "macro rules definition does not start with %<macro_rules%>");
1494 : 0 : add_error (std::move (error));
1495 : :
1496 : : // skip after somewhere?
1497 : 0 : return nullptr;
1498 : 0 : }
1499 : 1634 : lexer.skip_token ();
1500 : 1634 : location_t macro_locus = t->get_locus ();
1501 : :
1502 : 1634 : if (!skip_token (EXCLAM))
1503 : : {
1504 : : // skip after somewhere?
1505 : 0 : return nullptr;
1506 : : }
1507 : :
1508 : : // parse macro name
1509 : 1634 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1510 : 1634 : if (ident_tok == nullptr)
1511 : : {
1512 : 1 : return nullptr;
1513 : : }
1514 : 1633 : Identifier rule_name{ident_tok};
1515 : :
1516 : : // DEBUG
1517 : 1633 : rust_debug ("in macro rules def, about to parse parens.");
1518 : :
1519 : : // save delim type to ensure it is reused later
1520 : 1633 : AST::DelimType delim_type = AST::PARENS;
1521 : :
1522 : : // Map tokens to DelimType
1523 : 1633 : t = lexer.peek_token ();
1524 : 1633 : switch (t->get_id ())
1525 : : {
1526 : : case LEFT_PAREN:
1527 : : delim_type = AST::PARENS;
1528 : : break;
1529 : 0 : case LEFT_SQUARE:
1530 : 0 : delim_type = AST::SQUARE;
1531 : 0 : break;
1532 : 1632 : case LEFT_CURLY:
1533 : 1632 : delim_type = AST::CURLY;
1534 : 1632 : break;
1535 : 0 : default:
1536 : 0 : add_error (Error (t->get_locus (),
1537 : : "unexpected token %qs - expecting delimiters (for a "
1538 : : "macro rules definition)",
1539 : : t->get_token_description ()));
1540 : :
1541 : 0 : return nullptr;
1542 : : }
1543 : 1633 : lexer.skip_token ();
1544 : :
1545 : : // parse actual macro rules
1546 : 1633 : std::vector<AST::MacroRule> macro_rules;
1547 : :
1548 : : // must be at least one macro rule, so parse it
1549 : 1633 : AST::MacroRule initial_rule = parse_macro_rule ();
1550 : 1633 : if (initial_rule.is_error ())
1551 : : {
1552 : 12 : Error error (lexer.peek_token ()->get_locus (),
1553 : : "required first macro rule in macro rules definition "
1554 : : "could not be parsed");
1555 : 12 : add_error (std::move (error));
1556 : :
1557 : : // skip after somewhere?
1558 : 12 : return nullptr;
1559 : 12 : }
1560 : 1621 : macro_rules.push_back (std::move (initial_rule));
1561 : :
1562 : : // DEBUG
1563 : 1621 : rust_debug ("successfully pushed back initial macro rule");
1564 : :
1565 : 1621 : t = lexer.peek_token ();
1566 : : // parse macro rules
1567 : 1784 : while (t->get_id () == SEMICOLON)
1568 : : {
1569 : : // skip semicolon
1570 : 1271 : lexer.skip_token ();
1571 : :
1572 : : // don't parse if end of macro rules
1573 : 2542 : if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type))
1574 : : {
1575 : : // DEBUG
1576 : 1108 : rust_debug (
1577 : : "broke out of parsing macro rules loop due to finding delim");
1578 : :
1579 : 1108 : break;
1580 : : }
1581 : :
1582 : : // try to parse next rule
1583 : 163 : AST::MacroRule rule = parse_macro_rule ();
1584 : 163 : if (rule.is_error ())
1585 : : {
1586 : 0 : Error error (lexer.peek_token ()->get_locus (),
1587 : : "failed to parse macro rule in macro rules definition");
1588 : 0 : add_error (std::move (error));
1589 : :
1590 : 0 : return nullptr;
1591 : 0 : }
1592 : :
1593 : 163 : macro_rules.push_back (std::move (rule));
1594 : :
1595 : : // DEBUG
1596 : 163 : rust_debug ("successfully pushed back another macro rule");
1597 : :
1598 : 163 : t = lexer.peek_token ();
1599 : : }
1600 : :
1601 : : // parse end delimiters
1602 : 1621 : t = lexer.peek_token ();
1603 : 1621 : if (token_id_matches_delims (t->get_id (), delim_type))
1604 : : {
1605 : : // tokens match opening delimiter, so skip.
1606 : 1621 : lexer.skip_token ();
1607 : :
1608 : 1621 : if (delim_type != AST::CURLY)
1609 : : {
1610 : : // skip semicolon at end of non-curly macro definitions
1611 : 1 : if (!skip_token (SEMICOLON))
1612 : : {
1613 : : // as this is the end, allow recovery (probably) - may change
1614 : : return std::unique_ptr<AST::MacroRulesDefinition> (
1615 : 0 : AST::MacroRulesDefinition::mbe (
1616 : : std::move (rule_name), delim_type, std::move (macro_rules),
1617 : 0 : std::move (outer_attrs), macro_locus));
1618 : : }
1619 : : }
1620 : :
1621 : : return std::unique_ptr<AST::MacroRulesDefinition> (
1622 : 3242 : AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
1623 : : std::move (macro_rules),
1624 : 1621 : std::move (outer_attrs), macro_locus));
1625 : : }
1626 : : else
1627 : : {
1628 : : // tokens don't match opening delimiters, so produce error
1629 : 0 : Error error (t->get_locus (),
1630 : : "unexpected token %qs - expecting closing delimiter %qs "
1631 : : "(for a macro rules definition)",
1632 : : t->get_token_description (),
1633 : : (delim_type == AST::PARENS
1634 : : ? ")"
1635 : : : (delim_type == AST::SQUARE ? "]" : "}")));
1636 : 0 : add_error (std::move (error));
1637 : :
1638 : : /* return empty macro definiton despite possibly parsing mostly valid one
1639 : : * - TODO is this a good idea? */
1640 : 0 : return nullptr;
1641 : 0 : }
1642 : 4900 : }
1643 : :
1644 : : // Parses a declarative macro 2.0 definition.
1645 : : template <typename ManagedTokenSource>
1646 : : std::unique_ptr<AST::MacroRulesDefinition>
1647 : 64 : Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
1648 : : AST::AttrVec outer_attrs)
1649 : : {
1650 : : // ensure that first token is identifier saying "macro"
1651 : 64 : const_TokenPtr t = lexer.peek_token ();
1652 : 64 : if (t->get_id () != MACRO)
1653 : : {
1654 : 0 : Error error (
1655 : : t->get_locus (),
1656 : : "declarative macro definition does not start with %<macro%>");
1657 : 0 : add_error (std::move (error));
1658 : :
1659 : : // skip after somewhere?
1660 : 0 : return nullptr;
1661 : 0 : }
1662 : 64 : lexer.skip_token ();
1663 : 64 : location_t macro_locus = t->get_locus ();
1664 : :
1665 : : // parse macro name
1666 : 64 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1667 : 64 : if (ident_tok == nullptr)
1668 : : {
1669 : 0 : return nullptr;
1670 : : }
1671 : 64 : Identifier rule_name{ident_tok};
1672 : :
1673 : 64 : t = lexer.peek_token ();
1674 : 64 : if (t->get_id () == LEFT_PAREN)
1675 : : {
1676 : : // single definiton of macro rule
1677 : : // e.g. `macro foo($e:expr) {}`
1678 : :
1679 : : // parse macro matcher
1680 : 39 : location_t locus = lexer.peek_token ()->get_locus ();
1681 : 39 : AST::MacroMatcher matcher = parse_macro_matcher ();
1682 : 39 : if (matcher.is_error ())
1683 : 0 : return nullptr;
1684 : :
1685 : : // check delimiter of macro matcher
1686 : 39 : if (matcher.get_delim_type () != AST::DelimType::PARENS)
1687 : : {
1688 : 0 : Error error (locus, "only parenthesis can be used for a macro "
1689 : : "matcher in declarative macro definition");
1690 : 0 : add_error (std::move (error));
1691 : 0 : return nullptr;
1692 : 0 : }
1693 : :
1694 : 39 : location_t transcriber_loc = lexer.peek_token ()->get_locus ();
1695 : 39 : AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
1696 : 39 : AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc);
1697 : :
1698 : 39 : if (transcriber.get_token_tree ().get_delim_type ()
1699 : : != AST::DelimType::CURLY)
1700 : : {
1701 : 1 : Error error (transcriber_loc,
1702 : : "only braces can be used for a macro transcriber "
1703 : : "in declarative macro definition");
1704 : 1 : add_error (std::move (error));
1705 : 1 : return nullptr;
1706 : 1 : }
1707 : :
1708 : 38 : std::vector<AST::MacroRule> macro_rules;
1709 : 38 : macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
1710 : : locus);
1711 : :
1712 : : return std::unique_ptr<AST::MacroRulesDefinition> (
1713 : 76 : AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
1714 : : macro_rules,
1715 : : std::move (outer_attrs),
1716 : 38 : macro_locus, vis));
1717 : 116 : }
1718 : 25 : else if (t->get_id () == LEFT_CURLY)
1719 : : {
1720 : : // multiple definitions of macro rule separated by comma
1721 : : // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
1722 : :
1723 : : // parse left curly
1724 : 25 : const_TokenPtr left_curly = expect_token (LEFT_CURLY);
1725 : 25 : if (left_curly == nullptr)
1726 : : {
1727 : 0 : return nullptr;
1728 : : }
1729 : :
1730 : : // parse actual macro rules
1731 : 25 : std::vector<AST::MacroRule> macro_rules;
1732 : :
1733 : : // must be at least one macro rule, so parse it
1734 : 25 : AST::MacroRule initial_rule = parse_macro_rule ();
1735 : 25 : if (initial_rule.is_error ())
1736 : : {
1737 : 1 : Error error (
1738 : 1 : lexer.peek_token ()->get_locus (),
1739 : : "required first macro rule in declarative macro definition "
1740 : : "could not be parsed");
1741 : 1 : add_error (std::move (error));
1742 : :
1743 : : // skip after somewhere?
1744 : 1 : return nullptr;
1745 : 1 : }
1746 : 24 : macro_rules.push_back (std::move (initial_rule));
1747 : :
1748 : 24 : t = lexer.peek_token ();
1749 : : // parse macro rules
1750 : 40 : while (t->get_id () == COMMA)
1751 : : {
1752 : : // skip comma
1753 : 32 : lexer.skip_token ();
1754 : :
1755 : : // don't parse if end of macro rules
1756 : 64 : if (token_id_matches_delims (lexer.peek_token ()->get_id (),
1757 : : AST::CURLY))
1758 : : {
1759 : : break;
1760 : : }
1761 : :
1762 : : // try to parse next rule
1763 : 16 : AST::MacroRule rule = parse_macro_rule ();
1764 : 16 : if (rule.is_error ())
1765 : : {
1766 : 0 : Error error (
1767 : 0 : lexer.peek_token ()->get_locus (),
1768 : : "failed to parse macro rule in declarative macro definition");
1769 : 0 : add_error (std::move (error));
1770 : :
1771 : 0 : return nullptr;
1772 : 0 : }
1773 : :
1774 : 16 : macro_rules.push_back (std::move (rule));
1775 : :
1776 : 16 : t = lexer.peek_token ();
1777 : : }
1778 : :
1779 : : // parse right curly
1780 : 24 : const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
1781 : 24 : if (right_curly == nullptr)
1782 : : {
1783 : 0 : return nullptr;
1784 : : }
1785 : :
1786 : : return std::unique_ptr<AST::MacroRulesDefinition> (
1787 : 48 : AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
1788 : : std::move (macro_rules),
1789 : : std::move (outer_attrs),
1790 : 24 : macro_locus, vis));
1791 : 50 : }
1792 : : else
1793 : : {
1794 : 0 : add_error (Error (t->get_locus (),
1795 : : "unexpected token %qs - expecting delimiters "
1796 : : "(for a declarative macro definiton)",
1797 : : t->get_token_description ()));
1798 : 0 : return nullptr;
1799 : : }
1800 : 128 : }
1801 : :
1802 : : // Parses a semi-coloned (except for full block) macro invocation item.
1803 : : template <typename ManagedTokenSource>
1804 : : std::unique_ptr<AST::MacroInvocation>
1805 : 4977 : Parser<ManagedTokenSource>::parse_macro_invocation_semi (
1806 : : AST::AttrVec outer_attrs)
1807 : : {
1808 : 4977 : location_t macro_locus = lexer.peek_token ()->get_locus ();
1809 : 4977 : AST::SimplePath path = parse_simple_path ();
1810 : :
1811 : 4977 : if (!skip_token (EXCLAM))
1812 : : {
1813 : : // skip after somewhere?
1814 : 0 : return nullptr;
1815 : : }
1816 : :
1817 : : // save delim type to ensure it is reused later
1818 : 4977 : AST::DelimType delim_type = AST::PARENS;
1819 : :
1820 : : // Map tokens to DelimType
1821 : 4977 : const_TokenPtr t = lexer.peek_token ();
1822 : 4977 : switch (t->get_id ())
1823 : : {
1824 : : case LEFT_PAREN:
1825 : : delim_type = AST::PARENS;
1826 : : break;
1827 : 0 : case LEFT_SQUARE:
1828 : 0 : delim_type = AST::SQUARE;
1829 : 0 : break;
1830 : 3506 : case LEFT_CURLY:
1831 : 3506 : delim_type = AST::CURLY;
1832 : 3506 : break;
1833 : 0 : default:
1834 : 0 : add_error (Error (t->get_locus (),
1835 : : "unexpected token %qs - expecting delimiters (for a "
1836 : : "macro invocation semi body)",
1837 : : t->get_token_description ()));
1838 : :
1839 : 0 : return nullptr;
1840 : : }
1841 : 4977 : location_t tok_tree_locus = t->get_locus ();
1842 : 4977 : lexer.skip_token ();
1843 : :
1844 : : // parse actual token trees
1845 : 4977 : std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
1846 : 4977 : auto delim_open
1847 : 4977 : = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1848 : 4977 : token_trees.push_back (std::move (delim_open));
1849 : :
1850 : 4977 : t = lexer.peek_token ();
1851 : : // parse token trees until the initial delimiter token is found again
1852 : 63968 : while (!token_id_matches_delims (t->get_id (), delim_type)
1853 : 63968 : && t->get_id () != END_OF_FILE)
1854 : : {
1855 : 58991 : std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
1856 : :
1857 : 58991 : if (tree == nullptr)
1858 : 0 : return nullptr;
1859 : :
1860 : 58991 : token_trees.push_back (std::move (tree));
1861 : :
1862 : 58991 : t = lexer.peek_token ();
1863 : : }
1864 : 4977 : auto delim_close
1865 : 4977 : = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1866 : 4977 : token_trees.push_back (std::move (delim_close));
1867 : :
1868 : 4977 : AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
1869 : : tok_tree_locus);
1870 : 4977 : AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree));
1871 : :
1872 : : // parse end delimiters
1873 : 4977 : t = lexer.peek_token ();
1874 : 4977 : if (token_id_matches_delims (t->get_id (), delim_type))
1875 : : {
1876 : : // tokens match opening delimiter, so skip.
1877 : 4976 : lexer.skip_token ();
1878 : :
1879 : 4976 : if (delim_type != AST::CURLY)
1880 : : {
1881 : : // skip semicolon at end of non-curly macro invocation semis
1882 : 1470 : if (!skip_token (SEMICOLON))
1883 : : {
1884 : : // as this is the end, allow recovery (probably) - may change
1885 : :
1886 : 0 : return AST::MacroInvocation::Regular (std::move (invoc_data),
1887 : : std::move (outer_attrs),
1888 : 0 : macro_locus, true);
1889 : : }
1890 : : }
1891 : :
1892 : : // DEBUG:
1893 : 9952 : rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
1894 : : t->get_token_description (),
1895 : : lexer.peek_token ()->get_token_description ());
1896 : :
1897 : 9952 : return AST::MacroInvocation::Regular (std::move (invoc_data),
1898 : : std::move (outer_attrs),
1899 : 4976 : macro_locus, true);
1900 : : }
1901 : : else
1902 : : {
1903 : : // tokens don't match opening delimiters, so produce error
1904 : 1 : Error error (t->get_locus (),
1905 : : "unexpected token %qs - expecting closing delimiter %qs "
1906 : : "(for a macro invocation semi)",
1907 : : t->get_token_description (),
1908 : : (delim_type == AST::PARENS
1909 : : ? ")"
1910 : : : (delim_type == AST::SQUARE ? "]" : "}")));
1911 : 1 : add_error (std::move (error));
1912 : :
1913 : : /* return empty macro invocation despite possibly parsing mostly valid one
1914 : : * - TODO is this a good idea? */
1915 : 1 : return nullptr;
1916 : 1 : }
1917 : 9954 : }
1918 : :
1919 : : // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
1920 : : template <typename ManagedTokenSource>
1921 : : std::unique_ptr<AST::MacroInvocation>
1922 : 1710 : Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
1923 : : {
1924 : : // parse macro path
1925 : 1710 : AST::SimplePath macro_path = parse_simple_path ();
1926 : 1710 : if (macro_path.is_empty ())
1927 : : {
1928 : 296 : Error error (lexer.peek_token ()->get_locus (),
1929 : : "failed to parse macro invocation path");
1930 : 296 : add_error (std::move (error));
1931 : :
1932 : : // skip?
1933 : 296 : return nullptr;
1934 : 296 : }
1935 : :
1936 : 1414 : if (!skip_token (EXCLAM))
1937 : : {
1938 : : // skip after somewhere?
1939 : 3 : return nullptr;
1940 : : }
1941 : :
1942 : : // parse internal delim token tree
1943 : 1411 : AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
1944 : :
1945 : 1411 : location_t macro_locus = macro_path.get_locus ();
1946 : :
1947 : 2822 : return AST::MacroInvocation::Regular (
1948 : 2822 : AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)),
1949 : 1411 : std::move (outer_attrs), macro_locus);
1950 : 1411 : }
1951 : :
1952 : : // Parses a macro rule definition - does not parse semicolons.
1953 : : template <typename ManagedTokenSource>
1954 : : AST::MacroRule
1955 : 1837 : Parser<ManagedTokenSource>::parse_macro_rule ()
1956 : : {
1957 : 1837 : location_t locus = lexer.peek_token ()->get_locus ();
1958 : :
1959 : : // parse macro matcher
1960 : 1837 : AST::MacroMatcher matcher = parse_macro_matcher ();
1961 : :
1962 : 1837 : if (matcher.is_error ())
1963 : 13 : return AST::MacroRule::create_error (locus);
1964 : :
1965 : 1824 : if (!skip_token (MATCH_ARROW))
1966 : : {
1967 : : // skip after somewhere?
1968 : 0 : return AST::MacroRule::create_error (locus);
1969 : : }
1970 : :
1971 : : // parse transcriber (this is just a delim token tree)
1972 : 1824 : location_t token_tree_loc = lexer.peek_token ()->get_locus ();
1973 : 1824 : AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc);
1974 : :
1975 : 1824 : return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
1976 : 1824 : }
1977 : :
1978 : : // Parses a macro matcher (part of a macro rule definition).
1979 : : template <typename ManagedTokenSource>
1980 : : AST::MacroMatcher
1981 : 1983 : Parser<ManagedTokenSource>::parse_macro_matcher ()
1982 : : {
1983 : : // save delim type to ensure it is reused later
1984 : 1983 : AST::DelimType delim_type = AST::PARENS;
1985 : :
1986 : : // DEBUG
1987 : 1983 : rust_debug ("begun parsing macro matcher");
1988 : :
1989 : : // Map tokens to DelimType
1990 : 1983 : const_TokenPtr t = lexer.peek_token ();
1991 : 1983 : location_t locus = t->get_locus ();
1992 : 1983 : switch (t->get_id ())
1993 : : {
1994 : : case LEFT_PAREN:
1995 : : delim_type = AST::PARENS;
1996 : : break;
1997 : 65 : case LEFT_SQUARE:
1998 : 65 : delim_type = AST::SQUARE;
1999 : 65 : break;
2000 : 24 : case LEFT_CURLY:
2001 : 24 : delim_type = AST::CURLY;
2002 : 24 : break;
2003 : 1 : default:
2004 : 1 : add_error (Error (
2005 : : t->get_locus (),
2006 : : "unexpected token %qs - expecting delimiters (for a macro matcher)",
2007 : : t->get_token_description ()));
2008 : :
2009 : 1 : return AST::MacroMatcher::create_error (t->get_locus ());
2010 : : }
2011 : 1982 : lexer.skip_token ();
2012 : :
2013 : : // parse actual macro matches
2014 : 1982 : std::vector<std::unique_ptr<AST::MacroMatch>> matches;
2015 : : // Set of possible preceding macro matches to make sure follow-set
2016 : : // restrictions are respected.
2017 : : // TODO: Consider using std::reference_wrapper instead of raw pointers?
2018 : 1982 : std::vector<const AST::MacroMatch *> last_matches;
2019 : :
2020 : 1982 : t = lexer.peek_token ();
2021 : : // parse token trees until the initial delimiter token is found again
2022 : 6345 : while (!token_id_matches_delims (t->get_id (), delim_type))
2023 : : {
2024 : 4363 : std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
2025 : :
2026 : 4363 : if (match == nullptr)
2027 : : {
2028 : 1 : Error error (
2029 : : t->get_locus (),
2030 : : "failed to parse macro match for macro matcher - found %qs",
2031 : : t->get_token_description ());
2032 : 1 : add_error (std::move (error));
2033 : :
2034 : 1 : return AST::MacroMatcher::create_error (t->get_locus ());
2035 : 1 : }
2036 : :
2037 : 4362 : if (matches.size () > 0)
2038 : : {
2039 : 2752 : const auto *last_match = matches.back ().get ();
2040 : :
2041 : : // We want to check if we are dealing with a zeroable repetition
2042 : 2752 : bool zeroable = false;
2043 : 2752 : if (last_match->get_macro_match_type ()
2044 : : == AST::MacroMatch::MacroMatchType::Repetition)
2045 : : {
2046 : 42 : auto repetition
2047 : : = static_cast<const AST::MacroMatchRepetition *> (last_match);
2048 : :
2049 : 42 : if (repetition->get_op ()
2050 : : != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
2051 : : zeroable = true;
2052 : : }
2053 : :
2054 : : if (!zeroable)
2055 : 2752 : last_matches.clear ();
2056 : :
2057 : 2752 : last_matches.emplace_back (last_match);
2058 : :
2059 : 5507 : for (auto last : last_matches)
2060 : 2767 : if (!is_match_compatible (*last, *match))
2061 : : return AST::MacroMatcher::create_error (
2062 : 12 : match->get_match_locus ());
2063 : : }
2064 : :
2065 : 4350 : matches.push_back (std::move (match));
2066 : :
2067 : : // DEBUG
2068 : 4350 : rust_debug ("pushed back a match in macro matcher");
2069 : :
2070 : 4350 : t = lexer.peek_token ();
2071 : : }
2072 : :
2073 : : // parse end delimiters
2074 : 1969 : t = lexer.peek_token ();
2075 : 1969 : if (token_id_matches_delims (t->get_id (), delim_type))
2076 : : {
2077 : : // tokens match opening delimiter, so skip.
2078 : 1969 : lexer.skip_token ();
2079 : :
2080 : 1969 : return AST::MacroMatcher (delim_type, std::move (matches), locus);
2081 : : }
2082 : : else
2083 : : {
2084 : : // tokens don't match opening delimiters, so produce error
2085 : 0 : Error error (t->get_locus (),
2086 : : "unexpected token %qs - expecting closing delimiter %qs "
2087 : : "(for a macro matcher)",
2088 : : t->get_token_description (),
2089 : : (delim_type == AST::PARENS
2090 : : ? ")"
2091 : : : (delim_type == AST::SQUARE ? "]" : "}")));
2092 : 0 : add_error (std::move (error));
2093 : :
2094 : : /* return error macro matcher despite possibly parsing mostly correct one?
2095 : : * TODO is this the best idea? */
2096 : 0 : return AST::MacroMatcher::create_error (t->get_locus ());
2097 : 0 : }
2098 : 1982 : }
2099 : :
2100 : : // Parses a macro match (syntax match inside a matcher in a macro rule).
2101 : : template <typename ManagedTokenSource>
2102 : : std::unique_ptr<AST::MacroMatch>
2103 : 5247 : Parser<ManagedTokenSource>::parse_macro_match ()
2104 : : {
2105 : : // branch based on token available
2106 : 5247 : const_TokenPtr t = lexer.peek_token ();
2107 : 5247 : switch (t->get_id ())
2108 : : {
2109 : 107 : case LEFT_PAREN:
2110 : : case LEFT_SQUARE:
2111 : : case LEFT_CURLY:
2112 : : {
2113 : : // must be macro matcher as delimited
2114 : 107 : AST::MacroMatcher matcher = parse_macro_matcher ();
2115 : 107 : if (matcher.is_error ())
2116 : : {
2117 : 1 : Error error (lexer.peek_token ()->get_locus (),
2118 : : "failed to parse macro matcher in macro match");
2119 : 1 : add_error (std::move (error));
2120 : :
2121 : 1 : return nullptr;
2122 : 1 : }
2123 : 106 : return std::unique_ptr<AST::MacroMatcher> (
2124 : 106 : new AST::MacroMatcher (std::move (matcher)));
2125 : 107 : }
2126 : 3434 : case DOLLAR_SIGN:
2127 : : {
2128 : : // have to do more lookahead to determine if fragment or repetition
2129 : 3434 : const_TokenPtr t2 = lexer.peek_token (1);
2130 : 3434 : switch (t2->get_id ())
2131 : : {
2132 : 2747 : case IDENTIFIER:
2133 : : case UNDERSCORE:
2134 : : // macro fragment
2135 : 2747 : return parse_macro_match_fragment ();
2136 : 673 : case LEFT_PAREN:
2137 : : // macro repetition
2138 : 673 : return parse_macro_match_repetition ();
2139 : 14 : default:
2140 : 14 : if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
2141 : : {
2142 : : // keyword as macro fragment
2143 : 14 : return parse_macro_match_fragment ();
2144 : : }
2145 : : else
2146 : : {
2147 : : // error: unrecognised
2148 : 0 : add_error (Error (
2149 : : t2->get_locus (),
2150 : : "unrecognised token combination %<$%s%> at start of "
2151 : : "macro match - did you mean %<$identifier%> or %<$(%>?",
2152 : : t2->get_token_description ()));
2153 : :
2154 : : // skip somewhere?
2155 : 0 : return nullptr;
2156 : : }
2157 : : }
2158 : 3434 : }
2159 : 0 : case RIGHT_PAREN:
2160 : : case RIGHT_SQUARE:
2161 : : case RIGHT_CURLY:
2162 : : // not allowed
2163 : 0 : add_error (Error (
2164 : : t->get_locus (),
2165 : : "closing delimiters like %qs are not allowed at the start of a macro "
2166 : : "match",
2167 : : t->get_token_description ()));
2168 : :
2169 : : // skip somewhere?
2170 : 0 : return nullptr;
2171 : 1706 : default:
2172 : : // just the token
2173 : 1706 : lexer.skip_token ();
2174 : 1706 : return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
2175 : : }
2176 : 5247 : }
2177 : :
2178 : : // Parses a fragment macro match.
2179 : : template <typename ManagedTokenSource>
2180 : : std::unique_ptr<AST::MacroMatchFragment>
2181 : 2761 : Parser<ManagedTokenSource>::parse_macro_match_fragment ()
2182 : : {
2183 : 2761 : location_t fragment_locus = lexer.peek_token ()->get_locus ();
2184 : 2761 : skip_token (DOLLAR_SIGN);
2185 : :
2186 : 2761 : Identifier ident;
2187 : 2761 : auto identifier = lexer.peek_token ();
2188 : 2761 : if (identifier->get_id () == UNDERSCORE)
2189 : 6 : ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
2190 : : else
2191 : 5516 : ident = {identifier};
2192 : :
2193 : 2761 : if (ident.empty ())
2194 : : {
2195 : 0 : Error error (lexer.peek_token ()->get_locus (),
2196 : : "missing identifier in macro match fragment");
2197 : 0 : add_error (std::move (error));
2198 : :
2199 : 0 : return nullptr;
2200 : 0 : }
2201 : 2761 : skip_token (identifier->get_id ());
2202 : :
2203 : 2761 : if (!skip_token (COLON))
2204 : : {
2205 : : // skip after somewhere?
2206 : 0 : return nullptr;
2207 : : }
2208 : :
2209 : : // get MacroFragSpec for macro
2210 : 2761 : const_TokenPtr t = expect_token (IDENTIFIER);
2211 : 2761 : if (t == nullptr)
2212 : 0 : return nullptr;
2213 : :
2214 : : AST::MacroFragSpec frag
2215 : 2761 : = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
2216 : 2761 : if (frag.is_error ())
2217 : : {
2218 : 0 : Error error (t->get_locus (),
2219 : : "invalid fragment specifier %qs in fragment macro match",
2220 : 0 : t->get_str ().c_str ());
2221 : 0 : add_error (std::move (error));
2222 : :
2223 : 0 : return nullptr;
2224 : 0 : }
2225 : :
2226 : : return std::unique_ptr<AST::MacroMatchFragment> (
2227 : 2761 : new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
2228 : 5522 : }
2229 : :
2230 : : // Parses a repetition macro match.
2231 : : template <typename ManagedTokenSource>
2232 : : std::unique_ptr<AST::MacroMatchRepetition>
2233 : 673 : Parser<ManagedTokenSource>::parse_macro_match_repetition ()
2234 : : {
2235 : 673 : skip_token (DOLLAR_SIGN);
2236 : 673 : skip_token (LEFT_PAREN);
2237 : :
2238 : 673 : std::vector<std::unique_ptr<AST::MacroMatch>> matches;
2239 : :
2240 : : // parse required first macro match
2241 : 673 : std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
2242 : 673 : if (initial_match == nullptr)
2243 : : {
2244 : 0 : Error error (
2245 : 0 : lexer.peek_token ()->get_locus (),
2246 : : "could not parse required first macro match in macro match repetition");
2247 : 0 : add_error (std::move (error));
2248 : :
2249 : : // skip after somewhere?
2250 : 0 : return nullptr;
2251 : 0 : }
2252 : 673 : matches.push_back (std::move (initial_match));
2253 : :
2254 : : // parse optional later macro matches
2255 : 673 : const_TokenPtr t = lexer.peek_token ();
2256 : 884 : while (t->get_id () != RIGHT_PAREN)
2257 : : {
2258 : 211 : std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
2259 : :
2260 : 211 : if (match == nullptr)
2261 : : {
2262 : 0 : Error error (lexer.peek_token ()->get_locus (),
2263 : : "failed to parse macro match in macro match repetition");
2264 : 0 : add_error (std::move (error));
2265 : :
2266 : 0 : return nullptr;
2267 : 0 : }
2268 : :
2269 : 211 : matches.push_back (std::move (match));
2270 : :
2271 : 211 : t = lexer.peek_token ();
2272 : : }
2273 : :
2274 : 673 : if (!skip_token (RIGHT_PAREN))
2275 : : {
2276 : : // skip after somewhere?
2277 : 0 : return nullptr;
2278 : : }
2279 : :
2280 : 673 : t = lexer.peek_token ();
2281 : : // see if separator token exists
2282 : 673 : std::unique_ptr<AST::Token> separator = nullptr;
2283 : 673 : switch (t->get_id ())
2284 : : {
2285 : : // repetition operators
2286 : : case ASTERISK:
2287 : : case PLUS:
2288 : : case QUESTION_MARK:
2289 : : // delimiters
2290 : : case LEFT_PAREN:
2291 : : case LEFT_CURLY:
2292 : : case LEFT_SQUARE:
2293 : : case RIGHT_PAREN:
2294 : : case RIGHT_CURLY:
2295 : : case RIGHT_SQUARE:
2296 : : // separator does not exist, so still null and don't skip token
2297 : : break;
2298 : 165 : default:
2299 : : // separator does exist
2300 : 165 : separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
2301 : 165 : lexer.skip_token ();
2302 : : break;
2303 : : }
2304 : :
2305 : : // parse repetition operator
2306 : 673 : t = lexer.peek_token ();
2307 : 673 : AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
2308 : 673 : switch (t->get_id ())
2309 : : {
2310 : 536 : case ASTERISK:
2311 : 536 : op = AST::MacroMatchRepetition::ANY;
2312 : 536 : lexer.skip_token ();
2313 : : break;
2314 : 79 : case PLUS:
2315 : 79 : op = AST::MacroMatchRepetition::ONE_OR_MORE;
2316 : 79 : lexer.skip_token ();
2317 : : break;
2318 : 58 : case QUESTION_MARK:
2319 : 58 : op = AST::MacroMatchRepetition::ZERO_OR_ONE;
2320 : 58 : lexer.skip_token ();
2321 : :
2322 : 58 : if (separator != nullptr)
2323 : : {
2324 : 1 : add_error (
2325 : 2 : Error (separator->get_locus (),
2326 : : "the %<?%> macro repetition operator does not take a "
2327 : : "separator"));
2328 : 1 : separator = nullptr;
2329 : : }
2330 : :
2331 : : break;
2332 : 0 : default:
2333 : 0 : add_error (
2334 : 0 : Error (t->get_locus (),
2335 : : "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
2336 : : "macro match - found %qs",
2337 : : t->get_token_description ()));
2338 : :
2339 : : // skip after somewhere?
2340 : 0 : return nullptr;
2341 : : }
2342 : :
2343 : : return std::unique_ptr<AST::MacroMatchRepetition> (
2344 : 673 : new AST::MacroMatchRepetition (std::move (matches), op,
2345 : 673 : std::move (separator), t->get_locus ()));
2346 : 1346 : }
2347 : :
2348 : : /* Parses a visibility syntactical production (i.e. creating a non-default
2349 : : * visibility) */
2350 : : template <typename ManagedTokenSource>
2351 : : AST::Visibility
2352 : 53252 : Parser<ManagedTokenSource>::parse_visibility ()
2353 : : {
2354 : : // check for no visibility
2355 : 106504 : if (lexer.peek_token ()->get_id () != PUB)
2356 : : {
2357 : 39078 : return AST::Visibility::create_private ();
2358 : : }
2359 : :
2360 : 14174 : auto vis_loc = lexer.peek_token ()->get_locus ();
2361 : 14174 : lexer.skip_token ();
2362 : :
2363 : : // create simple pub visibility if
2364 : : // - found no parentheses
2365 : : // - found unit type `()`
2366 : 28348 : if (lexer.peek_token ()->get_id () != LEFT_PAREN
2367 : 14555 : || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
2368 : : {
2369 : 13794 : return AST::Visibility::create_public (vis_loc);
2370 : : // or whatever
2371 : : }
2372 : :
2373 : 380 : lexer.skip_token ();
2374 : :
2375 : 380 : const_TokenPtr t = lexer.peek_token ();
2376 : 380 : auto path_loc = t->get_locus ();
2377 : :
2378 : 380 : switch (t->get_id ())
2379 : : {
2380 : 266 : case CRATE:
2381 : 266 : lexer.skip_token ();
2382 : :
2383 : 266 : skip_token (RIGHT_PAREN);
2384 : :
2385 : 266 : return AST::Visibility::create_crate (path_loc, vis_loc);
2386 : 0 : case SELF:
2387 : 0 : lexer.skip_token ();
2388 : :
2389 : 0 : skip_token (RIGHT_PAREN);
2390 : :
2391 : 0 : return AST::Visibility::create_self (path_loc, vis_loc);
2392 : 96 : case SUPER:
2393 : 96 : lexer.skip_token ();
2394 : :
2395 : 96 : skip_token (RIGHT_PAREN);
2396 : :
2397 : 96 : return AST::Visibility::create_super (path_loc, vis_loc);
2398 : 18 : case IN:
2399 : : {
2400 : 18 : lexer.skip_token ();
2401 : :
2402 : : // parse the "in" path as well
2403 : 18 : AST::SimplePath path = parse_simple_path ();
2404 : 18 : if (path.is_empty ())
2405 : : {
2406 : 0 : Error error (lexer.peek_token ()->get_locus (),
2407 : : "missing path in pub(in path) visibility");
2408 : 0 : add_error (std::move (error));
2409 : :
2410 : : // skip after somewhere?
2411 : 0 : return AST::Visibility::create_error ();
2412 : 0 : }
2413 : :
2414 : 18 : skip_token (RIGHT_PAREN);
2415 : :
2416 : 18 : return AST::Visibility::create_in_path (std::move (path), vis_loc);
2417 : 18 : }
2418 : 0 : default:
2419 : 0 : add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
2420 : : t->get_token_description ()));
2421 : :
2422 : 0 : lexer.skip_token ();
2423 : 0 : return AST::Visibility::create_error ();
2424 : : }
2425 : 380 : }
2426 : :
2427 : : // Parses a module - either a bodied module or a module defined in another file.
2428 : : template <typename ManagedTokenSource>
2429 : : std::unique_ptr<AST::Module>
2430 : 1606 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
2431 : : AST::AttrVec outer_attrs)
2432 : : {
2433 : 1606 : location_t locus = lexer.peek_token ()->get_locus ();
2434 : :
2435 : 1606 : Unsafety safety = Unsafety::Normal;
2436 : 3212 : if (lexer.peek_token ()->get_id () == UNSAFE)
2437 : : {
2438 : 1 : safety = Unsafety::Unsafe;
2439 : 1 : skip_token (UNSAFE);
2440 : : }
2441 : :
2442 : 1606 : skip_token (MOD);
2443 : :
2444 : 1606 : const_TokenPtr module_name = expect_token (IDENTIFIER);
2445 : 1606 : if (module_name == nullptr)
2446 : : {
2447 : 0 : return nullptr;
2448 : : }
2449 : 1606 : Identifier name{module_name};
2450 : :
2451 : 1606 : const_TokenPtr t = lexer.peek_token ();
2452 : :
2453 : 1606 : switch (t->get_id ())
2454 : : {
2455 : 288 : case SEMICOLON:
2456 : 288 : lexer.skip_token ();
2457 : :
2458 : : // Construct an external module
2459 : : return std::unique_ptr<AST::Module> (
2460 : 864 : new AST::Module (std::move (name), std::move (vis),
2461 : : std::move (outer_attrs), locus, safety,
2462 : 864 : lexer.get_filename (), inline_module_stack));
2463 : 1318 : case LEFT_CURLY:
2464 : : {
2465 : 1318 : lexer.skip_token ();
2466 : :
2467 : : // parse inner attributes
2468 : 1318 : AST::AttrVec inner_attrs = parse_inner_attributes ();
2469 : :
2470 : 1318 : std::string default_path = name.as_string ();
2471 : :
2472 : 1318 : if (inline_module_stack.empty ())
2473 : : {
2474 : 778 : std::string filename = lexer.get_filename ();
2475 : 778 : auto slash_idx = filename.rfind (file_separator);
2476 : 778 : if (slash_idx == std::string::npos)
2477 : : slash_idx = 0;
2478 : : else
2479 : 778 : slash_idx++;
2480 : 778 : filename = filename.substr (slash_idx);
2481 : :
2482 : 778 : std::string subdir;
2483 : 778 : if (get_file_subdir (filename, subdir))
2484 : 770 : default_path = subdir + file_separator + name.as_string ();
2485 : 778 : }
2486 : :
2487 : 1318 : std::string module_path_name
2488 : : = extract_module_path (inner_attrs, outer_attrs, default_path);
2489 : 1318 : InlineModuleStackScope scope (*this, std::move (module_path_name));
2490 : :
2491 : : // parse items
2492 : 1318 : std::vector<std::unique_ptr<AST::Item>> items;
2493 : 1318 : const_TokenPtr tok = lexer.peek_token ();
2494 : 6240 : while (tok->get_id () != RIGHT_CURLY)
2495 : : {
2496 : 4922 : std::unique_ptr<AST::Item> item = parse_item (false);
2497 : 4922 : if (item == nullptr)
2498 : : {
2499 : 0 : Error error (tok->get_locus (),
2500 : : "failed to parse item in module");
2501 : 0 : add_error (std::move (error));
2502 : :
2503 : 0 : return nullptr;
2504 : 0 : }
2505 : :
2506 : 4922 : items.push_back (std::move (item));
2507 : :
2508 : 4922 : tok = lexer.peek_token ();
2509 : : }
2510 : :
2511 : 1318 : if (!skip_token (RIGHT_CURLY))
2512 : : {
2513 : : // skip somewhere?
2514 : 0 : return nullptr;
2515 : : }
2516 : :
2517 : : return std::unique_ptr<AST::Module> (
2518 : 1318 : new AST::Module (std::move (name), locus, std::move (items),
2519 : : std::move (vis), safety, std::move (inner_attrs),
2520 : 1318 : std::move (outer_attrs))); // module name?
2521 : 1318 : }
2522 : 0 : default:
2523 : 0 : add_error (
2524 : 0 : Error (t->get_locus (),
2525 : : "unexpected token %qs in module declaration/definition item",
2526 : : t->get_token_description ()));
2527 : :
2528 : 0 : lexer.skip_token ();
2529 : 0 : return nullptr;
2530 : : }
2531 : 1606 : }
2532 : :
2533 : : // Parses an extern crate declaration (dependency on external crate)
2534 : : template <typename ManagedTokenSource>
2535 : : std::unique_ptr<AST::ExternCrate>
2536 : 27 : Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
2537 : : AST::AttrVec outer_attrs)
2538 : : {
2539 : 27 : location_t locus = lexer.peek_token ()->get_locus ();
2540 : 27 : if (!skip_token (EXTERN_KW))
2541 : : {
2542 : 0 : skip_after_semicolon ();
2543 : 0 : return nullptr;
2544 : : }
2545 : :
2546 : 27 : if (!skip_token (CRATE))
2547 : : {
2548 : 0 : skip_after_semicolon ();
2549 : 0 : return nullptr;
2550 : : }
2551 : :
2552 : : /* parse crate reference name - this has its own syntactical rule in reference
2553 : : * but seems to not be used elsewhere, so i'm putting it here */
2554 : 27 : const_TokenPtr crate_name_tok = lexer.peek_token ();
2555 : 27 : std::string crate_name;
2556 : :
2557 : 27 : switch (crate_name_tok->get_id ())
2558 : : {
2559 : 27 : case IDENTIFIER:
2560 : 27 : crate_name = crate_name_tok->get_str ();
2561 : 27 : lexer.skip_token ();
2562 : : break;
2563 : 0 : case SELF:
2564 : 0 : crate_name = Values::Keywords::SELF;
2565 : 0 : lexer.skip_token ();
2566 : : break;
2567 : 0 : default:
2568 : 0 : add_error (
2569 : 0 : Error (crate_name_tok->get_locus (),
2570 : : "expecting crate name (identifier or %<self%>), found %qs",
2571 : : crate_name_tok->get_token_description ()));
2572 : :
2573 : 0 : skip_after_semicolon ();
2574 : 0 : return nullptr;
2575 : : }
2576 : :
2577 : : // don't parse as clause if it doesn't exist
2578 : 54 : if (lexer.peek_token ()->get_id () == SEMICOLON)
2579 : : {
2580 : 27 : lexer.skip_token ();
2581 : :
2582 : : return std::unique_ptr<AST::ExternCrate> (
2583 : 27 : new AST::ExternCrate (std::move (crate_name), std::move (vis),
2584 : 27 : std::move (outer_attrs), locus));
2585 : : }
2586 : :
2587 : : /* parse as clause - this also has its own syntactical rule in reference and
2588 : : * also seems to not be used elsewhere, so including here again. */
2589 : 0 : if (!skip_token (AS))
2590 : : {
2591 : 0 : skip_after_semicolon ();
2592 : 0 : return nullptr;
2593 : : }
2594 : :
2595 : 0 : const_TokenPtr as_name_tok = lexer.peek_token ();
2596 : 0 : std::string as_name;
2597 : :
2598 : 0 : switch (as_name_tok->get_id ())
2599 : : {
2600 : 0 : case IDENTIFIER:
2601 : 0 : as_name = as_name_tok->get_str ();
2602 : 0 : lexer.skip_token ();
2603 : : break;
2604 : 0 : case UNDERSCORE:
2605 : 0 : as_name = Values::Keywords::UNDERSCORE;
2606 : 0 : lexer.skip_token ();
2607 : : break;
2608 : 0 : default:
2609 : 0 : add_error (
2610 : 0 : Error (as_name_tok->get_locus (),
2611 : : "expecting as clause name (identifier or %<_%>), found %qs",
2612 : : as_name_tok->get_token_description ()));
2613 : :
2614 : 0 : skip_after_semicolon ();
2615 : 0 : return nullptr;
2616 : : }
2617 : :
2618 : 0 : if (!skip_token (SEMICOLON))
2619 : : {
2620 : 0 : skip_after_semicolon ();
2621 : 0 : return nullptr;
2622 : : }
2623 : :
2624 : : return std::unique_ptr<AST::ExternCrate> (
2625 : 0 : new AST::ExternCrate (std::move (crate_name), std::move (vis),
2626 : 0 : std::move (outer_attrs), locus, std::move (as_name)));
2627 : 54 : }
2628 : :
2629 : : // Parses a use declaration.
2630 : : template <typename ManagedTokenSource>
2631 : : std::unique_ptr<AST::UseDeclaration>
2632 : 1495 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
2633 : : AST::AttrVec outer_attrs)
2634 : : {
2635 : 1495 : location_t locus = lexer.peek_token ()->get_locus ();
2636 : 1495 : if (!skip_token (USE))
2637 : : {
2638 : 0 : skip_after_semicolon ();
2639 : 0 : return nullptr;
2640 : : }
2641 : :
2642 : : // parse use tree, which is required
2643 : 1495 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2644 : 1495 : if (use_tree == nullptr)
2645 : : {
2646 : 1 : Error error (lexer.peek_token ()->get_locus (),
2647 : : "could not parse use tree in use declaration");
2648 : 1 : add_error (std::move (error));
2649 : :
2650 : 1 : skip_after_semicolon ();
2651 : 1 : return nullptr;
2652 : 1 : }
2653 : :
2654 : 1494 : if (!skip_token (SEMICOLON))
2655 : : {
2656 : 0 : skip_after_semicolon ();
2657 : 0 : return nullptr;
2658 : : }
2659 : :
2660 : : return std::unique_ptr<AST::UseDeclaration> (
2661 : 1494 : new AST::UseDeclaration (std::move (use_tree), std::move (vis),
2662 : 1494 : std::move (outer_attrs), locus));
2663 : 1495 : }
2664 : :
2665 : : // Parses a use tree (which can be recursive and is actually a base class).
2666 : : template <typename ManagedTokenSource>
2667 : : std::unique_ptr<AST::UseTree>
2668 : 2836 : Parser<ManagedTokenSource>::parse_use_tree ()
2669 : : {
2670 : : /* potential syntax definitions in attempt to get algorithm:
2671 : : * Glob:
2672 : : * <- SimplePath :: *
2673 : : * <- :: *
2674 : : * <- *
2675 : : * Nested tree thing:
2676 : : * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
2677 : : * <- :: COMPLICATED_INNER_TREE_THING }
2678 : : * <- { COMPLICATED_INNER_TREE_THING }
2679 : : * Rebind thing:
2680 : : * <- SimplePath as IDENTIFIER
2681 : : * <- SimplePath as _
2682 : : * <- SimplePath
2683 : : */
2684 : :
2685 : : /* current plan of attack: try to parse SimplePath first - if fails, one of
2686 : : * top two then try parse :: - if fails, one of top two. Next is deciding
2687 : : * character for top two. */
2688 : :
2689 : : /* Thus, parsing smaller parts of use tree may require feeding into function
2690 : : * via parameters (or could handle all in this single function because other
2691 : : * use tree types aren't recognised as separate in the spec) */
2692 : :
2693 : : // TODO: I think this function is too complex, probably should split it
2694 : :
2695 : 2836 : location_t locus = lexer.peek_token ()->get_locus ();
2696 : :
2697 : : // bool has_path = false;
2698 : 2836 : AST::SimplePath path = parse_simple_path ();
2699 : :
2700 : 2836 : if (path.is_empty ())
2701 : : {
2702 : : // has no path, so must be glob or nested tree UseTree type
2703 : :
2704 : 2 : bool is_global = false;
2705 : :
2706 : : // check for global scope resolution operator
2707 : 4 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
2708 : : {
2709 : 0 : lexer.skip_token ();
2710 : 0 : is_global = true;
2711 : : }
2712 : :
2713 : 2 : const_TokenPtr t = lexer.peek_token ();
2714 : 2 : switch (t->get_id ())
2715 : : {
2716 : 0 : case ASTERISK:
2717 : : // glob UseTree type
2718 : 0 : lexer.skip_token ();
2719 : :
2720 : 0 : if (is_global)
2721 : 0 : return std::unique_ptr<AST::UseTreeGlob> (
2722 : 0 : new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
2723 : 0 : AST::SimplePath::create_empty (), locus));
2724 : : else
2725 : 0 : return std::unique_ptr<AST::UseTreeGlob> (
2726 : 0 : new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
2727 : 0 : AST::SimplePath::create_empty (), locus));
2728 : 2 : case LEFT_CURLY:
2729 : : {
2730 : : // nested tree UseTree type
2731 : 2 : lexer.skip_token ();
2732 : :
2733 : 2 : std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2734 : :
2735 : 2 : const_TokenPtr t = lexer.peek_token ();
2736 : 5 : while (t->get_id () != RIGHT_CURLY)
2737 : : {
2738 : 3 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2739 : 3 : if (use_tree == nullptr)
2740 : : {
2741 : : break;
2742 : : }
2743 : :
2744 : 3 : use_trees.push_back (std::move (use_tree));
2745 : :
2746 : 6 : if (lexer.peek_token ()->get_id () != COMMA)
2747 : : break;
2748 : :
2749 : 1 : lexer.skip_token ();
2750 : 1 : t = lexer.peek_token ();
2751 : : }
2752 : :
2753 : : // skip end curly delimiter
2754 : 2 : if (!skip_token (RIGHT_CURLY))
2755 : : {
2756 : : // skip after somewhere?
2757 : 0 : return nullptr;
2758 : : }
2759 : :
2760 : 2 : if (is_global)
2761 : 0 : return std::unique_ptr<AST::UseTreeList> (
2762 : 0 : new AST::UseTreeList (AST::UseTreeList::GLOBAL,
2763 : 0 : AST::SimplePath::create_empty (),
2764 : 0 : std::move (use_trees), locus));
2765 : : else
2766 : 2 : return std::unique_ptr<AST::UseTreeList> (
2767 : 4 : new AST::UseTreeList (AST::UseTreeList::NO_PATH,
2768 : 4 : AST::SimplePath::create_empty (),
2769 : 2 : std::move (use_trees), locus));
2770 : 2 : }
2771 : 0 : case AS:
2772 : : // this is not allowed
2773 : 0 : add_error (Error (
2774 : : t->get_locus (),
2775 : : "use declaration with rebind %<as%> requires a valid simple path - "
2776 : : "none found"));
2777 : :
2778 : 0 : skip_after_semicolon ();
2779 : 0 : return nullptr;
2780 : 0 : default:
2781 : 0 : add_error (Error (t->get_locus (),
2782 : : "unexpected token %qs in use tree with "
2783 : : "no valid simple path (i.e. list"
2784 : : " or glob use tree)",
2785 : : t->get_token_description ()));
2786 : :
2787 : 0 : skip_after_semicolon ();
2788 : 0 : return nullptr;
2789 : : }
2790 : 2 : }
2791 : : else
2792 : : {
2793 : 2834 : const_TokenPtr t = lexer.peek_token ();
2794 : :
2795 : 2834 : switch (t->get_id ())
2796 : : {
2797 : 22 : case AS:
2798 : : {
2799 : : // rebind UseTree type
2800 : 22 : lexer.skip_token ();
2801 : :
2802 : 22 : const_TokenPtr t = lexer.peek_token ();
2803 : 22 : switch (t->get_id ())
2804 : : {
2805 : 20 : case IDENTIFIER:
2806 : : // skip lexer token
2807 : 20 : lexer.skip_token ();
2808 : :
2809 : 20 : return std::unique_ptr<AST::UseTreeRebind> (
2810 : 60 : new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
2811 : 60 : std::move (path), locus, t));
2812 : 2 : case UNDERSCORE:
2813 : : // skip lexer token
2814 : 2 : lexer.skip_token ();
2815 : :
2816 : 2 : return std::unique_ptr<AST::UseTreeRebind> (
2817 : 6 : new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
2818 : : std::move (path), locus,
2819 : : {Values::Keywords::UNDERSCORE,
2820 : 2 : t->get_locus ()}));
2821 : 0 : default:
2822 : 0 : add_error (Error (
2823 : : t->get_locus (),
2824 : : "unexpected token %qs in use tree with as clause - expected "
2825 : : "identifier or %<_%>",
2826 : : t->get_token_description ()));
2827 : :
2828 : 0 : skip_after_semicolon ();
2829 : 0 : return nullptr;
2830 : : }
2831 : 22 : }
2832 : 2232 : case SEMICOLON:
2833 : : // rebind UseTree type without rebinding - path only
2834 : :
2835 : : // don't skip semicolon - handled in parse_use_tree
2836 : : // lexer.skip_token();
2837 : : case COMMA:
2838 : : case RIGHT_CURLY:
2839 : : // this may occur in recursive calls - assume it is ok and ignore it
2840 : 2232 : return std::unique_ptr<AST::UseTreeRebind> (
2841 : 4464 : new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
2842 : 2232 : locus));
2843 : : case SCOPE_RESOLUTION:
2844 : : // keep going
2845 : : break;
2846 : 1 : default:
2847 : 1 : add_error (Error (t->get_locus (),
2848 : : "unexpected token %qs in use tree with valid path",
2849 : : t->get_token_description ()));
2850 : 1 : return nullptr;
2851 : : }
2852 : :
2853 : 579 : skip_token ();
2854 : 579 : t = lexer.peek_token ();
2855 : :
2856 : 579 : switch (t->get_id ())
2857 : : {
2858 : 179 : case ASTERISK:
2859 : : // glob UseTree type
2860 : 179 : lexer.skip_token ();
2861 : :
2862 : 179 : return std::unique_ptr<AST::UseTreeGlob> (
2863 : 358 : new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
2864 : 179 : std::move (path), locus));
2865 : 400 : case LEFT_CURLY:
2866 : : {
2867 : : // nested tree UseTree type
2868 : 400 : lexer.skip_token ();
2869 : :
2870 : 400 : std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2871 : :
2872 : : // TODO: think of better control structure
2873 : 400 : const_TokenPtr t = lexer.peek_token ();
2874 : 1738 : while (t->get_id () != RIGHT_CURLY)
2875 : : {
2876 : 1338 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2877 : 1338 : if (use_tree == nullptr)
2878 : : {
2879 : : break;
2880 : : }
2881 : :
2882 : 1338 : use_trees.push_back (std::move (use_tree));
2883 : :
2884 : 2676 : if (lexer.peek_token ()->get_id () != COMMA)
2885 : : break;
2886 : :
2887 : 969 : lexer.skip_token ();
2888 : 969 : t = lexer.peek_token ();
2889 : : }
2890 : :
2891 : : // skip end curly delimiter
2892 : 400 : if (!skip_token (RIGHT_CURLY))
2893 : : {
2894 : : // skip after somewhere?
2895 : 0 : return nullptr;
2896 : : }
2897 : :
2898 : 400 : return std::unique_ptr<AST::UseTreeList> (
2899 : 800 : new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
2900 : : std::move (path), std::move (use_trees),
2901 : 400 : locus));
2902 : 400 : }
2903 : 0 : default:
2904 : 0 : add_error (Error (t->get_locus (),
2905 : : "unexpected token %qs in use tree with valid path",
2906 : : t->get_token_description ()));
2907 : :
2908 : : // skip_after_semicolon();
2909 : 0 : return nullptr;
2910 : : }
2911 : 2834 : }
2912 : 2836 : }
2913 : :
2914 : : // Parses a function (not a method).
2915 : : template <typename ManagedTokenSource>
2916 : : std::unique_ptr<AST::Function>
2917 : 16267 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
2918 : : AST::AttrVec outer_attrs,
2919 : : bool is_external)
2920 : : {
2921 : 16267 : location_t locus = lexer.peek_token ()->get_locus ();
2922 : : // Get qualifiers for function if they exist
2923 : 16267 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
2924 : :
2925 : 16267 : skip_token (FN_KW);
2926 : :
2927 : : // Save function name token
2928 : 16267 : const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
2929 : 16267 : if (function_name_tok == nullptr)
2930 : : {
2931 : 0 : skip_after_next_block ();
2932 : 0 : return nullptr;
2933 : : }
2934 : 16267 : Identifier function_name{function_name_tok};
2935 : :
2936 : : // parse generic params - if exist
2937 : 16267 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2938 : : = parse_generic_params_in_angles ();
2939 : :
2940 : 16267 : if (!skip_token (LEFT_PAREN))
2941 : : {
2942 : 0 : Error error (lexer.peek_token ()->get_locus (),
2943 : : "function declaration missing opening parentheses before "
2944 : : "parameter list");
2945 : 0 : add_error (std::move (error));
2946 : :
2947 : 0 : skip_after_next_block ();
2948 : 0 : return nullptr;
2949 : 0 : }
2950 : :
2951 : 16267 : auto initial_param = parse_self_param ();
2952 : :
2953 : 16267 : if (!initial_param.has_value ()
2954 : 16267 : && initial_param.error () != ParseSelfError::NOT_SELF)
2955 : 0 : return nullptr;
2956 : :
2957 : 18795 : if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
2958 : 1538 : skip_token ();
2959 : :
2960 : : // parse function parameters (only if next token isn't right paren)
2961 : 16267 : std::vector<std::unique_ptr<AST::Param>> function_params;
2962 : :
2963 : 32534 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
2964 : : function_params
2965 : 8111 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
2966 : :
2967 : 16267 : if (initial_param.has_value ())
2968 : 2528 : function_params.insert (function_params.begin (),
2969 : 2528 : std::move (*initial_param));
2970 : :
2971 : 16267 : if (!skip_token (RIGHT_PAREN))
2972 : : {
2973 : 0 : Error error (lexer.peek_token ()->get_locus (),
2974 : : "function declaration missing closing parentheses after "
2975 : : "parameter list");
2976 : 0 : add_error (std::move (error));
2977 : :
2978 : 0 : skip_after_next_block ();
2979 : 0 : return nullptr;
2980 : 0 : }
2981 : :
2982 : : // parse function return type - if exists
2983 : 16267 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
2984 : :
2985 : : // parse where clause - if exists
2986 : 16267 : AST::WhereClause where_clause = parse_where_clause ();
2987 : :
2988 : 16267 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
2989 : 32534 : if (lexer.peek_token ()->get_id () == SEMICOLON)
2990 : 4904 : lexer.skip_token ();
2991 : : else
2992 : : {
2993 : 11363 : std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
2994 : 11363 : if (block_expr == nullptr)
2995 : 28 : return nullptr;
2996 : 11335 : body = std::move (block_expr);
2997 : 11363 : }
2998 : :
2999 : : return std::unique_ptr<AST::Function> (
3000 : 43813 : new AST::Function (std::move (function_name), std::move (qualifiers),
3001 : : std::move (generic_params), std::move (function_params),
3002 : : std::move (return_type), std::move (where_clause),
3003 : : std::move (body), std::move (vis),
3004 : 16239 : std::move (outer_attrs), locus, false, is_external));
3005 : 48801 : }
3006 : :
3007 : : // Parses function or method qualifiers (i.e. const, unsafe, and extern).
3008 : : template <typename ManagedTokenSource>
3009 : : AST::FunctionQualifiers
3010 : 32129 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
3011 : : {
3012 : 32129 : Async async_status = Async::No;
3013 : 32129 : Const const_status = Const::No;
3014 : 32129 : Unsafety unsafe_status = Unsafety::Normal;
3015 : 32129 : bool has_extern = false;
3016 : 32129 : std::string abi;
3017 : :
3018 : 32129 : const_TokenPtr t;
3019 : : location_t locus;
3020 : : // Check in order of const, unsafe, then extern
3021 : 96387 : for (int i = 0; i < 2; i++)
3022 : : {
3023 : 64258 : t = lexer.peek_token ();
3024 : 64258 : locus = t->get_locus ();
3025 : :
3026 : 64258 : switch (t->get_id ())
3027 : : {
3028 : 2192 : case CONST:
3029 : 2192 : lexer.skip_token ();
3030 : 2192 : const_status = Const::Yes;
3031 : 2192 : break;
3032 : 8 : case ASYNC:
3033 : 8 : lexer.skip_token ();
3034 : 8 : async_status = Async::Yes;
3035 : 8 : break;
3036 : : default:
3037 : : // const status is still none
3038 : : break;
3039 : : }
3040 : : }
3041 : :
3042 : 64258 : if (lexer.peek_token ()->get_id () == UNSAFE)
3043 : : {
3044 : 4522 : lexer.skip_token ();
3045 : 4522 : unsafe_status = Unsafety::Unsafe;
3046 : : }
3047 : :
3048 : 64258 : if (lexer.peek_token ()->get_id () == EXTERN_KW)
3049 : : {
3050 : 740 : lexer.skip_token ();
3051 : 740 : has_extern = true;
3052 : :
3053 : : // detect optional abi name
3054 : 740 : const_TokenPtr next_tok = lexer.peek_token ();
3055 : 740 : if (next_tok->get_id () == STRING_LITERAL)
3056 : : {
3057 : 740 : lexer.skip_token ();
3058 : 740 : abi = next_tok->get_str ();
3059 : : }
3060 : 740 : }
3061 : :
3062 : 64258 : return AST::FunctionQualifiers (locus, async_status, const_status,
3063 : 32129 : unsafe_status, has_extern, std::move (abi));
3064 : 32129 : }
3065 : :
3066 : : // Parses generic (lifetime or type) params inside angle brackets (optional).
3067 : : template <typename ManagedTokenSource>
3068 : : std::vector<std::unique_ptr<AST::GenericParam>>
3069 : 54716 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
3070 : : {
3071 : 109432 : if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
3072 : : {
3073 : : // seems to be no generic params, so exit with empty vector
3074 : 46971 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
3075 : : }
3076 : 7745 : lexer.skip_token ();
3077 : :
3078 : : // DEBUG:
3079 : 7745 : rust_debug ("skipped left angle in generic param");
3080 : :
3081 : 7745 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3082 : : = parse_generic_params (is_right_angle_tok);
3083 : :
3084 : : // DEBUG:
3085 : 7745 : rust_debug ("finished parsing actual generic params (i.e. inside angles)");
3086 : :
3087 : 7745 : if (!skip_generics_right_angle ())
3088 : : {
3089 : : // DEBUG
3090 : 1 : rust_debug ("failed to skip generics right angle - returning empty "
3091 : : "generic params");
3092 : :
3093 : 1 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
3094 : : }
3095 : :
3096 : 7744 : return generic_params;
3097 : 7745 : }
3098 : :
3099 : : template <typename ManagedTokenSource>
3100 : : template <typename EndTokenPred>
3101 : : std::unique_ptr<AST::GenericParam>
3102 : 12978 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
3103 : : {
3104 : 12978 : auto outer_attrs = parse_outer_attributes ();
3105 : 12978 : std::unique_ptr<AST::GenericParam> param;
3106 : 12978 : auto token = lexer.peek_token ();
3107 : :
3108 : 12978 : switch (token->get_id ())
3109 : : {
3110 : 1359 : case LIFETIME:
3111 : : {
3112 : 1359 : auto lifetime = parse_lifetime (false);
3113 : 1359 : if (!lifetime)
3114 : : {
3115 : 0 : rust_error_at (
3116 : : token->get_locus (),
3117 : : "failed to parse lifetime in generic parameter list");
3118 : 0 : return nullptr;
3119 : : }
3120 : :
3121 : 1359 : std::vector<AST::Lifetime> lifetime_bounds;
3122 : 2718 : if (lexer.peek_token ()->get_id () == COLON)
3123 : : {
3124 : 19 : lexer.skip_token ();
3125 : : // parse required bounds
3126 : : lifetime_bounds
3127 : 19 : = parse_lifetime_bounds ([is_end_token] (TokenId id) {
3128 : 20 : return is_end_token (id) || id == COMMA;
3129 : : });
3130 : : }
3131 : :
3132 : 2718 : param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
3133 : 1359 : std::move (lifetime.value ()), std::move (lifetime_bounds),
3134 : 1359 : std::move (outer_attrs), token->get_locus ()));
3135 : : break;
3136 : 2718 : }
3137 : 11444 : case IDENTIFIER:
3138 : : {
3139 : 11444 : auto type_ident = token->get_str ();
3140 : 11444 : lexer.skip_token ();
3141 : :
3142 : 11444 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3143 : 22888 : if (lexer.peek_token ()->get_id () == COLON)
3144 : : {
3145 : 2309 : lexer.skip_token ();
3146 : :
3147 : : // parse optional type param bounds
3148 : 2309 : type_param_bounds = parse_type_param_bounds ();
3149 : : }
3150 : :
3151 : 11444 : std::unique_ptr<AST::Type> type = nullptr;
3152 : 22888 : if (lexer.peek_token ()->get_id () == EQUAL)
3153 : : {
3154 : 389 : lexer.skip_token ();
3155 : :
3156 : : // parse required type
3157 : 389 : type = parse_type ();
3158 : 389 : if (!type)
3159 : : {
3160 : 0 : rust_error_at (
3161 : 0 : lexer.peek_token ()->get_locus (),
3162 : : "failed to parse type in type param in generic params");
3163 : 0 : return nullptr;
3164 : : }
3165 : : }
3166 : :
3167 : 11444 : param = std::unique_ptr<AST::TypeParam> (
3168 : 34332 : new AST::TypeParam (std::move (type_ident), token->get_locus (),
3169 : : std::move (type_param_bounds), std::move (type),
3170 : 11444 : std::move (outer_attrs)));
3171 : : break;
3172 : 11444 : }
3173 : 174 : case CONST:
3174 : : {
3175 : 174 : lexer.skip_token ();
3176 : :
3177 : 174 : auto name_token = expect_token (IDENTIFIER);
3178 : :
3179 : 348 : if (!name_token || !expect_token (COLON))
3180 : 1 : return nullptr;
3181 : :
3182 : 173 : auto type = parse_type ();
3183 : 173 : if (!type)
3184 : 1 : return nullptr;
3185 : :
3186 : : // optional default value
3187 : 172 : tl::optional<AST::GenericArg> default_expr = tl::nullopt;
3188 : 344 : if (lexer.peek_token ()->get_id () == EQUAL)
3189 : : {
3190 : 20 : lexer.skip_token ();
3191 : 20 : auto tok = lexer.peek_token ();
3192 : 39 : default_expr = parse_generic_arg ();
3193 : :
3194 : 20 : if (!default_expr)
3195 : : {
3196 : 1 : rust_error_at (tok->get_locus (),
3197 : : "invalid token for start of default value for "
3198 : : "const generic parameter: expected %<block%>, "
3199 : : "%<identifier%> or %<literal%>, got %qs",
3200 : : token_id_to_str (tok->get_id ()));
3201 : 1 : return nullptr;
3202 : : }
3203 : :
3204 : : // At this point, we *know* that we are parsing a const
3205 : : // expression
3206 : 19 : if (default_expr.value ().get_kind ()
3207 : : == AST::GenericArg::Kind::Either)
3208 : 1 : default_expr = default_expr.value ().disambiguate_to_const ();
3209 : 20 : }
3210 : :
3211 : 171 : param = std::unique_ptr<AST::ConstGenericParam> (
3212 : 703 : new AST::ConstGenericParam (name_token->get_str (), std::move (type),
3213 : : default_expr, std::move (outer_attrs),
3214 : 171 : token->get_locus ()));
3215 : :
3216 : : break;
3217 : 347 : }
3218 : 1 : default:
3219 : : // FIXME: Can we clean this last call with a method call?
3220 : 1 : rust_error_at (token->get_locus (),
3221 : : "unexpected token when parsing generic parameters: %qs",
3222 : 1 : token->as_string ().c_str ());
3223 : 1 : return nullptr;
3224 : : }
3225 : :
3226 : 12974 : return param;
3227 : 12978 : }
3228 : :
3229 : : /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
3230 : : * always parse_generic_params_in_angles is what is wanted. */
3231 : : template <typename ManagedTokenSource>
3232 : : template <typename EndTokenPred>
3233 : : std::vector<std::unique_ptr<AST::GenericParam>>
3234 : 7745 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
3235 : : {
3236 : 7745 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
3237 : :
3238 : : /* can't parse lifetime and type params separately due to lookahead issues
3239 : : * thus, parse them all here */
3240 : :
3241 : : /* HACK: used to retain attribute data if a lifetime param is tentatively
3242 : : * parsed but it turns out to be type param */
3243 : 7745 : AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
3244 : :
3245 : : // Did we parse a generic type param yet
3246 : 7745 : auto type_seen = false;
3247 : : // Did we parse a const param with a default value yet
3248 : 7745 : auto const_with_default_seen = false;
3249 : : // Did the user write a lifetime parameter after a type one
3250 : 7745 : auto order_error = false;
3251 : : // Did the user write a const param with a default value after a type one
3252 : 7745 : auto const_with_default_order_error = false;
3253 : :
3254 : : // parse lifetime params
3255 : 54416 : while (!is_end_token (lexer.peek_token ()->get_id ()))
3256 : : {
3257 : 12978 : auto param = parse_generic_param (is_end_token);
3258 : 12978 : if (param)
3259 : : {
3260 : 12974 : if (param->get_kind () == AST::GenericParam::Kind::Type)
3261 : : {
3262 : 11444 : type_seen = true;
3263 : 11444 : if (const_with_default_seen)
3264 : 12974 : const_with_default_order_error = true;
3265 : : }
3266 : 1530 : else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
3267 : 1530 : && type_seen)
3268 : : {
3269 : 2 : order_error = true;
3270 : 2 : if (const_with_default_seen)
3271 : 0 : const_with_default_order_error = true;
3272 : : }
3273 : 1528 : else if (param->get_kind () == AST::GenericParam::Kind::Const)
3274 : : {
3275 : 171 : type_seen = true;
3276 : : AST::ConstGenericParam *const_param
3277 : 171 : = static_cast<AST::ConstGenericParam *> (param.get ());
3278 : 171 : if (const_param->has_default_value ())
3279 : : const_with_default_seen = true;
3280 : 152 : else if (const_with_default_seen)
3281 : 12974 : const_with_default_order_error = true;
3282 : : }
3283 : :
3284 : 12974 : generic_params.emplace_back (std::move (param));
3285 : 12974 : maybe_skip_token (COMMA);
3286 : : }
3287 : : else
3288 : : break;
3289 : : }
3290 : :
3291 : : // FIXME: Add reordering hint
3292 : 7745 : if (order_error)
3293 : : {
3294 : 2 : Error error (generic_params.front ()->get_locus (),
3295 : : "invalid order for generic parameters: lifetime parameters "
3296 : : "must be declared prior to type and const parameters");
3297 : 2 : add_error (std::move (error));
3298 : 2 : }
3299 : 7745 : if (const_with_default_order_error)
3300 : : {
3301 : 1 : Error error (generic_params.front ()->get_locus (),
3302 : : "invalid order for generic parameters: generic parameters "
3303 : : "with a default must be trailing");
3304 : 1 : add_error (std::move (error));
3305 : 1 : }
3306 : :
3307 : 7745 : generic_params.shrink_to_fit ();
3308 : 7745 : return generic_params;
3309 : 7745 : }
3310 : :
3311 : : /* Parses lifetime generic parameters (pointers). Will also consume any
3312 : : * trailing comma. No extra checks for end token. */
3313 : : template <typename ManagedTokenSource>
3314 : : std::vector<std::unique_ptr<AST::LifetimeParam>>
3315 : 17 : Parser<ManagedTokenSource>::parse_lifetime_params ()
3316 : : {
3317 : 17 : std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
3318 : :
3319 : 55 : while (lexer.peek_token ()->get_id () != END_OF_FILE)
3320 : : {
3321 : 19 : auto lifetime_param = parse_lifetime_param ();
3322 : :
3323 : 19 : if (!lifetime_param)
3324 : : {
3325 : : // can't treat as error as only way to get out with trailing comma
3326 : : break;
3327 : : }
3328 : :
3329 : 8 : lifetime_params.emplace_back (
3330 : 8 : new AST::LifetimeParam (std::move (lifetime_param.value ())));
3331 : :
3332 : 16 : if (lexer.peek_token ()->get_id () != COMMA)
3333 : : break;
3334 : :
3335 : : // skip commas, including trailing commas
3336 : 2 : lexer.skip_token ();
3337 : : }
3338 : :
3339 : 17 : lifetime_params.shrink_to_fit ();
3340 : :
3341 : 17 : return lifetime_params;
3342 : : }
3343 : :
3344 : : /* Parses lifetime generic parameters (pointers). Will also consume any
3345 : : * trailing comma. Has extra is_end_token predicate checking. */
3346 : : template <typename ManagedTokenSource>
3347 : : template <typename EndTokenPred>
3348 : : std::vector<std::unique_ptr<AST::LifetimeParam>>
3349 : : Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
3350 : : {
3351 : : std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
3352 : :
3353 : : // if end_token is not specified, it defaults to EOF, so should work fine
3354 : : while (!is_end_token (lexer.peek_token ()->get_id ()))
3355 : : {
3356 : : auto lifetime_param = parse_lifetime_param ();
3357 : :
3358 : : if (!lifetime_param)
3359 : : {
3360 : : /* TODO: is it worth throwing away all lifetime params just because
3361 : : * one failed? */
3362 : : Error error (lexer.peek_token ()->get_locus (),
3363 : : "failed to parse lifetime param in lifetime params");
3364 : : add_error (std::move (error));
3365 : :
3366 : : return {};
3367 : : }
3368 : :
3369 : : lifetime_params.emplace_back (
3370 : : new AST::LifetimeParam (std::move (lifetime_param)));
3371 : :
3372 : : if (lexer.peek_token ()->get_id () != COMMA)
3373 : : break;
3374 : :
3375 : : // skip commas, including trailing commas
3376 : : lexer.skip_token ();
3377 : : }
3378 : :
3379 : : lifetime_params.shrink_to_fit ();
3380 : :
3381 : : return lifetime_params;
3382 : : }
3383 : :
3384 : : /* Parses lifetime generic parameters (objects). Will also consume any
3385 : : * trailing comma. No extra checks for end token.
3386 : : * TODO: is this best solution? implements most of the same algorithm.
3387 : : * TODO: seems to be unused, remove? */
3388 : : template <typename ManagedTokenSource>
3389 : : std::vector<AST::LifetimeParam>
3390 : 0 : Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
3391 : : {
3392 : 0 : std::vector<AST::LifetimeParam> lifetime_params;
3393 : :
3394 : : // bad control structure as end token cannot be guaranteed
3395 : 0 : while (true)
3396 : : {
3397 : 0 : auto lifetime_param = parse_lifetime_param ();
3398 : :
3399 : 0 : if (!lifetime_param)
3400 : : {
3401 : : // not an error as only way to exit if trailing comma
3402 : : break;
3403 : : }
3404 : :
3405 : 0 : lifetime_params.push_back (std::move (lifetime_param.value ()));
3406 : :
3407 : 0 : if (lexer.peek_token ()->get_id () != COMMA)
3408 : : break;
3409 : :
3410 : : // skip commas, including trailing commas
3411 : 0 : lexer.skip_token ();
3412 : : }
3413 : :
3414 : 0 : lifetime_params.shrink_to_fit ();
3415 : :
3416 : 0 : return lifetime_params;
3417 : : }
3418 : :
3419 : : /* Parses lifetime generic parameters (objects). Will also consume any
3420 : : * trailing comma. Has extra is_end_token predicate checking.
3421 : : * TODO: is this best solution? implements most of the same algorithm. */
3422 : : template <typename ManagedTokenSource>
3423 : : template <typename EndTokenPred>
3424 : : std::vector<AST::LifetimeParam>
3425 : 28 : Parser<ManagedTokenSource>::parse_lifetime_params_objs (
3426 : : EndTokenPred is_end_token)
3427 : : {
3428 : 28 : std::vector<AST::LifetimeParam> lifetime_params;
3429 : :
3430 : 84 : while (!is_end_token (lexer.peek_token ()->get_id ()))
3431 : : {
3432 : 28 : auto lifetime_param = parse_lifetime_param ();
3433 : :
3434 : 28 : if (!lifetime_param)
3435 : : {
3436 : : /* TODO: is it worth throwing away all lifetime params just because
3437 : : * one failed? */
3438 : 0 : Error error (lexer.peek_token ()->get_locus (),
3439 : : "failed to parse lifetime param in lifetime params");
3440 : 0 : add_error (std::move (error));
3441 : :
3442 : 0 : return {};
3443 : 0 : }
3444 : :
3445 : 28 : lifetime_params.push_back (std::move (lifetime_param.value ()));
3446 : :
3447 : 56 : if (lexer.peek_token ()->get_id () != COMMA)
3448 : : break;
3449 : :
3450 : : // skip commas, including trailing commas
3451 : 0 : lexer.skip_token ();
3452 : : }
3453 : :
3454 : 28 : lifetime_params.shrink_to_fit ();
3455 : :
3456 : 28 : return lifetime_params;
3457 : 28 : }
3458 : :
3459 : : /* Parses a sequence of a certain grammar rule in object form (not pointer or
3460 : : * smart pointer), delimited by commas and ending when 'is_end_token' is
3461 : : * satisfied (templated). Will also consume any trailing comma.
3462 : : * FIXME: this cannot be used due to member function pointer problems (i.e.
3463 : : * parsing_function cannot be specified properly) */
3464 : : template <typename ManagedTokenSource>
3465 : : template <typename ParseFunction, typename EndTokenPred>
3466 : : auto
3467 : : Parser<ManagedTokenSource>::parse_non_ptr_sequence (
3468 : : ParseFunction parsing_function, EndTokenPred is_end_token,
3469 : : std::string error_msg) -> std::vector<decltype (parsing_function ())>
3470 : : {
3471 : : std::vector<decltype (parsing_function ())> params;
3472 : :
3473 : : while (!is_end_token (lexer.peek_token ()->get_id ()))
3474 : : {
3475 : : auto param = parsing_function ();
3476 : :
3477 : : if (param.is_error ())
3478 : : {
3479 : : // TODO: is it worth throwing away all params just because one
3480 : : // failed?
3481 : : Error error (lexer.peek_token ()->get_locus (),
3482 : : std::move (error_msg));
3483 : : add_error (std::move (error));
3484 : :
3485 : : return {};
3486 : : }
3487 : :
3488 : : params.push_back (std::move (param));
3489 : :
3490 : : if (lexer.peek_token ()->get_id () != COMMA)
3491 : : break;
3492 : :
3493 : : // skip commas, including trailing commas
3494 : : lexer.skip_token ();
3495 : : }
3496 : :
3497 : : params.shrink_to_fit ();
3498 : :
3499 : : return params;
3500 : : }
3501 : :
3502 : : /* Parses a single lifetime generic parameter (not including comma). */
3503 : : template <typename ManagedTokenSource>
3504 : : tl::expected<AST::LifetimeParam, ParseLifetimeParamError>
3505 : 47 : Parser<ManagedTokenSource>::parse_lifetime_param ()
3506 : : {
3507 : : // parse outer attributes, which are optional and may not exist
3508 : 47 : auto outer_attrs = parse_outer_attributes ();
3509 : :
3510 : : // save lifetime token - required
3511 : 47 : const_TokenPtr lifetime_tok = lexer.peek_token ();
3512 : 47 : if (lifetime_tok->get_id () != LIFETIME)
3513 : : {
3514 : : // if lifetime is missing, must not be a lifetime param, so return error
3515 : 11 : return tl::make_unexpected<ParseLifetimeParamError> ({});
3516 : : }
3517 : 36 : lexer.skip_token ();
3518 : 72 : AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
3519 : : lifetime_tok->get_locus ());
3520 : :
3521 : : // parse lifetime bounds, if it exists
3522 : 36 : std::vector<AST::Lifetime> lifetime_bounds;
3523 : 72 : if (lexer.peek_token ()->get_id () == COLON)
3524 : : {
3525 : : // parse lifetime bounds
3526 : 0 : lifetime_bounds = parse_lifetime_bounds ();
3527 : : // TODO: have end token passed in?
3528 : : }
3529 : :
3530 : 72 : return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
3531 : : std::move (outer_attrs),
3532 : 36 : lifetime_tok->get_locus ());
3533 : 83 : }
3534 : :
3535 : : // Parses type generic parameters. Will also consume any trailing comma.
3536 : : template <typename ManagedTokenSource>
3537 : : std::vector<std::unique_ptr<AST::TypeParam>>
3538 : 0 : Parser<ManagedTokenSource>::parse_type_params ()
3539 : : {
3540 : 0 : std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3541 : :
3542 : : // infinite loop with break on failure as no info on ending token
3543 : 0 : while (true)
3544 : : {
3545 : 0 : std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3546 : :
3547 : 0 : if (type_param == nullptr)
3548 : : {
3549 : : // break if fails to parse
3550 : : break;
3551 : : }
3552 : :
3553 : 0 : type_params.push_back (std::move (type_param));
3554 : :
3555 : 0 : if (lexer.peek_token ()->get_id () != COMMA)
3556 : : break;
3557 : :
3558 : : // skip commas, including trailing commas
3559 : 0 : lexer.skip_token ();
3560 : : }
3561 : :
3562 : 0 : type_params.shrink_to_fit ();
3563 : 0 : return type_params;
3564 : : }
3565 : :
3566 : : // Parses type generic parameters. Will also consume any trailing comma.
3567 : : template <typename ManagedTokenSource>
3568 : : template <typename EndTokenPred>
3569 : : std::vector<std::unique_ptr<AST::TypeParam>>
3570 : : Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
3571 : : {
3572 : : std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3573 : :
3574 : : while (!is_end_token (lexer.peek_token ()->get_id ()))
3575 : : {
3576 : : std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3577 : :
3578 : : if (type_param == nullptr)
3579 : : {
3580 : : Error error (lexer.peek_token ()->get_locus (),
3581 : : "failed to parse type param in type params");
3582 : : add_error (std::move (error));
3583 : :
3584 : : return {};
3585 : : }
3586 : :
3587 : : type_params.push_back (std::move (type_param));
3588 : :
3589 : : if (lexer.peek_token ()->get_id () != COMMA)
3590 : : break;
3591 : :
3592 : : // skip commas, including trailing commas
3593 : : lexer.skip_token ();
3594 : : }
3595 : :
3596 : : type_params.shrink_to_fit ();
3597 : : return type_params;
3598 : : /* TODO: this shares most code with parse_lifetime_params - good place to
3599 : : * use template (i.e. parse_non_ptr_sequence if doable) */
3600 : : }
3601 : :
3602 : : /* Parses a single type (generic) parameter, not including commas. May change
3603 : : * to return value. */
3604 : : template <typename ManagedTokenSource>
3605 : : std::unique_ptr<AST::TypeParam>
3606 : 0 : Parser<ManagedTokenSource>::parse_type_param ()
3607 : : {
3608 : : // parse outer attributes, which are optional and may not exist
3609 : 0 : auto outer_attrs = parse_outer_attributes ();
3610 : :
3611 : 0 : const_TokenPtr identifier_tok = lexer.peek_token ();
3612 : 0 : if (identifier_tok->get_id () != IDENTIFIER)
3613 : : {
3614 : : // return null as type param can't exist without this required
3615 : : // identifier
3616 : 0 : return nullptr;
3617 : : }
3618 : 0 : Identifier ident{identifier_tok};
3619 : 0 : lexer.skip_token ();
3620 : :
3621 : : // parse type param bounds (if they exist)
3622 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3623 : 0 : if (lexer.peek_token ()->get_id () == COLON)
3624 : : {
3625 : 0 : lexer.skip_token ();
3626 : :
3627 : : // parse type param bounds, which may or may not exist
3628 : 0 : type_param_bounds = parse_type_param_bounds ();
3629 : : }
3630 : :
3631 : : // parse type (if it exists)
3632 : 0 : std::unique_ptr<AST::Type> type = nullptr;
3633 : 0 : if (lexer.peek_token ()->get_id () == EQUAL)
3634 : : {
3635 : 0 : lexer.skip_token ();
3636 : :
3637 : : // parse type (now required)
3638 : 0 : type = parse_type ();
3639 : 0 : if (type == nullptr)
3640 : : {
3641 : 0 : Error error (lexer.peek_token ()->get_locus (),
3642 : : "failed to parse type in type param");
3643 : 0 : add_error (std::move (error));
3644 : :
3645 : 0 : return nullptr;
3646 : 0 : }
3647 : : }
3648 : :
3649 : : return std::unique_ptr<AST::TypeParam> (
3650 : 0 : new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
3651 : : std::move (type_param_bounds), std::move (type),
3652 : 0 : std::move (outer_attrs)));
3653 : 0 : }
3654 : :
3655 : : /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
3656 : : * has end token handling. */
3657 : : template <typename ManagedTokenSource>
3658 : : template <typename EndTokenPred>
3659 : : std::vector<std::unique_ptr<AST::Param>>
3660 : 20577 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
3661 : : {
3662 : 20577 : std::vector<std::unique_ptr<AST::Param>> params;
3663 : :
3664 : 41154 : if (is_end_token (lexer.peek_token ()->get_id ()))
3665 : 1700 : return params;
3666 : :
3667 : 18877 : auto initial_param = parse_function_param ();
3668 : :
3669 : : // Return empty parameter list if no parameter there
3670 : 18877 : if (initial_param == nullptr)
3671 : : {
3672 : : // TODO: is this an error?
3673 : 0 : return params;
3674 : : }
3675 : :
3676 : 18877 : params.push_back (std::move (initial_param));
3677 : :
3678 : : // maybe think of a better control structure here - do-while with an initial
3679 : : // error state? basically, loop through parameter list until can't find any
3680 : : // more params
3681 : 18877 : const_TokenPtr t = lexer.peek_token ();
3682 : 25853 : while (t->get_id () == COMMA)
3683 : : {
3684 : : // skip comma if applies
3685 : 7263 : lexer.skip_token ();
3686 : :
3687 : : // TODO: strictly speaking, shouldn't there be no trailing comma?
3688 : 14526 : if (is_end_token (lexer.peek_token ()->get_id ()))
3689 : : break;
3690 : :
3691 : : // now, as right paren would break, function param is required
3692 : 6976 : auto param = parse_function_param ();
3693 : 6976 : if (param == nullptr)
3694 : : {
3695 : 0 : Error error (lexer.peek_token ()->get_locus (),
3696 : : "failed to parse function param (in function params)");
3697 : 0 : add_error (std::move (error));
3698 : :
3699 : : // skip somewhere?
3700 : 0 : return std::vector<std::unique_ptr<AST::Param>> ();
3701 : 0 : }
3702 : :
3703 : 6976 : params.push_back (std::move (param));
3704 : :
3705 : 6976 : t = lexer.peek_token ();
3706 : : }
3707 : :
3708 : 18877 : params.shrink_to_fit ();
3709 : 18877 : return params;
3710 : 20577 : }
3711 : :
3712 : : /* Parses a single regular (i.e. non-generic) parameter in a function or
3713 : : * method, i.e. the "name: type" bit. Also handles it not existing. */
3714 : : template <typename ManagedTokenSource>
3715 : : std::unique_ptr<AST::Param>
3716 : 25853 : Parser<ManagedTokenSource>::parse_function_param ()
3717 : : {
3718 : : // parse outer attributes if they exist
3719 : 25853 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3720 : :
3721 : : // TODO: should saved location be at start of outer attributes or pattern?
3722 : 25853 : location_t locus = lexer.peek_token ()->get_locus ();
3723 : :
3724 : 51706 : if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
3725 : : {
3726 : 826 : lexer.skip_token (); // Skip ellipsis
3727 : 826 : return std::make_unique<AST::VariadicParam> (
3728 : 1652 : AST::VariadicParam (std::move (outer_attrs), locus));
3729 : : }
3730 : :
3731 : 25027 : std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
3732 : :
3733 : : // create error function param if it doesn't exist
3734 : 25027 : if (param_pattern == nullptr)
3735 : : {
3736 : : // skip after something
3737 : 0 : return nullptr;
3738 : : }
3739 : :
3740 : 25027 : if (!skip_token (COLON))
3741 : : {
3742 : : // skip after something
3743 : 0 : return nullptr;
3744 : : }
3745 : :
3746 : 50054 : if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
3747 : : {
3748 : 11 : lexer.skip_token (); // Skip ellipsis
3749 : 11 : return std::make_unique<AST::VariadicParam> (
3750 : 22 : AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
3751 : 11 : locus));
3752 : : }
3753 : : else
3754 : : {
3755 : 25016 : std::unique_ptr<AST::Type> param_type = parse_type ();
3756 : 25016 : if (param_type == nullptr)
3757 : : {
3758 : 0 : return nullptr;
3759 : : }
3760 : 25016 : return std::make_unique<AST::FunctionParam> (
3761 : 50032 : AST::FunctionParam (std::move (param_pattern), std::move (param_type),
3762 : 25016 : std::move (outer_attrs), locus));
3763 : 25016 : }
3764 : 25853 : }
3765 : :
3766 : : /* Parses a function or method return type syntactical construction. Also
3767 : : * handles a function return type not existing. */
3768 : : template <typename ManagedTokenSource>
3769 : : std::unique_ptr<AST::Type>
3770 : 31966 : Parser<ManagedTokenSource>::parse_function_return_type ()
3771 : : {
3772 : 63932 : if (lexer.peek_token ()->get_id () != RETURN_TYPE)
3773 : 8713 : return nullptr;
3774 : :
3775 : : // skip return type, as it now obviously exists
3776 : 23253 : lexer.skip_token ();
3777 : :
3778 : 23253 : std::unique_ptr<AST::Type> type = parse_type ();
3779 : :
3780 : 23253 : return type;
3781 : 23253 : }
3782 : :
3783 : : /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
3784 : : * a where clause not existing, in which it will return
3785 : : * WhereClause::create_empty(), which can be checked via
3786 : : * WhereClause::is_empty(). */
3787 : : template <typename ManagedTokenSource>
3788 : : AST::WhereClause
3789 : 54703 : Parser<ManagedTokenSource>::parse_where_clause ()
3790 : : {
3791 : 54703 : const_TokenPtr where_tok = lexer.peek_token ();
3792 : 54703 : if (where_tok->get_id () != WHERE)
3793 : : {
3794 : : // where clause doesn't exist, so create empty one
3795 : 53608 : return AST::WhereClause::create_empty ();
3796 : : }
3797 : :
3798 : 1095 : lexer.skip_token ();
3799 : :
3800 : : /* parse where clause items - this is not a separate rule in the reference
3801 : : * so won't be here */
3802 : 1095 : std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
3803 : :
3804 : 1095 : std::vector<AST::LifetimeParam> for_lifetimes;
3805 : 2190 : if (lexer.peek_token ()->get_id () == FOR)
3806 : 1 : for_lifetimes = parse_for_lifetimes ();
3807 : :
3808 : : /* HACK: where clauses end with a right curly or semicolon or equals in all
3809 : : * uses currently */
3810 : 1095 : const_TokenPtr t = lexer.peek_token ();
3811 : 2481 : while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
3812 : 2304 : && t->get_id () != EQUAL)
3813 : : {
3814 : 1386 : std::unique_ptr<AST::WhereClauseItem> where_clause_item
3815 : : = parse_where_clause_item (for_lifetimes);
3816 : :
3817 : 1386 : if (where_clause_item == nullptr)
3818 : : {
3819 : 0 : Error error (t->get_locus (), "failed to parse where clause item");
3820 : 0 : add_error (std::move (error));
3821 : :
3822 : 0 : return AST::WhereClause::create_empty ();
3823 : 0 : }
3824 : :
3825 : 1386 : where_clause_items.push_back (std::move (where_clause_item));
3826 : :
3827 : : // also skip comma if it exists
3828 : 2772 : if (lexer.peek_token ()->get_id () != COMMA)
3829 : : break;
3830 : :
3831 : 1209 : lexer.skip_token ();
3832 : 1209 : t = lexer.peek_token ();
3833 : : }
3834 : :
3835 : 1095 : where_clause_items.shrink_to_fit ();
3836 : 1095 : return AST::WhereClause (std::move (where_clause_items));
3837 : 1095 : }
3838 : :
3839 : : /* Parses a where clause item (lifetime or type bound). Does not parse any
3840 : : * commas. */
3841 : : template <typename ManagedTokenSource>
3842 : : std::unique_ptr<AST::WhereClauseItem>
3843 : 1386 : Parser<ManagedTokenSource>::parse_where_clause_item (
3844 : : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
3845 : : {
3846 : : // shitty cheat way of determining lifetime or type bound - test for
3847 : : // lifetime
3848 : 1386 : const_TokenPtr t = lexer.peek_token ();
3849 : :
3850 : 1386 : if (t->get_id () == LIFETIME)
3851 : 3 : return parse_lifetime_where_clause_item ();
3852 : : else
3853 : 1383 : return parse_type_bound_where_clause_item (outer_for_lifetimes);
3854 : 1386 : }
3855 : :
3856 : : // Parses a lifetime where clause item.
3857 : : template <typename ManagedTokenSource>
3858 : : std::unique_ptr<AST::LifetimeWhereClauseItem>
3859 : 3 : Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
3860 : : {
3861 : 3 : auto parsed_lifetime = parse_lifetime (false);
3862 : 3 : if (!parsed_lifetime)
3863 : : {
3864 : : // TODO: error here?
3865 : 0 : return nullptr;
3866 : : }
3867 : 3 : auto lifetime = parsed_lifetime.value ();
3868 : :
3869 : 3 : if (!skip_token (COLON))
3870 : : {
3871 : : // TODO: skip after somewhere
3872 : 0 : return nullptr;
3873 : : }
3874 : :
3875 : 3 : std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
3876 : : // TODO: have end token passed in?
3877 : :
3878 : 3 : location_t locus = lifetime.get_locus ();
3879 : :
3880 : : return std::unique_ptr<AST::LifetimeWhereClauseItem> (
3881 : 3 : new AST::LifetimeWhereClauseItem (std::move (lifetime),
3882 : 3 : std::move (lifetime_bounds), locus));
3883 : 6 : }
3884 : :
3885 : : // Parses a type bound where clause item.
3886 : : template <typename ManagedTokenSource>
3887 : : std::unique_ptr<AST::TypeBoundWhereClauseItem>
3888 : 1383 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
3889 : : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
3890 : : {
3891 : 1383 : std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
3892 : :
3893 : 1383 : std::unique_ptr<AST::Type> type = parse_type ();
3894 : 1383 : if (type == nullptr)
3895 : : {
3896 : 0 : return nullptr;
3897 : : }
3898 : :
3899 : 1383 : if (!skip_token (COLON))
3900 : : {
3901 : : // TODO: skip after somewhere
3902 : 0 : return nullptr;
3903 : : }
3904 : :
3905 : 2766 : if (lexer.peek_token ()->get_id () == FOR)
3906 : : {
3907 : 9 : auto for_lifetimes_inner = parse_for_lifetimes ();
3908 : 9 : for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
3909 : : for_lifetimes_inner.end ());
3910 : 9 : }
3911 : :
3912 : : // parse type param bounds if they exist
3913 : 1383 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
3914 : : = parse_type_param_bounds ();
3915 : :
3916 : 1383 : location_t locus = lexer.peek_token ()->get_locus ();
3917 : :
3918 : : return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
3919 : 1383 : new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
3920 : : std::move (type),
3921 : 1383 : std::move (type_param_bounds), locus));
3922 : 1383 : }
3923 : :
3924 : : // Parses a for lifetimes clause, including the for keyword and angle
3925 : : // brackets.
3926 : : template <typename ManagedTokenSource>
3927 : : std::vector<AST::LifetimeParam>
3928 : 28 : Parser<ManagedTokenSource>::parse_for_lifetimes ()
3929 : : {
3930 : 28 : std::vector<AST::LifetimeParam> params;
3931 : :
3932 : 28 : if (!skip_token (FOR))
3933 : : {
3934 : : // skip after somewhere?
3935 : : return params;
3936 : : }
3937 : :
3938 : 28 : if (!skip_token (LEFT_ANGLE))
3939 : : {
3940 : : // skip after somewhere?
3941 : : return params;
3942 : : }
3943 : :
3944 : : /* cannot specify end token due to parsing problems with '>' tokens being
3945 : : * nested */
3946 : 28 : params = parse_lifetime_params_objs (is_right_angle_tok);
3947 : :
3948 : 28 : if (!skip_generics_right_angle ())
3949 : : {
3950 : : // DEBUG
3951 : 0 : rust_debug ("failed to skip generics right angle after (supposedly) "
3952 : : "finished parsing where clause items");
3953 : : // ok, well this gets called.
3954 : :
3955 : : // skip after somewhere?
3956 : 0 : return params;
3957 : : }
3958 : :
3959 : : return params;
3960 : : }
3961 : :
3962 : : // Parses type parameter bounds in where clause or generic arguments.
3963 : : template <typename ManagedTokenSource>
3964 : : std::vector<std::unique_ptr<AST::TypeParamBound>>
3965 : 3771 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
3966 : : {
3967 : 3771 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3968 : :
3969 : 3771 : std::unique_ptr<AST::TypeParamBound> initial_bound
3970 : : = parse_type_param_bound ();
3971 : :
3972 : : // quick exit if null
3973 : 3771 : if (initial_bound == nullptr)
3974 : : {
3975 : : /* error? type param bounds must have at least one term, but are bounds
3976 : : * optional? */
3977 : : return type_param_bounds;
3978 : : }
3979 : 3771 : type_param_bounds.push_back (std::move (initial_bound));
3980 : :
3981 : 7962 : while (lexer.peek_token ()->get_id () == PLUS)
3982 : : {
3983 : 210 : lexer.skip_token ();
3984 : :
3985 : 210 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
3986 : 210 : if (bound == nullptr)
3987 : : {
3988 : : /* not an error: bound is allowed to be null as trailing plus is
3989 : : * allowed */
3990 : : return type_param_bounds;
3991 : : }
3992 : :
3993 : 210 : type_param_bounds.push_back (std::move (bound));
3994 : : }
3995 : :
3996 : 3771 : type_param_bounds.shrink_to_fit ();
3997 : : return type_param_bounds;
3998 : 3771 : }
3999 : :
4000 : : /* Parses type parameter bounds in where clause or generic arguments, with end
4001 : : * token handling. */
4002 : : template <typename ManagedTokenSource>
4003 : : template <typename EndTokenPred>
4004 : : std::vector<std::unique_ptr<AST::TypeParamBound>>
4005 : 643 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
4006 : : {
4007 : 643 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
4008 : :
4009 : 643 : std::unique_ptr<AST::TypeParamBound> initial_bound
4010 : : = parse_type_param_bound ();
4011 : :
4012 : : // quick exit if null
4013 : 643 : if (initial_bound == nullptr)
4014 : : {
4015 : : /* error? type param bounds must have at least one term, but are bounds
4016 : : * optional? */
4017 : 0 : return type_param_bounds;
4018 : : }
4019 : 643 : type_param_bounds.push_back (std::move (initial_bound));
4020 : :
4021 : 1486 : while (lexer.peek_token ()->get_id () == PLUS)
4022 : : {
4023 : 100 : lexer.skip_token ();
4024 : :
4025 : : // break if end token character
4026 : 200 : if (is_end_token (lexer.peek_token ()->get_id ()))
4027 : : break;
4028 : :
4029 : 100 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
4030 : 100 : if (bound == nullptr)
4031 : : {
4032 : : // TODO how wise is it to ditch all bounds if only one failed?
4033 : 0 : Error error (lexer.peek_token ()->get_locus (),
4034 : : "failed to parse type param bound in type param bounds");
4035 : 0 : add_error (std::move (error));
4036 : :
4037 : 0 : return {};
4038 : 0 : }
4039 : :
4040 : 100 : type_param_bounds.push_back (std::move (bound));
4041 : : }
4042 : :
4043 : 643 : type_param_bounds.shrink_to_fit ();
4044 : 643 : return type_param_bounds;
4045 : 643 : }
4046 : :
4047 : : /* Parses a single type parameter bound in a where clause or generic argument.
4048 : : * Does not parse the '+' between arguments. */
4049 : : template <typename ManagedTokenSource>
4050 : : std::unique_ptr<AST::TypeParamBound>
4051 : 4790 : Parser<ManagedTokenSource>::parse_type_param_bound ()
4052 : : {
4053 : : // shitty cheat way of determining lifetime or trait bound - test for
4054 : : // lifetime
4055 : 4790 : const_TokenPtr t = lexer.peek_token ();
4056 : 4790 : switch (t->get_id ())
4057 : : {
4058 : 113 : case LIFETIME:
4059 : 113 : return std::unique_ptr<AST::Lifetime> (
4060 : 226 : new AST::Lifetime (parse_lifetime (false).value ()));
4061 : 4677 : case LEFT_PAREN:
4062 : : case QUESTION_MARK:
4063 : : case FOR:
4064 : : case IDENTIFIER:
4065 : : case SUPER:
4066 : : case SELF:
4067 : : case SELF_ALIAS:
4068 : : case CRATE:
4069 : : case DOLLAR_SIGN:
4070 : : case SCOPE_RESOLUTION:
4071 : 4677 : return parse_trait_bound ();
4072 : 0 : default:
4073 : : // don't error - assume this is fine TODO
4074 : 0 : return nullptr;
4075 : : }
4076 : 4790 : }
4077 : :
4078 : : // Parses a trait bound type param bound.
4079 : : template <typename ManagedTokenSource>
4080 : : std::unique_ptr<AST::TraitBound>
4081 : 5137 : Parser<ManagedTokenSource>::parse_trait_bound ()
4082 : : {
4083 : 5137 : bool has_parens = false;
4084 : 5137 : bool has_question_mark = false;
4085 : :
4086 : 10274 : location_t locus = lexer.peek_token ()->get_locus ();
4087 : :
4088 : : /* parse optional `for lifetimes`. */
4089 : 5137 : std::vector<AST::LifetimeParam> for_lifetimes;
4090 : 10274 : if (lexer.peek_token ()->get_id () == FOR)
4091 : 14 : for_lifetimes = parse_for_lifetimes ();
4092 : :
4093 : : // handle trait bound being in parentheses
4094 : 10274 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
4095 : : {
4096 : 0 : has_parens = true;
4097 : 0 : lexer.skip_token ();
4098 : : }
4099 : :
4100 : : // handle having question mark (optional)
4101 : 10274 : if (lexer.peek_token ()->get_id () == QUESTION_MARK)
4102 : : {
4103 : 657 : has_question_mark = true;
4104 : 657 : lexer.skip_token ();
4105 : : }
4106 : :
4107 : : // handle TypePath
4108 : 5137 : AST::TypePath type_path = parse_type_path ();
4109 : :
4110 : : // handle closing parentheses
4111 : 5137 : if (has_parens)
4112 : : {
4113 : 0 : if (!skip_token (RIGHT_PAREN))
4114 : : {
4115 : 0 : return nullptr;
4116 : : }
4117 : : }
4118 : :
4119 : : return std::unique_ptr<AST::TraitBound> (
4120 : 5137 : new AST::TraitBound (std::move (type_path), locus, has_parens,
4121 : 5137 : has_question_mark, std::move (for_lifetimes)));
4122 : 5137 : }
4123 : :
4124 : : // Parses lifetime bounds.
4125 : : template <typename ManagedTokenSource>
4126 : : std::vector<AST::Lifetime>
4127 : 3 : Parser<ManagedTokenSource>::parse_lifetime_bounds ()
4128 : : {
4129 : 3 : std::vector<AST::Lifetime> lifetime_bounds;
4130 : :
4131 : 3 : while (true)
4132 : : {
4133 : 3 : auto lifetime = parse_lifetime (false);
4134 : :
4135 : : // quick exit for parsing failure
4136 : 3 : if (!lifetime)
4137 : : break;
4138 : :
4139 : 3 : lifetime_bounds.push_back (std::move (lifetime.value ()));
4140 : :
4141 : : /* plus is maybe not allowed at end - spec defines it weirdly, so
4142 : : * assuming allowed at end */
4143 : 6 : if (lexer.peek_token ()->get_id () != PLUS)
4144 : : break;
4145 : :
4146 : 0 : lexer.skip_token ();
4147 : : }
4148 : :
4149 : 3 : lifetime_bounds.shrink_to_fit ();
4150 : 3 : return lifetime_bounds;
4151 : : }
4152 : :
4153 : : // Parses lifetime bounds, with added check for ending token.
4154 : : template <typename ManagedTokenSource>
4155 : : template <typename EndTokenPred>
4156 : : std::vector<AST::Lifetime>
4157 : 19 : Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
4158 : : {
4159 : 19 : std::vector<AST::Lifetime> lifetime_bounds;
4160 : :
4161 : 79 : while (!is_end_token (lexer.peek_token ()->get_id ()))
4162 : : {
4163 : 20 : auto lifetime = parse_lifetime (false);
4164 : :
4165 : 20 : if (!lifetime)
4166 : : {
4167 : : /* TODO: is it worth throwing away all lifetime bound info just
4168 : : * because one failed? */
4169 : 0 : Error error (lexer.peek_token ()->get_locus (),
4170 : : "failed to parse lifetime in lifetime bounds");
4171 : 0 : add_error (std::move (error));
4172 : :
4173 : 0 : return {};
4174 : 0 : }
4175 : :
4176 : 20 : lifetime_bounds.push_back (std::move (lifetime.value ()));
4177 : :
4178 : : /* plus is maybe not allowed at end - spec defines it weirdly, so
4179 : : * assuming allowed at end */
4180 : 40 : if (lexer.peek_token ()->get_id () != PLUS)
4181 : : break;
4182 : :
4183 : 1 : lexer.skip_token ();
4184 : : }
4185 : :
4186 : 19 : lifetime_bounds.shrink_to_fit ();
4187 : 19 : return lifetime_bounds;
4188 : 19 : }
4189 : :
4190 : : /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
4191 : : * existing. */
4192 : : template <typename ManagedTokenSource>
4193 : : tl::expected<AST::Lifetime, ParseLifetimeError>
4194 : 23053 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
4195 : : {
4196 : 23053 : const_TokenPtr lifetime_tok = lexer.peek_token ();
4197 : 23053 : if (lifetime_tok->get_id () != LIFETIME)
4198 : : {
4199 : 18359 : if (allow_elided)
4200 : : {
4201 : 0 : return AST::Lifetime::elided ();
4202 : : }
4203 : : else
4204 : : {
4205 : 18359 : return tl::make_unexpected<ParseLifetimeError> ({});
4206 : : }
4207 : : }
4208 : 4694 : lexer.skip_token ();
4209 : :
4210 : 9388 : return lifetime_from_token (lifetime_tok);
4211 : 23053 : }
4212 : :
4213 : : template <typename ManagedTokenSource>
4214 : : AST::Lifetime
4215 : 4730 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
4216 : : {
4217 : 4730 : location_t locus = tok->get_locus ();
4218 : 4730 : std::string lifetime_ident = tok->get_str ();
4219 : :
4220 : 4730 : if (lifetime_ident == "static")
4221 : : {
4222 : 119 : return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
4223 : : }
4224 : 4611 : else if (lifetime_ident == "_")
4225 : : {
4226 : : // Explicitly and implicitly elided lifetimes follow the same rules.
4227 : 779 : return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
4228 : : }
4229 : : else
4230 : : {
4231 : 7664 : return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
4232 : 3832 : locus);
4233 : : }
4234 : 4730 : }
4235 : :
4236 : : template <typename ManagedTokenSource>
4237 : : std::unique_ptr<AST::ExternalTypeItem>
4238 : 5 : Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
4239 : : AST::AttrVec outer_attrs)
4240 : : {
4241 : 5 : location_t locus = lexer.peek_token ()->get_locus ();
4242 : 5 : skip_token (TYPE);
4243 : :
4244 : 5 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
4245 : 5 : if (alias_name_tok == nullptr)
4246 : : {
4247 : 0 : Error error (lexer.peek_token ()->get_locus (),
4248 : : "could not parse identifier in external opaque type");
4249 : 0 : add_error (std::move (error));
4250 : :
4251 : 0 : skip_after_semicolon ();
4252 : 0 : return nullptr;
4253 : 0 : }
4254 : :
4255 : 5 : if (!skip_token (SEMICOLON))
4256 : 1 : return nullptr;
4257 : :
4258 : : return std::unique_ptr<AST::ExternalTypeItem> (
4259 : 12 : new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
4260 : 4 : std::move (outer_attrs), std::move (locus)));
4261 : 5 : }
4262 : :
4263 : : // Parses a "type alias" (typedef) item.
4264 : : template <typename ManagedTokenSource>
4265 : : std::unique_ptr<AST::TypeAlias>
4266 : 3951 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
4267 : : AST::AttrVec outer_attrs)
4268 : : {
4269 : 3951 : location_t locus = lexer.peek_token ()->get_locus ();
4270 : 3951 : skip_token (TYPE);
4271 : :
4272 : : // TODO: use this token for identifier when finished that
4273 : 3951 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
4274 : 3951 : if (alias_name_tok == nullptr)
4275 : : {
4276 : 0 : Error error (lexer.peek_token ()->get_locus (),
4277 : : "could not parse identifier in type alias");
4278 : 0 : add_error (std::move (error));
4279 : :
4280 : 0 : skip_after_semicolon ();
4281 : 0 : return nullptr;
4282 : 0 : }
4283 : 3951 : Identifier alias_name{alias_name_tok};
4284 : :
4285 : : // parse generic params, which may not exist
4286 : 3951 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4287 : : = parse_generic_params_in_angles ();
4288 : :
4289 : : // parse where clause, which may not exist
4290 : 3951 : AST::WhereClause where_clause = parse_where_clause ();
4291 : :
4292 : 3951 : if (!skip_token (EQUAL))
4293 : : {
4294 : 0 : skip_after_semicolon ();
4295 : 0 : return nullptr;
4296 : : }
4297 : :
4298 : 3951 : std::unique_ptr<AST::Type> type_to_alias = parse_type ();
4299 : :
4300 : 3951 : if (!skip_token (SEMICOLON))
4301 : : {
4302 : : // should be skipping past this, not the next line
4303 : 0 : return nullptr;
4304 : : }
4305 : :
4306 : : return std::unique_ptr<AST::TypeAlias> (
4307 : 3951 : new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
4308 : : std::move (where_clause), std::move (type_to_alias),
4309 : 3951 : std::move (vis), std::move (outer_attrs), locus));
4310 : 7902 : }
4311 : :
4312 : : // Parse a struct item AST node.
4313 : : template <typename ManagedTokenSource>
4314 : : std::unique_ptr<AST::Struct>
4315 : 3319 : Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
4316 : : AST::AttrVec outer_attrs)
4317 : : {
4318 : : /* TODO: determine best way to parse the proper struct vs tuple struct -
4319 : : * share most of initial constructs so lookahead might be impossible, and if
4320 : : * not probably too expensive. Best way is probably unified parsing for the
4321 : : * initial parts and then pass them in as params to more derived functions.
4322 : : * Alternatively, just parse everything in this one function - do this if
4323 : : * function not too long. */
4324 : :
4325 : : /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
4326 : : * struct_fields? '}' | ';' ) */
4327 : : /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
4328 : : * where_clause? ';' */
4329 : 3319 : location_t locus = lexer.peek_token ()->get_locus ();
4330 : 3319 : skip_token (STRUCT_KW);
4331 : :
4332 : : // parse struct name
4333 : 3319 : const_TokenPtr name_tok = expect_token (IDENTIFIER);
4334 : 3319 : if (name_tok == nullptr)
4335 : : {
4336 : 0 : Error error (lexer.peek_token ()->get_locus (),
4337 : : "could not parse struct or tuple struct identifier");
4338 : 0 : add_error (std::move (error));
4339 : :
4340 : : // skip after somewhere?
4341 : 0 : return nullptr;
4342 : 0 : }
4343 : 3319 : Identifier struct_name{name_tok};
4344 : :
4345 : : // parse generic params, which may or may not exist
4346 : 3319 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4347 : : = parse_generic_params_in_angles ();
4348 : :
4349 : : // branch on next token - determines whether proper struct or tuple struct
4350 : 6638 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
4351 : : {
4352 : : // tuple struct
4353 : :
4354 : : // skip left parenthesis
4355 : 1083 : lexer.skip_token ();
4356 : :
4357 : : // parse tuple fields
4358 : 1083 : std::vector<AST::TupleField> tuple_fields;
4359 : : // Might be empty tuple for unit tuple struct.
4360 : 2166 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4361 : 23 : tuple_fields = std::vector<AST::TupleField> ();
4362 : : else
4363 : 1060 : tuple_fields = parse_tuple_fields ();
4364 : :
4365 : : // tuple parameters must have closing parenthesis
4366 : 1083 : if (!skip_token (RIGHT_PAREN))
4367 : : {
4368 : 0 : skip_after_semicolon ();
4369 : 0 : return nullptr;
4370 : : }
4371 : :
4372 : : // parse where clause, which is optional
4373 : 1083 : AST::WhereClause where_clause = parse_where_clause ();
4374 : :
4375 : 1083 : if (!skip_token (SEMICOLON))
4376 : : {
4377 : : // can't skip after semicolon because it's meant to be here
4378 : 0 : return nullptr;
4379 : : }
4380 : :
4381 : 1083 : return std::unique_ptr<AST::TupleStruct> (
4382 : 1083 : new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
4383 : : std::move (generic_params),
4384 : : std::move (where_clause), std::move (vis),
4385 : 1083 : std::move (outer_attrs), locus));
4386 : 1083 : }
4387 : :
4388 : : // assume it is a proper struct being parsed and continue outside of switch
4389 : : // - label only here to suppress warning
4390 : :
4391 : : // parse where clause, which is optional
4392 : 2236 : AST::WhereClause where_clause = parse_where_clause ();
4393 : :
4394 : : // branch on next token - determines whether struct is a unit struct
4395 : 2236 : const_TokenPtr t = lexer.peek_token ();
4396 : 2236 : switch (t->get_id ())
4397 : : {
4398 : 1115 : case LEFT_CURLY:
4399 : : {
4400 : : // struct with body
4401 : :
4402 : : // skip curly bracket
4403 : 1115 : lexer.skip_token ();
4404 : :
4405 : : // parse struct fields, if any
4406 : 1115 : std::vector<AST::StructField> struct_fields
4407 : : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4408 : :
4409 : 1115 : if (!skip_token (RIGHT_CURLY))
4410 : : {
4411 : : // skip somewhere?
4412 : 0 : return nullptr;
4413 : : }
4414 : :
4415 : 1115 : return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
4416 : : std::move (struct_fields), std::move (struct_name),
4417 : : std::move (generic_params), std::move (where_clause), false,
4418 : 1115 : std::move (vis), std::move (outer_attrs), locus));
4419 : 1115 : }
4420 : 1120 : case SEMICOLON:
4421 : : // unit struct declaration
4422 : :
4423 : 1120 : lexer.skip_token ();
4424 : :
4425 : 1120 : return std::unique_ptr<AST::StructStruct> (
4426 : 2240 : new AST::StructStruct (std::move (struct_name),
4427 : : std::move (generic_params),
4428 : : std::move (where_clause), std::move (vis),
4429 : 1120 : std::move (outer_attrs), locus));
4430 : 1 : default:
4431 : 1 : add_error (Error (t->get_locus (),
4432 : : "unexpected token %qs in struct declaration",
4433 : : t->get_token_description ()));
4434 : :
4435 : : // skip somewhere?
4436 : 1 : return nullptr;
4437 : : }
4438 : 3319 : }
4439 : :
4440 : : // Parses struct fields in struct declarations.
4441 : : template <typename ManagedTokenSource>
4442 : : std::vector<AST::StructField>
4443 : 0 : Parser<ManagedTokenSource>::parse_struct_fields ()
4444 : : {
4445 : 0 : std::vector<AST::StructField> fields;
4446 : :
4447 : 0 : AST::StructField initial_field = parse_struct_field ();
4448 : :
4449 : : // Return empty field list if no field there
4450 : 0 : if (initial_field.is_error ())
4451 : : return fields;
4452 : :
4453 : 0 : fields.push_back (std::move (initial_field));
4454 : :
4455 : 0 : while (lexer.peek_token ()->get_id () == COMMA)
4456 : : {
4457 : 0 : lexer.skip_token ();
4458 : :
4459 : 0 : AST::StructField field = parse_struct_field ();
4460 : :
4461 : 0 : if (field.is_error ())
4462 : : {
4463 : : // would occur with trailing comma, so allowed
4464 : : break;
4465 : : }
4466 : :
4467 : 0 : fields.push_back (std::move (field));
4468 : : }
4469 : :
4470 : 0 : fields.shrink_to_fit ();
4471 : : return fields;
4472 : : // TODO: template if possible (parse_non_ptr_seq)
4473 : 0 : }
4474 : :
4475 : : // Parses struct fields in struct declarations.
4476 : : template <typename ManagedTokenSource>
4477 : : template <typename EndTokenPred>
4478 : : std::vector<AST::StructField>
4479 : 1316 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
4480 : : {
4481 : 1316 : std::vector<AST::StructField> fields;
4482 : :
4483 : 1316 : AST::StructField initial_field = parse_struct_field ();
4484 : :
4485 : : // Return empty field list if no field there
4486 : 1316 : if (initial_field.is_error ())
4487 : 43 : return fields;
4488 : :
4489 : 1273 : fields.push_back (std::move (initial_field));
4490 : :
4491 : 5226 : while (lexer.peek_token ()->get_id () == COMMA)
4492 : : {
4493 : 2431 : lexer.skip_token ();
4494 : :
4495 : 4862 : if (is_end_tok (lexer.peek_token ()->get_id ()))
4496 : : break;
4497 : :
4498 : 1340 : AST::StructField field = parse_struct_field ();
4499 : 1340 : if (field.is_error ())
4500 : : {
4501 : : /* TODO: should every field be ditched just because one couldn't be
4502 : : * parsed? */
4503 : 0 : Error error (lexer.peek_token ()->get_locus (),
4504 : : "failed to parse struct field in struct fields");
4505 : 0 : add_error (std::move (error));
4506 : :
4507 : 0 : return {};
4508 : 0 : }
4509 : :
4510 : 1340 : fields.push_back (std::move (field));
4511 : : }
4512 : :
4513 : 1273 : fields.shrink_to_fit ();
4514 : 1273 : return fields;
4515 : : // TODO: template if possible (parse_non_ptr_seq)
4516 : 1316 : }
4517 : :
4518 : : // Parses a single struct field (in a struct definition). Does not parse
4519 : : // commas.
4520 : : template <typename ManagedTokenSource>
4521 : : AST::StructField
4522 : 2656 : Parser<ManagedTokenSource>::parse_struct_field ()
4523 : : {
4524 : : // parse outer attributes, if they exist
4525 : 2656 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4526 : :
4527 : : // parse visibility, if it exists
4528 : 2656 : AST::Visibility vis = parse_visibility ();
4529 : :
4530 : 2656 : location_t locus = lexer.peek_token ()->get_locus ();
4531 : :
4532 : : // parse field name
4533 : 2656 : const_TokenPtr field_name_tok = lexer.peek_token ();
4534 : 2656 : if (field_name_tok->get_id () != IDENTIFIER)
4535 : : {
4536 : : // if not identifier, assumes there is no struct field and exits - not
4537 : : // necessarily error
4538 : 43 : return AST::StructField::create_error ();
4539 : : }
4540 : 2613 : Identifier field_name{field_name_tok};
4541 : 2613 : lexer.skip_token ();
4542 : :
4543 : 2613 : if (!skip_token (COLON))
4544 : : {
4545 : : // skip after somewhere?
4546 : 0 : return AST::StructField::create_error ();
4547 : : }
4548 : :
4549 : : // parse field type - this is required
4550 : 2613 : std::unique_ptr<AST::Type> field_type = parse_type ();
4551 : 2613 : if (field_type == nullptr)
4552 : : {
4553 : 0 : Error error (lexer.peek_token ()->get_locus (),
4554 : : "could not parse type in struct field definition");
4555 : 0 : add_error (std::move (error));
4556 : :
4557 : : // skip after somewhere
4558 : 0 : return AST::StructField::create_error ();
4559 : 0 : }
4560 : :
4561 : 5226 : return AST::StructField (std::move (field_name), std::move (field_type),
4562 : 2613 : std::move (vis), locus, std::move (outer_attrs));
4563 : 7882 : }
4564 : :
4565 : : // Parses tuple fields in tuple/tuple struct declarations.
4566 : : template <typename ManagedTokenSource>
4567 : : std::vector<AST::TupleField>
4568 : 1511 : Parser<ManagedTokenSource>::parse_tuple_fields ()
4569 : : {
4570 : 1511 : std::vector<AST::TupleField> fields;
4571 : :
4572 : 1511 : AST::TupleField initial_field = parse_tuple_field ();
4573 : :
4574 : : // Return empty field list if no field there
4575 : 1511 : if (initial_field.is_error ())
4576 : : {
4577 : 0 : return fields;
4578 : : }
4579 : :
4580 : 1511 : fields.push_back (std::move (initial_field));
4581 : :
4582 : : // maybe think of a better control structure here - do-while with an initial
4583 : : // error state? basically, loop through field list until can't find any more
4584 : : // params HACK: all current syntax uses of tuple fields have them ending
4585 : : // with a right paren token
4586 : 1511 : const_TokenPtr t = lexer.peek_token ();
4587 : 2598 : while (t->get_id () == COMMA)
4588 : : {
4589 : : // skip comma if applies - e.g. trailing comma
4590 : 1089 : lexer.skip_token ();
4591 : :
4592 : : // break out due to right paren if it exists
4593 : 2178 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4594 : : {
4595 : : break;
4596 : : }
4597 : :
4598 : 1087 : AST::TupleField field = parse_tuple_field ();
4599 : 1087 : if (field.is_error ())
4600 : : {
4601 : 0 : Error error (lexer.peek_token ()->get_locus (),
4602 : : "failed to parse tuple field in tuple fields");
4603 : 0 : add_error (std::move (error));
4604 : :
4605 : 0 : return std::vector<AST::TupleField> ();
4606 : 0 : }
4607 : :
4608 : 1087 : fields.push_back (std::move (field));
4609 : :
4610 : 1087 : t = lexer.peek_token ();
4611 : : }
4612 : :
4613 : 1511 : fields.shrink_to_fit ();
4614 : 1511 : return fields;
4615 : :
4616 : : // TODO: this shares basically all code with function params and struct
4617 : : // fields
4618 : : // - templates?
4619 : 1511 : }
4620 : :
4621 : : /* Parses a single tuple struct field in a tuple struct definition. Does not
4622 : : * parse commas. */
4623 : : template <typename ManagedTokenSource>
4624 : : AST::TupleField
4625 : 2598 : Parser<ManagedTokenSource>::parse_tuple_field ()
4626 : : {
4627 : : // parse outer attributes if they exist
4628 : 2598 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4629 : :
4630 : : // parse visibility if it exists
4631 : 2598 : AST::Visibility vis = parse_visibility ();
4632 : :
4633 : 2598 : location_t locus = lexer.peek_token ()->get_locus ();
4634 : :
4635 : : // parse type, which is required
4636 : 2598 : std::unique_ptr<AST::Type> field_type = parse_type ();
4637 : 2598 : if (field_type == nullptr)
4638 : : {
4639 : : // error if null
4640 : 0 : Error error (lexer.peek_token ()->get_locus (),
4641 : : "could not parse type in tuple struct field");
4642 : 0 : add_error (std::move (error));
4643 : :
4644 : : // skip after something
4645 : 0 : return AST::TupleField::create_error ();
4646 : 0 : }
4647 : :
4648 : 2598 : return AST::TupleField (std::move (field_type), std::move (vis), locus,
4649 : 2598 : std::move (outer_attrs));
4650 : 2598 : }
4651 : :
4652 : : // Parses a Rust "enum" tagged union item definition.
4653 : : template <typename ManagedTokenSource>
4654 : : std::unique_ptr<AST::Enum>
4655 : 573 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
4656 : : AST::AttrVec outer_attrs)
4657 : : {
4658 : 573 : location_t locus = lexer.peek_token ()->get_locus ();
4659 : 573 : skip_token (ENUM_KW);
4660 : :
4661 : : // parse enum name
4662 : 573 : const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
4663 : 573 : if (enum_name_tok == nullptr)
4664 : 0 : return nullptr;
4665 : :
4666 : 573 : Identifier enum_name = {enum_name_tok};
4667 : :
4668 : : // parse generic params (of enum container, not enum variants) if they exist
4669 : 573 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4670 : : = parse_generic_params_in_angles ();
4671 : :
4672 : : // parse where clause if it exists
4673 : 573 : AST::WhereClause where_clause = parse_where_clause ();
4674 : :
4675 : 573 : if (!skip_token (LEFT_CURLY))
4676 : : {
4677 : 0 : skip_after_end_block ();
4678 : 0 : return nullptr;
4679 : : }
4680 : :
4681 : : // parse actual enum variant definitions
4682 : 573 : std::vector<std::unique_ptr<AST::EnumItem>> enum_items
4683 : : = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
4684 : :
4685 : 573 : if (!skip_token (RIGHT_CURLY))
4686 : : {
4687 : 0 : skip_after_end_block ();
4688 : 0 : return nullptr;
4689 : : }
4690 : :
4691 : : return std::unique_ptr<AST::Enum> (
4692 : 573 : new AST::Enum (std::move (enum_name), std::move (vis),
4693 : : std::move (generic_params), std::move (where_clause),
4694 : 573 : std::move (enum_items), std::move (outer_attrs), locus));
4695 : 1146 : }
4696 : :
4697 : : // Parses the enum variants inside an enum definiton.
4698 : : template <typename ManagedTokenSource>
4699 : : std::vector<std::unique_ptr<AST::EnumItem>>
4700 : 0 : Parser<ManagedTokenSource>::parse_enum_items ()
4701 : : {
4702 : 0 : std::vector<std::unique_ptr<AST::EnumItem>> items;
4703 : :
4704 : 0 : std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4705 : :
4706 : : // Return empty item list if no field there
4707 : 0 : if (initial_item == nullptr)
4708 : : return items;
4709 : :
4710 : 0 : items.push_back (std::move (initial_item));
4711 : :
4712 : 0 : while (lexer.peek_token ()->get_id () == COMMA)
4713 : : {
4714 : 0 : lexer.skip_token ();
4715 : :
4716 : 0 : std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4717 : 0 : if (item == nullptr)
4718 : : {
4719 : : // this would occur with a trailing comma, which is allowed
4720 : : break;
4721 : : }
4722 : :
4723 : 0 : items.push_back (std::move (item));
4724 : : }
4725 : :
4726 : 0 : items.shrink_to_fit ();
4727 : : return items;
4728 : :
4729 : : /* TODO: use template if doable (parse_non_ptr_sequence) */
4730 : 0 : }
4731 : :
4732 : : // Parses the enum variants inside an enum definiton.
4733 : : template <typename ManagedTokenSource>
4734 : : template <typename EndTokenPred>
4735 : : std::vector<std::unique_ptr<AST::EnumItem>>
4736 : 573 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
4737 : : {
4738 : 573 : std::vector<std::unique_ptr<AST::EnumItem>> items;
4739 : :
4740 : 573 : std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4741 : :
4742 : : // Return empty item list if no field there
4743 : 573 : if (initial_item == nullptr)
4744 : 17 : return items;
4745 : :
4746 : 556 : items.push_back (std::move (initial_item));
4747 : :
4748 : 2710 : while (lexer.peek_token ()->get_id () == COMMA)
4749 : : {
4750 : 1323 : lexer.skip_token ();
4751 : :
4752 : 2646 : if (is_end_tok (lexer.peek_token ()->get_id ()))
4753 : : break;
4754 : :
4755 : 799 : std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4756 : 799 : if (item == nullptr)
4757 : : {
4758 : : /* TODO should this ignore all successfully parsed enum items just
4759 : : * because one failed? */
4760 : 0 : Error error (lexer.peek_token ()->get_locus (),
4761 : : "failed to parse enum item in enum items");
4762 : 0 : add_error (std::move (error));
4763 : :
4764 : 0 : return {};
4765 : 0 : }
4766 : :
4767 : 799 : items.push_back (std::move (item));
4768 : : }
4769 : :
4770 : 556 : items.shrink_to_fit ();
4771 : 556 : return items;
4772 : :
4773 : : /* TODO: use template if doable (parse_non_ptr_sequence) */
4774 : 573 : }
4775 : :
4776 : : /* Parses a single enum variant item in an enum definition. Does not parse
4777 : : * commas. */
4778 : : template <typename ManagedTokenSource>
4779 : : std::unique_ptr<AST::EnumItem>
4780 : 1372 : Parser<ManagedTokenSource>::parse_enum_item ()
4781 : : {
4782 : : // parse outer attributes if they exist
4783 : 1372 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4784 : :
4785 : : // parse visibility, which may or may not exist
4786 : 1372 : AST::Visibility vis = parse_visibility ();
4787 : :
4788 : : // parse name for enum item, which is required
4789 : 1372 : const_TokenPtr item_name_tok = lexer.peek_token ();
4790 : 1372 : if (item_name_tok->get_id () != IDENTIFIER)
4791 : : {
4792 : : // this may not be an error but it means there is no enum item here
4793 : 17 : return nullptr;
4794 : : }
4795 : 1355 : lexer.skip_token ();
4796 : 1355 : Identifier item_name{item_name_tok};
4797 : :
4798 : : // branch based on next token
4799 : 1355 : const_TokenPtr t = lexer.peek_token ();
4800 : 1355 : switch (t->get_id ())
4801 : : {
4802 : 468 : case LEFT_PAREN:
4803 : : {
4804 : : // tuple enum item
4805 : 468 : lexer.skip_token ();
4806 : :
4807 : 468 : std::vector<AST::TupleField> tuple_fields;
4808 : : // Might be empty tuple for unit tuple enum variant.
4809 : 936 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4810 : 17 : tuple_fields = std::vector<AST::TupleField> ();
4811 : : else
4812 : 451 : tuple_fields = parse_tuple_fields ();
4813 : :
4814 : 468 : if (!skip_token (RIGHT_PAREN))
4815 : : {
4816 : : // skip after somewhere
4817 : 0 : return nullptr;
4818 : : }
4819 : :
4820 : 468 : return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
4821 : : std::move (item_name), std::move (vis), std::move (tuple_fields),
4822 : 468 : std::move (outer_attrs), item_name_tok->get_locus ()));
4823 : 468 : }
4824 : 92 : case LEFT_CURLY:
4825 : : {
4826 : : // struct enum item
4827 : 92 : lexer.skip_token ();
4828 : :
4829 : 92 : std::vector<AST::StructField> struct_fields
4830 : : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4831 : :
4832 : 92 : if (!skip_token (RIGHT_CURLY))
4833 : : {
4834 : : // skip after somewhere
4835 : 0 : return nullptr;
4836 : : }
4837 : :
4838 : 92 : return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
4839 : : std::move (item_name), std::move (vis), std::move (struct_fields),
4840 : 92 : std::move (outer_attrs), item_name_tok->get_locus ()));
4841 : 92 : }
4842 : 281 : case EQUAL:
4843 : : {
4844 : : // discriminant enum item
4845 : 281 : lexer.skip_token ();
4846 : :
4847 : 281 : std::unique_ptr<AST::Expr> discriminant_expr = parse_expr ();
4848 : :
4849 : 281 : return std::unique_ptr<AST::EnumItemDiscriminant> (
4850 : 562 : new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
4851 : : std::move (discriminant_expr),
4852 : : std::move (outer_attrs),
4853 : 281 : item_name_tok->get_locus ()));
4854 : 281 : }
4855 : 514 : default:
4856 : : // regular enum with just an identifier
4857 : : return std::unique_ptr<AST::EnumItem> (
4858 : 514 : new AST::EnumItem (std::move (item_name), std::move (vis),
4859 : : std::move (outer_attrs),
4860 : 514 : item_name_tok->get_locus ()));
4861 : : }
4862 : 2727 : }
4863 : :
4864 : : // Parses a C-style (and C-compat) untagged union declaration.
4865 : : template <typename ManagedTokenSource>
4866 : : std::unique_ptr<AST::Union>
4867 : 109 : Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
4868 : : AST::AttrVec outer_attrs)
4869 : : {
4870 : : /* hack - "weak keyword" by finding identifier called "union" (lookahead in
4871 : : * item switch) */
4872 : 109 : const_TokenPtr union_keyword = expect_token (IDENTIFIER);
4873 : 109 : rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
4874 : 109 : location_t locus = union_keyword->get_locus ();
4875 : :
4876 : : // parse actual union name
4877 : 109 : const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
4878 : 109 : if (union_name_tok == nullptr)
4879 : : {
4880 : 0 : skip_after_next_block ();
4881 : 0 : return nullptr;
4882 : : }
4883 : 109 : Identifier union_name{union_name_tok};
4884 : :
4885 : : // parse optional generic parameters
4886 : 109 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4887 : : = parse_generic_params_in_angles ();
4888 : :
4889 : : // parse optional where clause
4890 : 109 : AST::WhereClause where_clause = parse_where_clause ();
4891 : :
4892 : 109 : if (!skip_token (LEFT_CURLY))
4893 : : {
4894 : 0 : skip_after_end_block ();
4895 : 0 : return nullptr;
4896 : : }
4897 : :
4898 : : /* parse union inner items as "struct fields" because hey, syntax reuse.
4899 : : * Spec said so. */
4900 : 109 : std::vector<AST::StructField> union_fields
4901 : : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4902 : :
4903 : 109 : if (!skip_token (RIGHT_CURLY))
4904 : : {
4905 : : // skip after somewhere
4906 : 0 : return nullptr;
4907 : : }
4908 : :
4909 : : return std::unique_ptr<AST::Union> (
4910 : 109 : new AST::Union (std::move (union_name), std::move (vis),
4911 : : std::move (generic_params), std::move (where_clause),
4912 : 109 : std::move (union_fields), std::move (outer_attrs), locus));
4913 : 327 : }
4914 : :
4915 : : /* Parses a "constant item" (compile-time constant to maybe "inline"
4916 : : * throughout the program - like constexpr). */
4917 : : template <typename ManagedTokenSource>
4918 : : std::unique_ptr<AST::ConstantItem>
4919 : 1237 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
4920 : : AST::AttrVec outer_attrs)
4921 : : {
4922 : 1237 : location_t locus = lexer.peek_token ()->get_locus ();
4923 : 1237 : skip_token (CONST);
4924 : :
4925 : : /* get constant identifier - this is either a proper identifier or the _
4926 : : * wildcard */
4927 : 1237 : const_TokenPtr ident_tok = lexer.peek_token ();
4928 : : // make default identifier the underscore wildcard one
4929 : 1237 : std::string ident (Values::Keywords::UNDERSCORE);
4930 : 1237 : switch (ident_tok->get_id ())
4931 : : {
4932 : 1237 : case IDENTIFIER:
4933 : 1237 : ident = ident_tok->get_str ();
4934 : 1237 : lexer.skip_token ();
4935 : : break;
4936 : 0 : case UNDERSCORE:
4937 : : // do nothing - identifier is already "_"
4938 : 0 : lexer.skip_token ();
4939 : : break;
4940 : 0 : default:
4941 : 0 : add_error (
4942 : 0 : Error (ident_tok->get_locus (),
4943 : : "expected item name (identifier or %<_%>) in constant item "
4944 : : "declaration - found %qs",
4945 : : ident_tok->get_token_description ()));
4946 : :
4947 : 0 : skip_after_semicolon ();
4948 : 0 : return nullptr;
4949 : : }
4950 : :
4951 : 1237 : if (!skip_token (COLON))
4952 : : {
4953 : 0 : skip_after_semicolon ();
4954 : 0 : return nullptr;
4955 : : }
4956 : :
4957 : : // parse constant type (required)
4958 : 1237 : std::unique_ptr<AST::Type> type = parse_type ();
4959 : :
4960 : : // A const with no given expression value
4961 : 2474 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4962 : : {
4963 : 4 : lexer.skip_token ();
4964 : : return std::unique_ptr<AST::ConstantItem> (
4965 : 8 : new AST::ConstantItem (std::move (ident), std::move (vis),
4966 : : std::move (type), std::move (outer_attrs),
4967 : 4 : locus));
4968 : : }
4969 : :
4970 : 1233 : if (!skip_token (EQUAL))
4971 : : {
4972 : 0 : skip_after_semicolon ();
4973 : 0 : return nullptr;
4974 : : }
4975 : :
4976 : : // parse constant expression (required)
4977 : 1233 : std::unique_ptr<AST::Expr> expr = parse_expr ();
4978 : :
4979 : 1233 : if (!skip_token (SEMICOLON))
4980 : : {
4981 : : // skip somewhere?
4982 : 1 : return nullptr;
4983 : : }
4984 : :
4985 : : return std::unique_ptr<AST::ConstantItem> (
4986 : 2464 : new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
4987 : 1232 : std::move (expr), std::move (outer_attrs), locus));
4988 : 2474 : }
4989 : :
4990 : : // Parses a "static item" (static storage item, with 'static lifetime).
4991 : : template <typename ManagedTokenSource>
4992 : : std::unique_ptr<AST::StaticItem>
4993 : 93 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
4994 : : AST::AttrVec outer_attrs)
4995 : : {
4996 : 93 : location_t locus = lexer.peek_token ()->get_locus ();
4997 : 93 : skip_token (STATIC_KW);
4998 : :
4999 : : // determine whether static item is mutable
5000 : 93 : bool is_mut = false;
5001 : 186 : if (lexer.peek_token ()->get_id () == MUT)
5002 : : {
5003 : 4 : is_mut = true;
5004 : 4 : lexer.skip_token ();
5005 : : }
5006 : :
5007 : 93 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5008 : 93 : if (ident_tok == nullptr)
5009 : 0 : return nullptr;
5010 : :
5011 : 93 : Identifier ident{ident_tok};
5012 : :
5013 : 93 : if (!skip_token (COLON))
5014 : : {
5015 : 1 : skip_after_semicolon ();
5016 : 1 : return nullptr;
5017 : : }
5018 : :
5019 : : // parse static item type (required)
5020 : 92 : std::unique_ptr<AST::Type> type = parse_type ();
5021 : :
5022 : 92 : if (!skip_token (EQUAL))
5023 : : {
5024 : 0 : skip_after_semicolon ();
5025 : 0 : return nullptr;
5026 : : }
5027 : :
5028 : : // parse static item expression (required)
5029 : 92 : std::unique_ptr<AST::Expr> expr = parse_expr ();
5030 : :
5031 : 92 : if (!skip_token (SEMICOLON))
5032 : : {
5033 : : // skip after somewhere
5034 : 0 : return nullptr;
5035 : : }
5036 : :
5037 : : return std::unique_ptr<AST::StaticItem> (
5038 : 92 : new AST::StaticItem (std::move (ident), is_mut, std::move (type),
5039 : : std::move (expr), std::move (vis),
5040 : 92 : std::move (outer_attrs), locus));
5041 : 185 : }
5042 : :
5043 : : // Parses a trait definition item, including unsafe ones.
5044 : : template <typename ManagedTokenSource>
5045 : : std::unique_ptr<AST::Trait>
5046 : 3893 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
5047 : : AST::AttrVec outer_attrs)
5048 : : {
5049 : 3893 : location_t locus = lexer.peek_token ()->get_locus ();
5050 : 3893 : bool is_unsafe = false;
5051 : 3893 : bool is_auto_trait = false;
5052 : :
5053 : 7786 : if (lexer.peek_token ()->get_id () == UNSAFE)
5054 : : {
5055 : 72 : is_unsafe = true;
5056 : 72 : lexer.skip_token ();
5057 : : }
5058 : :
5059 : 7786 : if (lexer.peek_token ()->get_id () == AUTO)
5060 : : {
5061 : 24 : is_auto_trait = true;
5062 : 24 : lexer.skip_token ();
5063 : : }
5064 : :
5065 : 3893 : skip_token (TRAIT);
5066 : :
5067 : : // parse trait name
5068 : 3893 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5069 : 3893 : if (ident_tok == nullptr)
5070 : 0 : return nullptr;
5071 : :
5072 : 3893 : Identifier ident{ident_tok};
5073 : :
5074 : : // parse generic parameters (if they exist)
5075 : 3893 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5076 : : = parse_generic_params_in_angles ();
5077 : :
5078 : : // create placeholder type param bounds in case they don't exist
5079 : 3893 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
5080 : :
5081 : : // parse type param bounds (if they exist)
5082 : 7786 : if (lexer.peek_token ()->get_id () == COLON)
5083 : : {
5084 : 589 : lexer.skip_token ();
5085 : :
5086 : 589 : type_param_bounds = parse_type_param_bounds (
5087 : 90 : [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
5088 : : // type_param_bounds = parse_type_param_bounds ();
5089 : : }
5090 : :
5091 : : // parse where clause (if it exists)
5092 : 3893 : AST::WhereClause where_clause = parse_where_clause ();
5093 : :
5094 : 3893 : if (!skip_token (LEFT_CURLY))
5095 : : {
5096 : 0 : skip_after_end_block ();
5097 : 0 : return nullptr;
5098 : : }
5099 : :
5100 : : // parse inner attrs (if they exist)
5101 : 3893 : AST::AttrVec inner_attrs = parse_inner_attributes ();
5102 : :
5103 : : // parse trait items
5104 : 3893 : std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
5105 : :
5106 : 3893 : const_TokenPtr t = lexer.peek_token ();
5107 : 7623 : while (t->get_id () != RIGHT_CURLY)
5108 : : {
5109 : 3730 : std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
5110 : :
5111 : 3730 : if (trait_item == nullptr)
5112 : : {
5113 : 0 : Error error (lexer.peek_token ()->get_locus (),
5114 : : "failed to parse trait item in trait");
5115 : 0 : add_error (std::move (error));
5116 : :
5117 : 0 : return nullptr;
5118 : 0 : }
5119 : 3730 : trait_items.push_back (std::move (trait_item));
5120 : :
5121 : 3730 : t = lexer.peek_token ();
5122 : : }
5123 : :
5124 : 3893 : if (!skip_token (RIGHT_CURLY))
5125 : : {
5126 : : // skip after something
5127 : 0 : return nullptr;
5128 : : }
5129 : :
5130 : 3893 : trait_items.shrink_to_fit ();
5131 : : return std::unique_ptr<AST::Trait> (
5132 : 3893 : new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
5133 : : std::move (generic_params), std::move (type_param_bounds),
5134 : : std::move (where_clause), std::move (trait_items),
5135 : : std::move (vis), std::move (outer_attrs),
5136 : 3893 : std::move (inner_attrs), locus));
5137 : 7786 : }
5138 : :
5139 : : // Parses a trait item used inside traits (not trait, the Item).
5140 : : template <typename ManagedTokenSource>
5141 : : std::unique_ptr<AST::AssociatedItem>
5142 : 3732 : Parser<ManagedTokenSource>::parse_trait_item ()
5143 : : {
5144 : : // parse outer attributes (if they exist)
5145 : 3732 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5146 : :
5147 : 3732 : AST::Visibility vis = parse_visibility ();
5148 : :
5149 : : // lookahead to determine what type of trait item to parse
5150 : 3732 : const_TokenPtr tok = lexer.peek_token ();
5151 : 3732 : switch (tok->get_id ())
5152 : : {
5153 : 0 : case SUPER:
5154 : : case SELF:
5155 : : case CRATE:
5156 : : case DOLLAR_SIGN:
5157 : : // these seem to be SimplePath tokens, so this is a macro invocation
5158 : : // semi
5159 : 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
5160 : 1 : case IDENTIFIER:
5161 : 2 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
5162 : 0 : return parse_function (std::move (vis), std::move (outer_attrs));
5163 : : else
5164 : 2 : return parse_macro_invocation_semi (std::move (outer_attrs));
5165 : 784 : case TYPE:
5166 : 784 : return parse_trait_type (std::move (outer_attrs), vis);
5167 : 60 : case CONST:
5168 : : // disambiguate with function qualifier
5169 : 120 : if (lexer.peek_token (1)->get_id () == IDENTIFIER)
5170 : : {
5171 : 118 : return parse_trait_const (std::move (outer_attrs));
5172 : : }
5173 : : // else, fallthrough to function
5174 : : // TODO: find out how to disable gcc "implicit fallthrough" error
5175 : : gcc_fallthrough ();
5176 : : case ASYNC:
5177 : : case UNSAFE:
5178 : : case EXTERN_KW:
5179 : : case FN_KW:
5180 : 5776 : return parse_function (std::move (vis), std::move (outer_attrs));
5181 : : default:
5182 : : break;
5183 : : }
5184 : 0 : add_error (Error (tok->get_locus (),
5185 : : "unrecognised token %qs for item in trait",
5186 : : tok->get_token_description ()));
5187 : : // skip?
5188 : 0 : return nullptr;
5189 : 3732 : }
5190 : :
5191 : : // Parse a typedef trait item.
5192 : : template <typename ManagedTokenSource>
5193 : : std::unique_ptr<AST::TraitItemType>
5194 : 784 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
5195 : : AST::Visibility vis)
5196 : : {
5197 : 784 : location_t locus = lexer.peek_token ()->get_locus ();
5198 : 784 : skip_token (TYPE);
5199 : :
5200 : 784 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5201 : 784 : if (ident_tok == nullptr)
5202 : 0 : return nullptr;
5203 : :
5204 : 1568 : Identifier ident{ident_tok};
5205 : :
5206 : : // Parse optional generic parameters for GATs (Generic Associated Types)
5207 : 784 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
5208 : 1568 : if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
5209 : : {
5210 : 9 : generic_params = parse_generic_params_in_angles ();
5211 : : }
5212 : :
5213 : 784 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5214 : :
5215 : : // parse optional colon
5216 : 1568 : if (lexer.peek_token ()->get_id () == COLON)
5217 : : {
5218 : 54 : lexer.skip_token ();
5219 : :
5220 : : // parse optional type param bounds
5221 : : bounds
5222 : 54 : = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
5223 : : // bounds = parse_type_param_bounds ();
5224 : : }
5225 : :
5226 : 784 : if (!skip_token (SEMICOLON))
5227 : : {
5228 : : // skip?
5229 : 0 : return nullptr;
5230 : : }
5231 : :
5232 : : return std::unique_ptr<AST::TraitItemType> (
5233 : 784 : new AST::TraitItemType (std::move (ident), std::move (generic_params),
5234 : : std::move (bounds), std::move (outer_attrs), vis,
5235 : 784 : locus));
5236 : 784 : }
5237 : :
5238 : : // Parses a constant trait item.
5239 : : template <typename ManagedTokenSource>
5240 : : std::unique_ptr<AST::ConstantItem>
5241 : 59 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
5242 : : {
5243 : 59 : location_t locus = lexer.peek_token ()->get_locus ();
5244 : 59 : skip_token (CONST);
5245 : :
5246 : : // parse constant item name
5247 : 59 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5248 : 59 : if (ident_tok == nullptr)
5249 : 0 : return nullptr;
5250 : :
5251 : 59 : Identifier ident{ident_tok};
5252 : :
5253 : 59 : if (!skip_token (COLON))
5254 : : {
5255 : 0 : skip_after_semicolon ();
5256 : 0 : return nullptr;
5257 : : }
5258 : :
5259 : : // parse constant trait item type
5260 : 59 : std::unique_ptr<AST::Type> type = parse_type ();
5261 : :
5262 : : // parse constant trait body expression, if it exists
5263 : 59 : std::unique_ptr<AST::Expr> const_body = nullptr;
5264 : 118 : if (lexer.peek_token ()->get_id () == EQUAL)
5265 : : {
5266 : 12 : lexer.skip_token ();
5267 : :
5268 : : // expression must exist, so parse it
5269 : 12 : const_body = parse_expr ();
5270 : : }
5271 : :
5272 : 59 : if (!skip_token (SEMICOLON))
5273 : : {
5274 : : // skip after something?
5275 : 0 : return nullptr;
5276 : : }
5277 : :
5278 : 177 : return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
5279 : 118 : std::move (ident), AST::Visibility::create_private (), std::move (type),
5280 : 59 : std::move (const_body), std::move (outer_attrs), locus));
5281 : 118 : }
5282 : :
5283 : : /* Parses a struct "impl" item (both inherent impl and trait impl can be
5284 : : * parsed here), */
5285 : : template <typename ManagedTokenSource>
5286 : : std::unique_ptr<AST::Impl>
5287 : 11429 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
5288 : : AST::AttrVec outer_attrs)
5289 : : {
5290 : : /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
5291 : : * must be a trait impl. However, this isn't enough for full disambiguation,
5292 : : * so don't branch here. */
5293 : 11429 : location_t locus = lexer.peek_token ()->get_locus ();
5294 : 11429 : bool is_unsafe = false;
5295 : 22858 : if (lexer.peek_token ()->get_id () == UNSAFE)
5296 : : {
5297 : 219 : lexer.skip_token ();
5298 : 219 : is_unsafe = true;
5299 : : }
5300 : :
5301 : 11429 : if (!skip_token (IMPL))
5302 : : {
5303 : 0 : skip_after_next_block ();
5304 : 0 : return nullptr;
5305 : : }
5306 : :
5307 : : // parse generic params (shared by trait and inherent impls)
5308 : 11429 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5309 : : = parse_generic_params_in_angles ();
5310 : :
5311 : : // Again, trait impl-only feature, but optional one, so can be used for
5312 : : // branching yet.
5313 : 11429 : bool has_exclam = false;
5314 : 22858 : if (lexer.peek_token ()->get_id () == EXCLAM)
5315 : : {
5316 : 20 : lexer.skip_token ();
5317 : 20 : has_exclam = true;
5318 : : }
5319 : :
5320 : : /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
5321 : : * doesn't parse too much and not work. */
5322 : 11429 : AST::TypePath type_path = parse_type_path ();
5323 : 22647 : if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
5324 : : {
5325 : : /* cannot parse type path (or not for token next, at least), so must be
5326 : : * inherent impl */
5327 : :
5328 : : // hacky conversion of TypePath stack object to Type pointer
5329 : 1284 : std::unique_ptr<AST::Type> type = nullptr;
5330 : 1284 : if (!type_path.is_error ())
5331 : 1073 : type = std::unique_ptr<AST::TypePath> (
5332 : 1073 : new AST::TypePath (std::move (type_path)));
5333 : : else
5334 : 211 : type = parse_type ();
5335 : :
5336 : : // Type is required, so error if null
5337 : 1284 : if (type == nullptr)
5338 : : {
5339 : 1 : Error error (lexer.peek_token ()->get_locus (),
5340 : : "could not parse type in inherent impl");
5341 : 1 : add_error (std::move (error));
5342 : :
5343 : 1 : skip_after_next_block ();
5344 : 1 : return nullptr;
5345 : 1 : }
5346 : :
5347 : : // parse optional where clause
5348 : 1283 : AST::WhereClause where_clause = parse_where_clause ();
5349 : :
5350 : 1283 : if (!skip_token (LEFT_CURLY))
5351 : : {
5352 : : // TODO: does this still skip properly?
5353 : 0 : skip_after_end_block ();
5354 : 0 : return nullptr;
5355 : : }
5356 : :
5357 : : // parse inner attributes (optional)
5358 : 1283 : AST::AttrVec inner_attrs = parse_inner_attributes ();
5359 : :
5360 : : // parse inherent impl items
5361 : 1283 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
5362 : :
5363 : 1283 : const_TokenPtr t = lexer.peek_token ();
5364 : 5362 : while (t->get_id () != RIGHT_CURLY)
5365 : : {
5366 : 4089 : std::unique_ptr<AST::AssociatedItem> impl_item
5367 : : = parse_inherent_impl_item ();
5368 : :
5369 : 4089 : if (impl_item == nullptr)
5370 : : {
5371 : 10 : Error error (
5372 : 10 : lexer.peek_token ()->get_locus (),
5373 : : "failed to parse inherent impl item in inherent impl");
5374 : 10 : add_error (std::move (error));
5375 : :
5376 : 10 : return nullptr;
5377 : 10 : }
5378 : :
5379 : 4079 : impl_items.push_back (std::move (impl_item));
5380 : :
5381 : 4079 : t = lexer.peek_token ();
5382 : : }
5383 : :
5384 : 1273 : if (!skip_token (RIGHT_CURLY))
5385 : : {
5386 : : // skip somewhere
5387 : 0 : return nullptr;
5388 : : }
5389 : :
5390 : : // DEBUG
5391 : 1273 : rust_debug ("successfully parsed inherent impl");
5392 : :
5393 : 1273 : impl_items.shrink_to_fit ();
5394 : :
5395 : 1273 : return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
5396 : : std::move (impl_items), std::move (generic_params), std::move (type),
5397 : : std::move (where_clause), std::move (vis), std::move (inner_attrs),
5398 : 1273 : std::move (outer_attrs), locus));
5399 : 2567 : }
5400 : : else
5401 : : {
5402 : : // type path must both be valid and next token is for, so trait impl
5403 : 10145 : if (!skip_token (FOR))
5404 : : {
5405 : 0 : skip_after_next_block ();
5406 : 0 : return nullptr;
5407 : : }
5408 : :
5409 : : // parse type
5410 : 10145 : std::unique_ptr<AST::Type> type = parse_type ();
5411 : : // ensure type is included as it is required
5412 : 10145 : if (type == nullptr)
5413 : : {
5414 : 0 : Error error (lexer.peek_token ()->get_locus (),
5415 : : "could not parse type in trait impl");
5416 : 0 : add_error (std::move (error));
5417 : :
5418 : 0 : skip_after_next_block ();
5419 : 0 : return nullptr;
5420 : 0 : }
5421 : :
5422 : : // parse optional where clause
5423 : 10145 : AST::WhereClause where_clause = parse_where_clause ();
5424 : :
5425 : 10145 : if (!skip_token (LEFT_CURLY))
5426 : : {
5427 : : // TODO: does this still skip properly?
5428 : 0 : skip_after_end_block ();
5429 : 0 : return nullptr;
5430 : : }
5431 : :
5432 : : // parse inner attributes (optional)
5433 : 10145 : AST::AttrVec inner_attrs = parse_inner_attributes ();
5434 : :
5435 : : // parse trait impl items
5436 : 10145 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
5437 : :
5438 : 10145 : const_TokenPtr t = lexer.peek_token ();
5439 : 38357 : while (t->get_id () != RIGHT_CURLY)
5440 : : {
5441 : 14106 : std::unique_ptr<AST::AssociatedItem> impl_item
5442 : : = parse_trait_impl_item ();
5443 : :
5444 : 14106 : if (impl_item == nullptr)
5445 : : {
5446 : 0 : Error error (lexer.peek_token ()->get_locus (),
5447 : : "failed to parse trait impl item in trait impl");
5448 : 0 : add_error (std::move (error));
5449 : :
5450 : 0 : return nullptr;
5451 : 0 : }
5452 : :
5453 : 14106 : impl_items.push_back (std::move (impl_item));
5454 : :
5455 : 14106 : t = lexer.peek_token ();
5456 : :
5457 : : // DEBUG
5458 : 14106 : rust_debug ("successfully parsed a trait impl item");
5459 : : }
5460 : : // DEBUG
5461 : 10145 : rust_debug ("successfully finished trait impl items");
5462 : :
5463 : 10145 : if (!skip_token (RIGHT_CURLY))
5464 : : {
5465 : : // skip somewhere
5466 : 0 : return nullptr;
5467 : : }
5468 : :
5469 : : // DEBUG
5470 : 10145 : rust_debug ("successfully parsed trait impl");
5471 : :
5472 : 10145 : impl_items.shrink_to_fit ();
5473 : :
5474 : 10145 : return std::unique_ptr<AST::TraitImpl> (
5475 : 20290 : new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
5476 : : std::move (impl_items), std::move (generic_params),
5477 : : std::move (type), std::move (where_clause),
5478 : : std::move (vis), std::move (inner_attrs),
5479 : 10145 : std::move (outer_attrs), locus));
5480 : 20290 : }
5481 : 11429 : }
5482 : :
5483 : : // Parses a single inherent impl item (item inside an inherent impl block).
5484 : : template <typename ManagedTokenSource>
5485 : : std::unique_ptr<AST::AssociatedItem>
5486 : 6095 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
5487 : : {
5488 : : // parse outer attributes (if they exist)
5489 : 6095 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5490 : :
5491 : : // TODO: cleanup - currently an unreadable mess
5492 : :
5493 : : // branch on next token:
5494 : 6095 : const_TokenPtr t = lexer.peek_token ();
5495 : 6095 : switch (t->get_id ())
5496 : : {
5497 : 1091 : case IDENTIFIER:
5498 : : // FIXME: Arthur: Do we need to some lookahead here?
5499 : 2182 : return parse_macro_invocation_semi (outer_attrs);
5500 : 4281 : case SUPER:
5501 : : case SELF:
5502 : : case CRATE:
5503 : : case PUB:
5504 : : {
5505 : : // visibility, so not a macro invocation semi - must be constant,
5506 : : // function, or method
5507 : 4281 : AST::Visibility vis = parse_visibility ();
5508 : :
5509 : : // TODO: is a recursive call to parse_inherent_impl_item better?
5510 : 8562 : switch (lexer.peek_token ()->get_id ())
5511 : : {
5512 : 2109 : case EXTERN_KW:
5513 : : case UNSAFE:
5514 : : case FN_KW:
5515 : : // function or method
5516 : 4218 : return parse_inherent_impl_function_or_method (std::move (vis),
5517 : : std::move (
5518 : 2109 : outer_attrs));
5519 : 2172 : case CONST:
5520 : : // lookahead to resolve production - could be function/method or
5521 : : // const item
5522 : 2172 : t = lexer.peek_token (1);
5523 : :
5524 : 2172 : switch (t->get_id ())
5525 : : {
5526 : 100 : case IDENTIFIER:
5527 : : case UNDERSCORE:
5528 : 200 : return parse_const_item (std::move (vis),
5529 : 100 : std::move (outer_attrs));
5530 : 2072 : case UNSAFE:
5531 : : case EXTERN_KW:
5532 : : case FN_KW:
5533 : 4144 : return parse_inherent_impl_function_or_method (std::move (vis),
5534 : : std::move (
5535 : 2072 : outer_attrs));
5536 : 0 : default:
5537 : 0 : add_error (Error (t->get_locus (),
5538 : : "unexpected token %qs in some sort of const "
5539 : : "item in inherent impl",
5540 : : t->get_token_description ()));
5541 : :
5542 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
5543 : 0 : return nullptr;
5544 : : }
5545 : 0 : default:
5546 : 0 : add_error (
5547 : 0 : Error (t->get_locus (),
5548 : : "unrecognised token %qs for item in inherent impl",
5549 : : t->get_token_description ()));
5550 : : // skip?
5551 : 0 : return nullptr;
5552 : : }
5553 : 4281 : }
5554 : 671 : case ASYNC:
5555 : : case EXTERN_KW:
5556 : : case UNSAFE:
5557 : : case FN_KW:
5558 : : // function or method
5559 : 671 : return parse_inherent_impl_function_or_method (
5560 : 671 : AST::Visibility::create_private (), std::move (outer_attrs));
5561 : 52 : case CONST:
5562 : : /* lookahead to resolve production - could be function/method or const
5563 : : * item */
5564 : 52 : t = lexer.peek_token (1);
5565 : :
5566 : 52 : switch (t->get_id ())
5567 : : {
5568 : 40 : case IDENTIFIER:
5569 : : case UNDERSCORE:
5570 : 80 : return parse_const_item (AST::Visibility::create_private (),
5571 : 40 : std::move (outer_attrs));
5572 : 12 : case UNSAFE:
5573 : : case EXTERN_KW:
5574 : : case FN_KW:
5575 : 12 : return parse_inherent_impl_function_or_method (
5576 : 12 : AST::Visibility::create_private (), std::move (outer_attrs));
5577 : 0 : default:
5578 : 0 : add_error (Error (t->get_locus (),
5579 : : "unexpected token %qs in some sort of const item "
5580 : : "in inherent impl",
5581 : : t->get_token_description ()));
5582 : :
5583 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
5584 : 0 : return nullptr;
5585 : : }
5586 : : rust_unreachable ();
5587 : 0 : default:
5588 : 0 : add_error (Error (t->get_locus (),
5589 : : "unrecognised token %qs for item in inherent impl",
5590 : : t->get_token_description ()));
5591 : :
5592 : : // skip?
5593 : 0 : return nullptr;
5594 : : }
5595 : 6095 : }
5596 : :
5597 : : /* For internal use only by parse_inherent_impl_item() - splits giant method
5598 : : * into smaller ones and prevents duplication of logic. Strictly, this parses
5599 : : * a function or method item inside an inherent impl item block. */
5600 : : // TODO: make this a templated function with "return type" as type param -
5601 : : // InherentImplItem is this specialisation of the template while TraitImplItem
5602 : : // will be the other.
5603 : : template <typename ManagedTokenSource>
5604 : : std::unique_ptr<AST::AssociatedItem>
5605 : 4864 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
5606 : : AST::Visibility vis, AST::AttrVec outer_attrs)
5607 : : {
5608 : 4864 : location_t locus = lexer.peek_token ()->get_locus ();
5609 : : // parse function or method qualifiers
5610 : 4864 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5611 : :
5612 : 4864 : skip_token (FN_KW);
5613 : :
5614 : : // parse function or method name
5615 : 4864 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5616 : 4864 : if (ident_tok == nullptr)
5617 : 7 : return nullptr;
5618 : :
5619 : 4857 : Identifier ident{ident_tok};
5620 : :
5621 : : // parse generic params
5622 : 4857 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5623 : : = parse_generic_params_in_angles ();
5624 : :
5625 : 4857 : if (!skip_token (LEFT_PAREN))
5626 : : {
5627 : : // skip after somewhere?
5628 : 0 : return nullptr;
5629 : : }
5630 : :
5631 : : // now for function vs method disambiguation - method has opening "self"
5632 : : // param
5633 : 4857 : auto initial_param = parse_self_param ();
5634 : :
5635 : 4857 : if (!initial_param.has_value ()
5636 : 4857 : && initial_param.error () != ParseSelfError::NOT_SELF)
5637 : 3 : return nullptr;
5638 : :
5639 : : /* FIXME: ensure that self param doesn't accidently consume tokens for a
5640 : : * function one idea is to lookahead up to 4 tokens to see whether self is
5641 : : * one of them */
5642 : 4854 : bool is_method = false;
5643 : 4854 : if (initial_param.has_value ())
5644 : : {
5645 : 3567 : if ((*initial_param)->is_self ())
5646 : : is_method = true;
5647 : :
5648 : : /* skip comma so function and method regular params can be parsed in
5649 : : * same way */
5650 : 7134 : if (lexer.peek_token ()->get_id () == COMMA)
5651 : 2081 : lexer.skip_token ();
5652 : : }
5653 : :
5654 : : // parse trait function params
5655 : 4854 : std::vector<std::unique_ptr<AST::Param>> function_params
5656 : : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5657 : :
5658 : 4854 : if (initial_param.has_value ())
5659 : 3567 : function_params.insert (function_params.begin (),
5660 : 3567 : std::move (*initial_param));
5661 : :
5662 : 4854 : if (!skip_token (RIGHT_PAREN))
5663 : : {
5664 : 0 : skip_after_end_block ();
5665 : 0 : return nullptr;
5666 : : }
5667 : :
5668 : : // parse return type (optional)
5669 : 4854 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5670 : :
5671 : : // parse where clause (optional)
5672 : 4854 : AST::WhereClause where_clause = parse_where_clause ();
5673 : :
5674 : 4854 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
5675 : 9708 : if (lexer.peek_token ()->get_id () == SEMICOLON)
5676 : 2 : lexer.skip_token ();
5677 : : else
5678 : : {
5679 : 4852 : auto result = parse_block_expr ();
5680 : :
5681 : 4852 : if (result == nullptr)
5682 : : {
5683 : 0 : Error error (
5684 : 0 : lexer.peek_token ()->get_locus (),
5685 : : "could not parse definition in inherent impl %s definition",
5686 : : is_method ? "method" : "function");
5687 : 0 : add_error (std::move (error));
5688 : :
5689 : 0 : skip_after_end_block ();
5690 : 0 : return nullptr;
5691 : 0 : }
5692 : 4852 : body = std::move (result);
5693 : 4852 : }
5694 : :
5695 : 4854 : return std::unique_ptr<AST::Function> (
5696 : 19414 : new AST::Function (std::move (ident), std::move (qualifiers),
5697 : : std::move (generic_params), std::move (function_params),
5698 : : std::move (return_type), std::move (where_clause),
5699 : : std::move (body), std::move (vis),
5700 : 4854 : std::move (outer_attrs), locus));
5701 : 14575 : }
5702 : :
5703 : : // Parses a single trait impl item (item inside a trait impl block).
5704 : : template <typename ManagedTokenSource>
5705 : : std::unique_ptr<AST::AssociatedItem>
5706 : 14326 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
5707 : : {
5708 : : // parse outer attributes (if they exist)
5709 : 14326 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5710 : :
5711 : 14326 : auto visibility = AST::Visibility::create_private ();
5712 : 28652 : if (lexer.peek_token ()->get_id () == PUB)
5713 : 0 : visibility = parse_visibility ();
5714 : :
5715 : : // branch on next token:
5716 : 14326 : const_TokenPtr t = lexer.peek_token ();
5717 : 14326 : switch (t->get_id ())
5718 : : {
5719 : 0 : case SUPER:
5720 : : case SELF:
5721 : : case CRATE:
5722 : : case DOLLAR_SIGN:
5723 : : // these seem to be SimplePath tokens, so this is a macro invocation
5724 : : // semi
5725 : 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
5726 : 116 : case IDENTIFIER:
5727 : 232 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
5728 : 104 : return parse_trait_impl_function_or_method (visibility,
5729 : 52 : std::move (outer_attrs));
5730 : : else
5731 : 128 : return parse_macro_invocation_semi (std::move (outer_attrs));
5732 : 3878 : case TYPE:
5733 : 7756 : return parse_type_alias (visibility, std::move (outer_attrs));
5734 : 10256 : case EXTERN_KW:
5735 : : case UNSAFE:
5736 : : case FN_KW:
5737 : : // function or method
5738 : 20512 : return parse_trait_impl_function_or_method (visibility,
5739 : 10256 : std::move (outer_attrs));
5740 : 1 : case ASYNC:
5741 : 2 : return parse_async_item (visibility, std::move (outer_attrs));
5742 : 75 : case CONST:
5743 : : // lookahead to resolve production - could be function/method or const
5744 : : // item
5745 : 75 : t = lexer.peek_token (1);
5746 : :
5747 : 75 : switch (t->get_id ())
5748 : : {
5749 : 74 : case IDENTIFIER:
5750 : : case UNDERSCORE:
5751 : 148 : return parse_const_item (visibility, std::move (outer_attrs));
5752 : 1 : case UNSAFE:
5753 : : case EXTERN_KW:
5754 : : case FN_KW:
5755 : 2 : return parse_trait_impl_function_or_method (visibility,
5756 : 1 : std::move (outer_attrs));
5757 : 0 : default:
5758 : 0 : add_error (Error (
5759 : : t->get_locus (),
5760 : : "unexpected token %qs in some sort of const item in trait impl",
5761 : : t->get_token_description ()));
5762 : :
5763 : 0 : lexer.skip_token (1); // TODO: is this right thing to do?
5764 : 0 : return nullptr;
5765 : : }
5766 : : rust_unreachable ();
5767 : : default:
5768 : : break;
5769 : : }
5770 : 0 : add_error (Error (t->get_locus (),
5771 : : "unrecognised token %qs for item in trait impl",
5772 : : t->get_token_description ()));
5773 : :
5774 : : // skip?
5775 : 0 : return nullptr;
5776 : 14326 : }
5777 : :
5778 : : /* For internal use only by parse_trait_impl_item() - splits giant method into
5779 : : * smaller ones and prevents duplication of logic. Strictly, this parses a
5780 : : * function or method item inside a trait impl item block. */
5781 : : template <typename ManagedTokenSource>
5782 : : std::unique_ptr<AST::AssociatedItem>
5783 : 10309 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
5784 : : AST::Visibility vis, AST::AttrVec outer_attrs)
5785 : : {
5786 : : // this shares virtually all logic with
5787 : : // parse_inherent_impl_function_or_method
5788 : : // - template?
5789 : 10309 : location_t locus = lexer.peek_token ()->get_locus ();
5790 : :
5791 : 10309 : auto is_default = false;
5792 : 10309 : auto t = lexer.peek_token ();
5793 : 10309 : if (t->get_id () == IDENTIFIER
5794 : 10309 : && t->get_str () == Values::WeakKeywords::DEFAULT)
5795 : : {
5796 : 52 : is_default = true;
5797 : 52 : lexer.skip_token ();
5798 : : }
5799 : :
5800 : : // parse function or method qualifiers
5801 : 10309 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5802 : :
5803 : 10309 : skip_token (FN_KW);
5804 : :
5805 : : // parse function or method name
5806 : 10309 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5807 : 10309 : if (ident_tok == nullptr)
5808 : : {
5809 : 0 : return nullptr;
5810 : : }
5811 : 10309 : Identifier ident{ident_tok};
5812 : :
5813 : : // DEBUG:
5814 : 10309 : rust_debug (
5815 : : "about to start parsing generic params in trait impl function or method");
5816 : :
5817 : : // parse generic params
5818 : 10309 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5819 : : = parse_generic_params_in_angles ();
5820 : :
5821 : : // DEBUG:
5822 : 10309 : rust_debug (
5823 : : "finished parsing generic params in trait impl function or method");
5824 : :
5825 : 10309 : if (!skip_token (LEFT_PAREN))
5826 : : {
5827 : : // skip after somewhere?
5828 : 0 : return nullptr;
5829 : : }
5830 : :
5831 : : // now for function vs method disambiguation - method has opening "self"
5832 : : // param
5833 : 10309 : auto initial_param = parse_self_param ();
5834 : :
5835 : 10309 : if (!initial_param.has_value ()
5836 : 10309 : && initial_param.error () != ParseSelfError::NOT_SELF)
5837 : 0 : return nullptr;
5838 : :
5839 : : // FIXME: ensure that self param doesn't accidently consume tokens for a
5840 : : // function
5841 : 10309 : bool is_method = false;
5842 : 10309 : if (initial_param.has_value ())
5843 : : {
5844 : 9293 : if ((*initial_param)->is_self ())
5845 : : is_method = true;
5846 : :
5847 : : // skip comma so function and method regular params can be parsed in
5848 : : // same way
5849 : 18586 : if (lexer.peek_token ()->get_id () == COMMA)
5850 : : {
5851 : 6818 : lexer.skip_token ();
5852 : : }
5853 : :
5854 : : // DEBUG
5855 : 9293 : rust_debug ("successfully parsed self param in method trait impl item");
5856 : : }
5857 : :
5858 : : // DEBUG
5859 : 10309 : rust_debug (
5860 : : "started to parse function params in function or method trait impl item");
5861 : :
5862 : : // parse trait function params (only if next token isn't right paren)
5863 : 10309 : std::vector<std::unique_ptr<AST::Param>> function_params;
5864 : 20618 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
5865 : : {
5866 : : function_params
5867 : 7612 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5868 : :
5869 : 7612 : if (function_params.empty ())
5870 : : {
5871 : 0 : Error error (
5872 : 0 : lexer.peek_token ()->get_locus (),
5873 : : "failed to parse function params in trait impl %s definition",
5874 : : is_method ? "method" : "function");
5875 : 0 : add_error (std::move (error));
5876 : :
5877 : 0 : skip_after_next_block ();
5878 : 0 : return nullptr;
5879 : 0 : }
5880 : : }
5881 : :
5882 : 10309 : if (initial_param.has_value ())
5883 : 9293 : function_params.insert (function_params.begin (),
5884 : 9293 : std::move (*initial_param));
5885 : :
5886 : : // DEBUG
5887 : 10309 : rust_debug ("successfully parsed function params in function or method "
5888 : : "trait impl item");
5889 : :
5890 : 10309 : if (!skip_token (RIGHT_PAREN))
5891 : : {
5892 : 0 : skip_after_next_block ();
5893 : 0 : return nullptr;
5894 : : }
5895 : :
5896 : : // parse return type (optional)
5897 : 10309 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5898 : :
5899 : : // DEBUG
5900 : 10309 : rust_debug (
5901 : : "successfully parsed return type in function or method trait impl item");
5902 : :
5903 : : // parse where clause (optional)
5904 : 10309 : AST::WhereClause where_clause = parse_where_clause ();
5905 : :
5906 : : // DEBUG
5907 : 10309 : rust_debug (
5908 : : "successfully parsed where clause in function or method trait impl item");
5909 : :
5910 : : // parse function definition (in block) - semicolon not allowed
5911 : 10309 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
5912 : :
5913 : 20618 : if (lexer.peek_token ()->get_id () == SEMICOLON)
5914 : 1 : lexer.skip_token ();
5915 : : else
5916 : : {
5917 : 10308 : auto result = parse_block_expr ();
5918 : 10308 : if (result == nullptr)
5919 : : {
5920 : 0 : Error error (lexer.peek_token ()->get_locus (),
5921 : : "could not parse definition in trait impl %s definition",
5922 : : is_method ? "method" : "function");
5923 : 0 : add_error (std::move (error));
5924 : :
5925 : 0 : skip_after_end_block ();
5926 : 0 : return nullptr;
5927 : 0 : }
5928 : 10308 : body = std::move (result);
5929 : 10308 : }
5930 : :
5931 : 10309 : return std::unique_ptr<AST::Function> (
5932 : 41235 : new AST::Function (std::move (ident), std::move (qualifiers),
5933 : : std::move (generic_params), std::move (function_params),
5934 : : std::move (return_type), std::move (where_clause),
5935 : : std::move (body), std::move (vis),
5936 : 10309 : std::move (outer_attrs), locus, is_default));
5937 : 30927 : }
5938 : :
5939 : : // Parses an extern block of declarations.
5940 : : template <typename ManagedTokenSource>
5941 : : std::unique_ptr<AST::ExternBlock>
5942 : 1522 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
5943 : : AST::AttrVec outer_attrs)
5944 : : {
5945 : 1522 : location_t locus = lexer.peek_token ()->get_locus ();
5946 : 1522 : skip_token (EXTERN_KW);
5947 : :
5948 : : // detect optional abi name
5949 : 1522 : std::string abi;
5950 : 1522 : const_TokenPtr next_tok = lexer.peek_token ();
5951 : 1522 : if (next_tok->get_id () == STRING_LITERAL)
5952 : : {
5953 : 1522 : lexer.skip_token ();
5954 : 1522 : abi = next_tok->get_str ();
5955 : : }
5956 : :
5957 : 1522 : if (!skip_token (LEFT_CURLY))
5958 : : {
5959 : 0 : skip_after_end_block ();
5960 : 0 : return nullptr;
5961 : : }
5962 : :
5963 : 1522 : AST::AttrVec inner_attrs = parse_inner_attributes ();
5964 : :
5965 : : // parse declarations inside extern block
5966 : 1522 : std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
5967 : :
5968 : 1522 : const_TokenPtr t = lexer.peek_token ();
5969 : 4559 : while (t->get_id () != RIGHT_CURLY)
5970 : : {
5971 : 3038 : std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
5972 : :
5973 : 3038 : if (extern_item == nullptr)
5974 : : {
5975 : 1 : Error error (t->get_locus (),
5976 : : "failed to parse external item despite not reaching "
5977 : : "end of extern block");
5978 : 1 : add_error (std::move (error));
5979 : :
5980 : 1 : return nullptr;
5981 : 1 : }
5982 : :
5983 : 3037 : extern_items.push_back (std::move (extern_item));
5984 : :
5985 : 3037 : t = lexer.peek_token ();
5986 : : }
5987 : :
5988 : 1521 : if (!skip_token (RIGHT_CURLY))
5989 : : {
5990 : : // skip somewhere
5991 : 0 : return nullptr;
5992 : : }
5993 : :
5994 : 1521 : extern_items.shrink_to_fit ();
5995 : :
5996 : : return std::unique_ptr<AST::ExternBlock> (
5997 : 1521 : new AST::ExternBlock (std::move (abi), std::move (extern_items),
5998 : : std::move (vis), std::move (inner_attrs),
5999 : 1521 : std::move (outer_attrs), locus));
6000 : 3044 : }
6001 : :
6002 : : // Parses a single extern block item (static or function declaration).
6003 : : template <typename ManagedTokenSource>
6004 : : std::unique_ptr<AST::ExternalItem>
6005 : 3041 : Parser<ManagedTokenSource>::parse_external_item ()
6006 : : {
6007 : : // parse optional outer attributes
6008 : 3041 : AST::AttrVec outer_attrs = parse_outer_attributes ();
6009 : :
6010 : 3041 : location_t locus = lexer.peek_token ()->get_locus ();
6011 : :
6012 : : // parse optional visibility
6013 : 3041 : AST::Visibility vis = parse_visibility ();
6014 : :
6015 : 3041 : const_TokenPtr t = lexer.peek_token ();
6016 : 3041 : switch (t->get_id ())
6017 : : {
6018 : 2 : case IDENTIFIER:
6019 : 4 : return parse_macro_invocation_semi (outer_attrs);
6020 : 1 : case STATIC_KW:
6021 : : {
6022 : : // parse extern static item
6023 : 1 : lexer.skip_token ();
6024 : :
6025 : : // parse mut (optional)
6026 : 1 : bool has_mut = false;
6027 : 2 : if (lexer.peek_token ()->get_id () == MUT)
6028 : : {
6029 : 0 : lexer.skip_token ();
6030 : 0 : has_mut = true;
6031 : : }
6032 : :
6033 : : // parse identifier
6034 : 1 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
6035 : 1 : if (ident_tok == nullptr)
6036 : : {
6037 : 0 : skip_after_semicolon ();
6038 : 0 : return nullptr;
6039 : : }
6040 : 1 : Identifier ident{ident_tok};
6041 : :
6042 : 1 : if (!skip_token (COLON))
6043 : : {
6044 : 0 : skip_after_semicolon ();
6045 : 0 : return nullptr;
6046 : : }
6047 : :
6048 : : // parse type (required)
6049 : 1 : std::unique_ptr<AST::Type> type = parse_type ();
6050 : 1 : if (type == nullptr)
6051 : : {
6052 : 0 : Error error (lexer.peek_token ()->get_locus (),
6053 : : "failed to parse type in external static item");
6054 : 0 : add_error (std::move (error));
6055 : :
6056 : 0 : skip_after_semicolon ();
6057 : 0 : return nullptr;
6058 : 0 : }
6059 : :
6060 : 1 : if (!skip_token (SEMICOLON))
6061 : : {
6062 : : // skip after somewhere?
6063 : 0 : return nullptr;
6064 : : }
6065 : :
6066 : 1 : return std::unique_ptr<AST::ExternalStaticItem> (
6067 : 2 : new AST::ExternalStaticItem (std::move (ident), std::move (type),
6068 : : has_mut, std::move (vis),
6069 : 1 : std::move (outer_attrs), locus));
6070 : 3 : }
6071 : 3033 : case FN_KW:
6072 : 6066 : return parse_function (std::move (vis), std::move (outer_attrs), true);
6073 : :
6074 : 5 : case TYPE:
6075 : 5 : return parse_external_type_item (std::move (vis),
6076 : 5 : std::move (outer_attrs));
6077 : 0 : default:
6078 : : // error
6079 : 0 : add_error (
6080 : 0 : Error (t->get_locus (),
6081 : : "unrecognised token %qs in extern block item declaration",
6082 : : t->get_token_description ()));
6083 : :
6084 : 0 : skip_after_semicolon ();
6085 : 0 : return nullptr;
6086 : : }
6087 : 3041 : }
6088 : :
6089 : : // Parses a statement (will further disambiguate any statement).
6090 : : template <typename ManagedTokenSource>
6091 : : std::unique_ptr<AST::Stmt>
6092 : 900 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
6093 : : {
6094 : : // quick exit for empty statement
6095 : : // FIXME: Can we have empty statements without semicolons? Just nothing?
6096 : 900 : const_TokenPtr t = lexer.peek_token ();
6097 : 900 : if (t->get_id () == SEMICOLON)
6098 : : {
6099 : 30 : lexer.skip_token ();
6100 : 30 : return std::unique_ptr<AST::EmptyStmt> (
6101 : 30 : new AST::EmptyStmt (t->get_locus ()));
6102 : : }
6103 : :
6104 : : // parse outer attributes
6105 : 870 : AST::AttrVec outer_attrs = parse_outer_attributes ();
6106 : :
6107 : : // parsing this will be annoying because of the many different possibilities
6108 : : /* best may be just to copy paste in parse_item switch, and failing that try
6109 : : * to parse outer attributes, and then pass them in to either a let
6110 : : * statement or (fallback) expression statement. */
6111 : : // FIXME: think of a way to do this without such a large switch?
6112 : 870 : t = lexer.peek_token ();
6113 : 870 : switch (t->get_id ())
6114 : : {
6115 : 200 : case LET:
6116 : : // let statement
6117 : 200 : return parse_let_stmt (std::move (outer_attrs), restrictions);
6118 : 186 : case PUB:
6119 : : case MOD:
6120 : : case EXTERN_KW:
6121 : : case USE:
6122 : : case FN_KW:
6123 : : case TYPE:
6124 : : case STRUCT_KW:
6125 : : case ENUM_KW:
6126 : : case CONST:
6127 : : case STATIC_KW:
6128 : : case AUTO:
6129 : : case TRAIT:
6130 : : case IMPL:
6131 : : case MACRO:
6132 : : /* TODO: implement union keyword but not really because of
6133 : : * context-dependence crappy hack way to parse a union written below to
6134 : : * separate it from the good code. */
6135 : : // case UNION:
6136 : : case UNSAFE: // maybe - unsafe traits are a thing
6137 : : /* if any of these (should be all possible VisItem prefixes), parse a
6138 : : * VisItem can't parse item because would require reparsing outer
6139 : : * attributes */
6140 : : // may also be unsafe block
6141 : 372 : if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
6142 : : {
6143 : 1 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
6144 : : }
6145 : : else
6146 : : {
6147 : 185 : return parse_vis_item (std::move (outer_attrs));
6148 : : }
6149 : : break;
6150 : : // crappy hack to do union "keyword"
6151 : 240 : case IDENTIFIER:
6152 : 240 : if (t->get_str () == Values::WeakKeywords::UNION
6153 : 240 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
6154 : : {
6155 : 0 : return parse_vis_item (std::move (outer_attrs));
6156 : : // or should this go straight to parsing union?
6157 : : }
6158 : 480 : else if (is_macro_rules_def (t))
6159 : : {
6160 : : // macro_rules! macro item
6161 : 2 : return parse_macro_rules_def (std::move (outer_attrs));
6162 : : }
6163 : : gcc_fallthrough ();
6164 : : // TODO: find out how to disable gcc "implicit fallthrough" warning
6165 : : default:
6166 : : // fallback: expression statement
6167 : 482 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
6168 : : break;
6169 : : }
6170 : 870 : }
6171 : :
6172 : : // Parses a let statement.
6173 : : template <typename ManagedTokenSource>
6174 : : std::unique_ptr<AST::LetStmt>
6175 : 22751 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
6176 : : ParseRestrictions restrictions)
6177 : : {
6178 : 22751 : location_t locus = lexer.peek_token ()->get_locus ();
6179 : 22751 : skip_token (LET);
6180 : :
6181 : : // parse pattern (required)
6182 : 22751 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6183 : 22751 : if (pattern == nullptr)
6184 : : {
6185 : 0 : Error error (lexer.peek_token ()->get_locus (),
6186 : : "failed to parse pattern in let statement");
6187 : 0 : add_error (std::move (error));
6188 : :
6189 : 0 : skip_after_semicolon ();
6190 : 0 : return nullptr;
6191 : 0 : }
6192 : :
6193 : : // parse type declaration (optional)
6194 : 22751 : std::unique_ptr<AST::Type> type = nullptr;
6195 : 45502 : if (lexer.peek_token ()->get_id () == COLON)
6196 : : {
6197 : : // must have a type declaration
6198 : 2498 : lexer.skip_token ();
6199 : :
6200 : 2498 : type = parse_type ();
6201 : 2498 : if (type == nullptr)
6202 : : {
6203 : 0 : Error error (lexer.peek_token ()->get_locus (),
6204 : : "failed to parse type in let statement");
6205 : 0 : add_error (std::move (error));
6206 : :
6207 : 0 : skip_after_semicolon ();
6208 : 0 : return nullptr;
6209 : 0 : }
6210 : : }
6211 : :
6212 : : // parse expression to set variable to (optional)
6213 : 22751 : std::unique_ptr<AST::Expr> expr = nullptr;
6214 : 45502 : if (lexer.peek_token ()->get_id () == EQUAL)
6215 : : {
6216 : : // must have an expression
6217 : 21663 : lexer.skip_token ();
6218 : :
6219 : 21663 : expr = parse_expr ();
6220 : 21663 : if (expr == nullptr)
6221 : : {
6222 : 22 : skip_after_semicolon ();
6223 : 22 : return nullptr;
6224 : : }
6225 : : }
6226 : :
6227 : 22729 : tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
6228 : 22729 : if (maybe_skip_token (ELSE))
6229 : 0 : else_expr = parse_block_expr ();
6230 : :
6231 : 22729 : if (restrictions.consume_semi)
6232 : : {
6233 : : // `stmt` macro variables are parsed without a semicolon, but should be
6234 : : // parsed as a full statement when interpolated. This should be handled
6235 : : // by having the interpolated statement be distinguishable from normal
6236 : : // tokens, e.g. by NT tokens.
6237 : 22584 : if (restrictions.allow_close_after_expr_stmt)
6238 : 55 : maybe_skip_token (SEMICOLON);
6239 : 22529 : else if (!skip_token (SEMICOLON))
6240 : 1 : return nullptr;
6241 : : }
6242 : :
6243 : : return std::unique_ptr<AST::LetStmt> (
6244 : 45456 : new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
6245 : 22728 : std::move (else_expr), std::move (outer_attrs), locus));
6246 : 22751 : }
6247 : :
6248 : : // Parses a type path.
6249 : : template <typename ManagedTokenSource>
6250 : : AST::TypePath
6251 : 125610 : Parser<ManagedTokenSource>::parse_type_path ()
6252 : : {
6253 : 125610 : bool has_opening_scope_resolution = false;
6254 : 125610 : location_t locus = lexer.peek_token ()->get_locus ();
6255 : 251220 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6256 : : {
6257 : 28 : has_opening_scope_resolution = true;
6258 : 28 : lexer.skip_token ();
6259 : : }
6260 : :
6261 : : // create segment vector
6262 : 125610 : std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6263 : :
6264 : : // parse required initial segment
6265 : 125610 : std::unique_ptr<AST::TypePathSegment> initial_segment
6266 : : = parse_type_path_segment ();
6267 : 125610 : if (initial_segment == nullptr)
6268 : : {
6269 : : // skip after somewhere?
6270 : : // don't necessarily throw error but yeah
6271 : 211 : return AST::TypePath::create_error ();
6272 : : }
6273 : 125399 : segments.push_back (std::move (initial_segment));
6274 : :
6275 : : // parse optional segments (as long as scope resolution operator exists)
6276 : 125399 : const_TokenPtr t = lexer.peek_token ();
6277 : 129353 : while (t->get_id () == SCOPE_RESOLUTION)
6278 : : {
6279 : : // skip scope resolution operator
6280 : 3954 : lexer.skip_token ();
6281 : :
6282 : : // parse the actual segment - it is an error if it doesn't exist now
6283 : 3954 : std::unique_ptr<AST::TypePathSegment> segment
6284 : : = parse_type_path_segment ();
6285 : 3954 : if (segment == nullptr)
6286 : : {
6287 : : // skip after somewhere?
6288 : 0 : Error error (t->get_locus (), "could not parse type path segment");
6289 : 0 : add_error (std::move (error));
6290 : :
6291 : 0 : return AST::TypePath::create_error ();
6292 : 0 : }
6293 : :
6294 : 3954 : segments.push_back (std::move (segment));
6295 : :
6296 : 3954 : t = lexer.peek_token ();
6297 : : }
6298 : :
6299 : 125399 : segments.shrink_to_fit ();
6300 : :
6301 : 250798 : return AST::TypePath (std::move (segments), locus,
6302 : 125399 : has_opening_scope_resolution);
6303 : 125610 : }
6304 : :
6305 : : template <typename ManagedTokenSource>
6306 : : tl::optional<AST::GenericArg>
6307 : 19136 : Parser<ManagedTokenSource>::parse_generic_arg ()
6308 : : {
6309 : 19136 : auto tok = lexer.peek_token ();
6310 : 19136 : std::unique_ptr<AST::Expr> expr = nullptr;
6311 : :
6312 : 19136 : switch (tok->get_id ())
6313 : : {
6314 : 14498 : case IDENTIFIER:
6315 : : {
6316 : : // This is a bit of a weird situation: With an identifier token, we
6317 : : // could either have a valid type or a macro (FIXME: anything else?). So
6318 : : // we need one bit of lookahead to differentiate if this is really
6319 : 14498 : auto next_tok = lexer.peek_token (1);
6320 : 14498 : if (next_tok->get_id () == LEFT_ANGLE
6321 : 13727 : || next_tok->get_id () == SCOPE_RESOLUTION
6322 : 28149 : || next_tok->get_id () == EXCLAM)
6323 : : {
6324 : 855 : auto type = parse_type ();
6325 : 855 : if (type)
6326 : 855 : return AST::GenericArg::create_type (std::move (type));
6327 : : else
6328 : 0 : return tl::nullopt;
6329 : 855 : }
6330 : 13643 : else if (next_tok->get_id () == COLON)
6331 : : {
6332 : 79 : lexer.skip_token (); // skip ident
6333 : 79 : lexer.skip_token (); // skip colon
6334 : :
6335 : 79 : auto tok = lexer.peek_token ();
6336 : 79 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
6337 : : = parse_type_param_bounds ();
6338 : :
6339 : 79 : auto type = std::unique_ptr<AST::TraitObjectType> (
6340 : 79 : new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
6341 : : false));
6342 : 79 : if (type)
6343 : 79 : return AST::GenericArg::create_type (std::move (type));
6344 : : else
6345 : : return tl::nullopt;
6346 : 158 : }
6347 : 13564 : lexer.skip_token ();
6348 : 54256 : return AST::GenericArg::create_ambiguous (tok->get_str (),
6349 : 13564 : tok->get_locus ());
6350 : 14498 : }
6351 : 19 : case LEFT_CURLY:
6352 : 19 : expr = parse_block_expr ();
6353 : 19 : break;
6354 : 91 : case MINUS:
6355 : : case STRING_LITERAL:
6356 : : case CHAR_LITERAL:
6357 : : case INT_LITERAL:
6358 : : case FLOAT_LITERAL:
6359 : : case TRUE_LITERAL:
6360 : : case FALSE_LITERAL:
6361 : 91 : expr = parse_literal_expr ();
6362 : 91 : break;
6363 : : // FIXME: Because of this, error reporting is garbage for const generic
6364 : : // parameter's default values
6365 : 4528 : default:
6366 : : {
6367 : 4528 : auto type = parse_type ();
6368 : : // FIXME: Find a better way to do this?
6369 : 4528 : if (type)
6370 : 4527 : return AST::GenericArg::create_type (std::move (type));
6371 : : else
6372 : 1 : return tl::nullopt;
6373 : 4528 : }
6374 : : }
6375 : :
6376 : 110 : if (!expr)
6377 : 0 : return tl::nullopt;
6378 : :
6379 : 110 : return AST::GenericArg::create_const (std::move (expr));
6380 : 19136 : }
6381 : :
6382 : : // Parses the generic arguments in each path segment.
6383 : : template <typename ManagedTokenSource>
6384 : : AST::GenericArgs
6385 : 19174 : Parser<ManagedTokenSource>::parse_path_generic_args ()
6386 : : {
6387 : 38348 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
6388 : 19 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
6389 : :
6390 : 19174 : if (!skip_token (LEFT_ANGLE))
6391 : : {
6392 : : // skip after somewhere?
6393 : 0 : return AST::GenericArgs::create_empty ();
6394 : : }
6395 : :
6396 : : // We need to parse all lifetimes, then parse types and const generics in
6397 : : // any order.
6398 : :
6399 : : // try to parse lifetimes first
6400 : 19174 : std::vector<AST::Lifetime> lifetime_args;
6401 : :
6402 : 19174 : const_TokenPtr t = lexer.peek_token ();
6403 : 19174 : location_t locus = t->get_locus ();
6404 : 38847 : while (!is_right_angle_tok (t->get_id ()))
6405 : : {
6406 : 19673 : auto lifetime = parse_lifetime (false);
6407 : 19673 : if (!lifetime)
6408 : : {
6409 : : // not necessarily an error
6410 : : break;
6411 : : }
6412 : :
6413 : 1415 : lifetime_args.push_back (std::move (lifetime.value ()));
6414 : :
6415 : : // if next token isn't comma, then it must be end of list
6416 : 2830 : if (lexer.peek_token ()->get_id () != COMMA)
6417 : : {
6418 : : break;
6419 : : }
6420 : : // skip comma
6421 : 500 : lexer.skip_token ();
6422 : :
6423 : 500 : t = lexer.peek_token ();
6424 : : }
6425 : :
6426 : : // try to parse types and const generics second
6427 : 19174 : std::vector<AST::GenericArg> generic_args;
6428 : :
6429 : : // TODO: think of better control structure
6430 : 19174 : t = lexer.peek_token ();
6431 : 56547 : while (!is_right_angle_tok (t->get_id ()))
6432 : : {
6433 : : // FIXME: Is it fine to break if there is one binding? Can't there be
6434 : : // bindings in between types?
6435 : :
6436 : : // ensure not binding being parsed as type accidently
6437 : 24234 : if (t->get_id () == IDENTIFIER
6438 : 34259 : && lexer.peek_token (1)->get_id () == EQUAL)
6439 : : break;
6440 : :
6441 : 19116 : auto arg = parse_generic_arg ();
6442 : 19116 : if (arg)
6443 : : {
6444 : 19116 : generic_args.emplace_back (std::move (arg.value ()));
6445 : : }
6446 : :
6447 : : // FIXME: Do we need to break if we encounter an error?
6448 : :
6449 : : // if next token isn't comma, then it must be end of list
6450 : 38232 : if (lexer.peek_token ()->get_id () != COMMA)
6451 : : break;
6452 : :
6453 : : // skip comma
6454 : 1182 : lexer.skip_token ();
6455 : 1182 : t = lexer.peek_token ();
6456 : : }
6457 : :
6458 : : // try to parse bindings third
6459 : 19174 : std::vector<AST::GenericArgsBinding> binding_args;
6460 : :
6461 : : // TODO: think of better control structure
6462 : 19174 : t = lexer.peek_token ();
6463 : 19505 : while (!is_right_angle_tok (t->get_id ()))
6464 : : {
6465 : 331 : AST::GenericArgsBinding binding = parse_generic_args_binding ();
6466 : 331 : if (binding.is_error ())
6467 : : {
6468 : : // not necessarily an error
6469 : : break;
6470 : : }
6471 : :
6472 : 331 : binding_args.push_back (std::move (binding));
6473 : :
6474 : : // if next token isn't comma, then it must be end of list
6475 : 662 : if (lexer.peek_token ()->get_id () != COMMA)
6476 : : {
6477 : : break;
6478 : : }
6479 : : // skip comma
6480 : 8 : lexer.skip_token ();
6481 : :
6482 : 8 : t = lexer.peek_token ();
6483 : : }
6484 : :
6485 : : // skip any trailing commas
6486 : 38348 : if (lexer.peek_token ()->get_id () == COMMA)
6487 : 0 : lexer.skip_token ();
6488 : :
6489 : 19174 : if (!skip_generics_right_angle ())
6490 : 0 : return AST::GenericArgs::create_empty ();
6491 : :
6492 : 19174 : lifetime_args.shrink_to_fit ();
6493 : 19174 : generic_args.shrink_to_fit ();
6494 : 19174 : binding_args.shrink_to_fit ();
6495 : :
6496 : 19174 : return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
6497 : 19174 : std::move (binding_args), locus);
6498 : 38348 : }
6499 : :
6500 : : // Parses a binding in a generic args path segment.
6501 : : template <typename ManagedTokenSource>
6502 : : AST::GenericArgsBinding
6503 : 331 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
6504 : : {
6505 : 331 : const_TokenPtr ident_tok = lexer.peek_token ();
6506 : 331 : if (ident_tok->get_id () != IDENTIFIER)
6507 : : {
6508 : : // allow non error-inducing use
6509 : : // skip somewhere?
6510 : 0 : return AST::GenericArgsBinding::create_error ();
6511 : : }
6512 : 331 : lexer.skip_token ();
6513 : 331 : Identifier ident{ident_tok};
6514 : :
6515 : 331 : if (!skip_token (EQUAL))
6516 : : {
6517 : : // skip after somewhere?
6518 : 0 : return AST::GenericArgsBinding::create_error ();
6519 : : }
6520 : :
6521 : : // parse type (required)
6522 : 331 : std::unique_ptr<AST::Type> type = parse_type ();
6523 : 331 : if (type == nullptr)
6524 : : {
6525 : : // skip somewhere?
6526 : 0 : return AST::GenericArgsBinding::create_error ();
6527 : : }
6528 : :
6529 : 662 : return AST::GenericArgsBinding (std::move (ident), std::move (type),
6530 : 662 : ident_tok->get_locus ());
6531 : 662 : }
6532 : :
6533 : : /* Parses a single type path segment (not including opening scope resolution,
6534 : : * but includes any internal ones). Includes generic args or type path
6535 : : * functions too. */
6536 : : template <typename ManagedTokenSource>
6537 : : std::unique_ptr<AST::TypePathSegment>
6538 : 133124 : Parser<ManagedTokenSource>::parse_type_path_segment ()
6539 : : {
6540 : 133124 : location_t locus = lexer.peek_token ()->get_locus ();
6541 : : // parse ident segment part
6542 : 133124 : AST::PathIdentSegment ident_segment = parse_path_ident_segment ();
6543 : 133124 : if (ident_segment.is_error ())
6544 : : {
6545 : : // not necessarily an error
6546 : 211 : return nullptr;
6547 : : }
6548 : :
6549 : : /* lookahead to determine if variants exist - only consume scope resolution
6550 : : * then */
6551 : 132913 : bool has_separating_scope_resolution = false;
6552 : 132913 : const_TokenPtr next = lexer.peek_token (1);
6553 : 265826 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
6554 : 132913 : && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
6555 : : {
6556 : 0 : has_separating_scope_resolution = true;
6557 : 0 : lexer.skip_token ();
6558 : : }
6559 : :
6560 : : // branch into variants on next token
6561 : 132913 : const_TokenPtr t = lexer.peek_token ();
6562 : 132913 : switch (t->get_id ())
6563 : : {
6564 : 17793 : case LEFT_SHIFT:
6565 : : case LEFT_ANGLE:
6566 : : {
6567 : : // parse generic args
6568 : 17793 : AST::GenericArgs generic_args = parse_path_generic_args ();
6569 : :
6570 : 17793 : return std::unique_ptr<AST::TypePathSegmentGeneric> (
6571 : 35586 : new AST::TypePathSegmentGeneric (std::move (ident_segment),
6572 : : has_separating_scope_resolution,
6573 : 17793 : std::move (generic_args), locus));
6574 : 17793 : }
6575 : 536 : case LEFT_PAREN:
6576 : : {
6577 : : // parse type path function
6578 : 536 : AST::TypePathFunction type_path_function
6579 : : = parse_type_path_function (locus);
6580 : :
6581 : 536 : if (type_path_function.is_error ())
6582 : : {
6583 : : // skip after somewhere?
6584 : 0 : return nullptr;
6585 : : }
6586 : :
6587 : 536 : return std::unique_ptr<AST::TypePathSegmentFunction> (
6588 : 1608 : new AST::TypePathSegmentFunction (std::move (ident_segment),
6589 : : has_separating_scope_resolution,
6590 : : std::move (type_path_function),
6591 : 536 : locus));
6592 : 536 : }
6593 : 114584 : default:
6594 : : // neither of them
6595 : : return std::unique_ptr<AST::TypePathSegment> (
6596 : 114584 : new AST::TypePathSegment (std::move (ident_segment),
6597 : 114584 : has_separating_scope_resolution, locus));
6598 : : }
6599 : : rust_unreachable ();
6600 : 265826 : }
6601 : :
6602 : : // Parses a function call representation inside a type path.
6603 : : template <typename ManagedTokenSource>
6604 : : AST::TypePathFunction
6605 : 536 : Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
6606 : : {
6607 : 536 : if (!skip_token (LEFT_PAREN))
6608 : : {
6609 : : // skip somewhere?
6610 : : return AST::TypePathFunction::create_error ();
6611 : : }
6612 : :
6613 : : // parse function inputs
6614 : 536 : std::vector<std::unique_ptr<AST::Type>> inputs;
6615 : :
6616 : 2040 : while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
6617 : : {
6618 : 735 : std::unique_ptr<AST::Type> type = parse_type ();
6619 : 735 : if (type == nullptr)
6620 : : {
6621 : : /* this is an error as there should've been a ')' there if there
6622 : : * wasn't a type */
6623 : 0 : Error error (
6624 : 0 : lexer.peek_token ()->get_locus (),
6625 : : "failed to parse type in parameters of type path function");
6626 : 0 : add_error (std::move (error));
6627 : :
6628 : : // skip somewhere?
6629 : 0 : return AST::TypePathFunction::create_error ();
6630 : 0 : }
6631 : :
6632 : 735 : inputs.push_back (std::move (type));
6633 : :
6634 : : // skip commas, including trailing commas
6635 : 1470 : if (lexer.peek_token ()->get_id () != COMMA)
6636 : : break;
6637 : :
6638 : 226 : lexer.skip_token ();
6639 : : }
6640 : :
6641 : 536 : if (!skip_token (RIGHT_PAREN))
6642 : : {
6643 : : // skip somewhere?
6644 : : return AST::TypePathFunction::create_error ();
6645 : : }
6646 : :
6647 : : // parse optional return type
6648 : 536 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
6649 : :
6650 : 536 : inputs.shrink_to_fit ();
6651 : 536 : return AST::TypePathFunction (std::move (inputs), id_location,
6652 : 536 : std::move (return_type));
6653 : 536 : }
6654 : :
6655 : : // Parses a path inside an expression that allows generic arguments.
6656 : : template <typename ManagedTokenSource>
6657 : : AST::PathInExpression
6658 : 365139 : Parser<ManagedTokenSource>::parse_path_in_expression ()
6659 : : {
6660 : 365139 : location_t locus = UNKNOWN_LOCATION;
6661 : 365139 : bool has_opening_scope_resolution = false;
6662 : 730278 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6663 : : {
6664 : 9 : has_opening_scope_resolution = true;
6665 : :
6666 : 9 : locus = lexer.peek_token ()->get_locus ();
6667 : :
6668 : 9 : lexer.skip_token ();
6669 : : }
6670 : :
6671 : : // create segment vector
6672 : 365139 : std::vector<AST::PathExprSegment> segments;
6673 : :
6674 : 365139 : if (locus == UNKNOWN_LOCATION)
6675 : : {
6676 : 730260 : locus = lexer.peek_token ()->get_locus ();
6677 : : }
6678 : :
6679 : : // parse required initial segment
6680 : 365139 : AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6681 : 365139 : if (initial_segment.is_error ())
6682 : : {
6683 : : // skip after somewhere?
6684 : : // don't necessarily throw error but yeah
6685 : 4 : return AST::PathInExpression::create_error ();
6686 : : }
6687 : 365135 : segments.push_back (std::move (initial_segment));
6688 : :
6689 : : // parse optional segments (as long as scope resolution operator exists)
6690 : 365135 : const_TokenPtr t = lexer.peek_token ();
6691 : 381755 : while (t->get_id () == SCOPE_RESOLUTION)
6692 : : {
6693 : : // skip scope resolution operator
6694 : 16620 : lexer.skip_token ();
6695 : :
6696 : : // parse the actual segment - it is an error if it doesn't exist now
6697 : 16620 : AST::PathExprSegment segment = parse_path_expr_segment ();
6698 : 16620 : if (segment.is_error ())
6699 : : {
6700 : : // skip after somewhere?
6701 : 0 : Error error (t->get_locus (),
6702 : : "could not parse path expression segment");
6703 : 0 : add_error (std::move (error));
6704 : :
6705 : 0 : return AST::PathInExpression::create_error ();
6706 : 0 : }
6707 : :
6708 : 16620 : segments.push_back (std::move (segment));
6709 : :
6710 : 16620 : t = lexer.peek_token ();
6711 : : }
6712 : :
6713 : 365135 : segments.shrink_to_fit ();
6714 : :
6715 : 365135 : return AST::PathInExpression (std::move (segments), {}, locus,
6716 : 365135 : has_opening_scope_resolution);
6717 : 730274 : }
6718 : :
6719 : : /* Parses a single path in expression path segment (including generic
6720 : : * arguments). */
6721 : : template <typename ManagedTokenSource>
6722 : : AST::PathExprSegment
6723 : 411551 : Parser<ManagedTokenSource>::parse_path_expr_segment ()
6724 : : {
6725 : 411551 : location_t locus = lexer.peek_token ()->get_locus ();
6726 : : // parse ident segment
6727 : 411551 : AST::PathIdentSegment ident = parse_path_ident_segment ();
6728 : 411551 : if (ident.is_error ())
6729 : : {
6730 : : // not necessarily an error?
6731 : 4 : return AST::PathExprSegment::create_error ();
6732 : : }
6733 : :
6734 : : // parse generic args (and turbofish), if they exist
6735 : : /* use lookahead to determine if they actually exist (don't want to
6736 : : * accidently parse over next ident segment) */
6737 : 823094 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
6738 : 706742 : && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
6739 : 302433 : || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
6740 : : {
6741 : : // skip scope resolution
6742 : 1381 : lexer.skip_token ();
6743 : :
6744 : : // Let parse_path_generic_args split "<<" tokens
6745 : 1381 : AST::GenericArgs generic_args = parse_path_generic_args ();
6746 : :
6747 : 2762 : return AST::PathExprSegment (std::move (ident), locus,
6748 : 1381 : std::move (generic_args));
6749 : 1381 : }
6750 : :
6751 : : // return a generic parameter-less expr segment if not found
6752 : 410166 : return AST::PathExprSegment (std::move (ident), locus);
6753 : 411551 : }
6754 : :
6755 : : /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
6756 : : * not parse outer attrs. */
6757 : : template <typename ManagedTokenSource>
6758 : : AST::QualifiedPathInExpression
6759 : 187 : Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
6760 : : location_t pratt_parsed_loc)
6761 : : {
6762 : : /* Note: the Rust grammar is defined in such a way that it is impossible to
6763 : : * determine whether a prospective qualified path is a
6764 : : * QualifiedPathInExpression or QualifiedPathInType in all cases by the
6765 : : * rules themselves (the only possible difference is a TypePathSegment with
6766 : : * function, and lookahead to find this is too difficult). However, as this
6767 : : * is a pattern and QualifiedPathInType is a type, I believe it that their
6768 : : * construction will not be confused (due to rules regarding patterns vs
6769 : : * types).
6770 : : * As such, this function will not attempt to minimise errors created by
6771 : : * their confusion. */
6772 : :
6773 : : // parse the qualified path type (required)
6774 : 187 : AST::QualifiedPathType qual_path_type
6775 : : = parse_qualified_path_type (pratt_parsed_loc);
6776 : 187 : if (qual_path_type.is_error ())
6777 : : {
6778 : : // TODO: should this create a parse error?
6779 : 0 : return AST::QualifiedPathInExpression::create_error ();
6780 : : }
6781 : 187 : location_t locus = qual_path_type.get_locus ();
6782 : :
6783 : : // parse path segments
6784 : 187 : std::vector<AST::PathExprSegment> segments;
6785 : :
6786 : : // parse initial required segment
6787 : 374 : if (!expect_token (SCOPE_RESOLUTION))
6788 : : {
6789 : : // skip after somewhere?
6790 : :
6791 : 0 : return AST::QualifiedPathInExpression::create_error ();
6792 : : }
6793 : 187 : AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6794 : 187 : if (initial_segment.is_error ())
6795 : : {
6796 : : // skip after somewhere?
6797 : 0 : Error error (lexer.peek_token ()->get_locus (),
6798 : : "required initial path expression segment in "
6799 : : "qualified path in expression could not be parsed");
6800 : 0 : add_error (std::move (error));
6801 : :
6802 : 0 : return AST::QualifiedPathInExpression::create_error ();
6803 : 0 : }
6804 : 187 : segments.push_back (std::move (initial_segment));
6805 : :
6806 : : // parse optional segments (as long as scope resolution operator exists)
6807 : 187 : const_TokenPtr t = lexer.peek_token ();
6808 : 187 : while (t->get_id () == SCOPE_RESOLUTION)
6809 : : {
6810 : : // skip scope resolution operator
6811 : 0 : lexer.skip_token ();
6812 : :
6813 : : // parse the actual segment - it is an error if it doesn't exist now
6814 : 0 : AST::PathExprSegment segment = parse_path_expr_segment ();
6815 : 0 : if (segment.is_error ())
6816 : : {
6817 : : // skip after somewhere?
6818 : 0 : Error error (t->get_locus (),
6819 : : "could not parse path expression segment in qualified "
6820 : : "path in expression");
6821 : 0 : add_error (std::move (error));
6822 : :
6823 : 0 : return AST::QualifiedPathInExpression::create_error ();
6824 : 0 : }
6825 : :
6826 : 0 : segments.push_back (std::move (segment));
6827 : :
6828 : 0 : t = lexer.peek_token ();
6829 : : }
6830 : :
6831 : 187 : segments.shrink_to_fit ();
6832 : :
6833 : : // FIXME: outer attr parsing
6834 : 374 : return AST::QualifiedPathInExpression (std::move (qual_path_type),
6835 : 187 : std::move (segments), {}, locus);
6836 : 374 : }
6837 : :
6838 : : // Parses the type syntactical construction at the start of a qualified path.
6839 : : template <typename ManagedTokenSource>
6840 : : AST::QualifiedPathType
6841 : 3747 : Parser<ManagedTokenSource>::parse_qualified_path_type (
6842 : : location_t pratt_parsed_loc)
6843 : : {
6844 : 3747 : location_t locus = pratt_parsed_loc;
6845 : : /* TODO: should this actually be error? is there anywhere where this could
6846 : : * be valid? */
6847 : 3747 : if (locus == UNKNOWN_LOCATION)
6848 : : {
6849 : 3560 : locus = lexer.peek_token ()->get_locus ();
6850 : :
6851 : 7120 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
6852 : 2 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
6853 : :
6854 : : // skip after somewhere?
6855 : 3560 : if (!skip_token (LEFT_ANGLE))
6856 : 0 : return AST::QualifiedPathType::create_error ();
6857 : : }
6858 : :
6859 : : // parse type (required)
6860 : 3747 : std::unique_ptr<AST::Type> type = parse_type ();
6861 : 3747 : if (type == nullptr)
6862 : : {
6863 : 0 : Error error (lexer.peek_token ()->get_locus (),
6864 : : "could not parse type in qualified path type");
6865 : 0 : add_error (std::move (error));
6866 : :
6867 : : // skip somewhere?
6868 : 0 : return AST::QualifiedPathType::create_error ();
6869 : 0 : }
6870 : :
6871 : : // parse optional as clause
6872 : 3747 : AST::TypePath as_type_path = AST::TypePath::create_error ();
6873 : 7494 : if (lexer.peek_token ()->get_id () == AS)
6874 : : {
6875 : 3636 : lexer.skip_token ();
6876 : :
6877 : : // parse type path, which is required now
6878 : 3636 : as_type_path = parse_type_path ();
6879 : 3636 : if (as_type_path.is_error ())
6880 : : {
6881 : 0 : Error error (
6882 : 0 : lexer.peek_token ()->get_locus (),
6883 : : "could not parse type path in as clause in qualified path type");
6884 : 0 : add_error (std::move (error));
6885 : :
6886 : : // skip somewhere?
6887 : 0 : return AST::QualifiedPathType::create_error ();
6888 : 0 : }
6889 : : }
6890 : :
6891 : : /* NOTE: should actually be a right-angle token, so
6892 : : * skip_generics_right_angle shouldn't be required */
6893 : 3747 : if (!skip_token (RIGHT_ANGLE))
6894 : : {
6895 : : // skip after somewhere?
6896 : 0 : return AST::QualifiedPathType::create_error ();
6897 : : }
6898 : :
6899 : 3747 : return AST::QualifiedPathType (std::move (type), locus,
6900 : 3747 : std::move (as_type_path));
6901 : 3747 : }
6902 : :
6903 : : // Parses a fully qualified path in type (i.e. a type).
6904 : : template <typename ManagedTokenSource>
6905 : : AST::QualifiedPathInType
6906 : 3560 : Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
6907 : : {
6908 : 3560 : location_t locus = lexer.peek_token ()->get_locus ();
6909 : : // parse the qualified path type (required)
6910 : 3560 : AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
6911 : 3560 : if (qual_path_type.is_error ())
6912 : : {
6913 : : // TODO: should this create a parse error?
6914 : 0 : return AST::QualifiedPathInType::create_error ();
6915 : : }
6916 : :
6917 : : // parse initial required segment
6918 : 7120 : if (!expect_token (SCOPE_RESOLUTION))
6919 : : {
6920 : : // skip after somewhere?
6921 : :
6922 : 0 : return AST::QualifiedPathInType::create_error ();
6923 : : }
6924 : 3560 : std::unique_ptr<AST::TypePathSegment> initial_segment
6925 : : = parse_type_path_segment ();
6926 : 3560 : if (initial_segment == nullptr)
6927 : : {
6928 : : // skip after somewhere?
6929 : 0 : Error error (lexer.peek_token ()->get_locus (),
6930 : : "required initial type path segment in qualified path in "
6931 : : "type could not be parsed");
6932 : 0 : add_error (std::move (error));
6933 : :
6934 : 0 : return AST::QualifiedPathInType::create_error ();
6935 : 0 : }
6936 : :
6937 : : // parse optional segments (as long as scope resolution operator exists)
6938 : 3560 : std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6939 : 3560 : const_TokenPtr t = lexer.peek_token ();
6940 : 3560 : while (t->get_id () == SCOPE_RESOLUTION)
6941 : : {
6942 : : // skip scope resolution operator
6943 : 0 : lexer.skip_token ();
6944 : :
6945 : : // parse the actual segment - it is an error if it doesn't exist now
6946 : 0 : std::unique_ptr<AST::TypePathSegment> segment
6947 : : = parse_type_path_segment ();
6948 : 0 : if (segment == nullptr)
6949 : : {
6950 : : // skip after somewhere?
6951 : 0 : Error error (
6952 : : t->get_locus (),
6953 : : "could not parse type path segment in qualified path in type");
6954 : 0 : add_error (std::move (error));
6955 : :
6956 : 0 : return AST::QualifiedPathInType::create_error ();
6957 : 0 : }
6958 : :
6959 : 0 : segments.push_back (std::move (segment));
6960 : :
6961 : 0 : t = lexer.peek_token ();
6962 : : }
6963 : :
6964 : 3560 : segments.shrink_to_fit ();
6965 : :
6966 : 7120 : return AST::QualifiedPathInType (std::move (qual_path_type),
6967 : : std::move (initial_segment),
6968 : 3560 : std::move (segments), locus);
6969 : 3560 : }
6970 : :
6971 : : // Parses a self param. Also handles self param not existing.
6972 : : template <typename ManagedTokenSource>
6973 : : tl::expected<std::unique_ptr<AST::Param>, ParseSelfError>
6974 : 31433 : Parser<ManagedTokenSource>::parse_self_param ()
6975 : : {
6976 : 31433 : bool has_reference = false;
6977 : 31433 : AST::Lifetime lifetime = AST::Lifetime::elided ();
6978 : :
6979 : 31433 : location_t locus = lexer.peek_token ()->get_locus ();
6980 : :
6981 : : // TODO: Feels off, find a better way to clearly express this
6982 : 125732 : std::vector<std::vector<TokenId>> ptrs
6983 : : = {{ASTERISK, SELF} /* *self */,
6984 : : {ASTERISK, CONST, SELF} /* *const self */,
6985 : : {ASTERISK, MUT, SELF} /* *mut self */};
6986 : :
6987 : 125726 : for (auto &s : ptrs)
6988 : : {
6989 : : size_t i = 0;
6990 : 94307 : for (i = 0; i < s.size (); i++)
6991 : 188608 : if (lexer.peek_token (i)->get_id () != s[i])
6992 : : break;
6993 : 94296 : if (i == s.size ())
6994 : : {
6995 : 3 : rust_error_at (lexer.peek_token ()->get_locus (),
6996 : : "cannot pass %<self%> by raw pointer");
6997 : 3 : return tl::make_unexpected (ParseSelfError::SELF_PTR);
6998 : : }
6999 : : }
7000 : :
7001 : : // Trying to find those patterns:
7002 : : //
7003 : : // &'lifetime mut self
7004 : : // &'lifetime self
7005 : : // & mut self
7006 : : // & self
7007 : : // mut self
7008 : : // self
7009 : : //
7010 : : // If not found, it is probably a function, exit and let function parsing
7011 : : // handle it.
7012 : : bool is_self = false;
7013 : 188580 : for (size_t i = 0; i < 5; i++)
7014 : 314300 : if (lexer.peek_token (i)->get_id () == SELF)
7015 : 15393 : is_self = true;
7016 : :
7017 : 31430 : if (!is_self)
7018 : 16040 : return tl::make_unexpected (ParseSelfError::NOT_SELF);
7019 : :
7020 : : // test if self is a reference parameter
7021 : 30780 : if (lexer.peek_token ()->get_id () == AMP)
7022 : : {
7023 : 8339 : has_reference = true;
7024 : 8339 : lexer.skip_token ();
7025 : :
7026 : : // now test whether it has a lifetime
7027 : 16678 : if (lexer.peek_token ()->get_id () == LIFETIME)
7028 : : {
7029 : : // something went wrong somehow
7030 : 86 : if (auto parsed_lifetime = parse_lifetime (true))
7031 : : {
7032 : 43 : lifetime = parsed_lifetime.value ();
7033 : : }
7034 : : else
7035 : : {
7036 : 0 : Error error (lexer.peek_token ()->get_locus (),
7037 : : "failed to parse lifetime in self param");
7038 : 0 : add_error (std::move (error));
7039 : :
7040 : : // skip after somewhere?
7041 : 0 : return tl::make_unexpected (ParseSelfError::PARSING);
7042 : 0 : }
7043 : : }
7044 : : }
7045 : :
7046 : : // test for mut
7047 : 15390 : bool has_mut = false;
7048 : 30780 : if (lexer.peek_token ()->get_id () == MUT)
7049 : : {
7050 : 2159 : has_mut = true;
7051 : 2159 : lexer.skip_token ();
7052 : : }
7053 : :
7054 : : // skip self token
7055 : 15390 : const_TokenPtr self_tok = lexer.peek_token ();
7056 : 15390 : if (self_tok->get_id () != SELF)
7057 : : {
7058 : : // skip after somewhere?
7059 : 2 : return tl::make_unexpected (ParseSelfError::NOT_SELF);
7060 : : }
7061 : 15388 : lexer.skip_token ();
7062 : :
7063 : : // parse optional type
7064 : 15388 : std::unique_ptr<AST::Type> type = nullptr;
7065 : 30776 : if (lexer.peek_token ()->get_id () == COLON)
7066 : : {
7067 : 14 : lexer.skip_token ();
7068 : :
7069 : : // type is now required
7070 : 14 : type = parse_type ();
7071 : 14 : if (type == nullptr)
7072 : : {
7073 : 0 : Error error (lexer.peek_token ()->get_locus (),
7074 : : "could not parse type in self param");
7075 : 0 : add_error (std::move (error));
7076 : :
7077 : : // skip after somewhere?
7078 : 0 : return tl::make_unexpected (ParseSelfError::PARSING);
7079 : 0 : }
7080 : : }
7081 : :
7082 : : // ensure that cannot have both type and reference
7083 : 15388 : if (type != nullptr && has_reference)
7084 : : {
7085 : 0 : Error error (
7086 : 0 : lexer.peek_token ()->get_locus (),
7087 : : "cannot have both a reference and a type specified in a self param");
7088 : 0 : add_error (std::move (error));
7089 : :
7090 : : // skip after somewhere?
7091 : 0 : return tl::make_unexpected (ParseSelfError::PARSING);
7092 : 0 : }
7093 : :
7094 : 15388 : if (has_reference)
7095 : : {
7096 : 8339 : return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
7097 : 8339 : locus);
7098 : : }
7099 : : else
7100 : : {
7101 : : // note that type may be nullptr here and that's fine
7102 : 7049 : return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
7103 : 7049 : locus);
7104 : : }
7105 : 46821 : }
7106 : :
7107 : : /* Parses an expression or macro statement. */
7108 : : template <typename ManagedTokenSource>
7109 : : std::unique_ptr<AST::Stmt>
7110 : 483 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
7111 : : ParseRestrictions restrictions)
7112 : : {
7113 : 483 : location_t locus = lexer.peek_token ()->get_locus ();
7114 : :
7115 : 483 : std::unique_ptr<AST::Expr> expr;
7116 : :
7117 : 966 : switch (lexer.peek_token ()->get_id ())
7118 : : {
7119 : 244 : case IDENTIFIER:
7120 : : case CRATE:
7121 : : case SUPER:
7122 : : case SELF:
7123 : : case SELF_ALIAS:
7124 : : case DOLLAR_SIGN:
7125 : : case SCOPE_RESOLUTION:
7126 : : {
7127 : 244 : AST::PathInExpression path = parse_path_in_expression ();
7128 : 244 : std::unique_ptr<AST::Expr> null_denotation;
7129 : :
7130 : 488 : if (lexer.peek_token ()->get_id () == EXCLAM)
7131 : : {
7132 : 61 : std::unique_ptr<AST::MacroInvocation> invoc
7133 : 122 : = parse_macro_invocation_partial (std::move (path),
7134 : : std::move (outer_attrs));
7135 : :
7136 : 61 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7137 : : {
7138 : 59 : invoc->add_semicolon ();
7139 : : // Macro invocation with semicolon.
7140 : 59 : return invoc;
7141 : : }
7142 : :
7143 : 2 : TokenId after_macro = lexer.peek_token ()->get_id ();
7144 : :
7145 : 2 : if (restrictions.allow_close_after_expr_stmt
7146 : 2 : && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
7147 : : || after_macro == RIGHT_SQUARE))
7148 : 2 : return invoc;
7149 : :
7150 : 0 : if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
7151 : : == AST::CURLY
7152 : 0 : && after_macro != DOT && after_macro != QUESTION_MARK)
7153 : : {
7154 : 0 : rust_debug ("braced macro statement");
7155 : 0 : return invoc;
7156 : : }
7157 : :
7158 : 0 : null_denotation = std::move (invoc);
7159 : 61 : }
7160 : : else
7161 : : {
7162 : : null_denotation
7163 : 183 : = null_denotation_path (std::move (path), {}, restrictions);
7164 : : }
7165 : :
7166 : 183 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7167 : : std::move (outer_attrs), restrictions);
7168 : : break;
7169 : 244 : }
7170 : 239 : default:
7171 : 239 : restrictions.expr_can_be_stmt = true;
7172 : 239 : expr = parse_expr (std::move (outer_attrs), restrictions);
7173 : 239 : break;
7174 : : }
7175 : :
7176 : 422 : if (expr == nullptr)
7177 : : {
7178 : : // expr is required, error
7179 : 0 : Error error (lexer.peek_token ()->get_locus (),
7180 : : "failed to parse expr in expr statement");
7181 : 0 : add_error (std::move (error));
7182 : :
7183 : 0 : skip_after_semicolon ();
7184 : 0 : return nullptr;
7185 : 0 : }
7186 : :
7187 : 422 : bool has_semi = false;
7188 : :
7189 : 422 : if (restrictions.consume_semi)
7190 : : {
7191 : 408 : if (maybe_skip_token (SEMICOLON))
7192 : : {
7193 : : has_semi = true;
7194 : : }
7195 : 266 : else if (expr->is_expr_without_block ())
7196 : : {
7197 : 30 : if (restrictions.allow_close_after_expr_stmt)
7198 : : {
7199 : 30 : TokenId id = lexer.peek_token ()->get_id ();
7200 : 30 : if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
7201 : : {
7202 : 3 : expect_token (SEMICOLON);
7203 : 3 : return nullptr;
7204 : : }
7205 : : }
7206 : : else
7207 : : {
7208 : 0 : expect_token (SEMICOLON);
7209 : 0 : return nullptr;
7210 : : }
7211 : : }
7212 : : }
7213 : :
7214 : 419 : return std::unique_ptr<AST::ExprStmt> (
7215 : 419 : new AST::ExprStmt (std::move (expr), locus, has_semi));
7216 : 483 : }
7217 : :
7218 : : // Parses a block expression, including the curly braces at start and end.
7219 : : template <typename ManagedTokenSource>
7220 : : std::unique_ptr<AST::BlockExpr>
7221 : 39941 : Parser<ManagedTokenSource>::parse_block_expr (
7222 : : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
7223 : : location_t pratt_parsed_loc)
7224 : : {
7225 : 39941 : location_t locus = pratt_parsed_loc;
7226 : 39941 : if (locus == UNKNOWN_LOCATION)
7227 : : {
7228 : 37350 : locus = lexer.peek_token ()->get_locus ();
7229 : 37350 : if (!skip_token (LEFT_CURLY))
7230 : : {
7231 : 0 : skip_after_end_block ();
7232 : 0 : return nullptr;
7233 : : }
7234 : : }
7235 : :
7236 : 39941 : AST::AttrVec inner_attrs = parse_inner_attributes ();
7237 : :
7238 : : // parse statements and expression
7239 : 39941 : std::vector<std::unique_ptr<AST::Stmt>> stmts;
7240 : 39941 : std::unique_ptr<AST::Expr> expr = nullptr;
7241 : :
7242 : 39941 : const_TokenPtr t = lexer.peek_token ();
7243 : 110353 : while (t->get_id () != RIGHT_CURLY)
7244 : : {
7245 : 70412 : ExprOrStmt expr_or_stmt = parse_stmt_or_expr ();
7246 : 70412 : if (expr_or_stmt.is_error ())
7247 : : {
7248 : 30 : skip_after_end_block ();
7249 : 30 : return nullptr;
7250 : : }
7251 : :
7252 : 70382 : t = lexer.peek_token ();
7253 : :
7254 : 70382 : if (expr_or_stmt.stmt != nullptr)
7255 : : {
7256 : 40161 : stmts.push_back (std::move (expr_or_stmt.stmt));
7257 : : }
7258 : : else
7259 : : {
7260 : : // assign to expression and end parsing inside
7261 : 30221 : expr = std::move (expr_or_stmt.expr);
7262 : : break;
7263 : : }
7264 : : }
7265 : :
7266 : 39911 : location_t end_locus = t->get_locus ();
7267 : :
7268 : 39911 : if (!skip_token (RIGHT_CURLY))
7269 : : {
7270 : 0 : Error error (t->get_locus (),
7271 : : "error may be from having an expression (as opposed to "
7272 : : "statement) in the body of the function but not last");
7273 : 0 : add_error (std::move (error));
7274 : :
7275 : 0 : skip_after_end_block ();
7276 : 0 : return nullptr;
7277 : 0 : }
7278 : :
7279 : : // grammar allows for empty block expressions
7280 : :
7281 : 39911 : stmts.shrink_to_fit ();
7282 : :
7283 : : return std::unique_ptr<AST::BlockExpr> (
7284 : 39911 : new AST::BlockExpr (std::move (stmts), std::move (expr),
7285 : : std::move (inner_attrs), std::move (outer_attrs),
7286 : 39911 : std::move (label), locus, end_locus));
7287 : 39941 : }
7288 : :
7289 : : /* Parse an anonymous const expression. This can be a regular const expression
7290 : : * or an underscore for deferred const inference */
7291 : : template <typename ManagedTokenSource>
7292 : : tl::expected<AST::AnonConst, AnonConstError>
7293 : 999 : Parser<ManagedTokenSource>::parse_anon_const ()
7294 : : {
7295 : 999 : auto current = lexer.peek_token ();
7296 : 999 : auto locus = current->get_locus ();
7297 : :
7298 : : // Special case deferred inference constants
7299 : 999 : if (maybe_skip_token (UNDERSCORE))
7300 : 11 : return AST::AnonConst (locus);
7301 : :
7302 : 988 : auto expr = parse_expr ();
7303 : :
7304 : 988 : if (!expr)
7305 : 0 : return tl::make_unexpected (AnonConstError::InvalidSizeExpr);
7306 : :
7307 : 1976 : return AST::AnonConst (std::move (expr), locus);
7308 : 988 : }
7309 : :
7310 : : /* Parse a "const block", a block preceded by the `const` keyword whose
7311 : : * statements can be const evaluated and used in constant contexts */
7312 : : template <typename ManagedTokenSource>
7313 : : std::unique_ptr<AST::ConstBlock>
7314 : 15 : Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs,
7315 : : location_t locus)
7316 : : {
7317 : 15 : auto block = parse_block_expr ();
7318 : :
7319 : 15 : if (!block)
7320 : : {
7321 : 0 : add_error (Error (locus, "failed to parse inner block in const block"));
7322 : 0 : skip_after_end_block ();
7323 : :
7324 : 0 : return nullptr;
7325 : : }
7326 : :
7327 : 15 : auto block_locus = block->get_locus ();
7328 : :
7329 : 30 : return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block),
7330 : : block_locus),
7331 : 15 : locus, std::move (outer_attrs));
7332 : 15 : }
7333 : :
7334 : : /* Parses a "grouped" expression (expression in parentheses), used to control
7335 : : * precedence. */
7336 : : template <typename ManagedTokenSource>
7337 : : std::unique_ptr<AST::GroupedExpr>
7338 : 0 : Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
7339 : : {
7340 : 0 : location_t locus = lexer.peek_token ()->get_locus ();
7341 : 0 : skip_token (LEFT_PAREN);
7342 : :
7343 : 0 : AST::AttrVec inner_attrs = parse_inner_attributes ();
7344 : :
7345 : : // parse required expr inside parentheses
7346 : 0 : std::unique_ptr<AST::Expr> expr_in_parens = parse_expr ();
7347 : 0 : if (expr_in_parens == nullptr)
7348 : : {
7349 : : // skip after somewhere?
7350 : : // error?
7351 : 0 : return nullptr;
7352 : : }
7353 : :
7354 : 0 : if (!skip_token (RIGHT_PAREN))
7355 : : {
7356 : : // skip after somewhere?
7357 : 0 : return nullptr;
7358 : : }
7359 : :
7360 : : return std::unique_ptr<AST::GroupedExpr> (
7361 : 0 : new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs),
7362 : 0 : std::move (outer_attrs), locus));
7363 : 0 : }
7364 : :
7365 : : // Parses a closure expression (closure definition).
7366 : : template <typename ManagedTokenSource>
7367 : : std::unique_ptr<AST::ClosureExpr>
7368 : 0 : Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
7369 : : {
7370 : 0 : location_t locus = lexer.peek_token ()->get_locus ();
7371 : : // detect optional "move"
7372 : 0 : bool has_move = false;
7373 : 0 : if (lexer.peek_token ()->get_id () == MOVE)
7374 : : {
7375 : 0 : lexer.skip_token ();
7376 : 0 : has_move = true;
7377 : : }
7378 : :
7379 : : // handle parameter list
7380 : 0 : std::vector<AST::ClosureParam> params;
7381 : :
7382 : 0 : const_TokenPtr t = lexer.peek_token ();
7383 : 0 : switch (t->get_id ())
7384 : : {
7385 : 0 : case OR:
7386 : : // skip token, no parameters
7387 : 0 : lexer.skip_token ();
7388 : : break;
7389 : 0 : case PIPE:
7390 : : // actually may have parameters
7391 : 0 : lexer.skip_token ();
7392 : 0 : t = lexer.peek_token ();
7393 : :
7394 : 0 : while (t->get_id () != PIPE)
7395 : : {
7396 : 0 : AST::ClosureParam param = parse_closure_param ();
7397 : 0 : if (param.is_error ())
7398 : : {
7399 : : // TODO is this really an error?
7400 : 0 : Error error (t->get_locus (), "could not parse closure param");
7401 : 0 : add_error (std::move (error));
7402 : :
7403 : : break;
7404 : 0 : }
7405 : 0 : params.push_back (std::move (param));
7406 : :
7407 : 0 : if (lexer.peek_token ()->get_id () != COMMA)
7408 : : {
7409 : 0 : lexer.skip_token ();
7410 : : // not an error but means param list is done
7411 : : break;
7412 : : }
7413 : : // skip comma
7414 : 0 : lexer.skip_token ();
7415 : :
7416 : 0 : t = lexer.peek_token ();
7417 : : }
7418 : 0 : params.shrink_to_fit ();
7419 : : break;
7420 : 0 : default:
7421 : 0 : add_error (Error (t->get_locus (),
7422 : : "unexpected token %qs in closure expression - expected "
7423 : : "%<|%> or %<||%>",
7424 : : t->get_token_description ()));
7425 : :
7426 : : // skip somewhere?
7427 : 0 : return nullptr;
7428 : : }
7429 : :
7430 : : // again branch based on next token
7431 : 0 : t = lexer.peek_token ();
7432 : 0 : if (t->get_id () == RETURN_TYPE)
7433 : : {
7434 : : // must be return type closure with block expr
7435 : :
7436 : : // skip "return type" token
7437 : 0 : lexer.skip_token ();
7438 : :
7439 : : // parse actual type, which is required
7440 : 0 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
7441 : 0 : if (type == nullptr)
7442 : : {
7443 : : // error
7444 : 0 : Error error (t->get_locus (), "failed to parse type for closure");
7445 : 0 : add_error (std::move (error));
7446 : :
7447 : : // skip somewhere?
7448 : 0 : return nullptr;
7449 : 0 : }
7450 : :
7451 : : // parse block expr, which is required
7452 : 0 : std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
7453 : 0 : if (block == nullptr)
7454 : : {
7455 : : // error
7456 : 0 : Error error (lexer.peek_token ()->get_locus (),
7457 : : "failed to parse block expr in closure");
7458 : 0 : add_error (std::move (error));
7459 : :
7460 : : // skip somewhere?
7461 : 0 : return nullptr;
7462 : 0 : }
7463 : :
7464 : 0 : return std::unique_ptr<AST::ClosureExprInnerTyped> (
7465 : 0 : new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
7466 : : std::move (params), locus, has_move,
7467 : 0 : std::move (outer_attrs)));
7468 : 0 : }
7469 : : else
7470 : : {
7471 : : // must be expr-only closure
7472 : :
7473 : : // parse expr, which is required
7474 : 0 : std::unique_ptr<AST::Expr> expr = parse_expr ();
7475 : 0 : if (expr == nullptr)
7476 : : {
7477 : 0 : Error error (t->get_locus (),
7478 : : "failed to parse expression in closure");
7479 : 0 : add_error (std::move (error));
7480 : :
7481 : : // skip somewhere?
7482 : 0 : return nullptr;
7483 : 0 : }
7484 : :
7485 : 0 : return std::unique_ptr<AST::ClosureExprInner> (
7486 : 0 : new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
7487 : 0 : has_move, std::move (outer_attrs)));
7488 : 0 : }
7489 : 0 : }
7490 : :
7491 : : // Parses a literal token (to literal expression).
7492 : : template <typename ManagedTokenSource>
7493 : : std::unique_ptr<AST::LiteralExpr>
7494 : 3989 : Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
7495 : : {
7496 : : // TODO: change if literal representation in lexer changes
7497 : :
7498 : 3989 : std::string literal_value;
7499 : 3989 : AST::Literal::LitType type = AST::Literal::STRING;
7500 : :
7501 : : // branch based on token
7502 : 3989 : const_TokenPtr t = lexer.peek_token ();
7503 : 3989 : switch (t->get_id ())
7504 : : {
7505 : 2 : case CHAR_LITERAL:
7506 : 2 : type = AST::Literal::CHAR;
7507 : 2 : literal_value = t->get_str ();
7508 : 2 : lexer.skip_token ();
7509 : : break;
7510 : 579 : case STRING_LITERAL:
7511 : 579 : type = AST::Literal::STRING;
7512 : 579 : literal_value = t->get_str ();
7513 : 579 : lexer.skip_token ();
7514 : : break;
7515 : 0 : case BYTE_CHAR_LITERAL:
7516 : 0 : type = AST::Literal::BYTE;
7517 : 0 : literal_value = t->get_str ();
7518 : 0 : lexer.skip_token ();
7519 : : break;
7520 : 1 : case BYTE_STRING_LITERAL:
7521 : 1 : type = AST::Literal::BYTE_STRING;
7522 : 1 : literal_value = t->get_str ();
7523 : 1 : lexer.skip_token ();
7524 : : break;
7525 : 26 : case RAW_STRING_LITERAL:
7526 : 26 : type = AST::Literal::RAW_STRING;
7527 : 26 : literal_value = t->get_str ();
7528 : 26 : lexer.skip_token ();
7529 : : break;
7530 : 3371 : case INT_LITERAL:
7531 : 3371 : type = AST::Literal::INT;
7532 : 3371 : literal_value = t->get_str ();
7533 : 3371 : lexer.skip_token ();
7534 : : break;
7535 : 1 : case FLOAT_LITERAL:
7536 : 1 : type = AST::Literal::FLOAT;
7537 : 1 : literal_value = t->get_str ();
7538 : 1 : lexer.skip_token ();
7539 : : break;
7540 : : // case BOOL_LITERAL
7541 : : // use true and false keywords rather than "bool literal" Rust terminology
7542 : 0 : case TRUE_LITERAL:
7543 : 0 : type = AST::Literal::BOOL;
7544 : 0 : literal_value = Values::Keywords::TRUE_LITERAL;
7545 : 0 : lexer.skip_token ();
7546 : : break;
7547 : 2 : case FALSE_LITERAL:
7548 : 2 : type = AST::Literal::BOOL;
7549 : 2 : literal_value = Values::Keywords::FALSE_LITERAL;
7550 : 2 : lexer.skip_token ();
7551 : : break;
7552 : 7 : default:
7553 : : // error - cannot be a literal expr
7554 : 7 : add_error (Error (t->get_locus (),
7555 : : "unexpected token %qs when parsing literal expression",
7556 : : t->get_token_description ()));
7557 : :
7558 : : // skip?
7559 : 7 : return nullptr;
7560 : : }
7561 : :
7562 : : // create literal based on stuff in switch
7563 : : return std::unique_ptr<AST::LiteralExpr> (
7564 : 4593 : new AST::LiteralExpr (std::move (literal_value), std::move (type),
7565 : : t->get_type_hint (), std::move (outer_attrs),
7566 : 3982 : t->get_locus ()));
7567 : 3989 : }
7568 : :
7569 : : template <typename ManagedTokenSource>
7570 : : std::unique_ptr<AST::BoxExpr>
7571 : 2 : Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs,
7572 : : location_t pratt_parsed_loc)
7573 : : {
7574 : 2 : location_t locus = pratt_parsed_loc;
7575 : 2 : if (locus == UNKNOWN_LOCATION)
7576 : : {
7577 : 0 : locus = lexer.peek_token ()->get_locus ();
7578 : 0 : skip_token (BOX);
7579 : : }
7580 : :
7581 : 2 : ParseRestrictions restrictions;
7582 : : restrictions.expr_can_be_null = false;
7583 : :
7584 : 2 : std::unique_ptr<AST::Expr> expr = parse_expr (AST::AttrVec (), restrictions);
7585 : :
7586 : : return std::unique_ptr<AST::BoxExpr> (
7587 : 2 : new AST::BoxExpr (std::move (expr), std::move (outer_attrs), locus));
7588 : 2 : }
7589 : :
7590 : : // Parses a return expression (including any expression to return).
7591 : : template <typename ManagedTokenSource>
7592 : : std::unique_ptr<AST::ReturnExpr>
7593 : 896 : Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
7594 : : location_t pratt_parsed_loc)
7595 : : {
7596 : 896 : location_t locus = pratt_parsed_loc;
7597 : 896 : if (locus == UNKNOWN_LOCATION)
7598 : : {
7599 : 0 : locus = lexer.peek_token ()->get_locus ();
7600 : 0 : skip_token (RETURN_KW);
7601 : : }
7602 : :
7603 : : // parse expression to return, if it exists
7604 : 896 : ParseRestrictions restrictions;
7605 : 896 : restrictions.expr_can_be_null = true;
7606 : 896 : std::unique_ptr<AST::Expr> returned_expr
7607 : 896 : = parse_expr (AST::AttrVec (), restrictions);
7608 : :
7609 : : return std::unique_ptr<AST::ReturnExpr> (
7610 : 896 : new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs),
7611 : 896 : locus));
7612 : 896 : }
7613 : :
7614 : : // Parses a try expression.
7615 : : template <typename ManagedTokenSource>
7616 : : std::unique_ptr<AST::TryExpr>
7617 : 31 : Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs,
7618 : : location_t pratt_parsed_loc)
7619 : : {
7620 : 31 : location_t locus = pratt_parsed_loc;
7621 : 31 : if (locus == UNKNOWN_LOCATION)
7622 : : {
7623 : 0 : locus = lexer.peek_token ()->get_locus ();
7624 : 0 : skip_token (TRY);
7625 : : }
7626 : :
7627 : 31 : std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
7628 : :
7629 : 31 : if (!block_expr)
7630 : : {
7631 : 0 : Error error (lexer.peek_token ()->get_locus (),
7632 : : "failed to parse try block expression");
7633 : 0 : add_error (std::move (error));
7634 : :
7635 : 0 : return nullptr;
7636 : 0 : }
7637 : :
7638 : : return std::unique_ptr<AST::TryExpr> (
7639 : 31 : new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus));
7640 : 31 : }
7641 : :
7642 : : /* Parses a break expression (including any label to break to AND any return
7643 : : * expression). */
7644 : : template <typename ManagedTokenSource>
7645 : : std::unique_ptr<AST::BreakExpr>
7646 : 103 : Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
7647 : : location_t pratt_parsed_loc)
7648 : : {
7649 : 103 : location_t locus = pratt_parsed_loc;
7650 : 103 : if (locus == UNKNOWN_LOCATION)
7651 : : {
7652 : 0 : locus = lexer.peek_token ()->get_locus ();
7653 : 0 : skip_token (BREAK);
7654 : : }
7655 : :
7656 : 103 : auto parsed_label = parse_lifetime (false);
7657 : 103 : auto label = (parsed_label)
7658 : 103 : ? tl::optional<AST::Lifetime> (parsed_label.value ())
7659 : : : tl::nullopt;
7660 : :
7661 : : // parse break return expression if it exists
7662 : 103 : ParseRestrictions restrictions;
7663 : 103 : restrictions.expr_can_be_null = true;
7664 : 103 : std::unique_ptr<AST::Expr> return_expr
7665 : 103 : = parse_expr (AST::AttrVec (), restrictions);
7666 : :
7667 : : return std::unique_ptr<AST::BreakExpr> (
7668 : 124 : new AST::BreakExpr (std::move (label), std::move (return_expr),
7669 : 103 : std::move (outer_attrs), locus));
7670 : 124 : }
7671 : :
7672 : : // Parses a continue expression (including any label to continue from).
7673 : : template <typename ManagedTokenSource>
7674 : : std::unique_ptr<AST::ContinueExpr>
7675 : 26 : Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
7676 : : location_t pratt_parsed_loc)
7677 : : {
7678 : 26 : location_t locus = pratt_parsed_loc;
7679 : 26 : if (locus == UNKNOWN_LOCATION)
7680 : : {
7681 : 0 : locus = lexer.peek_token ()->get_locus ();
7682 : 0 : skip_token (CONTINUE);
7683 : : }
7684 : :
7685 : 26 : auto parsed_label = parse_lifetime (false);
7686 : 26 : auto label = (parsed_label)
7687 : 26 : ? tl::optional<AST::Lifetime> (parsed_label.value ())
7688 : : : tl::nullopt;
7689 : :
7690 : : return std::unique_ptr<AST::ContinueExpr> (
7691 : 33 : new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus));
7692 : 26 : }
7693 : :
7694 : : // Parses a loop label used in loop expressions.
7695 : : template <typename ManagedTokenSource>
7696 : : tl::expected<AST::LoopLabel, ParseLoopLabelError>
7697 : 36 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
7698 : : {
7699 : : // parse lifetime - if doesn't exist, assume no label
7700 : 36 : if (tok->get_id () != LIFETIME)
7701 : : {
7702 : : // not necessarily an error
7703 : : return tl::unexpected<ParseLoopLabelError> (
7704 : 0 : ParseLoopLabelError::NOT_LOOP_LABEL);
7705 : : }
7706 : : /* FIXME: check for named lifetime requirement here? or check in semantic
7707 : : * analysis phase? */
7708 : 36 : AST::Lifetime label = lifetime_from_token (tok);
7709 : :
7710 : 36 : if (!skip_token (COLON))
7711 : : {
7712 : : // skip somewhere?
7713 : : return tl::unexpected<ParseLoopLabelError> (
7714 : 0 : ParseLoopLabelError::MISSING_COLON);
7715 : : }
7716 : :
7717 : : return tl::expected<AST::LoopLabel, ParseLoopLabelError> (
7718 : 36 : AST::LoopLabel (std::move (label), tok->get_locus ()));
7719 : 36 : }
7720 : :
7721 : : /* Parses an if expression of any kind, including with else, else if, else if
7722 : : * let, and neither. Note that any outer attributes will be ignored because if
7723 : : * expressions don't support them. */
7724 : : template <typename ManagedTokenSource>
7725 : : std::unique_ptr<AST::IfExpr>
7726 : 3451 : Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
7727 : : location_t pratt_parsed_loc)
7728 : : {
7729 : : // TODO: make having outer attributes an error?
7730 : 3451 : location_t locus = pratt_parsed_loc;
7731 : 3451 : if (locus == UNKNOWN_LOCATION)
7732 : : {
7733 : 394 : locus = lexer.peek_token ()->get_locus ();
7734 : 394 : if (!skip_token (IF))
7735 : : {
7736 : 0 : skip_after_end_block ();
7737 : 0 : return nullptr;
7738 : : }
7739 : : }
7740 : :
7741 : : // detect accidental if let
7742 : 6902 : if (lexer.peek_token ()->get_id () == LET)
7743 : : {
7744 : 0 : Error error (lexer.peek_token ()->get_locus (),
7745 : : "if let expression probably exists, but is being parsed "
7746 : : "as an if expression. This may be a parser error");
7747 : 0 : add_error (std::move (error));
7748 : :
7749 : : // skip somewhere?
7750 : 0 : return nullptr;
7751 : 0 : }
7752 : :
7753 : : /* parse required condition expr - HACK to prevent struct expr from being
7754 : : * parsed */
7755 : 3451 : ParseRestrictions no_struct_expr;
7756 : 3451 : no_struct_expr.can_be_struct_expr = false;
7757 : 3451 : std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr);
7758 : 3451 : if (condition == nullptr)
7759 : : {
7760 : 0 : Error error (lexer.peek_token ()->get_locus (),
7761 : : "failed to parse condition expression in if expression");
7762 : 0 : add_error (std::move (error));
7763 : :
7764 : : // skip somewhere?
7765 : 0 : return nullptr;
7766 : 0 : }
7767 : :
7768 : : // parse required block expr
7769 : 3451 : std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr ();
7770 : 3451 : if (if_body == nullptr)
7771 : 1 : return nullptr;
7772 : :
7773 : : // branch to parse end or else (and then else, else if, or else if let)
7774 : 6900 : if (lexer.peek_token ()->get_id () != ELSE)
7775 : : {
7776 : : // single selection - end of if expression
7777 : : return std::unique_ptr<AST::IfExpr> (
7778 : 1133 : new AST::IfExpr (std::move (condition), std::move (if_body),
7779 : 1133 : std::move (outer_attrs), locus));
7780 : : }
7781 : : else
7782 : : {
7783 : : // double or multiple selection - branch on end, else if, or else if let
7784 : :
7785 : : // skip "else"
7786 : 2317 : lexer.skip_token ();
7787 : :
7788 : : // branch on whether next token is '{' or 'if'
7789 : 2317 : const_TokenPtr t = lexer.peek_token ();
7790 : 2317 : switch (t->get_id ())
7791 : : {
7792 : 1923 : case LEFT_CURLY:
7793 : : {
7794 : : // double selection - else
7795 : : // parse else block expr (required)
7796 : 1923 : std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7797 : 1923 : if (else_body == nullptr)
7798 : : {
7799 : 0 : Error error (lexer.peek_token ()->get_locus (),
7800 : : "failed to parse else body block expression in "
7801 : : "if expression");
7802 : 0 : add_error (std::move (error));
7803 : :
7804 : : // skip somewhere?
7805 : 0 : return nullptr;
7806 : 0 : }
7807 : :
7808 : 1923 : return std::unique_ptr<AST::IfExprConseqElse> (
7809 : 1923 : new AST::IfExprConseqElse (std::move (condition),
7810 : : std::move (if_body),
7811 : : std::move (else_body),
7812 : 1923 : std::move (outer_attrs), locus));
7813 : 1923 : }
7814 : 394 : case IF:
7815 : : {
7816 : : // multiple selection - else if or else if let
7817 : : // branch on whether next token is 'let' or not
7818 : 788 : if (lexer.peek_token (1)->get_id () == LET)
7819 : : {
7820 : : // parse if let expr (required)
7821 : 1 : std::unique_ptr<AST::IfLetExpr> if_let_expr
7822 : 1 : = parse_if_let_expr ();
7823 : 1 : if (if_let_expr == nullptr)
7824 : : {
7825 : 0 : Error error (lexer.peek_token ()->get_locus (),
7826 : : "failed to parse (else) if let expression "
7827 : : "after if expression");
7828 : 0 : add_error (std::move (error));
7829 : :
7830 : : // skip somewhere?
7831 : 0 : return nullptr;
7832 : 0 : }
7833 : :
7834 : 1 : return std::unique_ptr<AST::IfExprConseqElse> (
7835 : 1 : new AST::IfExprConseqElse (std::move (condition),
7836 : : std::move (if_body),
7837 : : std::move (if_let_expr),
7838 : 1 : std::move (outer_attrs), locus));
7839 : 1 : }
7840 : : else
7841 : : {
7842 : : // parse if expr (required)
7843 : 393 : std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
7844 : 393 : if (if_expr == nullptr)
7845 : : {
7846 : 0 : Error error (lexer.peek_token ()->get_locus (),
7847 : : "failed to parse (else) if expression after "
7848 : : "if expression");
7849 : 0 : add_error (std::move (error));
7850 : :
7851 : : // skip somewhere?
7852 : 0 : return nullptr;
7853 : 0 : }
7854 : :
7855 : 393 : return std::unique_ptr<AST::IfExprConseqElse> (
7856 : 393 : new AST::IfExprConseqElse (std::move (condition),
7857 : : std::move (if_body),
7858 : : std::move (if_expr),
7859 : 393 : std::move (outer_attrs), locus));
7860 : 393 : }
7861 : : }
7862 : 0 : default:
7863 : : // error - invalid token
7864 : 0 : add_error (Error (t->get_locus (),
7865 : : "unexpected token %qs after else in if expression",
7866 : : t->get_token_description ()));
7867 : :
7868 : : // skip somewhere?
7869 : 0 : return nullptr;
7870 : : }
7871 : 2317 : }
7872 : 3451 : }
7873 : :
7874 : : /* Parses an if let expression of any kind, including with else, else if, else
7875 : : * if let, and none. Note that any outer attributes will be ignored as if let
7876 : : * expressions don't support them. */
7877 : : template <typename ManagedTokenSource>
7878 : : std::unique_ptr<AST::IfLetExpr>
7879 : 122 : Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
7880 : : location_t pratt_parsed_loc)
7881 : : {
7882 : : // TODO: make having outer attributes an error?
7883 : 122 : location_t locus = pratt_parsed_loc;
7884 : 122 : if (locus == UNKNOWN_LOCATION)
7885 : : {
7886 : 2 : locus = lexer.peek_token ()->get_locus ();
7887 : 2 : if (!skip_token (IF))
7888 : : {
7889 : 0 : skip_after_end_block ();
7890 : 0 : return nullptr;
7891 : : }
7892 : : }
7893 : :
7894 : : // detect accidental if expr parsed as if let expr
7895 : 244 : if (lexer.peek_token ()->get_id () != LET)
7896 : : {
7897 : 0 : Error error (lexer.peek_token ()->get_locus (),
7898 : : "if expression probably exists, but is being parsed as an "
7899 : : "if let expression. This may be a parser error");
7900 : 0 : add_error (std::move (error));
7901 : :
7902 : : // skip somewhere?
7903 : 0 : return nullptr;
7904 : 0 : }
7905 : 122 : lexer.skip_token ();
7906 : :
7907 : : // parse match arm patterns (which are required)
7908 : 122 : std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
7909 : : = parse_match_arm_patterns (EQUAL);
7910 : 122 : if (match_arm_patterns.empty ())
7911 : : {
7912 : 0 : Error error (
7913 : 0 : lexer.peek_token ()->get_locus (),
7914 : : "failed to parse any match arm patterns in if let expression");
7915 : 0 : add_error (std::move (error));
7916 : :
7917 : : // skip somewhere?
7918 : 0 : return nullptr;
7919 : 0 : }
7920 : :
7921 : 122 : if (!skip_token (EQUAL))
7922 : : {
7923 : : // skip somewhere?
7924 : 0 : return nullptr;
7925 : : }
7926 : :
7927 : : // parse expression (required) - HACK to prevent struct expr being parsed
7928 : 122 : ParseRestrictions no_struct_expr;
7929 : 122 : no_struct_expr.can_be_struct_expr = false;
7930 : 122 : std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr);
7931 : 122 : if (scrutinee_expr == nullptr)
7932 : : {
7933 : 0 : Error error (lexer.peek_token ()->get_locus (),
7934 : : "failed to parse scrutinee expression in if let expression");
7935 : 0 : add_error (std::move (error));
7936 : :
7937 : : // skip somewhere?
7938 : 0 : return nullptr;
7939 : 0 : }
7940 : : /* TODO: check for expression not being a struct expression or lazy boolean
7941 : : * expression here? or actually probably in semantic analysis. */
7942 : :
7943 : : // parse block expression (required)
7944 : 122 : std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr ();
7945 : 122 : if (if_let_body == nullptr)
7946 : : {
7947 : 0 : Error error (
7948 : 0 : lexer.peek_token ()->get_locus (),
7949 : : "failed to parse if let body block expression in if let expression");
7950 : 0 : add_error (std::move (error));
7951 : :
7952 : : // skip somewhere?
7953 : 0 : return nullptr;
7954 : 0 : }
7955 : :
7956 : : // branch to parse end or else (and then else, else if, or else if let)
7957 : 244 : if (lexer.peek_token ()->get_id () != ELSE)
7958 : : {
7959 : : // single selection - end of if let expression
7960 : : return std::unique_ptr<AST::IfLetExpr> (
7961 : 80 : new AST::IfLetExpr (std::move (match_arm_patterns),
7962 : : std::move (scrutinee_expr), std::move (if_let_body),
7963 : 80 : std::move (outer_attrs), locus));
7964 : : }
7965 : : else
7966 : : {
7967 : : // double or multiple selection - branch on end, else if, or else if let
7968 : :
7969 : : // skip "else"
7970 : 42 : lexer.skip_token ();
7971 : :
7972 : : // branch on whether next token is '{' or 'if'
7973 : 42 : const_TokenPtr t = lexer.peek_token ();
7974 : 42 : switch (t->get_id ())
7975 : : {
7976 : 40 : case LEFT_CURLY:
7977 : : {
7978 : : // double selection - else
7979 : : // parse else block expr (required)
7980 : 40 : std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7981 : 40 : if (else_body == nullptr)
7982 : : {
7983 : 0 : Error error (lexer.peek_token ()->get_locus (),
7984 : : "failed to parse else body block expression in "
7985 : : "if let expression");
7986 : 0 : add_error (std::move (error));
7987 : :
7988 : : // skip somewhere?
7989 : 0 : return nullptr;
7990 : 0 : }
7991 : :
7992 : 40 : return std::unique_ptr<AST::IfLetExprConseqElse> (
7993 : 40 : new AST::IfLetExprConseqElse (std::move (match_arm_patterns),
7994 : : std::move (scrutinee_expr),
7995 : : std::move (if_let_body),
7996 : : std::move (else_body),
7997 : 40 : std::move (outer_attrs), locus));
7998 : 40 : }
7999 : 2 : case IF:
8000 : : {
8001 : : // multiple selection - else if or else if let
8002 : : // branch on whether next token is 'let' or not
8003 : 4 : if (lexer.peek_token (1)->get_id () == LET)
8004 : : {
8005 : : // parse if let expr (required)
8006 : 1 : std::unique_ptr<AST::IfLetExpr> if_let_expr
8007 : 1 : = parse_if_let_expr ();
8008 : 1 : if (if_let_expr == nullptr)
8009 : : {
8010 : 0 : Error error (lexer.peek_token ()->get_locus (),
8011 : : "failed to parse (else) if let expression "
8012 : : "after if let expression");
8013 : 0 : add_error (std::move (error));
8014 : :
8015 : : // skip somewhere?
8016 : 0 : return nullptr;
8017 : 0 : }
8018 : :
8019 : 1 : return std::unique_ptr<AST::IfLetExprConseqElse> (
8020 : 1 : new AST::IfLetExprConseqElse (
8021 : : std::move (match_arm_patterns), std::move (scrutinee_expr),
8022 : : std::move (if_let_body), std::move (if_let_expr),
8023 : 1 : std::move (outer_attrs), locus));
8024 : 1 : }
8025 : : else
8026 : : {
8027 : : // parse if expr (required)
8028 : 1 : std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
8029 : 1 : if (if_expr == nullptr)
8030 : : {
8031 : 0 : Error error (lexer.peek_token ()->get_locus (),
8032 : : "failed to parse (else) if expression after "
8033 : : "if let expression");
8034 : 0 : add_error (std::move (error));
8035 : :
8036 : : // skip somewhere?
8037 : 0 : return nullptr;
8038 : 0 : }
8039 : :
8040 : 1 : return std::unique_ptr<AST::IfLetExprConseqElse> (
8041 : 1 : new AST::IfLetExprConseqElse (
8042 : : std::move (match_arm_patterns), std::move (scrutinee_expr),
8043 : : std::move (if_let_body), std::move (if_expr),
8044 : 1 : std::move (outer_attrs), locus));
8045 : 1 : }
8046 : : }
8047 : 0 : default:
8048 : : // error - invalid token
8049 : 0 : add_error (
8050 : 0 : Error (t->get_locus (),
8051 : : "unexpected token %qs after else in if let expression",
8052 : : t->get_token_description ()));
8053 : :
8054 : : // skip somewhere?
8055 : 0 : return nullptr;
8056 : : }
8057 : 42 : }
8058 : 122 : }
8059 : :
8060 : : /* TODO: possibly decide on different method of handling label (i.e. not
8061 : : * parameter) */
8062 : :
8063 : : /* Parses a "loop" infinite loop expression. Label is not parsed and should be
8064 : : * parsed via parse_labelled_loop_expr, which would call this. */
8065 : : template <typename ManagedTokenSource>
8066 : : std::unique_ptr<AST::LoopExpr>
8067 : 139 : Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
8068 : : tl::optional<AST::LoopLabel> label,
8069 : : location_t pratt_parsed_loc)
8070 : : {
8071 : 139 : location_t locus = pratt_parsed_loc;
8072 : 139 : if (locus == UNKNOWN_LOCATION)
8073 : : {
8074 : 34 : if (label)
8075 : 34 : locus = label->get_locus ();
8076 : : else
8077 : 0 : locus = lexer.peek_token ()->get_locus ();
8078 : :
8079 : 34 : if (!skip_token (LOOP))
8080 : : {
8081 : 0 : skip_after_end_block ();
8082 : 0 : return nullptr;
8083 : : }
8084 : : }
8085 : : else
8086 : : {
8087 : 105 : if (label)
8088 : 0 : locus = label->get_locus ();
8089 : : }
8090 : :
8091 : : // parse loop body, which is required
8092 : 139 : std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr ();
8093 : 139 : if (loop_body == nullptr)
8094 : 1 : return nullptr;
8095 : :
8096 : : return std::unique_ptr<AST::LoopExpr> (
8097 : 172 : new AST::LoopExpr (std::move (loop_body), locus, std::move (label),
8098 : 138 : std::move (outer_attrs)));
8099 : 139 : }
8100 : :
8101 : : /* Parses a "while" loop expression. Label is not parsed and should be parsed
8102 : : * via parse_labelled_loop_expr, which would call this. */
8103 : : template <typename ManagedTokenSource>
8104 : : std::unique_ptr<AST::WhileLoopExpr>
8105 : 173 : Parser<ManagedTokenSource>::parse_while_loop_expr (
8106 : : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
8107 : : location_t pratt_parsed_loc)
8108 : : {
8109 : 173 : location_t locus = pratt_parsed_loc;
8110 : 173 : if (locus == UNKNOWN_LOCATION)
8111 : : {
8112 : 2 : if (label)
8113 : 2 : locus = label->get_locus ();
8114 : : else
8115 : 0 : locus = lexer.peek_token ()->get_locus ();
8116 : :
8117 : 2 : if (!skip_token (WHILE))
8118 : : {
8119 : 0 : skip_after_end_block ();
8120 : 0 : return nullptr;
8121 : : }
8122 : : }
8123 : : else
8124 : : {
8125 : 171 : if (label)
8126 : 0 : locus = label->get_locus ();
8127 : : }
8128 : :
8129 : : // ensure it isn't a while let loop
8130 : 346 : if (lexer.peek_token ()->get_id () == LET)
8131 : : {
8132 : 0 : Error error (lexer.peek_token ()->get_locus (),
8133 : : "appears to be while let loop but is being parsed by "
8134 : : "while loop - this may be a compiler issue");
8135 : 0 : add_error (std::move (error));
8136 : :
8137 : : // skip somewhere?
8138 : 0 : return nullptr;
8139 : 0 : }
8140 : :
8141 : : // parse loop predicate (required) with HACK to prevent struct expr parsing
8142 : 173 : ParseRestrictions no_struct_expr;
8143 : 173 : no_struct_expr.can_be_struct_expr = false;
8144 : 173 : std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr);
8145 : 173 : if (predicate == nullptr)
8146 : : {
8147 : 0 : Error error (lexer.peek_token ()->get_locus (),
8148 : : "failed to parse predicate expression in while loop");
8149 : 0 : add_error (std::move (error));
8150 : :
8151 : : // skip somewhere?
8152 : 0 : return nullptr;
8153 : 0 : }
8154 : : /* TODO: check that it isn't struct expression here? actually, probably in
8155 : : * semantic analysis */
8156 : :
8157 : : // parse loop body (required)
8158 : 173 : std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8159 : 173 : if (body == nullptr)
8160 : : {
8161 : 0 : Error error (lexer.peek_token ()->get_locus (),
8162 : : "failed to parse loop body block expression in while loop");
8163 : 0 : add_error (std::move (error));
8164 : :
8165 : : // skip somewhere
8166 : 0 : return nullptr;
8167 : 0 : }
8168 : :
8169 : : return std::unique_ptr<AST::WhileLoopExpr> (
8170 : 175 : new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus,
8171 : 173 : std::move (label), std::move (outer_attrs)));
8172 : 173 : }
8173 : :
8174 : : /* Parses a "while let" loop expression. Label is not parsed and should be
8175 : : * parsed via parse_labelled_loop_expr, which would call this. */
8176 : : template <typename ManagedTokenSource>
8177 : : std::unique_ptr<AST::WhileLetLoopExpr>
8178 : 29 : Parser<ManagedTokenSource>::parse_while_let_loop_expr (
8179 : : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
8180 : : {
8181 : 29 : location_t locus = UNKNOWN_LOCATION;
8182 : 29 : if (label)
8183 : 0 : locus = label->get_locus ();
8184 : : else
8185 : 58 : locus = lexer.peek_token ()->get_locus ();
8186 : 29 : maybe_skip_token (WHILE);
8187 : :
8188 : : /* check for possible accidental recognition of a while loop as a while let
8189 : : * loop */
8190 : 58 : if (lexer.peek_token ()->get_id () != LET)
8191 : : {
8192 : 0 : Error error (lexer.peek_token ()->get_locus (),
8193 : : "appears to be a while loop but is being parsed by "
8194 : : "while let loop - this may be a compiler issue");
8195 : 0 : add_error (std::move (error));
8196 : :
8197 : : // skip somewhere
8198 : 0 : return nullptr;
8199 : 0 : }
8200 : : // as this token is definitely let now, save the computation of comparison
8201 : 29 : lexer.skip_token ();
8202 : :
8203 : : // parse predicate patterns
8204 : 29 : std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns
8205 : : = parse_match_arm_patterns (EQUAL);
8206 : : // ensure that there is at least 1 pattern
8207 : 29 : if (predicate_patterns.empty ())
8208 : : {
8209 : 1 : Error error (lexer.peek_token ()->get_locus (),
8210 : : "should be at least 1 pattern");
8211 : 1 : add_error (std::move (error));
8212 : 1 : return nullptr;
8213 : 1 : }
8214 : :
8215 : 28 : if (!skip_token (EQUAL))
8216 : : {
8217 : : // skip somewhere?
8218 : 0 : return nullptr;
8219 : : }
8220 : :
8221 : : /* parse predicate expression, which is required (and HACK to prevent struct
8222 : : * expr) */
8223 : 28 : ParseRestrictions no_struct_expr;
8224 : 28 : no_struct_expr.can_be_struct_expr = false;
8225 : 28 : std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr);
8226 : 28 : if (predicate_expr == nullptr)
8227 : : {
8228 : 0 : Error error (lexer.peek_token ()->get_locus (),
8229 : : "failed to parse predicate expression in while let loop");
8230 : 0 : add_error (std::move (error));
8231 : :
8232 : : // skip somewhere?
8233 : 0 : return nullptr;
8234 : 0 : }
8235 : : /* TODO: ensure that struct expression is not parsed? Actually, probably in
8236 : : * semantic analysis. */
8237 : :
8238 : : // parse loop body, which is required
8239 : 28 : std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8240 : 28 : if (body == nullptr)
8241 : : {
8242 : 0 : Error error (lexer.peek_token ()->get_locus (),
8243 : : "failed to parse block expr (loop body) of while let loop");
8244 : 0 : add_error (std::move (error));
8245 : :
8246 : : // skip somewhere?
8247 : 0 : return nullptr;
8248 : 0 : }
8249 : :
8250 : 28 : return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr (
8251 : : std::move (predicate_patterns), std::move (predicate_expr),
8252 : 28 : std::move (body), locus, std::move (label), std::move (outer_attrs)));
8253 : 29 : }
8254 : :
8255 : : /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
8256 : : * parse_labelled_loop_expr, which would call this. */
8257 : : template <typename ManagedTokenSource>
8258 : : std::unique_ptr<AST::ForLoopExpr>
8259 : 221 : Parser<ManagedTokenSource>::parse_for_loop_expr (
8260 : : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
8261 : : {
8262 : 221 : location_t locus = UNKNOWN_LOCATION;
8263 : 221 : if (label)
8264 : 0 : locus = label->get_locus ();
8265 : : else
8266 : 442 : locus = lexer.peek_token ()->get_locus ();
8267 : 221 : maybe_skip_token (FOR);
8268 : :
8269 : : // parse pattern, which is required
8270 : 221 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8271 : 221 : if (pattern == nullptr)
8272 : : {
8273 : 0 : Error error (lexer.peek_token ()->get_locus (),
8274 : : "failed to parse iterator pattern in for loop");
8275 : 0 : add_error (std::move (error));
8276 : :
8277 : : // skip somewhere?
8278 : 0 : return nullptr;
8279 : 0 : }
8280 : :
8281 : 221 : if (!skip_token (IN))
8282 : : {
8283 : : // skip somewhere?
8284 : 0 : return nullptr;
8285 : : }
8286 : :
8287 : : /* parse iterator expression, which is required - also HACK to prevent
8288 : : * struct expr */
8289 : 221 : ParseRestrictions no_struct_expr;
8290 : 221 : no_struct_expr.can_be_struct_expr = false;
8291 : 221 : std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr);
8292 : 221 : if (expr == nullptr)
8293 : : {
8294 : 0 : Error error (lexer.peek_token ()->get_locus (),
8295 : : "failed to parse iterator expression in for loop");
8296 : 0 : add_error (std::move (error));
8297 : :
8298 : : // skip somewhere?
8299 : 0 : return nullptr;
8300 : 0 : }
8301 : : // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
8302 : :
8303 : : // parse loop body, which is required
8304 : 221 : std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8305 : 221 : if (body == nullptr)
8306 : : {
8307 : 0 : Error error (lexer.peek_token ()->get_locus (),
8308 : : "failed to parse loop body block expression in for loop");
8309 : 0 : add_error (std::move (error));
8310 : :
8311 : : // skip somewhere?
8312 : 0 : return nullptr;
8313 : 0 : }
8314 : :
8315 : : return std::unique_ptr<AST::ForLoopExpr> (
8316 : 221 : new AST::ForLoopExpr (std::move (pattern), std::move (expr),
8317 : : std::move (body), locus, std::move (label),
8318 : 221 : std::move (outer_attrs)));
8319 : 221 : }
8320 : :
8321 : : // Parses a loop expression with label (any kind of loop - disambiguates).
8322 : : template <typename ManagedTokenSource>
8323 : : std::unique_ptr<AST::Expr>
8324 : 36 : Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok,
8325 : : AST::AttrVec outer_attrs)
8326 : : {
8327 : : /* TODO: decide whether it should not work if there is no label, or parse it
8328 : : * with no label at the moment, I will make it not work with no label
8329 : : * because that's the implication. */
8330 : :
8331 : 36 : if (tok->get_id () != LIFETIME)
8332 : : {
8333 : 0 : Error error (tok->get_locus (),
8334 : : "expected lifetime in labelled loop expr (to parse loop "
8335 : : "label) - found %qs",
8336 : : tok->get_token_description ());
8337 : 0 : add_error (std::move (error));
8338 : :
8339 : : // skip?
8340 : 0 : return nullptr;
8341 : 0 : }
8342 : :
8343 : : // parse loop label (required)
8344 : : // TODO: Convert this return type to tl::expected instead of tl::optional
8345 : 72 : auto parsed_label = parse_loop_label (tok);
8346 : 36 : if (!parsed_label)
8347 : : {
8348 : 0 : Error error (lexer.peek_token ()->get_locus (),
8349 : : "failed to parse loop label in labelled loop expr");
8350 : 0 : add_error (std::move (error));
8351 : :
8352 : : // skip?
8353 : 0 : return nullptr;
8354 : 0 : }
8355 : :
8356 : 36 : auto label = parsed_label
8357 : : ? tl::optional<AST::LoopLabel> (parsed_label.value ())
8358 : : : tl::nullopt;
8359 : :
8360 : : // branch on next token
8361 : 36 : const_TokenPtr t = lexer.peek_token ();
8362 : 36 : switch (t->get_id ())
8363 : : {
8364 : 34 : case LOOP:
8365 : 68 : return parse_loop_expr (std::move (outer_attrs), std::move (label));
8366 : 0 : case FOR:
8367 : 0 : return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
8368 : 2 : case WHILE:
8369 : : // further disambiguate into while vs while let
8370 : 4 : if (lexer.peek_token (1)->get_id () == LET)
8371 : : {
8372 : 0 : return parse_while_let_loop_expr (std::move (outer_attrs),
8373 : 0 : std::move (label));
8374 : : }
8375 : : else
8376 : : {
8377 : 4 : return parse_while_loop_expr (std::move (outer_attrs),
8378 : 2 : std::move (label));
8379 : : }
8380 : 0 : case LEFT_CURLY:
8381 : 0 : return parse_block_expr (std::move (outer_attrs), std::move (label));
8382 : 0 : default:
8383 : : // error
8384 : 0 : add_error (Error (t->get_locus (),
8385 : : "unexpected token %qs when parsing labelled loop",
8386 : : t->get_token_description ()));
8387 : :
8388 : : // skip?
8389 : 0 : return nullptr;
8390 : : }
8391 : 108 : }
8392 : :
8393 : : // Parses a match expression.
8394 : : template <typename ManagedTokenSource>
8395 : : std::unique_ptr<AST::MatchExpr>
8396 : 5537 : Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
8397 : : location_t pratt_parsed_loc)
8398 : : {
8399 : 5537 : location_t locus = pratt_parsed_loc;
8400 : 5537 : if (locus == UNKNOWN_LOCATION)
8401 : : {
8402 : 0 : locus = lexer.peek_token ()->get_locus ();
8403 : 0 : skip_token (MATCH_KW);
8404 : : }
8405 : :
8406 : : /* parse scrutinee expression, which is required (and HACK to prevent struct
8407 : : * expr) */
8408 : 5537 : ParseRestrictions no_struct_expr;
8409 : 5537 : no_struct_expr.can_be_struct_expr = false;
8410 : 5537 : std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr);
8411 : 5537 : if (scrutinee == nullptr)
8412 : : {
8413 : 0 : Error error (lexer.peek_token ()->get_locus (),
8414 : : "failed to parse scrutinee expression in match expression");
8415 : 0 : add_error (std::move (error));
8416 : :
8417 : : // skip somewhere?
8418 : 0 : return nullptr;
8419 : 0 : }
8420 : : /* TODO: check for scrutinee expr not being struct expr? or do so in
8421 : : * semantic analysis */
8422 : :
8423 : 5537 : if (!skip_token (LEFT_CURLY))
8424 : : {
8425 : : // skip somewhere?
8426 : 0 : return nullptr;
8427 : : }
8428 : :
8429 : : // parse inner attributes (if they exist)
8430 : 5537 : AST::AttrVec inner_attrs = parse_inner_attributes ();
8431 : :
8432 : : // parse match arms (if they exist)
8433 : : // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
8434 : 5537 : std::vector<AST::MatchCase> match_arms;
8435 : :
8436 : : // parse match cases
8437 : 160339 : while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
8438 : : {
8439 : : // parse match arm itself, which is required
8440 : 49879 : AST::MatchArm arm = parse_match_arm ();
8441 : 49879 : if (arm.is_error ())
8442 : : {
8443 : : // TODO is this worth throwing everything away?
8444 : 0 : Error error (lexer.peek_token ()->get_locus (),
8445 : : "failed to parse match arm in match arms");
8446 : 0 : add_error (std::move (error));
8447 : :
8448 : 0 : return nullptr;
8449 : 0 : }
8450 : :
8451 : 49879 : if (!skip_token (MATCH_ARROW))
8452 : : {
8453 : : // skip after somewhere?
8454 : : // TODO is returning here a good idea? or is break better?
8455 : 0 : return nullptr;
8456 : : }
8457 : :
8458 : 49879 : ParseRestrictions restrictions;
8459 : 49879 : restrictions.expr_can_be_stmt = true;
8460 : :
8461 : 49879 : std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions);
8462 : :
8463 : 49879 : if (expr == nullptr)
8464 : : {
8465 : 0 : Error error (lexer.peek_token ()->get_locus (),
8466 : : "failed to parse expr in match arm in match expr");
8467 : 0 : add_error (std::move (error));
8468 : :
8469 : : // skip somewhere?
8470 : 0 : return nullptr;
8471 : 0 : }
8472 : :
8473 : 49879 : bool is_expr_without_block = expr->is_expr_without_block ();
8474 : :
8475 : 99758 : match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr)));
8476 : :
8477 : : // handle comma presence
8478 : 99758 : if (lexer.peek_token ()->get_id () != COMMA)
8479 : : {
8480 : 1008 : if (!is_expr_without_block)
8481 : : {
8482 : : // allowed even if not final case
8483 : : continue;
8484 : : }
8485 : 186 : else if (is_expr_without_block
8486 : 372 : && lexer.peek_token ()->get_id () != RIGHT_CURLY)
8487 : : {
8488 : : // not allowed if not final case
8489 : 1 : Error error (lexer.peek_token ()->get_locus (),
8490 : : "exprwithoutblock requires comma after match case "
8491 : : "expression in match arm (if not final case)");
8492 : 1 : add_error (std::move (error));
8493 : :
8494 : 1 : return nullptr;
8495 : 1 : }
8496 : : else
8497 : : {
8498 : : // otherwise, must be final case, so fine
8499 : : break;
8500 : : }
8501 : : }
8502 : 48871 : lexer.skip_token ();
8503 : : }
8504 : :
8505 : 5536 : if (!skip_token (RIGHT_CURLY))
8506 : : {
8507 : : // skip somewhere?
8508 : 0 : return nullptr;
8509 : : }
8510 : :
8511 : 5536 : match_arms.shrink_to_fit ();
8512 : :
8513 : : return std::unique_ptr<AST::MatchExpr> (
8514 : 5536 : new AST::MatchExpr (std::move (scrutinee), std::move (match_arms),
8515 : : std::move (inner_attrs), std::move (outer_attrs),
8516 : 5536 : locus));
8517 : 5537 : }
8518 : :
8519 : : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
8520 : : template <typename ManagedTokenSource>
8521 : : AST::MatchArm
8522 : 49879 : Parser<ManagedTokenSource>::parse_match_arm ()
8523 : : {
8524 : : // parse optional outer attributes
8525 : 49879 : AST::AttrVec outer_attrs = parse_outer_attributes ();
8526 : :
8527 : : // DEBUG
8528 : 49879 : rust_debug ("about to start parsing match arm patterns");
8529 : :
8530 : : // break early if find right curly
8531 : 99758 : if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
8532 : : {
8533 : : // not an error
8534 : 0 : return AST::MatchArm::create_error ();
8535 : : }
8536 : :
8537 : : // parse match arm patterns - at least 1 is required
8538 : 49879 : std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
8539 : : = parse_match_arm_patterns (RIGHT_CURLY);
8540 : 49879 : if (match_arm_patterns.empty ())
8541 : : {
8542 : 0 : Error error (lexer.peek_token ()->get_locus (),
8543 : : "failed to parse any patterns in match arm");
8544 : 0 : add_error (std::move (error));
8545 : :
8546 : : // skip somewhere?
8547 : 0 : return AST::MatchArm::create_error ();
8548 : 0 : }
8549 : :
8550 : : // DEBUG
8551 : 49879 : rust_debug ("successfully parsed match arm patterns");
8552 : :
8553 : : // parse match arm guard expr if it exists
8554 : 49879 : std::unique_ptr<AST::Expr> guard_expr = nullptr;
8555 : 99758 : if (lexer.peek_token ()->get_id () == IF)
8556 : : {
8557 : 34 : lexer.skip_token ();
8558 : :
8559 : 34 : guard_expr = parse_expr ();
8560 : 34 : if (guard_expr == nullptr)
8561 : : {
8562 : 0 : Error error (lexer.peek_token ()->get_locus (),
8563 : : "failed to parse guard expression in match arm");
8564 : 0 : add_error (std::move (error));
8565 : :
8566 : : // skip somewhere?
8567 : 0 : return AST::MatchArm::create_error ();
8568 : 0 : }
8569 : : }
8570 : :
8571 : : // DEBUG
8572 : 49879 : rust_debug ("successfully parsed match arm");
8573 : :
8574 : 99758 : return AST::MatchArm (std::move (match_arm_patterns),
8575 : 99758 : lexer.peek_token ()->get_locus (),
8576 : 49879 : std::move (guard_expr), std::move (outer_attrs));
8577 : 49879 : }
8578 : :
8579 : : /* Parses the patterns used in a match arm. End token id is the id of the
8580 : : * token that would exist after the patterns are done (e.g. '}' for match
8581 : : * expr, '=' for if let and while let). */
8582 : : template <typename ManagedTokenSource>
8583 : : std::vector<std::unique_ptr<AST::Pattern>>
8584 : 50030 : Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id)
8585 : : {
8586 : : // skip optional leading '|'
8587 : 100060 : if (lexer.peek_token ()->get_id () == PIPE)
8588 : 0 : lexer.skip_token ();
8589 : : /* TODO: do I even need to store the result of this? can't be used.
8590 : : * If semantically different, I need a wrapped "match arm patterns" object
8591 : : * for this. */
8592 : :
8593 : 50030 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
8594 : :
8595 : : // quick break out if end_token_id
8596 : 100060 : if (lexer.peek_token ()->get_id () == end_token_id)
8597 : 1 : return patterns;
8598 : :
8599 : : // parse required pattern - if doesn't exist, return empty
8600 : 50029 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
8601 : 50029 : if (initial_pattern == nullptr)
8602 : : {
8603 : : // FIXME: should this be an error?
8604 : 0 : return patterns;
8605 : : }
8606 : 50029 : patterns.push_back (std::move (initial_pattern));
8607 : :
8608 : : // DEBUG
8609 : 50029 : rust_debug ("successfully parsed initial match arm pattern");
8610 : :
8611 : : // parse new patterns as long as next char is '|'
8612 : 50029 : const_TokenPtr t = lexer.peek_token ();
8613 : 50029 : while (t->get_id () == PIPE)
8614 : : {
8615 : : // skip pipe token
8616 : 0 : lexer.skip_token ();
8617 : :
8618 : : // break if hit end token id
8619 : 0 : if (lexer.peek_token ()->get_id () == end_token_id)
8620 : : break;
8621 : :
8622 : : // parse pattern
8623 : 0 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8624 : 0 : if (pattern == nullptr)
8625 : : {
8626 : : // this is an error
8627 : 0 : Error error (lexer.peek_token ()->get_locus (),
8628 : : "failed to parse pattern in match arm patterns");
8629 : 0 : add_error (std::move (error));
8630 : :
8631 : : // skip somewhere?
8632 : 0 : return {};
8633 : 0 : }
8634 : :
8635 : 0 : patterns.push_back (std::move (pattern));
8636 : :
8637 : 0 : t = lexer.peek_token ();
8638 : : }
8639 : :
8640 : 50029 : patterns.shrink_to_fit ();
8641 : :
8642 : 50029 : return patterns;
8643 : 50030 : }
8644 : :
8645 : : // Parses an async block expression.
8646 : : template <typename ManagedTokenSource>
8647 : : std::unique_ptr<AST::AsyncBlockExpr>
8648 : 0 : Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
8649 : : {
8650 : 0 : location_t locus = lexer.peek_token ()->get_locus ();
8651 : 0 : skip_token (ASYNC);
8652 : :
8653 : : // detect optional move token
8654 : 0 : bool has_move = false;
8655 : 0 : if (lexer.peek_token ()->get_id () == MOVE)
8656 : : {
8657 : 0 : lexer.skip_token ();
8658 : 0 : has_move = true;
8659 : : }
8660 : :
8661 : : // parse block expression (required)
8662 : 0 : std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8663 : 0 : if (block_expr == nullptr)
8664 : : {
8665 : 0 : Error error (
8666 : 0 : lexer.peek_token ()->get_locus (),
8667 : : "failed to parse block expression of async block expression");
8668 : 0 : add_error (std::move (error));
8669 : :
8670 : : // skip somewhere?
8671 : 0 : return nullptr;
8672 : 0 : }
8673 : :
8674 : : return std::unique_ptr<AST::AsyncBlockExpr> (
8675 : 0 : new AST::AsyncBlockExpr (std::move (block_expr), has_move,
8676 : 0 : std::move (outer_attrs), locus));
8677 : 0 : }
8678 : :
8679 : : // Parses an unsafe block expression.
8680 : : template <typename ManagedTokenSource>
8681 : : std::unique_ptr<AST::UnsafeBlockExpr>
8682 : 4622 : Parser<ManagedTokenSource>::parse_unsafe_block_expr (
8683 : : AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
8684 : : {
8685 : 4622 : location_t locus = pratt_parsed_loc;
8686 : 4622 : if (locus == UNKNOWN_LOCATION)
8687 : : {
8688 : 0 : locus = lexer.peek_token ()->get_locus ();
8689 : 0 : skip_token (UNSAFE);
8690 : : }
8691 : :
8692 : : // parse block expression (required)
8693 : 4622 : std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8694 : 4622 : if (block_expr == nullptr)
8695 : : {
8696 : 0 : Error error (
8697 : 0 : lexer.peek_token ()->get_locus (),
8698 : : "failed to parse block expression of unsafe block expression");
8699 : 0 : add_error (std::move (error));
8700 : :
8701 : : // skip somewhere?
8702 : 0 : return nullptr;
8703 : 0 : }
8704 : :
8705 : : return std::unique_ptr<AST::UnsafeBlockExpr> (
8706 : 4622 : new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs),
8707 : 4622 : locus));
8708 : 4622 : }
8709 : :
8710 : : // Parses an array definition expression.
8711 : : template <typename ManagedTokenSource>
8712 : : std::unique_ptr<AST::ArrayExpr>
8713 : 13205 : Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
8714 : : location_t pratt_parsed_loc)
8715 : : {
8716 : 13205 : location_t locus = pratt_parsed_loc;
8717 : 13205 : if (locus == UNKNOWN_LOCATION)
8718 : : {
8719 : 0 : locus = lexer.peek_token ()->get_locus ();
8720 : 0 : skip_token (LEFT_SQUARE);
8721 : : }
8722 : :
8723 : : // parse optional inner attributes
8724 : 13205 : AST::AttrVec inner_attrs = parse_inner_attributes ();
8725 : :
8726 : : // parse the "array elements" section, which is optional
8727 : 26410 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8728 : : {
8729 : : // no array elements
8730 : 57 : lexer.skip_token ();
8731 : :
8732 : 57 : std::vector<std::unique_ptr<AST::Expr>> exprs;
8733 : 57 : auto array_elems
8734 : : = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
8735 : : return std::make_unique<AST::ArrayExpr> (std::move (array_elems),
8736 : : std::move (inner_attrs),
8737 : 57 : std::move (outer_attrs), locus);
8738 : 57 : }
8739 : : else
8740 : : {
8741 : : // should have array elements
8742 : : // parse initial expression, which is required for either
8743 : 13148 : std::unique_ptr<AST::Expr> initial_expr = parse_expr ();
8744 : 13148 : if (initial_expr == nullptr)
8745 : : {
8746 : 0 : Error error (lexer.peek_token ()->get_locus (),
8747 : : "could not parse expression in array expression "
8748 : : "(even though arrayelems seems to be present)");
8749 : 0 : add_error (std::move (error));
8750 : :
8751 : : // skip somewhere?
8752 : 0 : return nullptr;
8753 : 0 : }
8754 : :
8755 : 26296 : if (lexer.peek_token ()->get_id () == SEMICOLON)
8756 : : {
8757 : : // copy array elems
8758 : 260 : lexer.skip_token ();
8759 : :
8760 : : // parse copy amount expression (required)
8761 : 260 : std::unique_ptr<AST::Expr> copy_amount = parse_expr ();
8762 : 260 : if (copy_amount == nullptr)
8763 : : {
8764 : 0 : Error error (lexer.peek_token ()->get_locus (),
8765 : : "could not parse copy amount expression in array "
8766 : : "expression (arrayelems)");
8767 : 0 : add_error (std::move (error));
8768 : :
8769 : : // skip somewhere?
8770 : 0 : return nullptr;
8771 : 0 : }
8772 : :
8773 : 260 : skip_token (RIGHT_SQUARE);
8774 : :
8775 : 260 : std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
8776 : 260 : new AST::ArrayElemsCopied (std::move (initial_expr),
8777 : : std::move (copy_amount), locus));
8778 : : return std::unique_ptr<AST::ArrayExpr> (
8779 : 260 : new AST::ArrayExpr (std::move (copied_array_elems),
8780 : : std::move (inner_attrs),
8781 : 260 : std::move (outer_attrs), locus));
8782 : 260 : }
8783 : 25776 : else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8784 : : {
8785 : : // single-element array expression
8786 : 36 : std::vector<std::unique_ptr<AST::Expr>> exprs;
8787 : 36 : exprs.reserve (1);
8788 : 36 : exprs.push_back (std::move (initial_expr));
8789 : 36 : exprs.shrink_to_fit ();
8790 : :
8791 : 36 : skip_token (RIGHT_SQUARE);
8792 : :
8793 : 36 : std::unique_ptr<AST::ArrayElemsValues> array_elems (
8794 : 36 : new AST::ArrayElemsValues (std::move (exprs), locus));
8795 : : return std::unique_ptr<AST::ArrayExpr> (
8796 : 36 : new AST::ArrayExpr (std::move (array_elems),
8797 : : std::move (inner_attrs),
8798 : 36 : std::move (outer_attrs), locus));
8799 : 36 : }
8800 : 25704 : else if (lexer.peek_token ()->get_id () == COMMA)
8801 : : {
8802 : : // multi-element array expression (or trailing comma)
8803 : 12852 : std::vector<std::unique_ptr<AST::Expr>> exprs;
8804 : 12852 : exprs.push_back (std::move (initial_expr));
8805 : :
8806 : 12852 : const_TokenPtr t = lexer.peek_token ();
8807 : 123455 : while (t->get_id () == COMMA)
8808 : : {
8809 : 114568 : lexer.skip_token ();
8810 : :
8811 : : // quick break if right square bracket
8812 : 229136 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8813 : : break;
8814 : :
8815 : : // parse expression (required)
8816 : 110603 : std::unique_ptr<AST::Expr> expr = parse_expr ();
8817 : 110603 : if (expr == nullptr)
8818 : : {
8819 : 0 : Error error (lexer.peek_token ()->get_locus (),
8820 : : "failed to parse element in array expression");
8821 : 0 : add_error (std::move (error));
8822 : :
8823 : : // skip somewhere?
8824 : 0 : return nullptr;
8825 : 0 : }
8826 : 110603 : exprs.push_back (std::move (expr));
8827 : :
8828 : 110603 : t = lexer.peek_token ();
8829 : : }
8830 : :
8831 : 12852 : skip_token (RIGHT_SQUARE);
8832 : :
8833 : 12852 : exprs.shrink_to_fit ();
8834 : :
8835 : 12852 : std::unique_ptr<AST::ArrayElemsValues> array_elems (
8836 : 12852 : new AST::ArrayElemsValues (std::move (exprs), locus));
8837 : : return std::unique_ptr<AST::ArrayExpr> (
8838 : 12852 : new AST::ArrayExpr (std::move (array_elems),
8839 : : std::move (inner_attrs),
8840 : 12852 : std::move (outer_attrs), locus));
8841 : 25704 : }
8842 : : else
8843 : : {
8844 : : // error
8845 : 0 : Error error (lexer.peek_token ()->get_locus (),
8846 : : "unexpected token %qs in array expression (arrayelems)",
8847 : 0 : lexer.peek_token ()->get_token_description ());
8848 : 0 : add_error (std::move (error));
8849 : :
8850 : : // skip somewhere?
8851 : 0 : return nullptr;
8852 : 0 : }
8853 : 13148 : }
8854 : 13205 : }
8855 : :
8856 : : // Parses a single parameter used in a closure definition.
8857 : : template <typename ManagedTokenSource>
8858 : : AST::ClosureParam
8859 : 434 : Parser<ManagedTokenSource>::parse_closure_param ()
8860 : : {
8861 : 434 : AST::AttrVec outer_attrs = parse_outer_attributes ();
8862 : :
8863 : : // parse pattern (which is required)
8864 : 434 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
8865 : 434 : if (pattern == nullptr)
8866 : : {
8867 : : // not necessarily an error
8868 : 0 : return AST::ClosureParam::create_error ();
8869 : : }
8870 : :
8871 : : // parse optional type of param
8872 : 434 : std::unique_ptr<AST::Type> type = nullptr;
8873 : 868 : if (lexer.peek_token ()->get_id () == COLON)
8874 : : {
8875 : 80 : lexer.skip_token ();
8876 : :
8877 : : // parse type, which is now required
8878 : 80 : type = parse_type ();
8879 : 80 : if (type == nullptr)
8880 : : {
8881 : 0 : Error error (lexer.peek_token ()->get_locus (),
8882 : : "failed to parse type in closure parameter");
8883 : 0 : add_error (std::move (error));
8884 : :
8885 : : // skip somewhere?
8886 : 0 : return AST::ClosureParam::create_error ();
8887 : 0 : }
8888 : : }
8889 : :
8890 : 434 : location_t loc = pattern->get_locus ();
8891 : 434 : return AST::ClosureParam (std::move (pattern), loc, std::move (type),
8892 : 434 : std::move (outer_attrs));
8893 : 434 : }
8894 : :
8895 : : // Parses a grouped or tuple expression (disambiguates).
8896 : : template <typename ManagedTokenSource>
8897 : : std::unique_ptr<AST::ExprWithoutBlock>
8898 : 12550 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
8899 : : AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
8900 : : {
8901 : : // adjustment to allow Pratt parsing to reuse function without copy-paste
8902 : 12550 : location_t locus = pratt_parsed_loc;
8903 : 12550 : if (locus == UNKNOWN_LOCATION)
8904 : : {
8905 : 0 : locus = lexer.peek_token ()->get_locus ();
8906 : 0 : skip_token (LEFT_PAREN);
8907 : : }
8908 : :
8909 : : // parse optional inner attributes
8910 : 12550 : AST::AttrVec inner_attrs = parse_inner_attributes ();
8911 : :
8912 : 25100 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8913 : : {
8914 : : // must be empty tuple
8915 : 320 : lexer.skip_token ();
8916 : :
8917 : : // create tuple with empty tuple elems
8918 : 320 : return std::unique_ptr<AST::TupleExpr> (
8919 : 320 : new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
8920 : : std::move (inner_attrs), std::move (outer_attrs),
8921 : 320 : locus));
8922 : : }
8923 : :
8924 : : // parse first expression (required)
8925 : 12230 : std::unique_ptr<AST::Expr> first_expr = parse_expr ();
8926 : 12230 : if (first_expr == nullptr)
8927 : : {
8928 : 0 : Error error (lexer.peek_token ()->get_locus (),
8929 : : "failed to parse expression in grouped or tuple expression");
8930 : 0 : add_error (std::move (error));
8931 : :
8932 : : // skip after somewhere?
8933 : 0 : return nullptr;
8934 : 0 : }
8935 : :
8936 : : // detect whether grouped expression with right parentheses as next token
8937 : 24460 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8938 : : {
8939 : : // must be grouped expr
8940 : 8161 : lexer.skip_token ();
8941 : :
8942 : : // create grouped expr
8943 : 8161 : return std::unique_ptr<AST::GroupedExpr> (
8944 : 8161 : new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs),
8945 : 8161 : std::move (outer_attrs), locus));
8946 : : }
8947 : 8138 : else if (lexer.peek_token ()->get_id () == COMMA)
8948 : : {
8949 : : // tuple expr
8950 : 4068 : std::vector<std::unique_ptr<AST::Expr>> exprs;
8951 : 4068 : exprs.push_back (std::move (first_expr));
8952 : :
8953 : : // parse potential other tuple exprs
8954 : 4068 : const_TokenPtr t = lexer.peek_token ();
8955 : 8421 : while (t->get_id () == COMMA)
8956 : : {
8957 : 4416 : lexer.skip_token ();
8958 : :
8959 : : // break out if right paren
8960 : 8832 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8961 : : break;
8962 : :
8963 : : // parse expr, which is now required
8964 : 4353 : std::unique_ptr<AST::Expr> expr = parse_expr ();
8965 : 4353 : if (expr == nullptr)
8966 : : {
8967 : 0 : Error error (lexer.peek_token ()->get_locus (),
8968 : : "failed to parse expr in tuple expr");
8969 : 0 : add_error (std::move (error));
8970 : :
8971 : : // skip somewhere?
8972 : 0 : return nullptr;
8973 : 0 : }
8974 : 4353 : exprs.push_back (std::move (expr));
8975 : :
8976 : 4353 : t = lexer.peek_token ();
8977 : : }
8978 : :
8979 : : // skip right paren
8980 : 4068 : skip_token (RIGHT_PAREN);
8981 : :
8982 : 4068 : return std::unique_ptr<AST::TupleExpr> (
8983 : 4068 : new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
8984 : 4068 : std::move (outer_attrs), locus));
8985 : 4068 : }
8986 : : else
8987 : : {
8988 : : // error
8989 : 1 : const_TokenPtr t = lexer.peek_token ();
8990 : 1 : Error error (t->get_locus (),
8991 : : "unexpected token %qs in grouped or tuple expression "
8992 : : "(parenthesised expression) - expected %<)%> for grouped "
8993 : : "expr and %<,%> for tuple expr",
8994 : : t->get_token_description ());
8995 : 1 : add_error (std::move (error));
8996 : :
8997 : : // skip somewhere?
8998 : 1 : return nullptr;
8999 : 2 : }
9000 : 12550 : }
9001 : :
9002 : : // Parses a type (will further disambiguate any type).
9003 : : template <typename ManagedTokenSource>
9004 : : std::unique_ptr<AST::Type>
9005 : 104841 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
9006 : : {
9007 : : /* rules for all types:
9008 : : * NeverType: '!'
9009 : : * SliceType: '[' Type ']'
9010 : : * InferredType: '_'
9011 : : * MacroInvocation: SimplePath '!' DelimTokenTree
9012 : : * ParenthesisedType: '(' Type ')'
9013 : : * ImplTraitType: 'impl' TypeParamBounds
9014 : : * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
9015 : : * TypeParamBound Lifetime | TraitBound
9016 : : * ImplTraitTypeOneBound: 'impl' TraitBound
9017 : : * TraitObjectType: 'dyn'? TypeParamBounds
9018 : : * TraitObjectTypeOneBound: 'dyn'? TraitBound
9019 : : * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
9020 : : * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
9021 : : * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
9022 : : * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
9023 : : * 'unsafe'?
9024 : : * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
9025 : : * (
9026 : : * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
9027 : : * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
9028 : : * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
9029 : : * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
9030 : : * TupleType: '(' Type etc. - regular tuple stuff. Also
9031 : : * regular tuple vs parenthesised precedence
9032 : : *
9033 : : * Disambiguate between macro and type path via type path being parsed, and
9034 : : * then if '!' found, convert type path to simple path for macro. Usual
9035 : : * disambiguation for tuple vs parenthesised. For ImplTraitType and
9036 : : * TraitObjectType individual disambiguations, they seem more like "special
9037 : : * cases", so probably just try to parse the more general ImplTraitType or
9038 : : * TraitObjectType and return OneBound versions if they satisfy those
9039 : : * criteria. */
9040 : :
9041 : 104841 : const_TokenPtr t = lexer.peek_token ();
9042 : 104841 : switch (t->get_id ())
9043 : : {
9044 : 90 : case EXCLAM:
9045 : : // never type - can't be macro as no path beforehand
9046 : 90 : lexer.skip_token ();
9047 : 90 : return std::unique_ptr<AST::NeverType> (
9048 : 90 : new AST::NeverType (t->get_locus ()));
9049 : 1184 : case LEFT_SQUARE:
9050 : : // slice type or array type - requires further disambiguation
9051 : 1184 : return parse_slice_or_array_type ();
9052 : 3538 : case LEFT_SHIFT:
9053 : : case LEFT_ANGLE:
9054 : : {
9055 : : // qualified path in type
9056 : 3538 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
9057 : 3538 : if (path.is_error ())
9058 : : {
9059 : 0 : if (save_errors)
9060 : : {
9061 : 0 : Error error (t->get_locus (),
9062 : : "failed to parse qualified path in type");
9063 : 0 : add_error (std::move (error));
9064 : 0 : }
9065 : :
9066 : 0 : return nullptr;
9067 : : }
9068 : 3538 : return std::unique_ptr<AST::QualifiedPathInType> (
9069 : 3538 : new AST::QualifiedPathInType (std::move (path)));
9070 : 3538 : }
9071 : 315 : case UNDERSCORE:
9072 : : // inferred type
9073 : 315 : lexer.skip_token ();
9074 : 315 : return std::unique_ptr<AST::InferredType> (
9075 : 315 : new AST::InferredType (t->get_locus ()));
9076 : 3403 : case ASTERISK:
9077 : : // raw pointer type
9078 : 3403 : return parse_raw_pointer_type ();
9079 : 11612 : case AMP: // does this also include AMP_AMP?
9080 : : case LOGICAL_AND:
9081 : : // reference type
9082 : 11612 : return parse_reference_type ();
9083 : 0 : case LIFETIME:
9084 : : {
9085 : : /* probably a lifetime bound, so probably type param bounds in
9086 : : * TraitObjectType */
9087 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9088 : : = parse_type_param_bounds ();
9089 : :
9090 : 0 : return std::unique_ptr<AST::TraitObjectType> (
9091 : 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9092 : 0 : false));
9093 : 0 : }
9094 : 82700 : case IDENTIFIER:
9095 : : case SUPER:
9096 : : case SELF:
9097 : : case SELF_ALIAS:
9098 : : case CRATE:
9099 : : case DOLLAR_SIGN:
9100 : : case SCOPE_RESOLUTION:
9101 : : {
9102 : : // macro invocation or type path - requires further disambiguation.
9103 : : /* for parsing path component of each rule, perhaps parse it as a
9104 : : * typepath and attempt conversion to simplepath if a trailing '!' is
9105 : : * found */
9106 : : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9107 : : * with it, it is exactly the same as a TypePath syntactically, so
9108 : : * this is a syntactical ambiguity. As such, the parser will parse it
9109 : : * as a TypePath. This, however, does not prevent TraitObjectType from
9110 : : * starting with a typepath. */
9111 : :
9112 : : // parse path as type path
9113 : 82700 : AST::TypePath path = parse_type_path ();
9114 : 82700 : if (path.is_error ())
9115 : : {
9116 : 0 : if (save_errors)
9117 : : {
9118 : 0 : Error error (t->get_locus (),
9119 : : "failed to parse path as first component of type");
9120 : 0 : add_error (std::move (error));
9121 : 0 : }
9122 : :
9123 : 0 : return nullptr;
9124 : : }
9125 : 82700 : location_t locus = path.get_locus ();
9126 : :
9127 : : // branch on next token
9128 : 82700 : t = lexer.peek_token ();
9129 : 82700 : switch (t->get_id ())
9130 : : {
9131 : 496 : case EXCLAM:
9132 : : {
9133 : : // macro invocation
9134 : : // convert to simple path
9135 : 496 : AST::SimplePath macro_path = path.as_simple_path ();
9136 : 496 : if (macro_path.is_empty ())
9137 : : {
9138 : 0 : if (save_errors)
9139 : : {
9140 : 0 : Error error (t->get_locus (),
9141 : : "failed to parse simple path in macro "
9142 : : "invocation (for type)");
9143 : 0 : add_error (std::move (error));
9144 : 0 : }
9145 : :
9146 : 0 : return nullptr;
9147 : : }
9148 : :
9149 : 496 : lexer.skip_token ();
9150 : :
9151 : 496 : AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
9152 : :
9153 : 992 : return AST::MacroInvocation::Regular (
9154 : 992 : AST::MacroInvocData (std::move (macro_path),
9155 : : std::move (tok_tree)),
9156 : 496 : {}, locus);
9157 : 992 : }
9158 : 29 : case PLUS:
9159 : : {
9160 : : // type param bounds
9161 : 29 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9162 : :
9163 : : // convert type path to trait bound
9164 : 29 : std::unique_ptr<AST::TraitBound> path_bound (
9165 : 29 : new AST::TraitBound (std::move (path), locus, false, false));
9166 : 29 : bounds.push_back (std::move (path_bound));
9167 : :
9168 : : /* parse rest of bounds - FIXME: better way to find when to stop
9169 : : * parsing */
9170 : 58 : while (t->get_id () == PLUS)
9171 : : {
9172 : 29 : lexer.skip_token ();
9173 : :
9174 : : // parse bound if it exists - if not, assume end of sequence
9175 : 29 : std::unique_ptr<AST::TypeParamBound> bound
9176 : : = parse_type_param_bound ();
9177 : 29 : if (bound == nullptr)
9178 : : {
9179 : : break;
9180 : : }
9181 : 29 : bounds.push_back (std::move (bound));
9182 : :
9183 : 29 : t = lexer.peek_token ();
9184 : : }
9185 : :
9186 : 29 : return std::unique_ptr<AST::TraitObjectType> (
9187 : 29 : new AST::TraitObjectType (std::move (bounds), locus, false));
9188 : 29 : }
9189 : 82175 : default:
9190 : : // assume that this is a type path and not an error
9191 : 82175 : return std::unique_ptr<AST::TypePath> (
9192 : 82175 : new AST::TypePath (std::move (path)));
9193 : : }
9194 : 82700 : }
9195 : 1039 : case LEFT_PAREN:
9196 : : /* tuple type or parenthesised type - requires further disambiguation
9197 : : * (the usual). ok apparently can be a parenthesised TraitBound too, so
9198 : : * could be TraitObjectTypeOneBound or TraitObjectType */
9199 : 1039 : return parse_paren_prefixed_type ();
9200 : 4 : case FOR:
9201 : : // TraitObjectTypeOneBound or BareFunctionType
9202 : 4 : return parse_for_prefixed_type ();
9203 : 684 : case ASYNC:
9204 : : case CONST:
9205 : : case UNSAFE:
9206 : : case EXTERN_KW:
9207 : : case FN_KW:
9208 : : // bare function type (with no for lifetimes)
9209 : 684 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
9210 : 226 : case IMPL:
9211 : 226 : lexer.skip_token ();
9212 : 452 : if (lexer.peek_token ()->get_id () == LIFETIME)
9213 : : {
9214 : : /* cannot be one bound because lifetime prevents it from being
9215 : : * traitbound */
9216 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9217 : : = parse_type_param_bounds ();
9218 : :
9219 : 0 : return std::unique_ptr<AST::ImplTraitType> (
9220 : 0 : new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
9221 : 0 : }
9222 : : else
9223 : : {
9224 : : // should be trait bound, so parse trait bound
9225 : 226 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
9226 : 226 : if (initial_bound == nullptr)
9227 : : {
9228 : 0 : if (save_errors)
9229 : : {
9230 : 0 : Error error (lexer.peek_token ()->get_locus (),
9231 : : "failed to parse ImplTraitType initial bound");
9232 : 0 : add_error (std::move (error));
9233 : 0 : }
9234 : :
9235 : 0 : return nullptr;
9236 : : }
9237 : :
9238 : 226 : location_t locus = t->get_locus ();
9239 : :
9240 : : // short cut if next token isn't '+'
9241 : 226 : t = lexer.peek_token ();
9242 : 226 : if (t->get_id () != PLUS)
9243 : : {
9244 : 224 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
9245 : 224 : new AST::ImplTraitTypeOneBound (std::move (initial_bound),
9246 : 224 : locus));
9247 : : }
9248 : :
9249 : : // parse additional type param bounds
9250 : 2 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9251 : 2 : bounds.push_back (std::move (initial_bound));
9252 : 4 : while (t->get_id () == PLUS)
9253 : : {
9254 : 2 : lexer.skip_token ();
9255 : :
9256 : : // parse bound if it exists
9257 : 2 : std::unique_ptr<AST::TypeParamBound> bound
9258 : : = parse_type_param_bound ();
9259 : 2 : if (bound == nullptr)
9260 : : {
9261 : : // not an error as trailing plus may exist
9262 : : break;
9263 : : }
9264 : 2 : bounds.push_back (std::move (bound));
9265 : :
9266 : 2 : t = lexer.peek_token ();
9267 : : }
9268 : :
9269 : 2 : return std::unique_ptr<AST::ImplTraitType> (
9270 : 2 : new AST::ImplTraitType (std::move (bounds), locus));
9271 : 226 : }
9272 : 42 : case DYN:
9273 : : case QUESTION_MARK:
9274 : : {
9275 : : // either TraitObjectType or TraitObjectTypeOneBound
9276 : 42 : bool has_dyn = false;
9277 : 42 : if (t->get_id () == DYN)
9278 : : {
9279 : 42 : lexer.skip_token ();
9280 : 42 : has_dyn = true;
9281 : : }
9282 : :
9283 : 84 : if (lexer.peek_token ()->get_id () == LIFETIME)
9284 : : {
9285 : : /* cannot be one bound because lifetime prevents it from being
9286 : : * traitbound */
9287 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9288 : : = parse_type_param_bounds ();
9289 : :
9290 : 0 : return std::unique_ptr<AST::TraitObjectType> (
9291 : 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9292 : 0 : has_dyn));
9293 : 0 : }
9294 : : else
9295 : : {
9296 : : // should be trait bound, so parse trait bound
9297 : 42 : std::unique_ptr<AST::TraitBound> initial_bound
9298 : : = parse_trait_bound ();
9299 : 42 : if (initial_bound == nullptr)
9300 : : {
9301 : 0 : if (save_errors)
9302 : : {
9303 : 0 : Error error (
9304 : 0 : lexer.peek_token ()->get_locus (),
9305 : : "failed to parse TraitObjectType initial bound");
9306 : 0 : add_error (std::move (error));
9307 : 0 : }
9308 : :
9309 : 0 : return nullptr;
9310 : : }
9311 : :
9312 : : // short cut if next token isn't '+'
9313 : 42 : t = lexer.peek_token ();
9314 : 42 : if (t->get_id () != PLUS)
9315 : : {
9316 : : // convert trait bound to value object
9317 : 16 : AST::TraitBound value_bound (*initial_bound);
9318 : :
9319 : : // DEBUG: removed as unique ptr, so should auto delete
9320 : : // delete initial_bound;
9321 : :
9322 : 16 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9323 : 32 : new AST::TraitObjectTypeOneBound (std::move (value_bound),
9324 : 16 : t->get_locus (), has_dyn));
9325 : 16 : }
9326 : :
9327 : : // parse additional type param bounds
9328 : 26 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9329 : 26 : bounds.push_back (std::move (initial_bound));
9330 : 61 : while (t->get_id () == PLUS)
9331 : : {
9332 : 35 : lexer.skip_token ();
9333 : :
9334 : : // parse bound if it exists
9335 : 35 : std::unique_ptr<AST::TypeParamBound> bound
9336 : : = parse_type_param_bound ();
9337 : 35 : if (bound == nullptr)
9338 : : {
9339 : : // not an error as trailing plus may exist
9340 : : break;
9341 : : }
9342 : 35 : bounds.push_back (std::move (bound));
9343 : :
9344 : 35 : t = lexer.peek_token ();
9345 : : }
9346 : :
9347 : 26 : return std::unique_ptr<AST::TraitObjectType> (
9348 : 26 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9349 : 26 : has_dyn));
9350 : 42 : }
9351 : : }
9352 : 4 : default:
9353 : 4 : if (save_errors)
9354 : 4 : add_error (Error (t->get_locus (), "unrecognised token %qs in type",
9355 : : t->get_token_description ()));
9356 : :
9357 : 4 : return nullptr;
9358 : : }
9359 : 104841 : }
9360 : :
9361 : : /* Parses a type that has '(' as its first character. Returns a tuple type,
9362 : : * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
9363 : : * on following characters. */
9364 : : template <typename ManagedTokenSource>
9365 : : std::unique_ptr<AST::Type>
9366 : 1039 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
9367 : : {
9368 : : /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
9369 : : * a trait bound, not a parenthesised type, so that it can still be used in
9370 : : * type param bounds. */
9371 : :
9372 : : /* NOTE: this implementation is really shit but I couldn't think of a better
9373 : : * one. It requires essentially breaking polymorphism and downcasting via
9374 : : * virtual method abuse, as it was copied from the rustc implementation (in
9375 : : * which types are reified due to tagged union), after a more OOP attempt by
9376 : : * me failed. */
9377 : 1039 : location_t left_delim_locus = lexer.peek_token ()->get_locus ();
9378 : :
9379 : : // skip left delim
9380 : 1039 : lexer.skip_token ();
9381 : : /* while next token isn't close delim, parse comma-separated types, saving
9382 : : * whether trailing comma happens */
9383 : 1039 : const_TokenPtr t = lexer.peek_token ();
9384 : 1039 : bool trailing_comma = true;
9385 : 1039 : std::vector<std::unique_ptr<AST::Type>> types;
9386 : :
9387 : 2476 : while (t->get_id () != RIGHT_PAREN)
9388 : : {
9389 : 2158 : std::unique_ptr<AST::Type> type = parse_type ();
9390 : 2158 : if (type == nullptr)
9391 : : {
9392 : 0 : Error error (t->get_locus (),
9393 : : "failed to parse type inside parentheses (probably "
9394 : : "tuple or parenthesised)");
9395 : 0 : add_error (std::move (error));
9396 : :
9397 : 0 : return nullptr;
9398 : 0 : }
9399 : 2158 : types.push_back (std::move (type));
9400 : :
9401 : 2158 : t = lexer.peek_token ();
9402 : 2158 : if (t->get_id () != COMMA)
9403 : : {
9404 : 721 : trailing_comma = false;
9405 : : break;
9406 : : }
9407 : 1437 : lexer.skip_token ();
9408 : :
9409 : 1437 : t = lexer.peek_token ();
9410 : : }
9411 : :
9412 : 1039 : if (!skip_token (RIGHT_PAREN))
9413 : : {
9414 : 0 : return nullptr;
9415 : : }
9416 : :
9417 : : // if only one type and no trailing comma, then not a tuple type
9418 : 1039 : if (types.size () == 1 && !trailing_comma)
9419 : : {
9420 : : // must be a TraitObjectType (with more than one bound)
9421 : 10 : if (lexer.peek_token ()->get_id () == PLUS)
9422 : : {
9423 : : // create type param bounds vector
9424 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9425 : :
9426 : : // HACK: convert type to traitbound and add to bounds
9427 : 0 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9428 : 0 : std::unique_ptr<AST::TraitBound> converted_bound (
9429 : 0 : released_ptr->to_trait_bound (true));
9430 : 0 : if (converted_bound == nullptr)
9431 : : {
9432 : 0 : Error error (
9433 : 0 : lexer.peek_token ()->get_locus (),
9434 : : "failed to hackily converted parsed type to trait bound");
9435 : 0 : add_error (std::move (error));
9436 : :
9437 : 0 : return nullptr;
9438 : 0 : }
9439 : 0 : bounds.push_back (std::move (converted_bound));
9440 : :
9441 : 0 : t = lexer.peek_token ();
9442 : 0 : while (t->get_id () == PLUS)
9443 : : {
9444 : 0 : lexer.skip_token ();
9445 : :
9446 : : // attempt to parse typeparambound
9447 : 0 : std::unique_ptr<AST::TypeParamBound> bound
9448 : : = parse_type_param_bound ();
9449 : 0 : if (bound == nullptr)
9450 : : {
9451 : : // not an error if null
9452 : : break;
9453 : : }
9454 : 0 : bounds.push_back (std::move (bound));
9455 : :
9456 : 0 : t = lexer.peek_token ();
9457 : : }
9458 : :
9459 : 0 : return std::unique_ptr<AST::TraitObjectType> (
9460 : 0 : new AST::TraitObjectType (std::move (bounds), left_delim_locus,
9461 : 0 : false));
9462 : 0 : }
9463 : : else
9464 : : {
9465 : : // release vector pointer
9466 : 5 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9467 : : /* HACK: attempt to convert to trait bound. if fails, parenthesised
9468 : : * type */
9469 : 5 : std::unique_ptr<AST::TraitBound> converted_bound (
9470 : 5 : released_ptr->to_trait_bound (true));
9471 : 5 : if (converted_bound == nullptr)
9472 : : {
9473 : : // parenthesised type
9474 : 2 : return std::unique_ptr<AST::ParenthesisedType> (
9475 : 2 : new AST::ParenthesisedType (std::move (released_ptr),
9476 : 2 : left_delim_locus));
9477 : : }
9478 : : else
9479 : : {
9480 : : // trait object type (one bound)
9481 : :
9482 : : // get value semantics trait bound
9483 : 3 : AST::TraitBound value_bound (*converted_bound);
9484 : :
9485 : 3 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9486 : 6 : new AST::TraitObjectTypeOneBound (value_bound,
9487 : 3 : left_delim_locus));
9488 : 3 : }
9489 : 5 : }
9490 : : }
9491 : : else
9492 : : {
9493 : 1034 : return std::unique_ptr<AST::TupleType> (
9494 : 1034 : new AST::TupleType (std::move (types), left_delim_locus));
9495 : : }
9496 : : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
9497 : : * lost somehow */
9498 : 1039 : }
9499 : :
9500 : : /* Parses a type that has 'for' as its first character. This means it has a
9501 : : * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
9502 : : * TraitObjectTypeOneBound depending on following characters. */
9503 : : template <typename ManagedTokenSource>
9504 : : std::unique_ptr<AST::Type>
9505 : 4 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
9506 : : {
9507 : 4 : location_t for_locus = lexer.peek_token ()->get_locus ();
9508 : : // parse for lifetimes in type
9509 : 4 : std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
9510 : :
9511 : : // branch on next token - either function or a trait type
9512 : 4 : const_TokenPtr t = lexer.peek_token ();
9513 : 4 : switch (t->get_id ())
9514 : : {
9515 : 3 : case ASYNC:
9516 : : case CONST:
9517 : : case UNSAFE:
9518 : : case EXTERN_KW:
9519 : : case FN_KW:
9520 : 3 : return parse_bare_function_type (std::move (for_lifetimes));
9521 : 1 : case SCOPE_RESOLUTION:
9522 : : case IDENTIFIER:
9523 : : case SUPER:
9524 : : case SELF:
9525 : : case SELF_ALIAS:
9526 : : case CRATE:
9527 : : case DOLLAR_SIGN:
9528 : : {
9529 : : // path, so trait type
9530 : :
9531 : : // parse type path to finish parsing trait bound
9532 : 1 : AST::TypePath path = parse_type_path ();
9533 : :
9534 : 1 : t = lexer.peek_token ();
9535 : 1 : if (t->get_id () != PLUS)
9536 : : {
9537 : : // must be one-bound trait type
9538 : : // create trait bound value object
9539 : 1 : AST::TraitBound bound (std::move (path), for_locus, false, false,
9540 : : std::move (for_lifetimes));
9541 : :
9542 : 1 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9543 : 2 : new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
9544 : 1 : }
9545 : :
9546 : : /* more than one bound trait type (or at least parsed as it - could be
9547 : : * trailing '+') create trait bound pointer and bounds */
9548 : 0 : std::unique_ptr<AST::TraitBound> initial_bound (
9549 : 0 : new AST::TraitBound (std::move (path), for_locus, false, false,
9550 : : std::move (for_lifetimes)));
9551 : 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9552 : 0 : bounds.push_back (std::move (initial_bound));
9553 : :
9554 : 0 : while (t->get_id () == PLUS)
9555 : : {
9556 : 0 : lexer.skip_token ();
9557 : :
9558 : : // parse type param bound if it exists
9559 : 0 : std::unique_ptr<AST::TypeParamBound> bound
9560 : : = parse_type_param_bound ();
9561 : 0 : if (bound == nullptr)
9562 : : {
9563 : : // not an error - e.g. trailing plus
9564 : 0 : return nullptr;
9565 : : }
9566 : 0 : bounds.push_back (std::move (bound));
9567 : :
9568 : 0 : t = lexer.peek_token ();
9569 : : }
9570 : :
9571 : 0 : return std::unique_ptr<AST::TraitObjectType> (
9572 : 0 : new AST::TraitObjectType (std::move (bounds), for_locus, false));
9573 : 1 : }
9574 : 0 : default:
9575 : : // error
9576 : 0 : add_error (Error (t->get_locus (),
9577 : : "unrecognised token %qs in bare function type or trait "
9578 : : "object type or trait object type one bound",
9579 : : t->get_token_description ()));
9580 : :
9581 : 0 : return nullptr;
9582 : : }
9583 : 4 : }
9584 : :
9585 : : // Parses a maybe named param used in bare function types.
9586 : : template <typename ManagedTokenSource>
9587 : : AST::MaybeNamedParam
9588 : 3810 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
9589 : : {
9590 : : /* Basically guess that param is named if first token is identifier or
9591 : : * underscore and second token is semicolon. This should probably have no
9592 : : * exceptions. rustc uses backtracking to parse these, but at the time of
9593 : : * writing gccrs has no backtracking capabilities. */
9594 : 3810 : const_TokenPtr current = lexer.peek_token ();
9595 : 3810 : const_TokenPtr next = lexer.peek_token (1);
9596 : :
9597 : 3810 : Identifier name;
9598 : 3810 : AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
9599 : :
9600 : 3810 : if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
9601 : : {
9602 : : // named param
9603 : 1 : name = {current};
9604 : 1 : kind = AST::MaybeNamedParam::IDENTIFIER;
9605 : 1 : lexer.skip_token (1);
9606 : : }
9607 : 3809 : else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
9608 : : {
9609 : : // wildcard param
9610 : 12 : name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
9611 : 6 : kind = AST::MaybeNamedParam::WILDCARD;
9612 : 6 : lexer.skip_token (1);
9613 : : }
9614 : :
9615 : : // parse type (required)
9616 : 3810 : std::unique_ptr<AST::Type> type = parse_type ();
9617 : 3810 : if (type == nullptr)
9618 : : {
9619 : 0 : Error error (lexer.peek_token ()->get_locus (),
9620 : : "failed to parse type in maybe named param");
9621 : 0 : add_error (std::move (error));
9622 : :
9623 : 0 : return AST::MaybeNamedParam::create_error ();
9624 : 0 : }
9625 : :
9626 : 7620 : return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
9627 : 3810 : std::move (outer_attrs), current->get_locus ());
9628 : 7620 : }
9629 : :
9630 : : /* Parses a bare function type (with the given for lifetimes for convenience -
9631 : : * does not parse them itself). */
9632 : : template <typename ManagedTokenSource>
9633 : : std::unique_ptr<AST::BareFunctionType>
9634 : 689 : Parser<ManagedTokenSource>::parse_bare_function_type (
9635 : : std::vector<AST::LifetimeParam> for_lifetimes)
9636 : : {
9637 : : // TODO: pass in for lifetime location as param
9638 : 689 : location_t best_try_locus = lexer.peek_token ()->get_locus ();
9639 : :
9640 : 689 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
9641 : :
9642 : 689 : if (!skip_token (FN_KW))
9643 : 0 : return nullptr;
9644 : :
9645 : 689 : if (!skip_token (LEFT_PAREN))
9646 : 0 : return nullptr;
9647 : :
9648 : : // parse function params, if they exist
9649 : 689 : std::vector<AST::MaybeNamedParam> params;
9650 : 689 : bool is_variadic = false;
9651 : 689 : AST::AttrVec variadic_attrs;
9652 : :
9653 : 689 : const_TokenPtr t = lexer.peek_token ();
9654 : 8061 : while (t->get_id () != RIGHT_PAREN)
9655 : : {
9656 : 4002 : AST::AttrVec temp_attrs = parse_outer_attributes ();
9657 : :
9658 : 8004 : if (lexer.peek_token ()->get_id () == ELLIPSIS)
9659 : : {
9660 : 192 : lexer.skip_token ();
9661 : 192 : is_variadic = true;
9662 : 192 : variadic_attrs = std::move (temp_attrs);
9663 : :
9664 : 192 : t = lexer.peek_token ();
9665 : :
9666 : 192 : if (t->get_id () != RIGHT_PAREN)
9667 : : {
9668 : 0 : Error error (t->get_locus (),
9669 : : "expected right parentheses after variadic in maybe "
9670 : : "named function "
9671 : : "parameters, found %qs",
9672 : : t->get_token_description ());
9673 : 0 : add_error (std::move (error));
9674 : :
9675 : 0 : return nullptr;
9676 : 0 : }
9677 : :
9678 : : break;
9679 : : }
9680 : :
9681 : 3810 : AST::MaybeNamedParam param
9682 : 3810 : = parse_maybe_named_param (std::move (temp_attrs));
9683 : 3810 : if (param.is_error ())
9684 : : {
9685 : 0 : Error error (
9686 : 0 : lexer.peek_token ()->get_locus (),
9687 : : "failed to parse maybe named param in bare function type");
9688 : 0 : add_error (std::move (error));
9689 : :
9690 : 0 : return nullptr;
9691 : 0 : }
9692 : 3810 : params.push_back (std::move (param));
9693 : :
9694 : 7620 : if (lexer.peek_token ()->get_id () != COMMA)
9695 : : break;
9696 : :
9697 : 3370 : lexer.skip_token ();
9698 : 3370 : t = lexer.peek_token ();
9699 : : }
9700 : :
9701 : 689 : if (!skip_token (RIGHT_PAREN))
9702 : 0 : return nullptr;
9703 : :
9704 : : // bare function return type, if exists
9705 : 689 : std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
9706 : 1378 : if (lexer.peek_token ()->get_id () == RETURN_TYPE)
9707 : : {
9708 : 668 : lexer.skip_token ();
9709 : :
9710 : : // parse required TypeNoBounds
9711 : 668 : return_type = parse_type_no_bounds ();
9712 : 668 : if (return_type == nullptr)
9713 : : {
9714 : 0 : Error error (lexer.peek_token ()->get_locus (),
9715 : : "failed to parse return type (type no bounds) in bare "
9716 : : "function type");
9717 : 0 : add_error (std::move (error));
9718 : :
9719 : 0 : return nullptr;
9720 : 0 : }
9721 : : }
9722 : :
9723 : : return std::unique_ptr<AST::BareFunctionType> (
9724 : 689 : new AST::BareFunctionType (std::move (for_lifetimes),
9725 : : std::move (qualifiers), std::move (params),
9726 : : is_variadic, std::move (variadic_attrs),
9727 : 689 : std::move (return_type), best_try_locus));
9728 : 1378 : }
9729 : :
9730 : : template <typename ManagedTokenSource>
9731 : : std::unique_ptr<AST::ReferenceType>
9732 : 11656 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
9733 : : {
9734 : : // parse optional lifetime
9735 : 11656 : AST::Lifetime lifetime = AST::Lifetime::elided ();
9736 : 23312 : if (lexer.peek_token ()->get_id () == LIFETIME)
9737 : : {
9738 : 1710 : auto parsed_lifetime = parse_lifetime (true);
9739 : 1710 : if (parsed_lifetime)
9740 : : {
9741 : 1710 : lifetime = parsed_lifetime.value ();
9742 : : }
9743 : : else
9744 : : {
9745 : 0 : Error error (lexer.peek_token ()->get_locus (),
9746 : : "failed to parse lifetime in reference type");
9747 : 0 : add_error (std::move (error));
9748 : :
9749 : 0 : return nullptr;
9750 : 0 : }
9751 : 1710 : }
9752 : :
9753 : 11656 : bool is_mut = false;
9754 : 23312 : if (lexer.peek_token ()->get_id () == MUT)
9755 : : {
9756 : 1573 : lexer.skip_token ();
9757 : 1573 : is_mut = true;
9758 : : }
9759 : :
9760 : : // parse type no bounds, which is required
9761 : 11656 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9762 : 11656 : if (type == nullptr)
9763 : : {
9764 : 0 : Error error (lexer.peek_token ()->get_locus (),
9765 : : "failed to parse referenced type in reference type");
9766 : 0 : add_error (std::move (error));
9767 : :
9768 : 0 : return nullptr;
9769 : 0 : }
9770 : :
9771 : : return std::unique_ptr<AST::ReferenceType> (
9772 : 34968 : new AST::ReferenceType (is_mut, std::move (type), locus,
9773 : 11656 : std::move (lifetime)));
9774 : 11656 : }
9775 : :
9776 : : // Parses a reference type (mutable or immutable, with given lifetime).
9777 : : template <typename ManagedTokenSource>
9778 : : std::unique_ptr<AST::ReferenceType>
9779 : 11656 : Parser<ManagedTokenSource>::parse_reference_type ()
9780 : : {
9781 : 11656 : auto t = lexer.peek_token ();
9782 : 11656 : auto locus = t->get_locus ();
9783 : :
9784 : 11656 : switch (t->get_id ())
9785 : : {
9786 : 11617 : case AMP:
9787 : 11617 : skip_token (AMP);
9788 : 11617 : return parse_reference_type_inner (locus);
9789 : 39 : case LOGICAL_AND:
9790 : 39 : skip_token (LOGICAL_AND);
9791 : : return std::unique_ptr<AST::ReferenceType> (
9792 : 117 : new AST::ReferenceType (false, parse_reference_type_inner (locus),
9793 : 39 : locus));
9794 : 0 : default:
9795 : 0 : rust_unreachable ();
9796 : : }
9797 : 11656 : }
9798 : :
9799 : : // Parses a raw (unsafe) pointer type.
9800 : : template <typename ManagedTokenSource>
9801 : : std::unique_ptr<AST::RawPointerType>
9802 : 7861 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
9803 : : {
9804 : 7861 : location_t locus = lexer.peek_token ()->get_locus ();
9805 : 7861 : skip_token (ASTERISK);
9806 : :
9807 : 7861 : AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
9808 : :
9809 : : // branch on next token for pointer kind info
9810 : 7861 : const_TokenPtr t = lexer.peek_token ();
9811 : 7861 : switch (t->get_id ())
9812 : : {
9813 : 1353 : case MUT:
9814 : 1353 : kind = AST::RawPointerType::MUT;
9815 : 1353 : lexer.skip_token ();
9816 : : break;
9817 : 6508 : case CONST:
9818 : 6508 : kind = AST::RawPointerType::CONST;
9819 : 6508 : lexer.skip_token ();
9820 : : break;
9821 : 0 : default:
9822 : 0 : add_error (Error (t->get_locus (),
9823 : : "unrecognised token %qs in raw pointer type",
9824 : : t->get_token_description ()));
9825 : :
9826 : 0 : return nullptr;
9827 : : }
9828 : :
9829 : : // parse type no bounds (required)
9830 : 7861 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9831 : 7861 : if (type == nullptr)
9832 : : {
9833 : 0 : Error error (lexer.peek_token ()->get_locus (),
9834 : : "failed to parse pointed type of raw pointer type");
9835 : 0 : add_error (std::move (error));
9836 : :
9837 : 0 : return nullptr;
9838 : 0 : }
9839 : :
9840 : : return std::unique_ptr<AST::RawPointerType> (
9841 : 7861 : new AST::RawPointerType (kind, std::move (type), locus));
9842 : 7861 : }
9843 : :
9844 : : /* Parses a slice or array type, depending on following arguments (as
9845 : : * lookahead is not possible). */
9846 : : template <typename ManagedTokenSource>
9847 : : std::unique_ptr<AST::TypeNoBounds>
9848 : 2416 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
9849 : : {
9850 : 2416 : location_t locus = lexer.peek_token ()->get_locus ();
9851 : 2416 : skip_token (LEFT_SQUARE);
9852 : :
9853 : : // parse inner type (required)
9854 : 2416 : std::unique_ptr<AST::Type> inner_type = parse_type ();
9855 : 2416 : if (inner_type == nullptr)
9856 : : {
9857 : 0 : Error error (lexer.peek_token ()->get_locus (),
9858 : : "failed to parse inner type in slice or array type");
9859 : 0 : add_error (std::move (error));
9860 : :
9861 : 0 : return nullptr;
9862 : 0 : }
9863 : :
9864 : : // branch on next token
9865 : 2416 : const_TokenPtr t = lexer.peek_token ();
9866 : 2416 : switch (t->get_id ())
9867 : : {
9868 : 1417 : case RIGHT_SQUARE:
9869 : : // slice type
9870 : 1417 : lexer.skip_token ();
9871 : :
9872 : 1417 : return std::unique_ptr<AST::SliceType> (
9873 : 1417 : new AST::SliceType (std::move (inner_type), locus));
9874 : 999 : case SEMICOLON:
9875 : : {
9876 : : // array type
9877 : 999 : lexer.skip_token ();
9878 : :
9879 : : // parse required array size expression
9880 : 999 : auto size = parse_anon_const ();
9881 : :
9882 : 999 : if (!size)
9883 : : {
9884 : 0 : Error error (lexer.peek_token ()->get_locus (),
9885 : : "failed to parse size expression in array type");
9886 : 0 : add_error (std::move (error));
9887 : :
9888 : 0 : return nullptr;
9889 : 0 : }
9890 : :
9891 : 999 : if (!skip_token (RIGHT_SQUARE))
9892 : : {
9893 : 0 : return nullptr;
9894 : : }
9895 : :
9896 : 999 : return std::unique_ptr<AST::ArrayType> (
9897 : 1987 : new AST::ArrayType (std::move (inner_type), std::move (*size),
9898 : 999 : locus));
9899 : 999 : }
9900 : 0 : default:
9901 : : // error
9902 : 0 : add_error (
9903 : 0 : Error (t->get_locus (),
9904 : : "unrecognised token %qs in slice or array type after inner type",
9905 : : t->get_token_description ()));
9906 : :
9907 : 0 : return nullptr;
9908 : : }
9909 : 2416 : }
9910 : :
9911 : : // Parses a type, taking into account type boundary disambiguation.
9912 : : template <typename ManagedTokenSource>
9913 : : std::unique_ptr<AST::TypeNoBounds>
9914 : 29153 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
9915 : : {
9916 : 29153 : const_TokenPtr t = lexer.peek_token ();
9917 : 29153 : switch (t->get_id ())
9918 : : {
9919 : 4 : case EXCLAM:
9920 : : // never type - can't be macro as no path beforehand
9921 : 4 : lexer.skip_token ();
9922 : 4 : return std::unique_ptr<AST::NeverType> (
9923 : 4 : new AST::NeverType (t->get_locus ()));
9924 : 1232 : case LEFT_SQUARE:
9925 : : // slice type or array type - requires further disambiguation
9926 : 1232 : return parse_slice_or_array_type ();
9927 : 22 : case LEFT_SHIFT:
9928 : : case LEFT_ANGLE:
9929 : : {
9930 : : // qualified path in type
9931 : 22 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
9932 : 22 : if (path.is_error ())
9933 : : {
9934 : 0 : Error error (t->get_locus (),
9935 : : "failed to parse qualified path in type");
9936 : 0 : add_error (std::move (error));
9937 : :
9938 : 0 : return nullptr;
9939 : 0 : }
9940 : 22 : return std::unique_ptr<AST::QualifiedPathInType> (
9941 : 22 : new AST::QualifiedPathInType (std::move (path)));
9942 : 22 : }
9943 : 189 : case UNDERSCORE:
9944 : : // inferred type
9945 : 189 : lexer.skip_token ();
9946 : 189 : return std::unique_ptr<AST::InferredType> (
9947 : 189 : new AST::InferredType (t->get_locus ()));
9948 : 4458 : case ASTERISK:
9949 : : // raw pointer type
9950 : 4458 : return parse_raw_pointer_type ();
9951 : 44 : case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
9952 : : case LOGICAL_AND:
9953 : : // reference type
9954 : 44 : return parse_reference_type ();
9955 : 0 : case LIFETIME:
9956 : : /* probably a lifetime bound, so probably type param bounds in
9957 : : * TraitObjectType. this is not allowed, but detection here for error
9958 : : * message */
9959 : 0 : add_error (Error (t->get_locus (),
9960 : : "lifetime bounds (i.e. in type param bounds, in "
9961 : : "TraitObjectType) are not allowed as TypeNoBounds"));
9962 : :
9963 : 0 : return nullptr;
9964 : 22707 : case IDENTIFIER:
9965 : : case SUPER:
9966 : : case SELF:
9967 : : case SELF_ALIAS:
9968 : : case CRATE:
9969 : : case DOLLAR_SIGN:
9970 : : case SCOPE_RESOLUTION:
9971 : : {
9972 : : // macro invocation or type path - requires further disambiguation.
9973 : : /* for parsing path component of each rule, perhaps parse it as a
9974 : : * typepath and attempt conversion to simplepath if a trailing '!' is
9975 : : * found */
9976 : : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9977 : : * with it, it is exactly the same as a TypePath syntactically, so
9978 : : * this is a syntactical ambiguity. As such, the parser will parse it
9979 : : * as a TypePath. This, however, does not prevent TraitObjectType from
9980 : : * starting with a typepath. */
9981 : :
9982 : : // parse path as type path
9983 : 22707 : AST::TypePath path = parse_type_path ();
9984 : 22707 : if (path.is_error ())
9985 : : {
9986 : 0 : Error error (
9987 : : t->get_locus (),
9988 : : "failed to parse path as first component of type no bounds");
9989 : 0 : add_error (std::move (error));
9990 : :
9991 : 0 : return nullptr;
9992 : 0 : }
9993 : 22707 : location_t locus = path.get_locus ();
9994 : :
9995 : : // branch on next token
9996 : 22707 : t = lexer.peek_token ();
9997 : 22707 : switch (t->get_id ())
9998 : : {
9999 : 1 : case EXCLAM:
10000 : : {
10001 : : // macro invocation
10002 : : // convert to simple path
10003 : 1 : AST::SimplePath macro_path = path.as_simple_path ();
10004 : 1 : if (macro_path.is_empty ())
10005 : : {
10006 : 0 : Error error (t->get_locus (),
10007 : : "failed to parse simple path in macro "
10008 : : "invocation (for type)");
10009 : 0 : add_error (std::move (error));
10010 : :
10011 : 0 : return nullptr;
10012 : 0 : }
10013 : :
10014 : 1 : lexer.skip_token ();
10015 : :
10016 : 1 : AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
10017 : :
10018 : 2 : return AST::MacroInvocation::Regular (
10019 : 2 : AST::MacroInvocData (std::move (macro_path),
10020 : : std::move (tok_tree)),
10021 : 1 : {}, locus);
10022 : 2 : }
10023 : 22706 : default:
10024 : : // assume that this is a type path and not an error
10025 : 22706 : return std::unique_ptr<AST::TypePath> (
10026 : 22706 : new AST::TypePath (std::move (path)));
10027 : : }
10028 : 22707 : }
10029 : 303 : case LEFT_PAREN:
10030 : : /* tuple type or parenthesised type - requires further disambiguation
10031 : : * (the usual). ok apparently can be a parenthesised TraitBound too, so
10032 : : * could be TraitObjectTypeOneBound */
10033 : 303 : return parse_paren_prefixed_type_no_bounds ();
10034 : 2 : case FOR:
10035 : : case ASYNC:
10036 : : case CONST:
10037 : : case UNSAFE:
10038 : : case EXTERN_KW:
10039 : : case FN_KW:
10040 : : // bare function type (with no for lifetimes)
10041 : 2 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
10042 : 30 : case IMPL:
10043 : 30 : lexer.skip_token ();
10044 : 60 : if (lexer.peek_token ()->get_id () == LIFETIME)
10045 : : {
10046 : : /* cannot be one bound because lifetime prevents it from being
10047 : : * traitbound not allowed as type no bounds, only here for error
10048 : : * message */
10049 : 0 : Error error (
10050 : 0 : lexer.peek_token ()->get_locus (),
10051 : : "lifetime (probably lifetime bound, in type param "
10052 : : "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
10053 : 0 : add_error (std::move (error));
10054 : :
10055 : 0 : return nullptr;
10056 : 0 : }
10057 : : else
10058 : : {
10059 : : // should be trait bound, so parse trait bound
10060 : 30 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
10061 : 30 : if (initial_bound == nullptr)
10062 : : {
10063 : 0 : Error error (lexer.peek_token ()->get_locus (),
10064 : : "failed to parse ImplTraitTypeOneBound bound");
10065 : 0 : add_error (std::move (error));
10066 : :
10067 : 0 : return nullptr;
10068 : 0 : }
10069 : :
10070 : 30 : location_t locus = t->get_locus ();
10071 : :
10072 : : // ensure not a trait with multiple bounds
10073 : 30 : t = lexer.peek_token ();
10074 : 30 : if (t->get_id () == PLUS)
10075 : : {
10076 : 0 : Error error (t->get_locus (),
10077 : : "plus after trait bound means an ImplTraitType, "
10078 : : "which is not allowed as a TypeNoBounds");
10079 : 0 : add_error (std::move (error));
10080 : :
10081 : 0 : return nullptr;
10082 : 0 : }
10083 : :
10084 : 30 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
10085 : 30 : new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
10086 : 30 : }
10087 : 162 : case DYN:
10088 : : case QUESTION_MARK:
10089 : : {
10090 : : // either TraitObjectTypeOneBound
10091 : 162 : bool has_dyn = false;
10092 : 162 : if (t->get_id () == DYN)
10093 : : {
10094 : 162 : lexer.skip_token ();
10095 : 162 : has_dyn = true;
10096 : : }
10097 : :
10098 : 324 : if (lexer.peek_token ()->get_id () == LIFETIME)
10099 : : {
10100 : : /* means that cannot be TraitObjectTypeOneBound - so here for
10101 : : * error message */
10102 : 0 : Error error (lexer.peek_token ()->get_locus (),
10103 : : "lifetime as bound in TraitObjectTypeOneBound "
10104 : : "is not allowed, so cannot be TypeNoBounds");
10105 : 0 : add_error (std::move (error));
10106 : :
10107 : 0 : return nullptr;
10108 : 0 : }
10109 : :
10110 : : // should be trait bound, so parse trait bound
10111 : 162 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
10112 : 162 : if (initial_bound == nullptr)
10113 : : {
10114 : 0 : Error error (
10115 : 0 : lexer.peek_token ()->get_locus (),
10116 : : "failed to parse TraitObjectTypeOneBound initial bound");
10117 : 0 : add_error (std::move (error));
10118 : :
10119 : 0 : return nullptr;
10120 : 0 : }
10121 : :
10122 : 162 : location_t locus = t->get_locus ();
10123 : :
10124 : : // detect error with plus as next token
10125 : 162 : t = lexer.peek_token ();
10126 : 162 : if (t->get_id () == PLUS)
10127 : : {
10128 : 0 : Error error (t->get_locus (),
10129 : : "plus after trait bound means a TraitObjectType, "
10130 : : "which is not allowed as a TypeNoBounds");
10131 : 0 : add_error (std::move (error));
10132 : :
10133 : 0 : return nullptr;
10134 : 0 : }
10135 : :
10136 : : // convert trait bound to value object
10137 : 162 : AST::TraitBound value_bound (*initial_bound);
10138 : :
10139 : 162 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10140 : 324 : new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
10141 : 162 : has_dyn));
10142 : 162 : }
10143 : 0 : default:
10144 : 0 : add_error (Error (t->get_locus (),
10145 : : "unrecognised token %qs in type no bounds",
10146 : : t->get_token_description ()));
10147 : :
10148 : 0 : return nullptr;
10149 : : }
10150 : 29153 : }
10151 : :
10152 : : // Parses a type no bounds beginning with '('.
10153 : : template <typename ManagedTokenSource>
10154 : : std::unique_ptr<AST::TypeNoBounds>
10155 : 303 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
10156 : : {
10157 : : /* NOTE: this could probably be parsed without the HACK solution of
10158 : : * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
10159 : :
10160 : : /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
10161 : : * considered a trait bound, not a parenthesised type, so that it can still
10162 : : * be used in type param bounds. */
10163 : :
10164 : 303 : location_t left_paren_locus = lexer.peek_token ()->get_locus ();
10165 : :
10166 : : // skip left delim
10167 : 303 : lexer.skip_token ();
10168 : : /* while next token isn't close delim, parse comma-separated types, saving
10169 : : * whether trailing comma happens */
10170 : 303 : const_TokenPtr t = lexer.peek_token ();
10171 : 303 : bool trailing_comma = true;
10172 : 303 : std::vector<std::unique_ptr<AST::Type>> types;
10173 : :
10174 : 933 : while (t->get_id () != RIGHT_PAREN)
10175 : : {
10176 : 647 : std::unique_ptr<AST::Type> type = parse_type ();
10177 : 647 : if (type == nullptr)
10178 : : {
10179 : 0 : Error error (t->get_locus (),
10180 : : "failed to parse type inside parentheses (probably "
10181 : : "tuple or parenthesised)");
10182 : 0 : add_error (std::move (error));
10183 : :
10184 : 0 : return nullptr;
10185 : 0 : }
10186 : 647 : types.push_back (std::move (type));
10187 : :
10188 : 647 : t = lexer.peek_token ();
10189 : 647 : if (t->get_id () != COMMA)
10190 : : {
10191 : 17 : trailing_comma = false;
10192 : : break;
10193 : : }
10194 : 630 : lexer.skip_token ();
10195 : :
10196 : 630 : t = lexer.peek_token ();
10197 : : }
10198 : :
10199 : 303 : if (!skip_token (RIGHT_PAREN))
10200 : : {
10201 : 0 : return nullptr;
10202 : : }
10203 : :
10204 : : // if only one type and no trailing comma, then not a tuple type
10205 : 303 : if (types.size () == 1 && !trailing_comma)
10206 : : {
10207 : : // must be a TraitObjectType (with more than one bound)
10208 : 22 : if (lexer.peek_token ()->get_id () == PLUS)
10209 : : {
10210 : : // error - this is not allowed for type no bounds
10211 : 0 : Error error (lexer.peek_token ()->get_locus (),
10212 : : "plus (implying TraitObjectType as type param "
10213 : : "bounds) is not allowed in type no bounds");
10214 : 0 : add_error (std::move (error));
10215 : :
10216 : 0 : return nullptr;
10217 : 0 : }
10218 : : else
10219 : : {
10220 : : // release vector pointer
10221 : 11 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
10222 : : /* HACK: attempt to convert to trait bound. if fails, parenthesised
10223 : : * type */
10224 : 11 : std::unique_ptr<AST::TraitBound> converted_bound (
10225 : 11 : released_ptr->to_trait_bound (true));
10226 : 11 : if (converted_bound == nullptr)
10227 : : {
10228 : : // parenthesised type
10229 : 11 : return std::unique_ptr<AST::ParenthesisedType> (
10230 : 11 : new AST::ParenthesisedType (std::move (released_ptr),
10231 : 11 : left_paren_locus));
10232 : : }
10233 : : else
10234 : : {
10235 : : // trait object type (one bound)
10236 : :
10237 : : // get value semantics trait bound
10238 : 0 : AST::TraitBound value_bound (*converted_bound);
10239 : :
10240 : 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10241 : 0 : new AST::TraitObjectTypeOneBound (value_bound,
10242 : 0 : left_paren_locus));
10243 : 0 : }
10244 : 11 : }
10245 : : }
10246 : : else
10247 : : {
10248 : 292 : return std::unique_ptr<AST::TupleType> (
10249 : 292 : new AST::TupleType (std::move (types), left_paren_locus));
10250 : : }
10251 : : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
10252 : : * lost somehow */
10253 : 303 : }
10254 : :
10255 : : /* Parses a literal pattern or range pattern. Assumes that literals passed in
10256 : : * are valid range pattern bounds. Do not pass in paths in expressions, for
10257 : : * instance. */
10258 : : template <typename ManagedTokenSource>
10259 : : std::unique_ptr<AST::Pattern>
10260 : 45625 : Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
10261 : : {
10262 : 45625 : const_TokenPtr range_lower = lexer.peek_token ();
10263 : 45625 : AST::Literal::LitType type = AST::Literal::STRING;
10264 : 45625 : bool has_minus = false;
10265 : :
10266 : : // get lit type
10267 : 45625 : switch (range_lower->get_id ())
10268 : : {
10269 : 98 : case CHAR_LITERAL:
10270 : 98 : type = AST::Literal::CHAR;
10271 : 98 : lexer.skip_token ();
10272 : : break;
10273 : 87 : case BYTE_CHAR_LITERAL:
10274 : 87 : type = AST::Literal::BYTE;
10275 : 87 : lexer.skip_token ();
10276 : : break;
10277 : 45413 : case INT_LITERAL:
10278 : 45413 : type = AST::Literal::INT;
10279 : 45413 : lexer.skip_token ();
10280 : : break;
10281 : 1 : case FLOAT_LITERAL:
10282 : 1 : type = AST::Literal::FLOAT;
10283 : 1 : lexer.skip_token ();
10284 : : break;
10285 : 26 : case MINUS:
10286 : : // branch on next token
10287 : 26 : range_lower = lexer.peek_token (1);
10288 : 26 : switch (range_lower->get_id ())
10289 : : {
10290 : 24 : case INT_LITERAL:
10291 : 24 : type = AST::Literal::INT;
10292 : 24 : has_minus = true;
10293 : 24 : lexer.skip_token (1);
10294 : 24 : break;
10295 : 2 : case FLOAT_LITERAL:
10296 : 2 : type = AST::Literal::FLOAT;
10297 : 2 : has_minus = true;
10298 : 2 : lexer.skip_token (1);
10299 : 2 : break;
10300 : 0 : default:
10301 : 0 : add_error (Error (range_lower->get_locus (),
10302 : : "token type %qs cannot be parsed as range pattern "
10303 : : "bound or literal after minus symbol",
10304 : : range_lower->get_token_description ()));
10305 : :
10306 : 0 : return nullptr;
10307 : : }
10308 : : break;
10309 : 0 : default:
10310 : 0 : add_error (
10311 : 0 : Error (range_lower->get_locus (),
10312 : : "token type %qs cannot be parsed as range pattern bound",
10313 : : range_lower->get_token_description ()));
10314 : :
10315 : 0 : return nullptr;
10316 : : }
10317 : :
10318 : 45625 : const_TokenPtr next = lexer.peek_token ();
10319 : 45625 : if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
10320 : 91113 : || next->get_id () == DOT_DOT)
10321 : : {
10322 : 161 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
10323 : : // range pattern
10324 : 161 : lexer.skip_token ();
10325 : 161 : std::unique_ptr<AST::RangePatternBound> lower (
10326 : 322 : new AST::RangePatternBoundLiteral (
10327 : 483 : AST::Literal (range_lower->get_str (), type,
10328 : : PrimitiveCoreType::CORETYPE_UNKNOWN),
10329 : : range_lower->get_locus (), has_minus));
10330 : :
10331 : 161 : std::unique_ptr<AST::RangePatternBound> upper
10332 : : = parse_range_pattern_bound ();
10333 : 161 : if (upper == nullptr)
10334 : : {
10335 : 0 : Error error (next->get_locus (),
10336 : : "failed to parse range pattern bound in range pattern");
10337 : 0 : add_error (std::move (error));
10338 : :
10339 : 0 : return nullptr;
10340 : 0 : }
10341 : :
10342 : 161 : return std::unique_ptr<AST::RangePattern> (
10343 : 161 : new AST::RangePattern (std::move (lower), std::move (upper), kind,
10344 : 161 : range_lower->get_locus ()));
10345 : 161 : }
10346 : : else
10347 : : {
10348 : : // literal pattern
10349 : 45464 : return std::unique_ptr<AST::LiteralPattern> (
10350 : 140091 : new AST::LiteralPattern (range_lower->get_str (), type,
10351 : : range_lower->get_locus (),
10352 : 45464 : range_lower->get_type_hint (), has_minus));
10353 : : }
10354 : 45625 : }
10355 : :
10356 : : // Parses a range pattern bound (value only).
10357 : : template <typename ManagedTokenSource>
10358 : : std::unique_ptr<AST::RangePatternBound>
10359 : 169 : Parser<ManagedTokenSource>::parse_range_pattern_bound ()
10360 : : {
10361 : 169 : const_TokenPtr range_lower = lexer.peek_token ();
10362 : 169 : location_t range_lower_locus = range_lower->get_locus ();
10363 : :
10364 : : // get lit type
10365 : 169 : switch (range_lower->get_id ())
10366 : : {
10367 : 52 : case CHAR_LITERAL:
10368 : 52 : lexer.skip_token ();
10369 : 52 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10370 : 104 : new AST::RangePatternBoundLiteral (
10371 : 208 : AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
10372 : : range_lower->get_type_hint ()),
10373 : 52 : range_lower_locus));
10374 : 35 : case BYTE_CHAR_LITERAL:
10375 : 35 : lexer.skip_token ();
10376 : 35 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10377 : 70 : new AST::RangePatternBoundLiteral (
10378 : 140 : AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
10379 : : range_lower->get_type_hint ()),
10380 : 35 : range_lower_locus));
10381 : 55 : case INT_LITERAL:
10382 : 55 : lexer.skip_token ();
10383 : 55 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10384 : 110 : new AST::RangePatternBoundLiteral (
10385 : 195 : AST::Literal (range_lower->get_str (), AST::Literal::INT,
10386 : : range_lower->get_type_hint ()),
10387 : 55 : range_lower_locus));
10388 : 0 : case FLOAT_LITERAL:
10389 : 0 : lexer.skip_token ();
10390 : 0 : rust_debug ("warning: used deprecated float range pattern bound");
10391 : 0 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10392 : 0 : new AST::RangePatternBoundLiteral (
10393 : 0 : AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10394 : : range_lower->get_type_hint ()),
10395 : 0 : range_lower_locus));
10396 : 12 : case MINUS:
10397 : : // branch on next token
10398 : 12 : range_lower = lexer.peek_token (1);
10399 : 12 : switch (range_lower->get_id ())
10400 : : {
10401 : 10 : case INT_LITERAL:
10402 : 10 : lexer.skip_token (1);
10403 : 10 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10404 : 20 : new AST::RangePatternBoundLiteral (
10405 : 30 : AST::Literal (range_lower->get_str (), AST::Literal::INT,
10406 : : range_lower->get_type_hint ()),
10407 : 10 : range_lower_locus, true));
10408 : 2 : case FLOAT_LITERAL:
10409 : 2 : lexer.skip_token (1);
10410 : 2 : rust_debug ("warning: used deprecated float range pattern bound");
10411 : 2 : return std::unique_ptr<AST::RangePatternBoundLiteral> (
10412 : 4 : new AST::RangePatternBoundLiteral (
10413 : 8 : AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10414 : : range_lower->get_type_hint ()),
10415 : 2 : range_lower_locus, true));
10416 : 0 : default:
10417 : 0 : add_error (Error (range_lower->get_locus (),
10418 : : "token type %qs cannot be parsed as range pattern "
10419 : : "bound after minus symbol",
10420 : : range_lower->get_token_description ()));
10421 : :
10422 : 0 : return nullptr;
10423 : : }
10424 : 15 : case IDENTIFIER:
10425 : : case SUPER:
10426 : : case SELF:
10427 : : case SELF_ALIAS:
10428 : : case CRATE:
10429 : : case SCOPE_RESOLUTION:
10430 : : case DOLLAR_SIGN:
10431 : : {
10432 : : // path in expression
10433 : 15 : AST::PathInExpression path = parse_path_in_expression ();
10434 : 15 : if (path.is_error ())
10435 : : {
10436 : 0 : Error error (
10437 : : range_lower->get_locus (),
10438 : : "failed to parse path in expression range pattern bound");
10439 : 0 : add_error (std::move (error));
10440 : :
10441 : 0 : return nullptr;
10442 : 0 : }
10443 : 15 : return std::unique_ptr<AST::RangePatternBoundPath> (
10444 : 15 : new AST::RangePatternBoundPath (std::move (path)));
10445 : 15 : }
10446 : 0 : case LEFT_SHIFT:
10447 : : case LEFT_ANGLE:
10448 : : {
10449 : : // qualified path in expression
10450 : 0 : AST::QualifiedPathInExpression path
10451 : : = parse_qualified_path_in_expression ();
10452 : 0 : if (path.is_error ())
10453 : : {
10454 : 0 : Error error (range_lower->get_locus (),
10455 : : "failed to parse qualified path in expression range "
10456 : : "pattern bound");
10457 : 0 : add_error (std::move (error));
10458 : :
10459 : 0 : return nullptr;
10460 : 0 : }
10461 : 0 : return std::unique_ptr<AST::RangePatternBoundQualPath> (
10462 : 0 : new AST::RangePatternBoundQualPath (std::move (path)));
10463 : 0 : }
10464 : 0 : default:
10465 : 0 : add_error (
10466 : 0 : Error (range_lower->get_locus (),
10467 : : "token type %qs cannot be parsed as range pattern bound",
10468 : : range_lower->get_token_description ()));
10469 : :
10470 : 0 : return nullptr;
10471 : : }
10472 : 169 : }
10473 : :
10474 : : template <typename ManagedTokenSource>
10475 : : std::unique_ptr<AST::Pattern>
10476 : 106859 : Parser<ManagedTokenSource>::parse_pattern ()
10477 : : {
10478 : 106859 : location_t start_locus = lexer.peek_token ()->get_locus ();
10479 : :
10480 : : /* skip optional starting pipe */
10481 : 106859 : maybe_skip_token (PIPE);
10482 : :
10483 : 106859 : auto first = parse_pattern_no_alt ();
10484 : :
10485 : 213718 : if (lexer.peek_token ()->get_id () != PIPE)
10486 : : /* no alternates */
10487 : 106615 : return first;
10488 : :
10489 : 244 : std::vector<std::unique_ptr<AST::Pattern>> alts;
10490 : 244 : if (first != nullptr)
10491 : 243 : alts.push_back (std::move (first));
10492 : :
10493 : : do
10494 : : {
10495 : 299 : lexer.skip_token ();
10496 : 299 : auto follow = parse_pattern_no_alt ();
10497 : 299 : if (follow != nullptr)
10498 : 299 : alts.push_back (std::move (follow));
10499 : 299 : }
10500 : :
10501 : 598 : while (lexer.peek_token ()->get_id () == PIPE);
10502 : :
10503 : 244 : if (alts.empty ())
10504 : 0 : return nullptr;
10505 : :
10506 : : /* alternates */
10507 : : return std::unique_ptr<AST::Pattern> (
10508 : 244 : new AST::AltPattern (std::move (alts), start_locus));
10509 : 106859 : }
10510 : :
10511 : : // Parses a pattern without alternates ('|')
10512 : : // (will further disambiguate any pattern).
10513 : : template <typename ManagedTokenSource>
10514 : : std::unique_ptr<AST::Pattern>
10515 : 107723 : Parser<ManagedTokenSource>::parse_pattern_no_alt ()
10516 : : {
10517 : 107723 : const_TokenPtr t = lexer.peek_token ();
10518 : 107723 : switch (t->get_id ())
10519 : : {
10520 : 31 : case TRUE_LITERAL:
10521 : 31 : lexer.skip_token ();
10522 : 31 : return std::unique_ptr<AST::LiteralPattern> (
10523 : 93 : new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
10524 : : AST::Literal::BOOL, t->get_locus (),
10525 : 31 : t->get_type_hint ()));
10526 : 23 : case FALSE_LITERAL:
10527 : 23 : lexer.skip_token ();
10528 : 23 : return std::unique_ptr<AST::LiteralPattern> (
10529 : 69 : new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
10530 : : AST::Literal::BOOL, t->get_locus (),
10531 : 23 : t->get_type_hint ()));
10532 : 45599 : case CHAR_LITERAL:
10533 : : case BYTE_CHAR_LITERAL:
10534 : : case INT_LITERAL:
10535 : : case FLOAT_LITERAL:
10536 : 45599 : return parse_literal_or_range_pattern ();
10537 : 4 : case STRING_LITERAL:
10538 : 4 : lexer.skip_token ();
10539 : 4 : return std::unique_ptr<AST::LiteralPattern> (
10540 : 16 : new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
10541 : 4 : t->get_locus (), t->get_type_hint ()));
10542 : 0 : case BYTE_STRING_LITERAL:
10543 : 0 : lexer.skip_token ();
10544 : 0 : return std::unique_ptr<AST::LiteralPattern> (
10545 : 0 : new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
10546 : 0 : t->get_locus (), t->get_type_hint ()));
10547 : 0 : case RAW_STRING_LITERAL:
10548 : 0 : lexer.skip_token ();
10549 : 0 : return std::unique_ptr<AST::LiteralPattern> (
10550 : 0 : new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
10551 : 0 : t->get_locus (), t->get_type_hint ()));
10552 : : // raw string and raw byte string literals too if they are readded to
10553 : : // lexer
10554 : 26 : case MINUS:
10555 : 52 : if (lexer.peek_token (1)->get_id () == INT_LITERAL)
10556 : : {
10557 : 24 : return parse_literal_or_range_pattern ();
10558 : : }
10559 : 4 : else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
10560 : : {
10561 : 2 : return parse_literal_or_range_pattern ();
10562 : : }
10563 : : else
10564 : : {
10565 : 0 : Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
10566 : : "did you forget an integer literal");
10567 : 0 : add_error (std::move (error));
10568 : :
10569 : 0 : return nullptr;
10570 : 0 : }
10571 : 5355 : case UNDERSCORE:
10572 : 5355 : lexer.skip_token ();
10573 : 5355 : return std::unique_ptr<AST::WildcardPattern> (
10574 : 5355 : new AST::WildcardPattern (t->get_locus ()));
10575 : 4 : case DOT_DOT:
10576 : 4 : lexer.skip_token ();
10577 : 4 : return std::unique_ptr<AST::RestPattern> (
10578 : 4 : new AST::RestPattern (t->get_locus ()));
10579 : 2027 : case REF:
10580 : : case MUT:
10581 : 2027 : return parse_identifier_pattern ();
10582 : 51476 : case IDENTIFIER:
10583 : : /* if identifier with no scope resolution afterwards, identifier
10584 : : * pattern. if scope resolution afterwards, path pattern (or range
10585 : : * pattern or struct pattern or tuple struct pattern) or macro
10586 : : * invocation */
10587 : 51476 : return parse_ident_leading_pattern ();
10588 : 89 : case AMP:
10589 : : case LOGICAL_AND:
10590 : : // reference pattern
10591 : 89 : return parse_reference_pattern ();
10592 : 2985 : case LEFT_PAREN:
10593 : : // tuple pattern or grouped pattern
10594 : 2985 : return parse_grouped_or_tuple_pattern ();
10595 : 94 : case LEFT_SQUARE:
10596 : : // slice pattern
10597 : 94 : return parse_slice_pattern ();
10598 : 0 : case LEFT_SHIFT:
10599 : : case LEFT_ANGLE:
10600 : : {
10601 : : // qualified path in expression or qualified range pattern bound
10602 : 0 : AST::QualifiedPathInExpression path
10603 : : = parse_qualified_path_in_expression ();
10604 : :
10605 : 0 : if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
10606 : 0 : || lexer.peek_token ()->get_id () == ELLIPSIS
10607 : 0 : || lexer.peek_token ()->get_id () == DOT_DOT)
10608 : : {
10609 : : // qualified range pattern bound, so parse rest of range pattern
10610 : : AST::RangeKind kind
10611 : 0 : = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
10612 : 0 : lexer.skip_token ();
10613 : :
10614 : 0 : std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
10615 : 0 : new AST::RangePatternBoundQualPath (std::move (path)));
10616 : 0 : std::unique_ptr<AST::RangePatternBound> upper_bound
10617 : : = parse_range_pattern_bound ();
10618 : :
10619 : 0 : return std::unique_ptr<AST::RangePattern> (
10620 : 0 : new AST::RangePattern (std::move (lower_bound),
10621 : : std::move (upper_bound), kind,
10622 : 0 : t->get_locus ()));
10623 : 0 : }
10624 : : else
10625 : : {
10626 : : // just qualified path in expression
10627 : 0 : return std::unique_ptr<AST::QualifiedPathInExpression> (
10628 : 0 : new AST::QualifiedPathInExpression (std::move (path)));
10629 : : }
10630 : 0 : }
10631 : 9 : case SUPER:
10632 : : case SELF:
10633 : : case SELF_ALIAS:
10634 : : case CRATE:
10635 : : case SCOPE_RESOLUTION:
10636 : : case DOLLAR_SIGN:
10637 : : {
10638 : : // path in expression or range pattern bound
10639 : 9 : AST::PathInExpression path = parse_path_in_expression ();
10640 : :
10641 : 9 : const_TokenPtr next = lexer.peek_token ();
10642 : 9 : switch (next->get_id ())
10643 : : {
10644 : 0 : case DOT_DOT_EQ:
10645 : : case DOT_DOT:
10646 : : case ELLIPSIS:
10647 : : {
10648 : : // qualified range pattern bound, so parse rest of range pattern
10649 : 0 : AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
10650 : 0 : lexer.skip_token ();
10651 : :
10652 : 0 : std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
10653 : 0 : new AST::RangePatternBoundPath (std::move (path)));
10654 : 0 : std::unique_ptr<AST::RangePatternBound> upper_bound
10655 : : = parse_range_pattern_bound ();
10656 : :
10657 : 0 : return std::unique_ptr<AST::RangePattern> (
10658 : 0 : new AST::RangePattern (std::move (lower_bound),
10659 : : std::move (upper_bound), kind,
10660 : 0 : next->get_locus ()));
10661 : 0 : }
10662 : 0 : case EXCLAM:
10663 : 0 : return parse_macro_invocation_partial (std::move (path),
10664 : 0 : AST::AttrVec ());
10665 : 0 : case LEFT_PAREN:
10666 : : {
10667 : : // tuple struct
10668 : 0 : lexer.skip_token ();
10669 : :
10670 : : // parse items
10671 : 0 : std::unique_ptr<AST::TupleStructItems> items
10672 : : = parse_tuple_struct_items ();
10673 : 0 : if (items == nullptr)
10674 : : {
10675 : 0 : Error error (lexer.peek_token ()->get_locus (),
10676 : : "failed to parse tuple struct items");
10677 : 0 : add_error (std::move (error));
10678 : :
10679 : 0 : return nullptr;
10680 : 0 : }
10681 : :
10682 : 0 : if (!skip_token (RIGHT_PAREN))
10683 : : {
10684 : 0 : return nullptr;
10685 : : }
10686 : :
10687 : 0 : return std::unique_ptr<AST::TupleStructPattern> (
10688 : 0 : new AST::TupleStructPattern (std::move (path),
10689 : 0 : std::move (items)));
10690 : 0 : }
10691 : 1 : case LEFT_CURLY:
10692 : : {
10693 : : // struct
10694 : 1 : lexer.skip_token ();
10695 : :
10696 : : // parse elements (optional)
10697 : 1 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
10698 : :
10699 : 1 : if (!skip_token (RIGHT_CURLY))
10700 : : {
10701 : 0 : return nullptr;
10702 : : }
10703 : :
10704 : 1 : return std::unique_ptr<AST::StructPattern> (
10705 : 2 : new AST::StructPattern (std::move (path), t->get_locus (),
10706 : 1 : std::move (elems)));
10707 : 1 : }
10708 : 8 : default:
10709 : : // assume path in expression
10710 : 8 : return std::unique_ptr<AST::PathInExpression> (
10711 : 8 : new AST::PathInExpression (std::move (path)));
10712 : : }
10713 : 9 : }
10714 : 1 : default:
10715 : 1 : add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
10716 : : t->get_token_description ()));
10717 : :
10718 : 1 : return nullptr;
10719 : : }
10720 : 107723 : }
10721 : :
10722 : : // Parses a single or double reference pattern.
10723 : : template <typename ManagedTokenSource>
10724 : : std::unique_ptr<AST::ReferencePattern>
10725 : 89 : Parser<ManagedTokenSource>::parse_reference_pattern ()
10726 : : {
10727 : : // parse double or single ref
10728 : 89 : bool is_double_ref = false;
10729 : 89 : const_TokenPtr t = lexer.peek_token ();
10730 : 89 : switch (t->get_id ())
10731 : : {
10732 : 77 : case AMP:
10733 : : // still false
10734 : 77 : lexer.skip_token ();
10735 : : break;
10736 : 12 : case LOGICAL_AND:
10737 : 12 : is_double_ref = true;
10738 : 12 : lexer.skip_token ();
10739 : : break;
10740 : 0 : default:
10741 : 0 : add_error (Error (t->get_locus (),
10742 : : "unexpected token %qs in reference pattern",
10743 : : t->get_token_description ()));
10744 : :
10745 : 0 : return nullptr;
10746 : : }
10747 : :
10748 : : // parse mut (if it exists)
10749 : 89 : bool is_mut = false;
10750 : 178 : if (lexer.peek_token ()->get_id () == MUT)
10751 : : {
10752 : 4 : is_mut = true;
10753 : 4 : lexer.skip_token ();
10754 : : }
10755 : :
10756 : : // parse pattern to get reference of (required)
10757 : 89 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
10758 : 89 : if (pattern == nullptr)
10759 : : {
10760 : 0 : Error error (lexer.peek_token ()->get_locus (),
10761 : : "failed to parse pattern in reference pattern");
10762 : 0 : add_error (std::move (error));
10763 : :
10764 : : // skip somewhere?
10765 : 0 : return nullptr;
10766 : 0 : }
10767 : :
10768 : : return std::unique_ptr<AST::ReferencePattern> (
10769 : 89 : new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
10770 : 89 : t->get_locus ()));
10771 : 89 : }
10772 : :
10773 : : /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
10774 : : * only a single element with no commas. */
10775 : : template <typename ManagedTokenSource>
10776 : : std::unique_ptr<AST::Pattern>
10777 : 2985 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
10778 : : {
10779 : 2985 : location_t paren_locus = lexer.peek_token ()->get_locus ();
10780 : 2985 : skip_token (LEFT_PAREN);
10781 : :
10782 : : // detect '..' token (ranged with no lower range)
10783 : 5970 : if (lexer.peek_token ()->get_id () == DOT_DOT)
10784 : : {
10785 : 0 : lexer.skip_token ();
10786 : :
10787 : : // parse new patterns while next token is a comma
10788 : 0 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
10789 : :
10790 : 0 : const_TokenPtr t = lexer.peek_token ();
10791 : 0 : while (t->get_id () == COMMA)
10792 : : {
10793 : 0 : lexer.skip_token ();
10794 : :
10795 : : // break if next token is ')'
10796 : 0 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10797 : : {
10798 : : break;
10799 : : }
10800 : :
10801 : : // parse pattern, which is required
10802 : 0 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10803 : 0 : if (pattern == nullptr)
10804 : : {
10805 : 0 : Error error (
10806 : 0 : lexer.peek_token ()->get_locus (),
10807 : : "failed to parse pattern inside ranged tuple pattern");
10808 : 0 : add_error (std::move (error));
10809 : :
10810 : : // skip somewhere?
10811 : 0 : return nullptr;
10812 : 0 : }
10813 : 0 : patterns.push_back (std::move (pattern));
10814 : :
10815 : 0 : t = lexer.peek_token ();
10816 : : }
10817 : :
10818 : 0 : if (!skip_token (RIGHT_PAREN))
10819 : : {
10820 : : // skip somewhere?
10821 : 0 : return nullptr;
10822 : : }
10823 : :
10824 : : // create tuple pattern items with only upper pattern items
10825 : 0 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
10826 : 0 : new AST::TuplePatternItemsHasRest (
10827 : 0 : std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
10828 : 0 : return std::unique_ptr<AST::TuplePattern> (
10829 : 0 : new AST::TuplePattern (std::move (items), paren_locus));
10830 : 0 : }
10831 : 5970 : else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10832 : : {
10833 : 23 : skip_token (RIGHT_PAREN);
10834 : 23 : auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
10835 : 23 : new AST::TuplePatternItemsNoRest (
10836 : 23 : std::vector<std::unique_ptr<AST::Pattern>> ()));
10837 : 23 : return std::unique_ptr<AST::TuplePattern> (
10838 : 23 : new AST::TuplePattern (std::move (items), paren_locus));
10839 : 23 : }
10840 : :
10841 : : // parse initial pattern (required)
10842 : 2962 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
10843 : 2962 : if (initial_pattern == nullptr)
10844 : : {
10845 : 0 : Error error (lexer.peek_token ()->get_locus (),
10846 : : "failed to parse pattern in grouped or tuple pattern");
10847 : 0 : add_error (std::move (error));
10848 : :
10849 : 0 : return nullptr;
10850 : 0 : }
10851 : :
10852 : : // branch on whether next token is a comma or not
10853 : 2962 : const_TokenPtr t = lexer.peek_token ();
10854 : 2962 : switch (t->get_id ())
10855 : : {
10856 : 44 : case RIGHT_PAREN:
10857 : : // grouped pattern
10858 : 44 : lexer.skip_token ();
10859 : :
10860 : 44 : return std::unique_ptr<AST::GroupedPattern> (
10861 : 44 : new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
10862 : 2917 : case COMMA:
10863 : : {
10864 : : // tuple pattern
10865 : 2917 : lexer.skip_token ();
10866 : :
10867 : : // create vector of patterns
10868 : 2917 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
10869 : 2917 : patterns.push_back (std::move (initial_pattern));
10870 : :
10871 : 2917 : t = lexer.peek_token ();
10872 : 6701 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
10873 : : {
10874 : : // parse pattern (required)
10875 : 3784 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10876 : 3784 : if (pattern == nullptr)
10877 : : {
10878 : 0 : Error error (t->get_locus (),
10879 : : "failed to parse pattern in tuple pattern");
10880 : 0 : add_error (std::move (error));
10881 : :
10882 : 0 : return nullptr;
10883 : 0 : }
10884 : 3784 : patterns.push_back (std::move (pattern));
10885 : :
10886 : 7568 : if (lexer.peek_token ()->get_id () != COMMA)
10887 : : break;
10888 : :
10889 : 954 : lexer.skip_token ();
10890 : 954 : t = lexer.peek_token ();
10891 : : }
10892 : :
10893 : 2917 : t = lexer.peek_token ();
10894 : 2917 : if (t->get_id () == RIGHT_PAREN)
10895 : : {
10896 : : // non-ranged tuple pattern
10897 : 2890 : lexer.skip_token ();
10898 : :
10899 : 2890 : std::unique_ptr<AST::TuplePatternItemsNoRest> items (
10900 : 2890 : new AST::TuplePatternItemsNoRest (std::move (patterns)));
10901 : 2890 : return std::unique_ptr<AST::TuplePattern> (
10902 : 2890 : new AST::TuplePattern (std::move (items), paren_locus));
10903 : 2890 : }
10904 : 27 : else if (t->get_id () == DOT_DOT)
10905 : : {
10906 : : // ranged tuple pattern
10907 : 27 : lexer.skip_token ();
10908 : :
10909 : : // parse upper patterns
10910 : 27 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
10911 : 27 : t = lexer.peek_token ();
10912 : 59 : while (t->get_id () == COMMA)
10913 : : {
10914 : 32 : lexer.skip_token ();
10915 : :
10916 : : // break if end
10917 : 64 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10918 : : break;
10919 : :
10920 : : // parse pattern (required)
10921 : 32 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10922 : 32 : if (pattern == nullptr)
10923 : : {
10924 : 0 : Error error (lexer.peek_token ()->get_locus (),
10925 : : "failed to parse pattern in tuple pattern");
10926 : 0 : add_error (std::move (error));
10927 : :
10928 : 0 : return nullptr;
10929 : 0 : }
10930 : 32 : upper_patterns.push_back (std::move (pattern));
10931 : :
10932 : 32 : t = lexer.peek_token ();
10933 : : }
10934 : :
10935 : 27 : if (!skip_token (RIGHT_PAREN))
10936 : : {
10937 : 0 : return nullptr;
10938 : : }
10939 : :
10940 : 27 : std::unique_ptr<AST::TuplePatternItemsHasRest> items (
10941 : 27 : new AST::TuplePatternItemsHasRest (std::move (patterns),
10942 : : std::move (upper_patterns)));
10943 : 27 : return std::unique_ptr<AST::TuplePattern> (
10944 : 27 : new AST::TuplePattern (std::move (items), paren_locus));
10945 : 27 : }
10946 : : else
10947 : : {
10948 : : // some kind of error
10949 : 0 : Error error (t->get_locus (),
10950 : : "failed to parse tuple pattern (probably) or maybe "
10951 : : "grouped pattern");
10952 : 0 : add_error (std::move (error));
10953 : :
10954 : 0 : return nullptr;
10955 : 0 : }
10956 : 2917 : }
10957 : 1 : default:
10958 : : // error
10959 : 1 : add_error (Error (t->get_locus (),
10960 : : "unrecognised token %qs in grouped or tuple pattern "
10961 : : "after first pattern",
10962 : : t->get_token_description ()));
10963 : :
10964 : 1 : return nullptr;
10965 : : }
10966 : 2962 : }
10967 : :
10968 : : /* Parses a slice pattern that can match arrays or slices. Parses the square
10969 : : * brackets too. */
10970 : : template <typename ManagedTokenSource>
10971 : : std::unique_ptr<AST::SlicePattern>
10972 : 94 : Parser<ManagedTokenSource>::parse_slice_pattern ()
10973 : : {
10974 : 188 : location_t square_locus = lexer.peek_token ()->get_locus ();
10975 : 94 : std::vector<std::unique_ptr<AST::Pattern>> patterns;
10976 : 94 : tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
10977 : : = tl::nullopt;
10978 : :
10979 : : // lambda function to determine which vector to push new patterns into
10980 : 94 : auto get_pattern_ref
10981 : 87 : = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
10982 : 87 : return upper_patterns.has_value () ? upper_patterns.value () : patterns;
10983 : : };
10984 : :
10985 : 94 : skip_token (LEFT_SQUARE);
10986 : :
10987 : 188 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
10988 : : {
10989 : 5 : skip_token (RIGHT_SQUARE);
10990 : 5 : std::unique_ptr<AST::SlicePatternItemsNoRest> items (
10991 : 5 : new AST::SlicePatternItemsNoRest (std::move (patterns)));
10992 : : return std::unique_ptr<AST::SlicePattern> (
10993 : 5 : new AST::SlicePattern (std::move (items), square_locus));
10994 : 5 : }
10995 : :
10996 : : // parse initial pattern (required)
10997 : 178 : if (lexer.peek_token ()->get_id () == DOT_DOT)
10998 : : {
10999 : 3 : lexer.skip_token ();
11000 : 3 : upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
11001 : : }
11002 : : else
11003 : : {
11004 : : // Not a rest pattern `..`, parse normally
11005 : 86 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
11006 : 86 : if (initial_pattern == nullptr)
11007 : : {
11008 : 0 : Error error (lexer.peek_token ()->get_locus (),
11009 : : "failed to parse initial pattern in slice pattern");
11010 : 0 : add_error (std::move (error));
11011 : :
11012 : 0 : return nullptr;
11013 : 0 : }
11014 : :
11015 : 86 : patterns.push_back (std::move (initial_pattern));
11016 : 86 : }
11017 : :
11018 : 89 : const_TokenPtr t = lexer.peek_token ();
11019 : 225 : while (t->get_id () == COMMA)
11020 : : {
11021 : 136 : lexer.skip_token ();
11022 : :
11023 : : // break if end bracket
11024 : 272 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
11025 : : break;
11026 : :
11027 : 272 : if (lexer.peek_token ()->get_id () == DOT_DOT)
11028 : : {
11029 : 49 : if (upper_patterns.has_value ())
11030 : : {
11031 : : // DOT_DOT has been parsed before
11032 : 0 : Error error (lexer.peek_token ()->get_locus (), "%s",
11033 : : "`..` can only be used once per slice pattern");
11034 : 0 : add_error (std::move (error));
11035 : :
11036 : 0 : return nullptr;
11037 : 0 : }
11038 : 49 : upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
11039 : 49 : lexer.skip_token ();
11040 : 49 : t = lexer.peek_token ();
11041 : 49 : continue;
11042 : 49 : }
11043 : :
11044 : : // parse pattern (required)
11045 : 87 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11046 : 87 : if (pattern == nullptr)
11047 : : {
11048 : 0 : Error error (lexer.peek_token ()->get_locus (),
11049 : : "failed to parse pattern in slice pattern");
11050 : 0 : add_error (std::move (error));
11051 : :
11052 : 0 : return nullptr;
11053 : 0 : }
11054 : 87 : get_pattern_ref ().push_back (std::move (pattern));
11055 : :
11056 : 87 : t = lexer.peek_token ();
11057 : : }
11058 : :
11059 : 89 : if (!skip_token (RIGHT_SQUARE))
11060 : : {
11061 : 0 : return nullptr;
11062 : : }
11063 : :
11064 : 89 : if (upper_patterns.has_value ())
11065 : : {
11066 : : // Slice pattern with rest
11067 : 52 : std::unique_ptr<AST::SlicePatternItemsHasRest> items (
11068 : 104 : new AST::SlicePatternItemsHasRest (
11069 : 52 : std::move (patterns), std::move (upper_patterns.value ())));
11070 : : return std::unique_ptr<AST::SlicePattern> (
11071 : 52 : new AST::SlicePattern (std::move (items), square_locus));
11072 : 52 : }
11073 : :
11074 : : // Rest-less slice pattern
11075 : 37 : std::unique_ptr<AST::SlicePatternItemsNoRest> items (
11076 : 37 : new AST::SlicePatternItemsNoRest (std::move (patterns)));
11077 : : return std::unique_ptr<AST::SlicePattern> (
11078 : 37 : new AST::SlicePattern (std::move (items), square_locus));
11079 : 220 : }
11080 : :
11081 : : /* Parses an identifier pattern (pattern that binds a value matched to a
11082 : : * variable). */
11083 : : template <typename ManagedTokenSource>
11084 : : std::unique_ptr<AST::IdentifierPattern>
11085 : 2027 : Parser<ManagedTokenSource>::parse_identifier_pattern ()
11086 : : {
11087 : 2027 : location_t locus = lexer.peek_token ()->get_locus ();
11088 : :
11089 : 2027 : bool has_ref = false;
11090 : 4054 : if (lexer.peek_token ()->get_id () == REF)
11091 : : {
11092 : 232 : has_ref = true;
11093 : 232 : lexer.skip_token ();
11094 : :
11095 : : // DEBUG
11096 : 232 : rust_debug ("parsed ref in identifier pattern");
11097 : : }
11098 : :
11099 : 2027 : bool has_mut = false;
11100 : 4054 : if (lexer.peek_token ()->get_id () == MUT)
11101 : : {
11102 : 1849 : has_mut = true;
11103 : 1849 : lexer.skip_token ();
11104 : : }
11105 : :
11106 : : // parse identifier (required)
11107 : 2027 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
11108 : 2027 : if (ident_tok == nullptr)
11109 : : {
11110 : : // skip somewhere?
11111 : 0 : return nullptr;
11112 : : }
11113 : 2027 : Identifier ident{ident_tok};
11114 : :
11115 : : // DEBUG
11116 : 2027 : rust_debug ("parsed identifier in identifier pattern");
11117 : :
11118 : : // parse optional pattern binding thing
11119 : 2027 : std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
11120 : 4054 : if (lexer.peek_token ()->get_id () == PATTERN_BIND)
11121 : : {
11122 : 1 : lexer.skip_token ();
11123 : :
11124 : : // parse required pattern to bind
11125 : 1 : bind_pattern = parse_pattern_no_alt ();
11126 : 1 : if (bind_pattern == nullptr)
11127 : : {
11128 : 0 : Error error (lexer.peek_token ()->get_locus (),
11129 : : "failed to parse pattern to bind in identifier pattern");
11130 : 0 : add_error (std::move (error));
11131 : :
11132 : 0 : return nullptr;
11133 : 0 : }
11134 : : }
11135 : :
11136 : : // DEBUG
11137 : 2027 : rust_debug ("about to return identifier pattern");
11138 : :
11139 : : return std::unique_ptr<AST::IdentifierPattern> (
11140 : 2027 : new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
11141 : 2027 : std::move (bind_pattern)));
11142 : 2027 : }
11143 : :
11144 : : /* Parses a pattern that opens with an identifier. This includes identifier
11145 : : * patterns, path patterns (and derivatives such as struct patterns, tuple
11146 : : * struct patterns, and macro invocations), and ranges. */
11147 : : template <typename ManagedTokenSource>
11148 : : std::unique_ptr<AST::Pattern>
11149 : 51476 : Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
11150 : : {
11151 : : // ensure first token is actually identifier
11152 : 51476 : const_TokenPtr initial_tok = lexer.peek_token ();
11153 : 51476 : if (initial_tok->get_id () != IDENTIFIER)
11154 : : {
11155 : 0 : return nullptr;
11156 : : }
11157 : :
11158 : : // save initial identifier as it may be useful (but don't skip)
11159 : 51476 : std::string initial_ident = initial_tok->get_str ();
11160 : :
11161 : : // parse next tokens as a PathInExpression
11162 : 51476 : AST::PathInExpression path = parse_path_in_expression ();
11163 : :
11164 : : // branch on next token
11165 : 51476 : const_TokenPtr t = lexer.peek_token ();
11166 : 51476 : switch (t->get_id ())
11167 : : {
11168 : 3 : case EXCLAM:
11169 : 6 : return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
11170 : 1655 : case LEFT_PAREN:
11171 : : {
11172 : : // tuple struct
11173 : 1655 : lexer.skip_token ();
11174 : :
11175 : : // DEBUG
11176 : 1655 : rust_debug ("parsing tuple struct pattern");
11177 : :
11178 : : // parse items
11179 : 1655 : std::unique_ptr<AST::TupleStructItems> items
11180 : : = parse_tuple_struct_items ();
11181 : 1655 : if (items == nullptr)
11182 : : {
11183 : 1 : Error error (lexer.peek_token ()->get_locus (),
11184 : : "failed to parse tuple struct items");
11185 : 1 : add_error (std::move (error));
11186 : :
11187 : 1 : return nullptr;
11188 : 1 : }
11189 : :
11190 : : // DEBUG
11191 : 1654 : rust_debug ("successfully parsed tuple struct items");
11192 : :
11193 : 1654 : if (!skip_token (RIGHT_PAREN))
11194 : : {
11195 : 0 : return nullptr;
11196 : : }
11197 : :
11198 : : // DEBUG
11199 : 1654 : rust_debug ("successfully parsed tuple struct pattern");
11200 : :
11201 : 1654 : return std::unique_ptr<AST::TupleStructPattern> (
11202 : 1654 : new AST::TupleStructPattern (std::move (path), std::move (items)));
11203 : 1655 : }
11204 : 135 : case LEFT_CURLY:
11205 : : {
11206 : : // struct
11207 : 135 : lexer.skip_token ();
11208 : :
11209 : : // parse elements (optional)
11210 : 135 : AST::StructPatternElements elems = parse_struct_pattern_elems ();
11211 : :
11212 : 135 : if (!skip_token (RIGHT_CURLY))
11213 : : {
11214 : 0 : return nullptr;
11215 : : }
11216 : :
11217 : : // DEBUG
11218 : 135 : rust_debug ("successfully parsed struct pattern");
11219 : :
11220 : 135 : return std::unique_ptr<AST::StructPattern> (
11221 : 270 : new AST::StructPattern (std::move (path), initial_tok->get_locus (),
11222 : 135 : std::move (elems)));
11223 : 135 : }
11224 : 8 : case DOT_DOT_EQ:
11225 : : case DOT_DOT:
11226 : : case ELLIPSIS:
11227 : : {
11228 : : // range
11229 : : AST::RangeKind kind
11230 : 8 : = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
11231 : :
11232 : 8 : lexer.skip_token ();
11233 : :
11234 : 8 : std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
11235 : 8 : new AST::RangePatternBoundPath (std::move (path)));
11236 : 8 : std::unique_ptr<AST::RangePatternBound> upper_bound
11237 : : = parse_range_pattern_bound ();
11238 : :
11239 : 8 : return std::unique_ptr<AST::RangePattern> (
11240 : 8 : new AST::RangePattern (std::move (lower_bound),
11241 : : std::move (upper_bound), kind,
11242 : 8 : t->get_locus ()));
11243 : 8 : }
11244 : 41 : case PATTERN_BIND:
11245 : : {
11246 : : // only allow on single-segment paths
11247 : 41 : if (path.is_single_segment ())
11248 : : {
11249 : : // identifier with pattern bind
11250 : 41 : lexer.skip_token ();
11251 : :
11252 : 41 : std::unique_ptr<AST::Pattern> bind_pattern
11253 : : = parse_pattern_no_alt ();
11254 : 41 : if (bind_pattern == nullptr)
11255 : : {
11256 : 1 : Error error (
11257 : : t->get_locus (),
11258 : : "failed to parse pattern to bind to identifier pattern");
11259 : 1 : add_error (std::move (error));
11260 : :
11261 : 1 : return nullptr;
11262 : 1 : }
11263 : 40 : return std::unique_ptr<AST::IdentifierPattern> (
11264 : 120 : new AST::IdentifierPattern (std::move (initial_ident),
11265 : : initial_tok->get_locus (), false,
11266 : 40 : false, std::move (bind_pattern)));
11267 : 41 : }
11268 : 0 : Error error (
11269 : : t->get_locus (),
11270 : : "failed to parse pattern bind to a path, not an identifier");
11271 : 0 : add_error (std::move (error));
11272 : :
11273 : 0 : return nullptr;
11274 : 0 : }
11275 : 49634 : default:
11276 : : // assume identifier if single segment
11277 : 49634 : if (path.is_single_segment ())
11278 : : {
11279 : 48540 : return std::unique_ptr<AST::IdentifierPattern> (
11280 : 145620 : new AST::IdentifierPattern (std::move (initial_ident),
11281 : 48540 : initial_tok->get_locus ()));
11282 : : }
11283 : : // return path otherwise
11284 : 1094 : return std::unique_ptr<AST::PathInExpression> (
11285 : 1094 : new AST::PathInExpression (std::move (path)));
11286 : : }
11287 : 51476 : }
11288 : :
11289 : : // Parses tuple struct items if they exist. Does not parse parentheses.
11290 : : template <typename ManagedTokenSource>
11291 : : std::unique_ptr<AST::TupleStructItems>
11292 : 1655 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
11293 : : {
11294 : 1655 : std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
11295 : :
11296 : : // DEBUG
11297 : 1655 : rust_debug ("started parsing tuple struct items");
11298 : :
11299 : : // check for '..' at front
11300 : 3310 : if (lexer.peek_token ()->get_id () == DOT_DOT)
11301 : : {
11302 : : // only parse upper patterns
11303 : 23 : lexer.skip_token ();
11304 : :
11305 : : // DEBUG
11306 : 23 : rust_debug ("'..' at front in tuple struct items detected");
11307 : :
11308 : 23 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11309 : :
11310 : 23 : const_TokenPtr t = lexer.peek_token ();
11311 : 40 : while (t->get_id () == COMMA)
11312 : : {
11313 : 17 : lexer.skip_token ();
11314 : :
11315 : : // break if right paren
11316 : 34 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11317 : : break;
11318 : :
11319 : : // parse pattern, which is now required
11320 : 17 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11321 : 17 : if (pattern == nullptr)
11322 : : {
11323 : 0 : Error error (lexer.peek_token ()->get_locus (),
11324 : : "failed to parse pattern in tuple struct items");
11325 : 0 : add_error (std::move (error));
11326 : :
11327 : 0 : return nullptr;
11328 : 0 : }
11329 : 17 : upper_patterns.push_back (std::move (pattern));
11330 : :
11331 : 17 : t = lexer.peek_token ();
11332 : : }
11333 : :
11334 : : // DEBUG
11335 : 23 : rust_debug (
11336 : : "finished parsing tuple struct items ranged (upper/none only)");
11337 : :
11338 : 23 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
11339 : 23 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
11340 : 23 : std::move (upper_patterns)));
11341 : 23 : }
11342 : :
11343 : : // has at least some lower patterns
11344 : 1632 : const_TokenPtr t = lexer.peek_token ();
11345 : 3331 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
11346 : : {
11347 : : // DEBUG
11348 : 1699 : rust_debug ("about to parse pattern in tuple struct items");
11349 : :
11350 : : // parse pattern, which is required
11351 : 1699 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11352 : 1699 : if (pattern == nullptr)
11353 : : {
11354 : 0 : Error error (t->get_locus (),
11355 : : "failed to parse pattern in tuple struct items");
11356 : 0 : add_error (std::move (error));
11357 : :
11358 : 0 : return nullptr;
11359 : 0 : }
11360 : 1699 : lower_patterns.push_back (std::move (pattern));
11361 : :
11362 : : // DEBUG
11363 : 1699 : rust_debug ("successfully parsed pattern in tuple struct items");
11364 : :
11365 : 3398 : if (lexer.peek_token ()->get_id () != COMMA)
11366 : : {
11367 : : // DEBUG
11368 : 1586 : rust_debug ("broke out of parsing patterns in tuple struct "
11369 : : "items as no comma");
11370 : :
11371 : : break;
11372 : : }
11373 : 113 : lexer.skip_token ();
11374 : 113 : t = lexer.peek_token ();
11375 : : }
11376 : :
11377 : : // branch on next token
11378 : 1632 : t = lexer.peek_token ();
11379 : 1632 : switch (t->get_id ())
11380 : : {
11381 : 1608 : case RIGHT_PAREN:
11382 : 1608 : return std::unique_ptr<AST::TupleStructItemsNoRest> (
11383 : 1608 : new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
11384 : 23 : case DOT_DOT:
11385 : : {
11386 : : // has an upper range that must be parsed separately
11387 : 23 : lexer.skip_token ();
11388 : :
11389 : 23 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11390 : :
11391 : 23 : t = lexer.peek_token ();
11392 : 25 : while (t->get_id () == COMMA)
11393 : : {
11394 : 2 : lexer.skip_token ();
11395 : :
11396 : : // break if next token is right paren
11397 : 4 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11398 : : break;
11399 : :
11400 : : // parse pattern, which is required
11401 : 2 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11402 : 2 : if (pattern == nullptr)
11403 : : {
11404 : 0 : Error error (lexer.peek_token ()->get_locus (),
11405 : : "failed to parse pattern in tuple struct items");
11406 : 0 : add_error (std::move (error));
11407 : :
11408 : 0 : return nullptr;
11409 : 0 : }
11410 : 2 : upper_patterns.push_back (std::move (pattern));
11411 : :
11412 : 2 : t = lexer.peek_token ();
11413 : : }
11414 : :
11415 : 23 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
11416 : 23 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
11417 : 23 : std::move (upper_patterns)));
11418 : 23 : }
11419 : 1 : default:
11420 : : // error
11421 : 1 : add_error (Error (t->get_locus (),
11422 : : "unexpected token %qs in tuple struct items",
11423 : : t->get_token_description ()));
11424 : :
11425 : 1 : return nullptr;
11426 : : }
11427 : 1655 : }
11428 : :
11429 : : // Parses struct pattern elements if they exist.
11430 : : template <typename ManagedTokenSource>
11431 : : AST::StructPatternElements
11432 : 136 : Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
11433 : : {
11434 : 136 : std::vector<std::unique_ptr<AST::StructPatternField>> fields;
11435 : :
11436 : 136 : AST::AttrVec etc_attrs;
11437 : 136 : bool has_rest = false;
11438 : :
11439 : : // try parsing struct pattern fields
11440 : 136 : const_TokenPtr t = lexer.peek_token ();
11441 : 418 : while (t->get_id () != RIGHT_CURLY)
11442 : : {
11443 : 202 : AST::AttrVec outer_attrs = parse_outer_attributes ();
11444 : :
11445 : : // parse etc (must be last in struct pattern, so breaks)
11446 : 404 : if (lexer.peek_token ()->get_id () == DOT_DOT)
11447 : : {
11448 : 3 : lexer.skip_token ();
11449 : 3 : etc_attrs = std::move (outer_attrs);
11450 : 3 : has_rest = true;
11451 : 3 : break;
11452 : : }
11453 : :
11454 : 199 : std::unique_ptr<AST::StructPatternField> field
11455 : 199 : = parse_struct_pattern_field_partial (std::move (outer_attrs));
11456 : 199 : if (field == nullptr)
11457 : : {
11458 : 0 : Error error (lexer.peek_token ()->get_locus (),
11459 : : "failed to parse struct pattern field");
11460 : 0 : add_error (std::move (error));
11461 : :
11462 : : // skip after somewhere?
11463 : 0 : return AST::StructPatternElements::create_empty ();
11464 : 0 : }
11465 : 199 : fields.push_back (std::move (field));
11466 : :
11467 : 398 : if (lexer.peek_token ()->get_id () != COMMA)
11468 : : break;
11469 : :
11470 : : // skip comma
11471 : 80 : lexer.skip_token ();
11472 : 80 : t = lexer.peek_token ();
11473 : : }
11474 : :
11475 : 136 : if (has_rest)
11476 : 3 : return AST::StructPatternElements (std::move (fields),
11477 : 3 : std::move (etc_attrs));
11478 : : else
11479 : 133 : return AST::StructPatternElements (std::move (fields));
11480 : 136 : }
11481 : :
11482 : : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11483 : : * identifier). */
11484 : : template <typename ManagedTokenSource>
11485 : : std::unique_ptr<AST::StructPatternField>
11486 : 0 : Parser<ManagedTokenSource>::parse_struct_pattern_field ()
11487 : : {
11488 : : // parse outer attributes (if they exist)
11489 : 0 : AST::AttrVec outer_attrs = parse_outer_attributes ();
11490 : :
11491 : 0 : return parse_struct_pattern_field_partial (std::move (outer_attrs));
11492 : 0 : }
11493 : :
11494 : : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11495 : : * identifier), with outer attributes passed in. */
11496 : : template <typename ManagedTokenSource>
11497 : : std::unique_ptr<AST::StructPatternField>
11498 : 199 : Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
11499 : : AST::AttrVec outer_attrs)
11500 : : {
11501 : : // branch based on next token
11502 : 199 : const_TokenPtr t = lexer.peek_token ();
11503 : 199 : switch (t->get_id ())
11504 : : {
11505 : 3 : case INT_LITERAL:
11506 : : {
11507 : : // tuple index
11508 : 6 : std::string index_str = t->get_str ();
11509 : 3 : int index = atoi (index_str.c_str ());
11510 : :
11511 : 3 : lexer.skip_token ();
11512 : :
11513 : 3 : if (!skip_token (COLON))
11514 : : {
11515 : 0 : return nullptr;
11516 : : }
11517 : :
11518 : : // parse required pattern
11519 : 3 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11520 : 3 : if (pattern == nullptr)
11521 : : {
11522 : 0 : Error error (
11523 : : t->get_locus (),
11524 : : "failed to parse pattern in tuple index struct pattern field");
11525 : 0 : add_error (std::move (error));
11526 : :
11527 : 0 : return nullptr;
11528 : 0 : }
11529 : :
11530 : 3 : return std::unique_ptr<AST::StructPatternFieldTuplePat> (
11531 : 3 : new AST::StructPatternFieldTuplePat (index, std::move (pattern),
11532 : : std::move (outer_attrs),
11533 : 3 : t->get_locus ()));
11534 : 6 : }
11535 : 196 : case IDENTIFIER:
11536 : : // identifier-pattern OR only identifier
11537 : : // branch on next token
11538 : 392 : switch (lexer.peek_token (1)->get_id ())
11539 : : {
11540 : 98 : case COLON:
11541 : : {
11542 : : // identifier-pattern
11543 : 98 : Identifier ident{t};
11544 : 98 : lexer.skip_token ();
11545 : :
11546 : 98 : skip_token (COLON);
11547 : :
11548 : : // parse required pattern
11549 : 98 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11550 : 98 : if (pattern == nullptr)
11551 : : {
11552 : 0 : Error error (t->get_locus (),
11553 : : "failed to parse pattern in struct pattern field");
11554 : 0 : add_error (std::move (error));
11555 : :
11556 : 0 : return nullptr;
11557 : 0 : }
11558 : :
11559 : 98 : return std::unique_ptr<AST::StructPatternFieldIdentPat> (
11560 : 196 : new AST::StructPatternFieldIdentPat (std::move (ident),
11561 : : std::move (pattern),
11562 : : std::move (outer_attrs),
11563 : 98 : t->get_locus ()));
11564 : 98 : }
11565 : 98 : case COMMA:
11566 : : case RIGHT_CURLY:
11567 : : {
11568 : : // identifier only
11569 : 98 : Identifier ident = {t};
11570 : 98 : lexer.skip_token ();
11571 : :
11572 : 98 : return std::unique_ptr<AST::StructPatternFieldIdent> (
11573 : 196 : new AST::StructPatternFieldIdent (std::move (ident), false, false,
11574 : : std::move (outer_attrs),
11575 : 98 : t->get_locus ()));
11576 : 98 : }
11577 : 0 : default:
11578 : : // error
11579 : 0 : add_error (Error (t->get_locus (),
11580 : : "unrecognised token %qs in struct pattern field",
11581 : : t->get_token_description ()));
11582 : :
11583 : 0 : return nullptr;
11584 : : }
11585 : 0 : case REF:
11586 : : case MUT:
11587 : : {
11588 : : // only identifier
11589 : 0 : bool has_ref = false;
11590 : 0 : if (t->get_id () == REF)
11591 : : {
11592 : 0 : has_ref = true;
11593 : 0 : lexer.skip_token ();
11594 : : }
11595 : :
11596 : 0 : bool has_mut = false;
11597 : 0 : if (lexer.peek_token ()->get_id () == MUT)
11598 : : {
11599 : 0 : has_mut = true;
11600 : 0 : lexer.skip_token ();
11601 : : }
11602 : :
11603 : 0 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
11604 : 0 : if (ident_tok == nullptr)
11605 : : {
11606 : 0 : return nullptr;
11607 : : }
11608 : 0 : Identifier ident{ident_tok};
11609 : :
11610 : 0 : return std::unique_ptr<AST::StructPatternFieldIdent> (
11611 : 0 : new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
11612 : : std::move (outer_attrs),
11613 : 0 : t->get_locus ()));
11614 : 0 : }
11615 : 0 : default:
11616 : : // not necessarily an error
11617 : 0 : return nullptr;
11618 : : }
11619 : 199 : }
11620 : :
11621 : : /* Parses a statement or expression (depending on whether a trailing semicolon
11622 : : * exists). Useful for block expressions where it cannot be determined through
11623 : : * lookahead whether it is a statement or expression to be parsed. */
11624 : : template <typename ManagedTokenSource>
11625 : : ExprOrStmt
11626 : 70412 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
11627 : : {
11628 : : // quick exit for empty statement
11629 : 70412 : const_TokenPtr t = lexer.peek_token ();
11630 : 70412 : if (t->get_id () == SEMICOLON)
11631 : : {
11632 : 17 : lexer.skip_token ();
11633 : 17 : std::unique_ptr<AST::EmptyStmt> stmt (
11634 : 17 : new AST::EmptyStmt (t->get_locus ()));
11635 : 17 : return ExprOrStmt (std::move (stmt));
11636 : 17 : }
11637 : :
11638 : : // parse outer attributes
11639 : 70395 : AST::AttrVec outer_attrs = parse_outer_attributes ();
11640 : 70395 : ParseRestrictions restrictions;
11641 : 70395 : restrictions.expr_can_be_stmt = true;
11642 : 70395 : std::unique_ptr<AST::Expr> expr;
11643 : :
11644 : : // parsing this will be annoying because of the many different possibilities
11645 : : /* best may be just to copy paste in parse_item switch, and failing that try
11646 : : * to parse outer attributes, and then pass them in to either a let
11647 : : * statement or (fallback) expression statement. */
11648 : : // FIXME: think of a way to do this without such a large switch?
11649 : :
11650 : : /* FIXME: for expressions at least, the only way that they can really be
11651 : : * parsed properly in this way is if they don't support operators on them.
11652 : : * They must be pratt-parsed otherwise. As such due to composability, only
11653 : : * explicit statements will have special cases here. This should roughly
11654 : : * correspond to "expr-with-block", but this warning is here in case it
11655 : : * isn't the case. */
11656 : 70395 : t = lexer.peek_token ();
11657 : 70395 : switch (t->get_id ())
11658 : : {
11659 : 22551 : case LET:
11660 : : {
11661 : : // let statement
11662 : 22551 : std::unique_ptr<AST::LetStmt> stmt (
11663 : 22551 : parse_let_stmt (std::move (outer_attrs)));
11664 : 22551 : return ExprOrStmt (std::move (stmt));
11665 : 22551 : }
11666 : 838 : case PUB:
11667 : : case MOD:
11668 : : case EXTERN_KW:
11669 : : case USE:
11670 : : case FN_KW:
11671 : : case TYPE:
11672 : : case STRUCT_KW:
11673 : : case ENUM_KW:
11674 : : case CONST:
11675 : : case STATIC_KW:
11676 : : case AUTO:
11677 : : case TRAIT:
11678 : : case IMPL:
11679 : : {
11680 : 838 : std::unique_ptr<AST::VisItem> item (
11681 : 838 : parse_vis_item (std::move (outer_attrs)));
11682 : 838 : return ExprOrStmt (std::move (item));
11683 : 838 : }
11684 : : /* TODO: implement union keyword but not really because of
11685 : : * context-dependence crappy hack way to parse a union written below to
11686 : : * separate it from the good code. */
11687 : : // case UNION:
11688 : 3878 : case UNSAFE:
11689 : : { // maybe - unsafe traits are a thing
11690 : : /* if any of these (should be all possible VisItem prefixes), parse a
11691 : : * VisItem - can't parse item because would require reparsing outer
11692 : : * attributes */
11693 : 3878 : const_TokenPtr t2 = lexer.peek_token (1);
11694 : 3878 : switch (t2->get_id ())
11695 : : {
11696 : 3861 : case LEFT_CURLY:
11697 : : {
11698 : : // unsafe block: parse as expression
11699 : 3861 : expr = parse_expr (std::move (outer_attrs), restrictions);
11700 : : break;
11701 : : }
11702 : 0 : case AUTO:
11703 : : case TRAIT:
11704 : : {
11705 : : // unsafe trait
11706 : 0 : std::unique_ptr<AST::VisItem> item (
11707 : 0 : parse_vis_item (std::move (outer_attrs)));
11708 : 0 : return ExprOrStmt (std::move (item));
11709 : 0 : }
11710 : 17 : case EXTERN_KW:
11711 : : case FN_KW:
11712 : : {
11713 : : // unsafe function
11714 : 17 : std::unique_ptr<AST::VisItem> item (
11715 : 17 : parse_vis_item (std::move (outer_attrs)));
11716 : 17 : return ExprOrStmt (std::move (item));
11717 : 17 : }
11718 : 0 : case IMPL:
11719 : : {
11720 : : // unsafe trait impl
11721 : 0 : std::unique_ptr<AST::VisItem> item (
11722 : 0 : parse_vis_item (std::move (outer_attrs)));
11723 : 0 : return ExprOrStmt (std::move (item));
11724 : 0 : }
11725 : 0 : default:
11726 : 0 : add_error (Error (t2->get_locus (),
11727 : : "unrecognised token %qs after parsing unsafe - "
11728 : : "expected beginning of expression or statement",
11729 : : t->get_token_description ()));
11730 : :
11731 : : // skip somewhere?
11732 : : return ExprOrStmt::create_error ();
11733 : : }
11734 : : break;
11735 : 3878 : }
11736 : : /* FIXME: this is either a macro invocation or macro invocation semi.
11737 : : * start parsing to determine which one it is. */
11738 : : // FIXME: old code there
11739 : :
11740 : : // crappy hack to do union "keyword"
11741 : 25917 : case IDENTIFIER:
11742 : 42889 : if (t->get_str () == Values::WeakKeywords::UNION
11743 : 25953 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
11744 : : {
11745 : 1 : std::unique_ptr<AST::VisItem> item (
11746 : 1 : parse_vis_item (std::move (outer_attrs)));
11747 : 1 : return ExprOrStmt (std::move (item));
11748 : : // or should this go straight to parsing union?
11749 : 1 : }
11750 : 42887 : else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
11751 : 26432 : && lexer.peek_token (1)->get_id () == EXCLAM)
11752 : : {
11753 : : // macro_rules! macro item
11754 : 516 : std::unique_ptr<AST::Item> item (
11755 : 516 : parse_macro_rules_def (std::move (outer_attrs)));
11756 : 516 : return ExprOrStmt (std::move (item));
11757 : 516 : }
11758 : : gcc_fallthrough ();
11759 : : case SUPER:
11760 : : case SELF:
11761 : : case SELF_ALIAS:
11762 : : case CRATE:
11763 : : case SCOPE_RESOLUTION:
11764 : : case DOLLAR_SIGN:
11765 : : {
11766 : 30298 : AST::PathInExpression path = parse_path_in_expression ();
11767 : 30298 : std::unique_ptr<AST::Expr> null_denotation;
11768 : :
11769 : 60596 : if (lexer.peek_token ()->get_id () == EXCLAM)
11770 : : {
11771 : 2529 : std::unique_ptr<AST::MacroInvocation> invoc
11772 : 5058 : = parse_macro_invocation_partial (std::move (path),
11773 : : std::move (outer_attrs));
11774 : 2529 : if (invoc == nullptr)
11775 : : return ExprOrStmt::create_error ();
11776 : :
11777 : 2529 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
11778 : : {
11779 : 1362 : invoc->add_semicolon ();
11780 : : // Macro invocation with semicolon.
11781 : : return ExprOrStmt (
11782 : 1362 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
11783 : : }
11784 : :
11785 : 2334 : TokenId after_macro = lexer.peek_token ()->get_id ();
11786 : :
11787 : 1167 : AST::DelimType delim_type = invoc->get_invoc_data ()
11788 : 1167 : .get_delim_tok_tree ()
11789 : 1167 : .get_delim_type ();
11790 : :
11791 : 1167 : if (delim_type == AST::CURLY && after_macro != DOT
11792 : 6 : && after_macro != QUESTION_MARK)
11793 : : {
11794 : 6 : rust_debug ("braced macro statement");
11795 : : return ExprOrStmt (
11796 : 6 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
11797 : : }
11798 : :
11799 : 1161 : null_denotation = std::move (invoc);
11800 : 2529 : }
11801 : : else
11802 : : {
11803 : : null_denotation
11804 : 27769 : = null_denotation_path (std::move (path), {}, restrictions);
11805 : : }
11806 : :
11807 : 28930 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
11808 : : std::move (outer_attrs), restrictions);
11809 : : break;
11810 : 30298 : }
11811 : 12313 : default:
11812 : : /* expression statement or expression itself - parse
11813 : : * expression then make it statement if semi afterwards */
11814 : 12313 : expr = parse_expr (std::move (outer_attrs), restrictions);
11815 : 12313 : break;
11816 : : }
11817 : :
11818 : 45104 : const_TokenPtr after_expr = lexer.peek_token ();
11819 : 45104 : if (after_expr->get_id () == SEMICOLON)
11820 : : {
11821 : : // must be expression statement
11822 : 12428 : lexer.skip_token ();
11823 : :
11824 : 12428 : if (expr)
11825 : : {
11826 : 12427 : std::unique_ptr<AST::ExprStmt> stmt (
11827 : 12427 : new AST::ExprStmt (std::move (expr), t->get_locus (), true));
11828 : 12427 : return ExprOrStmt (std::move (stmt));
11829 : 12427 : }
11830 : : else
11831 : : {
11832 : : return ExprOrStmt::create_error ();
11833 : : }
11834 : : }
11835 : :
11836 : 32670 : if (expr && !expr->is_expr_without_block ()
11837 : 41434 : && after_expr->get_id () != RIGHT_CURLY)
11838 : : {
11839 : : // block expression statement.
11840 : 2449 : std::unique_ptr<AST::ExprStmt> stmt (
11841 : 2449 : new AST::ExprStmt (std::move (expr), t->get_locus (), false));
11842 : 2449 : return ExprOrStmt (std::move (stmt));
11843 : 2449 : }
11844 : :
11845 : : // return expression
11846 : 30227 : return ExprOrStmt (std::move (expr));
11847 : 70395 : }
11848 : :
11849 : : // Parses a struct expression field.
11850 : : template <typename ManagedTokenSource>
11851 : : std::unique_ptr<AST::StructExprField>
11852 : 2860 : Parser<ManagedTokenSource>::parse_struct_expr_field ()
11853 : : {
11854 : 2860 : AST::AttrVec outer_attrs = parse_outer_attributes ();
11855 : 2860 : const_TokenPtr t = lexer.peek_token ();
11856 : 2860 : switch (t->get_id ())
11857 : : {
11858 : 2816 : case IDENTIFIER:
11859 : 5632 : if (lexer.peek_token (1)->get_id () == COLON)
11860 : : {
11861 : : // struct expr field with identifier and expr
11862 : 2429 : Identifier ident = {t};
11863 : 2429 : lexer.skip_token (1);
11864 : :
11865 : : // parse expression (required)
11866 : 2429 : std::unique_ptr<AST::Expr> expr = parse_expr ();
11867 : 2429 : if (expr == nullptr)
11868 : : {
11869 : 0 : Error error (t->get_locus (),
11870 : : "failed to parse struct expression field with "
11871 : : "identifier and expression");
11872 : 0 : add_error (std::move (error));
11873 : :
11874 : 0 : return nullptr;
11875 : 0 : }
11876 : :
11877 : 2429 : return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
11878 : 4858 : new AST::StructExprFieldIdentifierValue (std::move (ident),
11879 : : std::move (expr),
11880 : : std::move (outer_attrs),
11881 : 2429 : t->get_locus ()));
11882 : 2429 : }
11883 : : else
11884 : : {
11885 : : // struct expr field with identifier only
11886 : 387 : Identifier ident{t};
11887 : 387 : lexer.skip_token ();
11888 : :
11889 : 387 : return std::unique_ptr<AST::StructExprFieldIdentifier> (
11890 : 774 : new AST::StructExprFieldIdentifier (std::move (ident),
11891 : : std::move (outer_attrs),
11892 : 387 : t->get_locus ()));
11893 : 387 : }
11894 : 44 : case INT_LITERAL:
11895 : : {
11896 : : // parse tuple index field
11897 : 44 : int index = atoi (t->get_str ().c_str ());
11898 : 44 : lexer.skip_token ();
11899 : :
11900 : 44 : if (!skip_token (COLON))
11901 : : {
11902 : : // skip somewhere?
11903 : 0 : return nullptr;
11904 : : }
11905 : :
11906 : : // parse field expression (required)
11907 : 44 : std::unique_ptr<AST::Expr> expr = parse_expr ();
11908 : 44 : if (expr == nullptr)
11909 : : {
11910 : 0 : Error error (t->get_locus (),
11911 : : "failed to parse expr in struct (or enum) expr "
11912 : : "field with tuple index");
11913 : 0 : add_error (std::move (error));
11914 : :
11915 : 0 : return nullptr;
11916 : 0 : }
11917 : :
11918 : 44 : return std::unique_ptr<AST::StructExprFieldIndexValue> (
11919 : 44 : new AST::StructExprFieldIndexValue (index, std::move (expr),
11920 : : std::move (outer_attrs),
11921 : 44 : t->get_locus ()));
11922 : 44 : }
11923 : 0 : case DOT_DOT:
11924 : : /* this is a struct base and can't be parsed here, so just return
11925 : : * nothing without erroring */
11926 : :
11927 : 0 : return nullptr;
11928 : 0 : default:
11929 : 0 : add_error (
11930 : 0 : Error (t->get_locus (),
11931 : : "unrecognised token %qs as first token of struct expr field - "
11932 : : "expected identifier or integer literal",
11933 : : t->get_token_description ()));
11934 : :
11935 : 0 : return nullptr;
11936 : : }
11937 : 2860 : }
11938 : :
11939 : : // "Unexpected token" panic mode - flags gcc error at unexpected token
11940 : : // TODO: seems to be unused, remove?
11941 : : template <typename ManagedTokenSource>
11942 : : void
11943 : 0 : Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
11944 : : {
11945 : 0 : Error error (t->get_locus (), "unexpected token %qs",
11946 : : t->get_token_description ());
11947 : 0 : add_error (std::move (error));
11948 : 0 : }
11949 : :
11950 : : /* Crappy "error recovery" performed after error by skipping tokens until a
11951 : : * semi-colon is found */
11952 : : template <typename ManagedTokenSource>
11953 : : void
11954 : 24 : Parser<ManagedTokenSource>::skip_after_semicolon ()
11955 : : {
11956 : 24 : const_TokenPtr t = lexer.peek_token ();
11957 : :
11958 : 31 : while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
11959 : : {
11960 : 7 : lexer.skip_token ();
11961 : 7 : t = lexer.peek_token ();
11962 : : }
11963 : :
11964 : 24 : if (t->get_id () == SEMICOLON)
11965 : 3 : lexer.skip_token ();
11966 : 24 : }
11967 : :
11968 : : /* Skips the current token */
11969 : : template <typename ManagedTokenSource>
11970 : : void
11971 : 70230 : Parser<ManagedTokenSource>::skip_token ()
11972 : : {
11973 : 2117 : lexer.skip_token ();
11974 : 1538 : }
11975 : :
11976 : : /* Checks if current token has inputted id - skips it and returns true if so,
11977 : : * diagnoses an error and returns false otherwise. */
11978 : : template <typename ManagedTokenSource>
11979 : : bool
11980 : 1070360 : Parser<ManagedTokenSource>::skip_token (TokenId token_id)
11981 : : {
11982 : 1070360 : return expect_token (token_id) != const_TokenPtr ();
11983 : : }
11984 : :
11985 : : /* Checks if current token is similar to inputted token - skips it and returns
11986 : : * true if so, diagnoses an error and returns false otherwise. */
11987 : : template <typename ManagedTokenSource>
11988 : : bool
11989 : 134761 : Parser<ManagedTokenSource>::skip_token (const_TokenPtr token)
11990 : : {
11991 : 403562 : return expect_token (token) != const_TokenPtr ();
11992 : : }
11993 : :
11994 : : /* Checks if current token has inputted id - skips it and returns true if so,
11995 : : * returns false otherwise without diagnosing an error */
11996 : : template <typename ManagedTokenSource>
11997 : : bool
11998 : 147003 : Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
11999 : : {
12000 : 294006 : if (lexer.peek_token ()->get_id () != token_id)
12001 : : return false;
12002 : : else
12003 : 6968 : return skip_token (token_id);
12004 : : }
12005 : :
12006 : : /* Checks the current token - if id is same as expected, skips and returns it,
12007 : : * otherwise diagnoses error and returns null. */
12008 : : template <typename ManagedTokenSource>
12009 : : const_TokenPtr
12010 : 1143589 : Parser<ManagedTokenSource>::expect_token (TokenId token_id)
12011 : : {
12012 : 1143589 : const_TokenPtr t = lexer.peek_token ();
12013 : 1143589 : if (t->get_id () == token_id)
12014 : : {
12015 : 1139976 : lexer.skip_token ();
12016 : 1139976 : return t;
12017 : : }
12018 : : else
12019 : : {
12020 : 3613 : Error error (t->get_locus (), "expecting %qs but %qs found",
12021 : : get_token_description (token_id),
12022 : : t->get_token_description ());
12023 : 3613 : add_error (std::move (error));
12024 : :
12025 : 3613 : return const_TokenPtr ();
12026 : 3613 : }
12027 : 1143589 : }
12028 : :
12029 : : /* Checks the current token - if same as expected, skips and returns it,
12030 : : * otherwise diagnoses error and returns null. */
12031 : : template <typename ManagedTokenSource>
12032 : : const_TokenPtr
12033 : 134761 : Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect)
12034 : : {
12035 : 134761 : const_TokenPtr t = lexer.peek_token ();
12036 : 134761 : if (t->get_id () == token_expect->get_id ()
12037 : 134761 : && (!t->should_have_str () || t->get_str () == token_expect->get_str ()))
12038 : : {
12039 : 134040 : lexer.skip_token ();
12040 : 134040 : return t;
12041 : : }
12042 : : else
12043 : : {
12044 : 721 : Error error (t->get_locus (), "expecting %qs but %qs found",
12045 : : token_expect->get_token_description (),
12046 : : t->get_token_description ());
12047 : 721 : add_error (std::move (error));
12048 : :
12049 : 721 : return const_TokenPtr ();
12050 : 721 : }
12051 : 134761 : }
12052 : :
12053 : : // Skips all tokens until EOF or }. Don't use.
12054 : : template <typename ManagedTokenSource>
12055 : : void
12056 : 0 : Parser<ManagedTokenSource>::skip_after_end ()
12057 : : {
12058 : 0 : const_TokenPtr t = lexer.peek_token ();
12059 : :
12060 : 0 : while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
12061 : : {
12062 : 0 : lexer.skip_token ();
12063 : 0 : t = lexer.peek_token ();
12064 : : }
12065 : :
12066 : 0 : if (t->get_id () == RIGHT_CURLY)
12067 : : {
12068 : 0 : lexer.skip_token ();
12069 : : }
12070 : 0 : }
12071 : :
12072 : : /* A slightly more aware error-handler that skips all tokens until it reaches
12073 : : * the end of the block scope (i.e. when left curly brackets = right curly
12074 : : * brackets). Note: assumes currently in the middle of a block. Use
12075 : : * skip_after_next_block to skip based on the assumption that the block
12076 : : * has not been entered yet. */
12077 : : template <typename ManagedTokenSource>
12078 : : void
12079 : 31 : Parser<ManagedTokenSource>::skip_after_end_block ()
12080 : : {
12081 : 31 : const_TokenPtr t = lexer.peek_token ();
12082 : 31 : int curly_count = 1;
12083 : :
12084 : 62 : while (curly_count > 0 && t->get_id () != END_OF_FILE)
12085 : : {
12086 : 31 : switch (t->get_id ())
12087 : : {
12088 : 2 : case LEFT_CURLY:
12089 : 2 : curly_count++;
12090 : 2 : break;
12091 : 12 : case RIGHT_CURLY:
12092 : 12 : curly_count--;
12093 : 12 : break;
12094 : : default:
12095 : : break;
12096 : : }
12097 : 31 : lexer.skip_token ();
12098 : 31 : t = lexer.peek_token ();
12099 : : }
12100 : 31 : }
12101 : :
12102 : : /* Skips tokens until the end of the next block. i.e. assumes that the block
12103 : : * has not been entered yet. */
12104 : : template <typename ManagedTokenSource>
12105 : : void
12106 : 1 : Parser<ManagedTokenSource>::skip_after_next_block ()
12107 : : {
12108 : 1 : const_TokenPtr t = lexer.peek_token ();
12109 : :
12110 : : // initial loop - skip until EOF if no left curlies encountered
12111 : 1 : while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
12112 : : {
12113 : 0 : lexer.skip_token ();
12114 : :
12115 : 0 : t = lexer.peek_token ();
12116 : : }
12117 : :
12118 : : // if next token is left, skip it and then skip after the block ends
12119 : 1 : if (t->get_id () == LEFT_CURLY)
12120 : : {
12121 : 1 : lexer.skip_token ();
12122 : :
12123 : 1 : skip_after_end_block ();
12124 : : }
12125 : : // otherwise, do nothing as EOF
12126 : 1 : }
12127 : :
12128 : : /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
12129 : : * (as designed for attribute body use) */
12130 : : template <typename ManagedTokenSource>
12131 : : void
12132 : 0 : Parser<ManagedTokenSource>::skip_after_end_attribute ()
12133 : : {
12134 : 0 : const_TokenPtr t = lexer.peek_token ();
12135 : :
12136 : 0 : while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE)
12137 : : {
12138 : 0 : lexer.skip_token ();
12139 : 0 : t = lexer.peek_token ();
12140 : : }
12141 : :
12142 : : // Don't skip the RIGHT_SQUARE token
12143 : 0 : }
12144 : :
12145 : : /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
12146 : : * probably will be changed. */
12147 : : template <typename ManagedTokenSource>
12148 : : std::unique_ptr<AST::Expr>
12149 : 725798 : Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
12150 : : AST::AttrVec outer_attrs,
12151 : : ParseRestrictions restrictions)
12152 : : {
12153 : 725798 : const_TokenPtr current_token = lexer.peek_token ();
12154 : : // Special hack because we are allowed to return nullptr, in that case we
12155 : : // don't want to skip the token, since we don't actually parse it. But if
12156 : : // null isn't allowed it indicates an error, and we want to skip past that.
12157 : : // So return early if it is one of the tokens that ends an expression
12158 : : // (or at least cannot start a new expression).
12159 : 725798 : if (restrictions.expr_can_be_null)
12160 : : {
12161 : 2207 : TokenId id = current_token->get_id ();
12162 : 2207 : if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
12163 : : || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY)
12164 : 244 : return nullptr;
12165 : : }
12166 : :
12167 : 725554 : ParseRestrictions null_denotation_restrictions = restrictions;
12168 : 725554 : null_denotation_restrictions.expr_can_be_stmt = false;
12169 : :
12170 : : // parse null denotation (unary part of expression)
12171 : 725554 : std::unique_ptr<AST::Expr> expr
12172 : 725554 : = null_denotation ({}, null_denotation_restrictions);
12173 : 725554 : if (expr == nullptr)
12174 : 33 : return nullptr;
12175 : :
12176 : 725521 : return left_denotations (std::move (expr), right_binding_power,
12177 : 725521 : std::move (outer_attrs), restrictions);
12178 : 725554 : }
12179 : :
12180 : : template <typename ManagedTokenSource>
12181 : : std::unique_ptr<AST::Expr>
12182 : 754634 : Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr,
12183 : : int right_binding_power,
12184 : : AST::AttrVec outer_attrs,
12185 : : ParseRestrictions restrictions)
12186 : : {
12187 : 754634 : if (expr == nullptr)
12188 : : {
12189 : : // DEBUG
12190 : 0 : rust_debug ("null denotation is null; returning null for parse_expr");
12191 : 0 : return nullptr;
12192 : : }
12193 : :
12194 : 754634 : const_TokenPtr current_token = lexer.peek_token ();
12195 : :
12196 : 95217 : if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block ()
12197 : 10236 : && current_token->get_id () != DOT
12198 : 764861 : && current_token->get_id () != QUESTION_MARK)
12199 : : {
12200 : 10227 : rust_debug ("statement expression with block");
12201 : 10227 : expr->set_outer_attrs (std::move (outer_attrs));
12202 : 10227 : return expr;
12203 : : }
12204 : :
12205 : 840238 : restrictions.expr_can_be_stmt = false;
12206 : :
12207 : : // stop parsing if find lower priority token - parse higher priority first
12208 : 2520714 : while (right_binding_power < left_binding_power (current_token))
12209 : : {
12210 : 95833 : lexer.skip_token ();
12211 : :
12212 : : // FIXME attributes should generally be applied to the null denotation.
12213 : 287499 : expr = left_denotation (current_token, std::move (expr),
12214 : : std::move (outer_attrs), restrictions);
12215 : :
12216 : 95833 : if (expr == nullptr)
12217 : : {
12218 : : // DEBUG
12219 : 2 : rust_debug ("left denotation is null; returning null for parse_expr");
12220 : :
12221 : 2 : return nullptr;
12222 : : }
12223 : :
12224 : 95831 : current_token = lexer.peek_token ();
12225 : : }
12226 : :
12227 : 744405 : return expr;
12228 : 754634 : }
12229 : :
12230 : : // Parse expression with lowest left binding power.
12231 : : template <typename ManagedTokenSource>
12232 : : std::unique_ptr<AST::Expr>
12233 : 669621 : Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
12234 : : ParseRestrictions restrictions)
12235 : : {
12236 : 669621 : return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
12237 : : }
12238 : :
12239 : : /* Determines action to take when finding token at beginning of expression. */
12240 : : template <typename ManagedTokenSource>
12241 : : std::unique_ptr<AST::Expr>
12242 : 725554 : Parser<ManagedTokenSource>::null_denotation (AST::AttrVec outer_attrs,
12243 : : ParseRestrictions restrictions)
12244 : : {
12245 : : /* note: tok is previous character in input stream, not current one, as
12246 : : * parse_expr skips it before passing it in */
12247 : :
12248 : : /* as a Pratt parser (which works by decomposing expressions into a null
12249 : : * denotation and then a left denotation), null denotations handle primaries
12250 : : * and unary operands (but only prefix unary operands) */
12251 : :
12252 : 725554 : auto tok = lexer.peek_token ();
12253 : :
12254 : 725554 : switch (tok->get_id ())
12255 : : {
12256 : 283094 : case IDENTIFIER:
12257 : : case SELF:
12258 : : case SELF_ALIAS:
12259 : : case DOLLAR_SIGN:
12260 : : case CRATE:
12261 : : case SUPER:
12262 : : case SCOPE_RESOLUTION:
12263 : : {
12264 : : // DEBUG
12265 : 283094 : rust_debug ("beginning null denotation identifier handling");
12266 : :
12267 : : /* best option: parse as path, then extract identifier, macro,
12268 : : * struct/enum, or just path info from it */
12269 : 283094 : AST::PathInExpression path = parse_path_in_expression ();
12270 : :
12271 : 566188 : return null_denotation_path (std::move (path), std::move (outer_attrs),
12272 : 283094 : restrictions);
12273 : 283094 : }
12274 : 442460 : default:
12275 : 442460 : if (tok->get_id () == LEFT_SHIFT)
12276 : : {
12277 : 2 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
12278 : 2 : tok = lexer.peek_token ();
12279 : : }
12280 : :
12281 : 442460 : lexer.skip_token ();
12282 : 884920 : return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
12283 : 442460 : restrictions);
12284 : : }
12285 : 725554 : }
12286 : :
12287 : : // Handling of expresions that start with a path for `null_denotation`.
12288 : : template <typename ManagedTokenSource>
12289 : : std::unique_ptr<AST::Expr>
12290 : 311046 : Parser<ManagedTokenSource>::null_denotation_path (
12291 : : AST::PathInExpression path, AST::AttrVec outer_attrs,
12292 : : ParseRestrictions restrictions)
12293 : : {
12294 : 311046 : rust_debug ("parsing null denotation after path");
12295 : :
12296 : : // HACK: always make "self" by itself a path (regardless of next
12297 : : // tokens)
12298 : 311046 : if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
12299 : : {
12300 : : // HACK: add outer attrs to path
12301 : 20011 : path.set_outer_attrs (std::move (outer_attrs));
12302 : 20011 : return std::unique_ptr<AST::PathInExpression> (
12303 : 20011 : new AST::PathInExpression (std::move (path)));
12304 : : }
12305 : :
12306 : : // branch on next token
12307 : 291035 : const_TokenPtr t = lexer.peek_token ();
12308 : 291035 : switch (t->get_id ())
12309 : : {
12310 : 49952 : case EXCLAM:
12311 : : // macro
12312 : 99904 : return parse_macro_invocation_partial (std::move (path),
12313 : 49952 : std::move (outer_attrs));
12314 : 3798 : case LEFT_CURLY:
12315 : : {
12316 : 3798 : bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
12317 : 10304 : && (lexer.peek_token (2)->get_id () == COMMA
12318 : 9180 : || (lexer.peek_token (2)->get_id () == COLON
12319 : 5984 : && (lexer.peek_token (4)->get_id () == COMMA
12320 : 815 : || !can_tok_start_type (
12321 : 1960 : lexer.peek_token (3)->get_id ()))));
12322 : :
12323 : : /* definitely not a block:
12324 : : * path '{' ident ','
12325 : : * path '{' ident ':' [anything] ','
12326 : : * path '{' ident ':' [not a type]
12327 : : * otherwise, assume block expr and thus path */
12328 : : // DEBUG
12329 : 15192 : rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
12330 : : lexer.peek_token (1)->get_token_description (),
12331 : : lexer.peek_token (2)->get_token_description (),
12332 : : lexer.peek_token (3)->get_token_description (),
12333 : : lexer.peek_token (4)->get_token_description ());
12334 : :
12335 : 8555 : rust_debug ("can be struct expr: '%s', not a block: '%s'",
12336 : : restrictions.can_be_struct_expr ? "true" : "false",
12337 : : not_a_block ? "true" : "false");
12338 : :
12339 : : // struct/enum expr struct
12340 : 3798 : if (!restrictions.can_be_struct_expr && !not_a_block)
12341 : : {
12342 : : // HACK: add outer attrs to path
12343 : 2104 : path.set_outer_attrs (std::move (outer_attrs));
12344 : 2104 : return std::unique_ptr<AST::PathInExpression> (
12345 : 2104 : new AST::PathInExpression (std::move (path)));
12346 : : }
12347 : 1694 : return parse_struct_expr_struct_partial (std::move (path),
12348 : 1694 : std::move (outer_attrs));
12349 : : }
12350 : 79124 : case LEFT_PAREN:
12351 : : // struct/enum expr tuple
12352 : 79124 : if (!restrictions.can_be_struct_expr)
12353 : : {
12354 : : // assume path is returned
12355 : : // HACK: add outer attributes to path
12356 : 380 : path.set_outer_attrs (std::move (outer_attrs));
12357 : 380 : return std::unique_ptr<AST::PathInExpression> (
12358 : 380 : new AST::PathInExpression (std::move (path)));
12359 : : }
12360 : 78744 : return parse_struct_expr_tuple_partial (std::move (path),
12361 : 78744 : std::move (outer_attrs));
12362 : 158161 : default:
12363 : : // assume path is returned if not single segment
12364 : 158161 : if (path.is_single_segment ())
12365 : : {
12366 : : // FIXME: This should probably be returned as a path.
12367 : : /* HACK: may have to become permanent, but this is my current
12368 : : * identifier expression */
12369 : 465792 : return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
12370 : 621056 : path.get_segments ()[0].get_ident_segment ().as_string (), {},
12371 : 155264 : path.get_locus ()));
12372 : : }
12373 : : // HACK: add outer attrs to path
12374 : 2897 : path.set_outer_attrs (std::move (outer_attrs));
12375 : 2897 : return std::unique_ptr<AST::PathInExpression> (
12376 : 2897 : new AST::PathInExpression (std::move (path)));
12377 : : }
12378 : : rust_unreachable ();
12379 : 291035 : }
12380 : :
12381 : : // Handling of expresions that do not start with a path for `null_denotation`.
12382 : : template <typename ManagedTokenSource>
12383 : : std::unique_ptr<AST::Expr>
12384 : 442460 : Parser<ManagedTokenSource>::null_denotation_not_path (
12385 : : const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
12386 : : {
12387 : 442460 : switch (tok->get_id ())
12388 : : {
12389 : : // FIXME: Handle in null_denotation_path?
12390 : 187 : case LEFT_SHIFT:
12391 : : case LEFT_ANGLE:
12392 : : {
12393 : : // qualified path
12394 : : // HACK: add outer attrs to path
12395 : 187 : AST::QualifiedPathInExpression path
12396 : : = parse_qualified_path_in_expression (tok->get_locus ());
12397 : 187 : path.set_outer_attrs (std::move (outer_attrs));
12398 : 187 : return std::unique_ptr<AST::QualifiedPathInExpression> (
12399 : 187 : new AST::QualifiedPathInExpression (std::move (path)));
12400 : 187 : }
12401 : : // FIXME: delegate to parse_literal_expr instead? would have to rejig
12402 : : // tokens and whatever.
12403 : : // FIXME: for literal exprs, outer attrs should be passed in, and later
12404 : : // error if it does not make up the entire statement.
12405 : 350733 : case INT_LITERAL:
12406 : : // we should check the range, but ignore for now
12407 : : // encode as int?
12408 : 350733 : return std::unique_ptr<AST::LiteralExpr> (
12409 : 1061750 : new AST::LiteralExpr (tok->get_str (), AST::Literal::INT,
12410 : 350733 : tok->get_type_hint (), {}, tok->get_locus ()));
12411 : 13763 : case FLOAT_LITERAL:
12412 : : // encode as float?
12413 : 13763 : return std::unique_ptr<AST::LiteralExpr> (
12414 : 55052 : new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT,
12415 : 13763 : tok->get_type_hint (), {}, tok->get_locus ()));
12416 : 3193 : case STRING_LITERAL:
12417 : 3193 : return std::unique_ptr<AST::LiteralExpr> (
12418 : 12772 : new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
12419 : 3193 : tok->get_type_hint (), {}, tok->get_locus ()));
12420 : 137 : case BYTE_STRING_LITERAL:
12421 : 137 : return std::unique_ptr<AST::LiteralExpr> (
12422 : 548 : new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
12423 : 137 : tok->get_type_hint (), {}, tok->get_locus ()));
12424 : 103 : case RAW_STRING_LITERAL:
12425 : 103 : return std::unique_ptr<AST::LiteralExpr> (
12426 : 412 : new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
12427 : 103 : tok->get_type_hint (), {}, tok->get_locus ()));
12428 : 11747 : case CHAR_LITERAL:
12429 : 11747 : return std::unique_ptr<AST::LiteralExpr> (
12430 : 46988 : new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
12431 : 11747 : tok->get_type_hint (), {}, tok->get_locus ()));
12432 : 132 : case BYTE_CHAR_LITERAL:
12433 : 132 : return std::unique_ptr<AST::LiteralExpr> (
12434 : 528 : new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
12435 : 132 : tok->get_type_hint (), {}, tok->get_locus ()));
12436 : 882 : case TRUE_LITERAL:
12437 : 882 : return std::unique_ptr<AST::LiteralExpr> (
12438 : 2646 : new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL,
12439 : : AST::Literal::BOOL, tok->get_type_hint (), {},
12440 : 882 : tok->get_locus ()));
12441 : 755 : case FALSE_LITERAL:
12442 : 755 : return std::unique_ptr<AST::LiteralExpr> (
12443 : 2265 : new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL,
12444 : : AST::Literal::BOOL, tok->get_type_hint (), {},
12445 : 755 : tok->get_locus ()));
12446 : 12550 : case LEFT_PAREN:
12447 : 12550 : return parse_grouped_or_tuple_expr (std::move (outer_attrs),
12448 : 12550 : tok->get_locus ());
12449 : :
12450 : : /*case PLUS: { // unary plus operator
12451 : : // invoke parse_expr recursively with appropriate priority, etc. for
12452 : : below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
12453 : :
12454 : : if (expr == nullptr)
12455 : : return nullptr;
12456 : : // can only apply to integer and float expressions
12457 : : if (expr->get_type() != integer_type_node || expr->get_type() !=
12458 : : float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12459 : : plus must be int or float but it is %s", print_type(expr->get_type()));
12460 : : return nullptr;
12461 : : }
12462 : :
12463 : : return Tree(expr, tok->get_locus());
12464 : : }*/
12465 : : // Rust has no unary plus operator
12466 : 3447 : case MINUS:
12467 : : { // unary minus
12468 : 3447 : ParseRestrictions entered_from_unary;
12469 : 3447 : entered_from_unary.entered_from_unary = true;
12470 : 3447 : if (!restrictions.can_be_struct_expr)
12471 : 14 : entered_from_unary.can_be_struct_expr = false;
12472 : 3447 : std::unique_ptr<AST::Expr> expr
12473 : 3447 : = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
12474 : :
12475 : 3447 : if (expr == nullptr)
12476 : 0 : return nullptr;
12477 : : // can only apply to integer and float expressions
12478 : : /*if (expr.get_type() != integer_type_node || expr.get_type() !=
12479 : : float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12480 : : minus must be int or float but it is %s",
12481 : : print_type(expr.get_type())); return Tree::error();
12482 : : }*/
12483 : : /* FIXME: when implemented the "get type" method on expr, ensure it is
12484 : : * int or float type (except unsigned int). Actually, this would
12485 : : * probably have to be done in semantic analysis (as type checking).
12486 : : */
12487 : :
12488 : : /* FIXME: allow outer attributes on these expressions by having an
12489 : : * outer attrs parameter in function*/
12490 : 3447 : return std::unique_ptr<AST::NegationExpr> (
12491 : 3447 : new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE,
12492 : 3447 : std::move (outer_attrs), tok->get_locus ()));
12493 : 3447 : }
12494 : 615 : case EXCLAM:
12495 : : { // logical or bitwise not
12496 : 615 : ParseRestrictions entered_from_unary;
12497 : 615 : entered_from_unary.entered_from_unary = true;
12498 : 615 : if (!restrictions.can_be_struct_expr)
12499 : 159 : entered_from_unary.can_be_struct_expr = false;
12500 : 615 : std::unique_ptr<AST::Expr> expr
12501 : 615 : = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
12502 : :
12503 : 615 : if (expr == nullptr)
12504 : 0 : return nullptr;
12505 : : // can only apply to boolean expressions
12506 : : /*if (expr.get_type() != boolean_type_node) {
12507 : : rust_error_at(tok->get_locus(),
12508 : : "operand of logical not must be a boolean but it is %s",
12509 : : print_type(expr.get_type()));
12510 : : return Tree::error();
12511 : : }*/
12512 : : /* FIXME: type checking for boolean or integer expressions in semantic
12513 : : * analysis */
12514 : :
12515 : : // FIXME: allow outer attributes on these expressions
12516 : 615 : return std::unique_ptr<AST::NegationExpr> (
12517 : 615 : new AST::NegationExpr (std::move (expr), NegationOperator::NOT,
12518 : 615 : std::move (outer_attrs), tok->get_locus ()));
12519 : 615 : }
12520 : 9320 : case ASTERISK:
12521 : : {
12522 : : /* pointer dereference only - HACK: as struct expressions should
12523 : : * always be value expressions, cannot be dereferenced */
12524 : 9320 : ParseRestrictions entered_from_unary;
12525 : 9320 : entered_from_unary.entered_from_unary = true;
12526 : 9320 : entered_from_unary.can_be_struct_expr = false;
12527 : 9320 : std::unique_ptr<AST::Expr> expr
12528 : 9320 : = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
12529 : : // FIXME: allow outer attributes on expression
12530 : 9320 : return std::unique_ptr<AST::DereferenceExpr> (
12531 : 9320 : new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs),
12532 : 9320 : tok->get_locus ()));
12533 : 9320 : }
12534 : 3514 : case AMP:
12535 : : {
12536 : : // (single) "borrow" expression - shared (mutable) or immutable
12537 : 3514 : std::unique_ptr<AST::Expr> expr = nullptr;
12538 : 3514 : Mutability mutability = Mutability::Imm;
12539 : 3514 : bool raw_borrow = false;
12540 : :
12541 : 3514 : ParseRestrictions entered_from_unary;
12542 : 3514 : entered_from_unary.entered_from_unary = true;
12543 : 3514 : if (!restrictions.can_be_struct_expr)
12544 : 14 : entered_from_unary.can_be_struct_expr = false;
12545 : :
12546 : 9 : auto is_mutability = [] (const_TokenPtr token) {
12547 : 9 : return token->get_id () == CONST || token->get_id () == MUT;
12548 : : };
12549 : :
12550 : 3514 : auto t = lexer.peek_token ();
12551 : : // Weak raw keyword, we look (1) ahead and treat it as an identifier if
12552 : : // there is no mut nor const.
12553 : 5917 : if (t->get_id () == IDENTIFIER
12554 : 1602 : && t->get_str () == Values::WeakKeywords::RAW
12555 : 4651 : && is_mutability (lexer.peek_token (1)))
12556 : : {
12557 : 7 : lexer.skip_token ();
12558 : 14 : switch (lexer.peek_token ()->get_id ())
12559 : : {
12560 : : case MUT:
12561 : : mutability = Mutability::Mut;
12562 : : break;
12563 : : case CONST:
12564 : 1 : mutability = Mutability::Imm;
12565 : : break;
12566 : 0 : default:
12567 : 0 : rust_error_at (lexer.peek_token ()->get_locus (),
12568 : : "raw borrow should be either const or mut");
12569 : : }
12570 : 7 : lexer.skip_token ();
12571 : 7 : expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12572 : 7 : raw_borrow = true;
12573 : : }
12574 : 3507 : else if (t->get_id () == MUT)
12575 : : {
12576 : 855 : lexer.skip_token ();
12577 : 855 : expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12578 : 855 : mutability = Mutability::Mut;
12579 : 855 : raw_borrow = false;
12580 : : }
12581 : : else
12582 : : {
12583 : 2652 : expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
12584 : 2652 : raw_borrow = false;
12585 : : }
12586 : :
12587 : : // FIXME: allow outer attributes on expression
12588 : 3514 : return std::unique_ptr<AST::BorrowExpr> (
12589 : 3514 : new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false,
12590 : 3514 : std::move (outer_attrs), tok->get_locus ()));
12591 : 3514 : }
12592 : 38 : case LOGICAL_AND:
12593 : : {
12594 : : // (double) "borrow" expression - shared (mutable) or immutable
12595 : 38 : std::unique_ptr<AST::Expr> expr = nullptr;
12596 : 38 : Mutability mutability = Mutability::Imm;
12597 : :
12598 : 38 : ParseRestrictions entered_from_unary;
12599 : 38 : entered_from_unary.entered_from_unary = true;
12600 : :
12601 : 76 : if (lexer.peek_token ()->get_id () == MUT)
12602 : : {
12603 : 0 : lexer.skip_token ();
12604 : 0 : expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12605 : 0 : mutability = Mutability::Mut;
12606 : : }
12607 : : else
12608 : : {
12609 : 38 : expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
12610 : 38 : mutability = Mutability::Imm;
12611 : : }
12612 : :
12613 : : // FIXME: allow outer attributes on expression
12614 : 38 : return std::unique_ptr<AST::BorrowExpr> (
12615 : 38 : new AST::BorrowExpr (std::move (expr), mutability, false, true,
12616 : 38 : std::move (outer_attrs), tok->get_locus ()));
12617 : 38 : }
12618 : 376 : case OR:
12619 : : case PIPE:
12620 : : case MOVE:
12621 : : // closure expression
12622 : 1128 : return parse_closure_expr_pratt (tok, std::move (outer_attrs));
12623 : 173 : case DOT_DOT:
12624 : : // either "range to" or "range full" expressions
12625 : 519 : return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
12626 : 0 : case DOT_DOT_EQ:
12627 : : // range to inclusive expr
12628 : 0 : return parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
12629 : 896 : case RETURN_KW:
12630 : : // FIXME: is this really a null denotation expression?
12631 : 896 : return parse_return_expr (std::move (outer_attrs), tok->get_locus ());
12632 : 31 : case TRY:
12633 : : // FIXME: is this really a null denotation expression?
12634 : 31 : return parse_try_expr (std::move (outer_attrs), tok->get_locus ());
12635 : 103 : case BREAK:
12636 : : // FIXME: is this really a null denotation expression?
12637 : 103 : return parse_break_expr (std::move (outer_attrs), tok->get_locus ());
12638 : 26 : case CONTINUE:
12639 : 26 : return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
12640 : 2591 : case LEFT_CURLY:
12641 : : // ok - this is an expression with block for once.
12642 : 2591 : return parse_block_expr (std::move (outer_attrs), tl::nullopt,
12643 : 2591 : tok->get_locus ());
12644 : 3177 : case IF:
12645 : : // if or if let, so more lookahead to find out
12646 : 6354 : if (lexer.peek_token ()->get_id () == LET)
12647 : : {
12648 : : // if let expr
12649 : 120 : return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
12650 : : }
12651 : : else
12652 : : {
12653 : : // if expr
12654 : 3057 : return parse_if_expr (std::move (outer_attrs), tok->get_locus ());
12655 : : }
12656 : 36 : case LIFETIME:
12657 : 108 : return parse_labelled_loop_expr (tok, std::move (outer_attrs));
12658 : 105 : case LOOP:
12659 : 105 : return parse_loop_expr (std::move (outer_attrs), tl::nullopt,
12660 : 105 : tok->get_locus ());
12661 : 200 : case WHILE:
12662 : 400 : if (lexer.peek_token ()->get_id () == LET)
12663 : : {
12664 : 29 : return parse_while_let_loop_expr (std::move (outer_attrs));
12665 : : }
12666 : : else
12667 : : {
12668 : 171 : return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt,
12669 : 171 : tok->get_locus ());
12670 : : }
12671 : 221 : case FOR:
12672 : 221 : return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt);
12673 : 5537 : case MATCH_KW:
12674 : : // also an expression with block
12675 : 5537 : return parse_match_expr (std::move (outer_attrs), tok->get_locus ());
12676 : 13205 : case LEFT_SQUARE:
12677 : : // array definition expr (not indexing)
12678 : 13205 : return parse_array_expr (std::move (outer_attrs), tok->get_locus ());
12679 : 4622 : case UNSAFE:
12680 : 4622 : return parse_unsafe_block_expr (std::move (outer_attrs),
12681 : 4622 : tok->get_locus ());
12682 : 2 : case BOX:
12683 : 2 : return parse_box_expr (std::move (outer_attrs), tok->get_locus ());
12684 : 1 : case UNDERSCORE:
12685 : 1 : add_error (
12686 : 1 : Error (tok->get_locus (),
12687 : : "use of %qs is not allowed on the right-side of an assignment",
12688 : : tok->get_token_description ()));
12689 : 1 : return nullptr;
12690 : 15 : case CONST:
12691 : 15 : return parse_const_block_expr (std::move (outer_attrs),
12692 : 15 : tok->get_locus ());
12693 : 27 : default:
12694 : 27 : if (!restrictions.expr_can_be_null)
12695 : 27 : add_error (Error (tok->get_locus (),
12696 : : "found unexpected token %qs in null denotation",
12697 : : tok->get_token_description ()));
12698 : 27 : return nullptr;
12699 : : }
12700 : : }
12701 : :
12702 : : /* Called for each token that can appear in infix (between) position. Can be
12703 : : * operators or other punctuation. Returns a function pointer to member
12704 : : * function that implements the left denotation for the token given. */
12705 : : template <typename ManagedTokenSource>
12706 : : std::unique_ptr<AST::Expr>
12707 : 95833 : Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
12708 : : std::unique_ptr<AST::Expr> left,
12709 : : AST::AttrVec outer_attrs,
12710 : : ParseRestrictions restrictions)
12711 : : {
12712 : : // Token passed in has already been skipped, so peek gives "next" token
12713 : 95833 : switch (tok->get_id ())
12714 : : {
12715 : : // FIXME: allow for outer attributes to be applied
12716 : 203 : case QUESTION_MARK:
12717 : : {
12718 : 203 : location_t left_locus = left->get_locus ();
12719 : : // error propagation expression - unary postfix
12720 : 203 : return std::unique_ptr<AST::ErrorPropagationExpr> (
12721 : 203 : new AST::ErrorPropagationExpr (std::move (left),
12722 : 203 : std::move (outer_attrs), left_locus));
12723 : : }
12724 : 11184 : case PLUS:
12725 : : // sum expression - binary infix
12726 : : /*return parse_binary_plus_expr (tok, std::move (left),
12727 : : std::move (outer_attrs), restrictions);*/
12728 : 33552 : return parse_arithmetic_or_logical_expr (tok, std::move (left),
12729 : : std::move (outer_attrs),
12730 : : ArithmeticOrLogicalOperator::ADD,
12731 : 11184 : restrictions);
12732 : 3418 : case MINUS:
12733 : : // difference expression - binary infix
12734 : : /*return parse_binary_minus_expr (tok, std::move (left),
12735 : : std::move (outer_attrs),
12736 : : restrictions);*/
12737 : 10254 : return parse_arithmetic_or_logical_expr (
12738 : : tok, std::move (left), std::move (outer_attrs),
12739 : 3418 : ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
12740 : 423 : case ASTERISK:
12741 : : // product expression - binary infix
12742 : : /*return parse_binary_mult_expr (tok, std::move (left),
12743 : : std::move (outer_attrs), restrictions);*/
12744 : 1269 : return parse_arithmetic_or_logical_expr (
12745 : : tok, std::move (left), std::move (outer_attrs),
12746 : 423 : ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
12747 : 219 : case DIV:
12748 : : // quotient expression - binary infix
12749 : : /*return parse_binary_div_expr (tok, std::move (left),
12750 : : std::move (outer_attrs), restrictions);*/
12751 : 657 : return parse_arithmetic_or_logical_expr (
12752 : : tok, std::move (left), std::move (outer_attrs),
12753 : 219 : ArithmeticOrLogicalOperator::DIVIDE, restrictions);
12754 : 202 : case PERCENT:
12755 : : // modulo expression - binary infix
12756 : : /*return parse_binary_mod_expr (tok, std::move (left),
12757 : : std::move (outer_attrs), restrictions);*/
12758 : 606 : return parse_arithmetic_or_logical_expr (
12759 : : tok, std::move (left), std::move (outer_attrs),
12760 : 202 : ArithmeticOrLogicalOperator::MODULUS, restrictions);
12761 : 4341 : case AMP:
12762 : : // logical or bitwise and expression - binary infix
12763 : : /*return parse_bitwise_and_expr (tok, std::move (left),
12764 : : std::move (outer_attrs), restrictions);*/
12765 : 13023 : return parse_arithmetic_or_logical_expr (
12766 : : tok, std::move (left), std::move (outer_attrs),
12767 : 4341 : ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
12768 : 1732 : case PIPE:
12769 : : // logical or bitwise or expression - binary infix
12770 : : /*return parse_bitwise_or_expr (tok, std::move (left),
12771 : : std::move (outer_attrs), restrictions);*/
12772 : 5196 : return parse_arithmetic_or_logical_expr (
12773 : : tok, std::move (left), std::move (outer_attrs),
12774 : 1732 : ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
12775 : 125 : case CARET:
12776 : : // logical or bitwise xor expression - binary infix
12777 : : /*return parse_bitwise_xor_expr (tok, std::move (left),
12778 : : std::move (outer_attrs), restrictions);*/
12779 : 375 : return parse_arithmetic_or_logical_expr (
12780 : : tok, std::move (left), std::move (outer_attrs),
12781 : 125 : ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
12782 : 2495 : case LEFT_SHIFT:
12783 : : // left shift expression - binary infix
12784 : : /*return parse_left_shift_expr (tok, std::move (left),
12785 : : std::move (outer_attrs), restrictions);*/
12786 : 7485 : return parse_arithmetic_or_logical_expr (
12787 : : tok, std::move (left), std::move (outer_attrs),
12788 : 2495 : ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
12789 : 3839 : case RIGHT_SHIFT:
12790 : : // right shift expression - binary infix
12791 : : /*return parse_right_shift_expr (tok, std::move (left),
12792 : : std::move (outer_attrs), restrictions);*/
12793 : 11517 : return parse_arithmetic_or_logical_expr (
12794 : : tok, std::move (left), std::move (outer_attrs),
12795 : 3839 : ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
12796 : 1569 : case EQUAL_EQUAL:
12797 : : // equal to expression - binary infix (no associativity)
12798 : : /*return parse_binary_equal_expr (tok, std::move (left),
12799 : : std::move (outer_attrs),
12800 : : restrictions);*/
12801 : 4707 : return parse_comparison_expr (tok, std::move (left),
12802 : : std::move (outer_attrs),
12803 : 1569 : ComparisonOperator::EQUAL, restrictions);
12804 : 674 : case NOT_EQUAL:
12805 : : // not equal to expression - binary infix (no associativity)
12806 : : /*return parse_binary_not_equal_expr (tok, std::move (left),
12807 : : std::move (outer_attrs),
12808 : : restrictions);*/
12809 : 2022 : return parse_comparison_expr (tok, std::move (left),
12810 : : std::move (outer_attrs),
12811 : : ComparisonOperator::NOT_EQUAL,
12812 : 674 : restrictions);
12813 : 952 : case RIGHT_ANGLE:
12814 : : // greater than expression - binary infix (no associativity)
12815 : : /*return parse_binary_greater_than_expr (tok, std::move (left),
12816 : : std::move (outer_attrs),
12817 : : restrictions);*/
12818 : 2856 : return parse_comparison_expr (tok, std::move (left),
12819 : : std::move (outer_attrs),
12820 : : ComparisonOperator::GREATER_THAN,
12821 : 952 : restrictions);
12822 : 902 : case LEFT_ANGLE:
12823 : : // less than expression - binary infix (no associativity)
12824 : : /*return parse_binary_less_than_expr (tok, std::move (left),
12825 : : std::move (outer_attrs),
12826 : : restrictions);*/
12827 : 2706 : return parse_comparison_expr (tok, std::move (left),
12828 : : std::move (outer_attrs),
12829 : : ComparisonOperator::LESS_THAN,
12830 : 902 : restrictions);
12831 : 391 : case GREATER_OR_EQUAL:
12832 : : // greater than or equal to expression - binary infix (no associativity)
12833 : : /*return parse_binary_greater_equal_expr (tok, std::move (left),
12834 : : std::move (outer_attrs),
12835 : : restrictions);*/
12836 : 1173 : return parse_comparison_expr (tok, std::move (left),
12837 : : std::move (outer_attrs),
12838 : : ComparisonOperator::GREATER_OR_EQUAL,
12839 : 391 : restrictions);
12840 : 323 : case LESS_OR_EQUAL:
12841 : : // less than or equal to expression - binary infix (no associativity)
12842 : : /*return parse_binary_less_equal_expr (tok, std::move (left),
12843 : : std::move (outer_attrs),
12844 : : restrictions);*/
12845 : 969 : return parse_comparison_expr (tok, std::move (left),
12846 : : std::move (outer_attrs),
12847 : : ComparisonOperator::LESS_OR_EQUAL,
12848 : 323 : restrictions);
12849 : 246 : case OR:
12850 : : // lazy logical or expression - binary infix
12851 : 738 : return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
12852 : 246 : restrictions);
12853 : 536 : case LOGICAL_AND:
12854 : : // lazy logical and expression - binary infix
12855 : 1608 : return parse_lazy_and_expr (tok, std::move (left),
12856 : 536 : std::move (outer_attrs), restrictions);
12857 : 8936 : case AS:
12858 : : /* type cast expression - kind of binary infix (RHS is actually a
12859 : : * TypeNoBounds) */
12860 : 26808 : return parse_type_cast_expr (tok, std::move (left),
12861 : 8936 : std::move (outer_attrs), restrictions);
12862 : 3616 : case EQUAL:
12863 : : // assignment expression - binary infix (note right-to-left
12864 : : // associativity)
12865 : 10848 : return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
12866 : 3616 : restrictions);
12867 : 326 : case PLUS_EQ:
12868 : : /* plus-assignment expression - binary infix (note right-to-left
12869 : : * associativity) */
12870 : : /*return parse_plus_assig_expr (tok, std::move (left),
12871 : : std::move (outer_attrs), restrictions);*/
12872 : 978 : return parse_compound_assignment_expr (tok, std::move (left),
12873 : : std::move (outer_attrs),
12874 : : CompoundAssignmentOperator::ADD,
12875 : 326 : restrictions);
12876 : 209 : case MINUS_EQ:
12877 : : /* minus-assignment expression - binary infix (note right-to-left
12878 : : * associativity) */
12879 : : /*return parse_minus_assig_expr (tok, std::move (left),
12880 : : std::move (outer_attrs), restrictions);*/
12881 : 627 : return parse_compound_assignment_expr (
12882 : : tok, std::move (left), std::move (outer_attrs),
12883 : 209 : CompoundAssignmentOperator::SUBTRACT, restrictions);
12884 : 28 : case ASTERISK_EQ:
12885 : : /* multiply-assignment expression - binary infix (note right-to-left
12886 : : * associativity) */
12887 : : /*return parse_mult_assig_expr (tok, std::move (left),
12888 : : std::move (outer_attrs), restrictions);*/
12889 : 84 : return parse_compound_assignment_expr (
12890 : : tok, std::move (left), std::move (outer_attrs),
12891 : 28 : CompoundAssignmentOperator::MULTIPLY, restrictions);
12892 : 92 : case DIV_EQ:
12893 : : /* division-assignment expression - binary infix (note right-to-left
12894 : : * associativity) */
12895 : : /*return parse_div_assig_expr (tok, std::move (left),
12896 : : std::move (outer_attrs), restrictions);*/
12897 : 276 : return parse_compound_assignment_expr (tok, std::move (left),
12898 : : std::move (outer_attrs),
12899 : : CompoundAssignmentOperator::DIVIDE,
12900 : 92 : restrictions);
12901 : 22 : case PERCENT_EQ:
12902 : : /* modulo-assignment expression - binary infix (note right-to-left
12903 : : * associativity) */
12904 : : /*return parse_mod_assig_expr (tok, std::move (left),
12905 : : std::move (outer_attrs), restrictions);*/
12906 : 66 : return parse_compound_assignment_expr (
12907 : : tok, std::move (left), std::move (outer_attrs),
12908 : 22 : CompoundAssignmentOperator::MODULUS, restrictions);
12909 : 34 : case AMP_EQ:
12910 : : /* bitwise and-assignment expression - binary infix (note right-to-left
12911 : : * associativity) */
12912 : : /*return parse_and_assig_expr (tok, std::move (left),
12913 : : std::move (outer_attrs), restrictions);*/
12914 : 102 : return parse_compound_assignment_expr (
12915 : : tok, std::move (left), std::move (outer_attrs),
12916 : 34 : CompoundAssignmentOperator::BITWISE_AND, restrictions);
12917 : 86 : case PIPE_EQ:
12918 : : /* bitwise or-assignment expression - binary infix (note right-to-left
12919 : : * associativity) */
12920 : : /*return parse_or_assig_expr (tok, std::move (left),
12921 : : std::move (outer_attrs), restrictions);*/
12922 : 258 : return parse_compound_assignment_expr (
12923 : : tok, std::move (left), std::move (outer_attrs),
12924 : 86 : CompoundAssignmentOperator::BITWISE_OR, restrictions);
12925 : 403 : case CARET_EQ:
12926 : : /* bitwise xor-assignment expression - binary infix (note right-to-left
12927 : : * associativity) */
12928 : : /*return parse_xor_assig_expr (tok, std::move (left),
12929 : : std::move (outer_attrs), restrictions);*/
12930 : 1209 : return parse_compound_assignment_expr (
12931 : : tok, std::move (left), std::move (outer_attrs),
12932 : 403 : CompoundAssignmentOperator::BITWISE_XOR, restrictions);
12933 : 159 : case LEFT_SHIFT_EQ:
12934 : : /* left shift-assignment expression - binary infix (note right-to-left
12935 : : * associativity) */
12936 : : /*return parse_left_shift_assig_expr (tok, std::move (left),
12937 : : std::move (outer_attrs),
12938 : : restrictions);*/
12939 : 477 : return parse_compound_assignment_expr (
12940 : : tok, std::move (left), std::move (outer_attrs),
12941 : 159 : CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
12942 : 155 : case RIGHT_SHIFT_EQ:
12943 : : /* right shift-assignment expression - binary infix (note right-to-left
12944 : : * associativity) */
12945 : : /*return parse_right_shift_assig_expr (tok, std::move (left),
12946 : : std::move (outer_attrs),
12947 : : restrictions);*/
12948 : 465 : return parse_compound_assignment_expr (
12949 : : tok, std::move (left), std::move (outer_attrs),
12950 : 155 : CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
12951 : 356 : case DOT_DOT:
12952 : : /* range exclusive expression - binary infix (no associativity)
12953 : : * either "range" or "range from" */
12954 : 1068 : return parse_led_range_exclusive_expr (tok, std::move (left),
12955 : : std::move (outer_attrs),
12956 : 356 : restrictions);
12957 : 13 : case DOT_DOT_EQ:
12958 : : /* range inclusive expression - binary infix (no associativity)
12959 : : * unambiguously RangeInclusiveExpr */
12960 : 39 : return parse_range_inclusive_expr (tok, std::move (left),
12961 : 13 : std::move (outer_attrs), restrictions);
12962 : 0 : case SCOPE_RESOLUTION:
12963 : : // path expression - binary infix? FIXME should this even be parsed
12964 : : // here?
12965 : 0 : add_error (
12966 : 0 : Error (tok->get_locus (),
12967 : : "found scope resolution operator in left denotation "
12968 : : "function - this should probably be handled elsewhere"));
12969 : :
12970 : 0 : return nullptr;
12971 : 46259 : case DOT:
12972 : : {
12973 : : /* field expression or method call - relies on parentheses after next
12974 : : * identifier or await if token after is "await" (unary postfix) or
12975 : : * tuple index if token after is a decimal int literal */
12976 : :
12977 : 46259 : const_TokenPtr next_tok = lexer.peek_token ();
12978 : 46259 : if (next_tok->get_id () == IDENTIFIER
12979 : 46259 : && next_tok->get_str () == Values::Keywords::AWAIT)
12980 : : {
12981 : : // await expression
12982 : 0 : return parse_await_expr (tok, std::move (left),
12983 : 0 : std::move (outer_attrs));
12984 : : }
12985 : 46259 : else if (next_tok->get_id () == INT_LITERAL)
12986 : : {
12987 : : // tuple index expression - TODO check for decimal int literal
12988 : 26829 : return parse_tuple_index_expr (tok, std::move (left),
12989 : : std::move (outer_attrs),
12990 : 8943 : restrictions);
12991 : : }
12992 : 37316 : else if (next_tok->get_id () == FLOAT_LITERAL)
12993 : : {
12994 : : // Lexer has misidentified a tuple index as a float literal
12995 : : // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
12996 : : // literal. This means we should split it into three new separate
12997 : : // tokens, the first tuple index, the dot and the second tuple
12998 : : // index.
12999 : 2 : auto current_loc = next_tok->get_locus ();
13000 : 2 : auto str = next_tok->get_str ();
13001 : 2 : auto dot_pos = str.find (".");
13002 : 2 : auto prefix = str.substr (0, dot_pos);
13003 : 2 : auto suffix = str.substr (dot_pos + 1);
13004 : 2 : if (dot_pos == str.size () - 1)
13005 : 3 : lexer.split_current_token (
13006 : 2 : {Token::make_int (current_loc, std::move (prefix),
13007 : : CORETYPE_PURE_DECIMAL),
13008 : : Token::make (DOT, current_loc + 1)});
13009 : : else
13010 : 5 : lexer.split_current_token (
13011 : 2 : {Token::make_int (current_loc, std::move (prefix),
13012 : : CORETYPE_PURE_DECIMAL),
13013 : : Token::make (DOT, current_loc + 1),
13014 : 2 : Token::make_int (current_loc + 2, std::move (suffix),
13015 : : CORETYPE_PURE_DECIMAL)});
13016 : 6 : return parse_tuple_index_expr (tok, std::move (left),
13017 : : std::move (outer_attrs),
13018 : 2 : restrictions);
13019 : 2 : }
13020 : 48812 : else if (next_tok->get_id () == IDENTIFIER
13021 : 79084 : && lexer.peek_token (1)->get_id () != LEFT_PAREN
13022 : 75339 : && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
13023 : : {
13024 : : /* field expression (or should be) - FIXME: scope resolution right
13025 : : * after identifier should always be method, I'm pretty sure */
13026 : 23127 : return parse_field_access_expr (tok, std::move (left),
13027 : : std::move (outer_attrs),
13028 : 7709 : restrictions);
13029 : : }
13030 : : else
13031 : : {
13032 : : // method call (probably)
13033 : 88815 : return parse_method_call_expr (tok, std::move (left),
13034 : : std::move (outer_attrs),
13035 : 29605 : restrictions);
13036 : : }
13037 : 46259 : }
13038 : 558 : case LEFT_PAREN:
13039 : : // function call - method call is based on dot notation first
13040 : 1674 : return parse_function_call_expr (tok, std::move (left),
13041 : 558 : std::move (outer_attrs), restrictions);
13042 : 807 : case LEFT_SQUARE:
13043 : : // array or slice index expression (pseudo binary infix)
13044 : 2421 : return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
13045 : 807 : restrictions);
13046 : 0 : default:
13047 : 0 : add_error (Error (tok->get_locus (),
13048 : : "found unexpected token %qs in left denotation",
13049 : : tok->get_token_description ()));
13050 : :
13051 : 0 : return nullptr;
13052 : : }
13053 : : }
13054 : :
13055 : : /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
13056 : : * TODO make constexpr? Would that even do anything useful? */
13057 : : inline binding_powers
13058 : 27978 : get_lbp_for_arithmetic_or_logical_expr (
13059 : : AST::ArithmeticOrLogicalExpr::ExprType expr_type)
13060 : : {
13061 : 27978 : switch (expr_type)
13062 : : {
13063 : : case ArithmeticOrLogicalOperator::ADD:
13064 : : return LBP_PLUS;
13065 : : case ArithmeticOrLogicalOperator::SUBTRACT:
13066 : : return LBP_MINUS;
13067 : : case ArithmeticOrLogicalOperator::MULTIPLY:
13068 : : return LBP_MUL;
13069 : : case ArithmeticOrLogicalOperator::DIVIDE:
13070 : : return LBP_DIV;
13071 : : case ArithmeticOrLogicalOperator::MODULUS:
13072 : : return LBP_MOD;
13073 : : case ArithmeticOrLogicalOperator::BITWISE_AND:
13074 : : return LBP_AMP;
13075 : : case ArithmeticOrLogicalOperator::BITWISE_OR:
13076 : : return LBP_PIPE;
13077 : : case ArithmeticOrLogicalOperator::BITWISE_XOR:
13078 : : return LBP_CARET;
13079 : : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
13080 : : return LBP_L_SHIFT;
13081 : : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
13082 : : return LBP_R_SHIFT;
13083 : 0 : default:
13084 : : // WTF? should not happen, this is an error
13085 : 0 : rust_unreachable ();
13086 : :
13087 : : return LBP_PLUS;
13088 : : }
13089 : : }
13090 : :
13091 : : // Parses an arithmetic or logical expression (with Pratt parsing).
13092 : : template <typename ManagedTokenSource>
13093 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13094 : 27978 : Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
13095 : : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13096 : : AST::ArithmeticOrLogicalExpr::ExprType expr_type,
13097 : : ParseRestrictions restrictions)
13098 : : {
13099 : : // parse RHS (as tok has already been consumed in parse_expression)
13100 : 27978 : std::unique_ptr<AST::Expr> right
13101 : 27978 : = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
13102 : 55956 : AST::AttrVec (), restrictions);
13103 : 27978 : if (right == nullptr)
13104 : 2 : return nullptr;
13105 : :
13106 : : // TODO: check types. actually, do so during semantic analysis
13107 : 27976 : location_t locus = left->get_locus ();
13108 : :
13109 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13110 : 27976 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13111 : 27976 : expr_type, locus));
13112 : 27978 : }
13113 : :
13114 : : // Parses a binary addition expression (with Pratt parsing).
13115 : : template <typename ManagedTokenSource>
13116 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13117 : 0 : Parser<ManagedTokenSource>::parse_binary_plus_expr (
13118 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13119 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13120 : : {
13121 : : // parse RHS (as tok has already been consumed in parse_expression)
13122 : 0 : std::unique_ptr<AST::Expr> right
13123 : 0 : = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions);
13124 : 0 : if (right == nullptr)
13125 : 0 : return nullptr;
13126 : :
13127 : : // TODO: check types. actually, do so during semantic analysis
13128 : 0 : location_t locus = left->get_locus ();
13129 : :
13130 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13131 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13132 : 0 : ArithmeticOrLogicalOperator::ADD, locus));
13133 : 0 : }
13134 : :
13135 : : // Parses a binary subtraction expression (with Pratt parsing).
13136 : : template <typename ManagedTokenSource>
13137 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13138 : 0 : Parser<ManagedTokenSource>::parse_binary_minus_expr (
13139 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13140 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13141 : : {
13142 : : // parse RHS (as tok has already been consumed in parse_expression)
13143 : 0 : std::unique_ptr<AST::Expr> right
13144 : 0 : = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions);
13145 : 0 : if (right == nullptr)
13146 : 0 : return nullptr;
13147 : :
13148 : : // TODO: check types. actually, do so during semantic analysis
13149 : 0 : location_t locus = left->get_locus ();
13150 : :
13151 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13152 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13153 : : ArithmeticOrLogicalOperator::SUBTRACT,
13154 : 0 : locus));
13155 : 0 : }
13156 : :
13157 : : // Parses a binary multiplication expression (with Pratt parsing).
13158 : : template <typename ManagedTokenSource>
13159 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13160 : 0 : Parser<ManagedTokenSource>::parse_binary_mult_expr (
13161 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13162 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13163 : : {
13164 : : // parse RHS (as tok has already been consumed in parse_expression)
13165 : 0 : std::unique_ptr<AST::Expr> right
13166 : 0 : = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
13167 : 0 : if (right == nullptr)
13168 : 0 : return nullptr;
13169 : :
13170 : : // TODO: check types. actually, do so during semantic analysis
13171 : 0 : location_t locus = left->get_locus ();
13172 : :
13173 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13174 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13175 : : ArithmeticOrLogicalOperator::MULTIPLY,
13176 : 0 : locus));
13177 : 0 : }
13178 : :
13179 : : // Parses a binary division expression (with Pratt parsing).
13180 : : template <typename ManagedTokenSource>
13181 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13182 : 0 : Parser<ManagedTokenSource>::parse_binary_div_expr (
13183 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13184 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13185 : : {
13186 : : // parse RHS (as tok has already been consumed in parse_expression)
13187 : 0 : std::unique_ptr<AST::Expr> right
13188 : 0 : = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
13189 : 0 : if (right == nullptr)
13190 : 0 : return nullptr;
13191 : :
13192 : : // TODO: check types. actually, do so during semantic analysis
13193 : 0 : location_t locus = left->get_locus ();
13194 : :
13195 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13196 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13197 : : ArithmeticOrLogicalOperator::DIVIDE,
13198 : 0 : locus));
13199 : 0 : }
13200 : :
13201 : : // Parses a binary modulo expression (with Pratt parsing).
13202 : : template <typename ManagedTokenSource>
13203 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13204 : 0 : Parser<ManagedTokenSource>::parse_binary_mod_expr (
13205 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13206 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13207 : : {
13208 : : // parse RHS (as tok has already been consumed in parse_expression)
13209 : 0 : std::unique_ptr<AST::Expr> right
13210 : 0 : = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
13211 : 0 : if (right == nullptr)
13212 : 0 : return nullptr;
13213 : :
13214 : : // TODO: check types. actually, do so during semantic analysis
13215 : 0 : location_t locus = left->get_locus ();
13216 : :
13217 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13218 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13219 : : ArithmeticOrLogicalOperator::MODULUS,
13220 : 0 : locus));
13221 : 0 : }
13222 : :
13223 : : /* Parses a binary bitwise (or eager logical) and expression (with Pratt
13224 : : * parsing). */
13225 : : template <typename ManagedTokenSource>
13226 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13227 : 0 : Parser<ManagedTokenSource>::parse_bitwise_and_expr (
13228 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13229 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13230 : : {
13231 : : // parse RHS (as tok has already been consumed in parse_expression)
13232 : 0 : std::unique_ptr<AST::Expr> right
13233 : 0 : = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
13234 : 0 : if (right == nullptr)
13235 : 0 : return nullptr;
13236 : :
13237 : : // TODO: check types. actually, do so during semantic analysis
13238 : 0 : location_t locus = left->get_locus ();
13239 : :
13240 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13241 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13242 : : ArithmeticOrLogicalOperator::BITWISE_AND,
13243 : 0 : locus));
13244 : 0 : }
13245 : :
13246 : : /* Parses a binary bitwise (or eager logical) or expression (with Pratt
13247 : : * parsing). */
13248 : : template <typename ManagedTokenSource>
13249 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13250 : 0 : Parser<ManagedTokenSource>::parse_bitwise_or_expr (
13251 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13252 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13253 : : {
13254 : : // parse RHS (as tok has already been consumed in parse_expression)
13255 : 0 : std::unique_ptr<AST::Expr> right
13256 : 0 : = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
13257 : 0 : if (right == nullptr)
13258 : 0 : return nullptr;
13259 : :
13260 : : // TODO: check types. actually, do so during semantic analysis
13261 : 0 : location_t locus = left->get_locus ();
13262 : :
13263 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13264 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13265 : : ArithmeticOrLogicalOperator::BITWISE_OR,
13266 : 0 : locus));
13267 : 0 : }
13268 : :
13269 : : /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
13270 : : * parsing). */
13271 : : template <typename ManagedTokenSource>
13272 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13273 : 0 : Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
13274 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13275 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13276 : : {
13277 : : // parse RHS (as tok has already been consumed in parse_expression)
13278 : 0 : std::unique_ptr<AST::Expr> right
13279 : 0 : = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
13280 : 0 : if (right == nullptr)
13281 : 0 : return nullptr;
13282 : :
13283 : : // TODO: check types. actually, do so during semantic analysis
13284 : 0 : location_t locus = left->get_locus ();
13285 : :
13286 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13287 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13288 : : ArithmeticOrLogicalOperator::BITWISE_XOR,
13289 : 0 : locus));
13290 : 0 : }
13291 : :
13292 : : // Parses a binary left shift expression (with Pratt parsing).
13293 : : template <typename ManagedTokenSource>
13294 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13295 : 0 : Parser<ManagedTokenSource>::parse_left_shift_expr (
13296 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13297 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13298 : : {
13299 : : // parse RHS (as tok has already been consumed in parse_expression)
13300 : 0 : std::unique_ptr<AST::Expr> right
13301 : 0 : = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
13302 : 0 : if (right == nullptr)
13303 : 0 : return nullptr;
13304 : :
13305 : : // TODO: check types. actually, do so during semantic analysis
13306 : 0 : location_t locus = left->get_locus ();
13307 : :
13308 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13309 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13310 : : ArithmeticOrLogicalOperator::LEFT_SHIFT,
13311 : 0 : locus));
13312 : 0 : }
13313 : :
13314 : : // Parses a binary right shift expression (with Pratt parsing).
13315 : : template <typename ManagedTokenSource>
13316 : : std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13317 : 0 : Parser<ManagedTokenSource>::parse_right_shift_expr (
13318 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13319 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13320 : : {
13321 : : // parse RHS (as tok has already been consumed in parse_expression)
13322 : 0 : std::unique_ptr<AST::Expr> right
13323 : 0 : = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
13324 : 0 : if (right == nullptr)
13325 : 0 : return nullptr;
13326 : :
13327 : : // TODO: check types. actually, do so during semantic analysis
13328 : 0 : location_t locus = left->get_locus ();
13329 : :
13330 : : return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13331 : 0 : new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13332 : : ArithmeticOrLogicalOperator::RIGHT_SHIFT,
13333 : 0 : locus));
13334 : 0 : }
13335 : :
13336 : : /* Returns the left binding power for the given ComparisonExpr type.
13337 : : * TODO make constexpr? Would that even do anything useful? */
13338 : : inline binding_powers
13339 : 4811 : get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
13340 : : {
13341 : 4811 : switch (expr_type)
13342 : : {
13343 : : case ComparisonOperator::EQUAL:
13344 : : return LBP_EQUAL;
13345 : : case ComparisonOperator::NOT_EQUAL:
13346 : : return LBP_NOT_EQUAL;
13347 : : case ComparisonOperator::GREATER_THAN:
13348 : : return LBP_GREATER_THAN;
13349 : : case ComparisonOperator::LESS_THAN:
13350 : : return LBP_SMALLER_THAN;
13351 : : case ComparisonOperator::GREATER_OR_EQUAL:
13352 : : return LBP_GREATER_EQUAL;
13353 : : case ComparisonOperator::LESS_OR_EQUAL:
13354 : : return LBP_SMALLER_EQUAL;
13355 : 0 : default:
13356 : : // WTF? should not happen, this is an error
13357 : 0 : rust_unreachable ();
13358 : :
13359 : : return LBP_EQUAL;
13360 : : }
13361 : : }
13362 : :
13363 : : /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
13364 : : * specify one and have the other looked up - e.g. specify ExprType and
13365 : : * binding power is looked up? */
13366 : : template <typename ManagedTokenSource>
13367 : : std::unique_ptr<AST::ComparisonExpr>
13368 : 4811 : Parser<ManagedTokenSource>::parse_comparison_expr (
13369 : : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13370 : : AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
13371 : : {
13372 : : // parse RHS (as tok has already been consumed in parse_expression)
13373 : 4811 : std::unique_ptr<AST::Expr> right
13374 : 4811 : = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (),
13375 : : restrictions);
13376 : 4811 : if (right == nullptr)
13377 : 0 : return nullptr;
13378 : :
13379 : : // TODO: check types. actually, do so during semantic analysis
13380 : 4811 : location_t locus = left->get_locus ();
13381 : :
13382 : : return std::unique_ptr<AST::ComparisonExpr> (
13383 : 4811 : new AST::ComparisonExpr (std::move (left), std::move (right), expr_type,
13384 : 4811 : locus));
13385 : 4811 : }
13386 : :
13387 : : // Parses a binary equal to expression (with Pratt parsing).
13388 : : template <typename ManagedTokenSource>
13389 : : std::unique_ptr<AST::ComparisonExpr>
13390 : 0 : Parser<ManagedTokenSource>::parse_binary_equal_expr (
13391 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13392 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13393 : : {
13394 : : // parse RHS (as tok has already been consumed in parse_expression)
13395 : 0 : std::unique_ptr<AST::Expr> right
13396 : 0 : = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
13397 : 0 : if (right == nullptr)
13398 : 0 : return nullptr;
13399 : :
13400 : : // TODO: check types. actually, do so during semantic analysis
13401 : 0 : location_t locus = left->get_locus ();
13402 : :
13403 : : return std::unique_ptr<AST::ComparisonExpr> (
13404 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13405 : 0 : ComparisonOperator::EQUAL, locus));
13406 : 0 : }
13407 : :
13408 : : // Parses a binary not equal to expression (with Pratt parsing).
13409 : : template <typename ManagedTokenSource>
13410 : : std::unique_ptr<AST::ComparisonExpr>
13411 : 0 : Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
13412 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13413 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13414 : : {
13415 : : // parse RHS (as tok has already been consumed in parse_expression)
13416 : 0 : std::unique_ptr<AST::Expr> right
13417 : 0 : = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
13418 : 0 : if (right == nullptr)
13419 : 0 : return nullptr;
13420 : :
13421 : : // TODO: check types. actually, do so during semantic analysis
13422 : 0 : location_t locus = left->get_locus ();
13423 : :
13424 : : return std::unique_ptr<AST::ComparisonExpr> (
13425 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13426 : 0 : ComparisonOperator::NOT_EQUAL, locus));
13427 : 0 : }
13428 : :
13429 : : // Parses a binary greater than expression (with Pratt parsing).
13430 : : template <typename ManagedTokenSource>
13431 : : std::unique_ptr<AST::ComparisonExpr>
13432 : 0 : Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
13433 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13434 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13435 : : {
13436 : : // parse RHS (as tok has already been consumed in parse_expression)
13437 : 0 : std::unique_ptr<AST::Expr> right
13438 : 0 : = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
13439 : 0 : if (right == nullptr)
13440 : 0 : return nullptr;
13441 : :
13442 : : // TODO: check types. actually, do so during semantic analysis
13443 : 0 : location_t locus = left->get_locus ();
13444 : :
13445 : : return std::unique_ptr<AST::ComparisonExpr> (
13446 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13447 : 0 : ComparisonOperator::GREATER_THAN, locus));
13448 : 0 : }
13449 : :
13450 : : // Parses a binary less than expression (with Pratt parsing).
13451 : : template <typename ManagedTokenSource>
13452 : : std::unique_ptr<AST::ComparisonExpr>
13453 : 0 : Parser<ManagedTokenSource>::parse_binary_less_than_expr (
13454 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13455 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13456 : : {
13457 : : // parse RHS (as tok has already been consumed in parse_expression)
13458 : 0 : std::unique_ptr<AST::Expr> right
13459 : 0 : = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
13460 : 0 : if (right == nullptr)
13461 : 0 : return nullptr;
13462 : :
13463 : : // TODO: check types. actually, do so during semantic analysis
13464 : 0 : location_t locus = left->get_locus ();
13465 : :
13466 : : return std::unique_ptr<AST::ComparisonExpr> (
13467 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13468 : 0 : ComparisonOperator::LESS_THAN, locus));
13469 : 0 : }
13470 : :
13471 : : // Parses a binary greater than or equal to expression (with Pratt parsing).
13472 : : template <typename ManagedTokenSource>
13473 : : std::unique_ptr<AST::ComparisonExpr>
13474 : 0 : Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
13475 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13476 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13477 : : {
13478 : : // parse RHS (as tok has already been consumed in parse_expression)
13479 : 0 : std::unique_ptr<AST::Expr> right
13480 : 0 : = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
13481 : 0 : if (right == nullptr)
13482 : 0 : return nullptr;
13483 : :
13484 : : // TODO: check types. actually, do so during semantic analysis
13485 : 0 : location_t locus = left->get_locus ();
13486 : :
13487 : : return std::unique_ptr<AST::ComparisonExpr> (
13488 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13489 : 0 : ComparisonOperator::GREATER_OR_EQUAL, locus));
13490 : 0 : }
13491 : :
13492 : : // Parses a binary less than or equal to expression (with Pratt parsing).
13493 : : template <typename ManagedTokenSource>
13494 : : std::unique_ptr<AST::ComparisonExpr>
13495 : 0 : Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
13496 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13497 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13498 : : {
13499 : : // parse RHS (as tok has already been consumed in parse_expression)
13500 : 0 : std::unique_ptr<AST::Expr> right
13501 : 0 : = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
13502 : 0 : if (right == nullptr)
13503 : 0 : return nullptr;
13504 : :
13505 : : // TODO: check types. actually, do so during semantic analysis
13506 : 0 : location_t locus = left->get_locus ();
13507 : :
13508 : : return std::unique_ptr<AST::ComparisonExpr> (
13509 : 0 : new AST::ComparisonExpr (std::move (left), std::move (right),
13510 : 0 : ComparisonOperator::LESS_OR_EQUAL, locus));
13511 : 0 : }
13512 : :
13513 : : // Parses a binary lazy boolean or expression (with Pratt parsing).
13514 : : template <typename ManagedTokenSource>
13515 : : std::unique_ptr<AST::LazyBooleanExpr>
13516 : 246 : Parser<ManagedTokenSource>::parse_lazy_or_expr (
13517 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13518 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13519 : : {
13520 : : // parse RHS (as tok has already been consumed in parse_expression)
13521 : 246 : std::unique_ptr<AST::Expr> right
13522 : 246 : = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
13523 : 246 : if (right == nullptr)
13524 : 0 : return nullptr;
13525 : :
13526 : : // TODO: check types. actually, do so during semantic analysis
13527 : 246 : location_t locus = left->get_locus ();
13528 : :
13529 : : return std::unique_ptr<AST::LazyBooleanExpr> (
13530 : 246 : new AST::LazyBooleanExpr (std::move (left), std::move (right),
13531 : 246 : LazyBooleanOperator::LOGICAL_OR, locus));
13532 : 246 : }
13533 : :
13534 : : // Parses a binary lazy boolean and expression (with Pratt parsing).
13535 : : template <typename ManagedTokenSource>
13536 : : std::unique_ptr<AST::LazyBooleanExpr>
13537 : 536 : Parser<ManagedTokenSource>::parse_lazy_and_expr (
13538 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13539 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13540 : : {
13541 : : // parse RHS (as tok has already been consumed in parse_expression)
13542 : 536 : std::unique_ptr<AST::Expr> right
13543 : 536 : = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
13544 : 536 : if (right == nullptr)
13545 : 0 : return nullptr;
13546 : :
13547 : : // TODO: check types. actually, do so during semantic analysis
13548 : 536 : location_t locus = left->get_locus ();
13549 : :
13550 : : return std::unique_ptr<AST::LazyBooleanExpr> (
13551 : 536 : new AST::LazyBooleanExpr (std::move (left), std::move (right),
13552 : 536 : LazyBooleanOperator::LOGICAL_AND, locus));
13553 : 536 : }
13554 : :
13555 : : // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
13556 : : template <typename ManagedTokenSource>
13557 : : std::unique_ptr<AST::TypeCastExpr>
13558 : 8936 : Parser<ManagedTokenSource>::parse_type_cast_expr (
13559 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
13560 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
13561 : : ParseRestrictions restrictions ATTRIBUTE_UNUSED)
13562 : : {
13563 : : // parse RHS (as tok has already been consumed in parse_expression)
13564 : 8936 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
13565 : 8936 : if (type == nullptr)
13566 : 0 : return nullptr;
13567 : : // FIXME: how do I get precedence put in here?
13568 : :
13569 : : // TODO: check types. actually, do so during semantic analysis
13570 : 8936 : location_t locus = expr_to_cast->get_locus ();
13571 : :
13572 : : return std::unique_ptr<AST::TypeCastExpr> (
13573 : 8936 : new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus));
13574 : 8936 : }
13575 : :
13576 : : // Parses a binary assignment expression (with Pratt parsing).
13577 : : template <typename ManagedTokenSource>
13578 : : std::unique_ptr<AST::AssignmentExpr>
13579 : 3616 : Parser<ManagedTokenSource>::parse_assig_expr (
13580 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13581 : : AST::AttrVec outer_attrs, ParseRestrictions restrictions)
13582 : : {
13583 : : // parse RHS (as tok has already been consumed in parse_expression)
13584 : 3616 : std::unique_ptr<AST::Expr> right
13585 : 3616 : = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
13586 : 3616 : if (right == nullptr)
13587 : 0 : return nullptr;
13588 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13589 : :
13590 : : // TODO: check types. actually, do so during semantic analysis
13591 : 3616 : location_t locus = left->get_locus ();
13592 : :
13593 : : return std::unique_ptr<AST::AssignmentExpr> (
13594 : 3616 : new AST::AssignmentExpr (std::move (left), std::move (right),
13595 : 3616 : std::move (outer_attrs), locus));
13596 : 3616 : }
13597 : :
13598 : : /* Returns the left binding power for the given CompoundAssignmentExpr type.
13599 : : * TODO make constexpr? Would that even do anything useful? */
13600 : : inline binding_powers
13601 : 1514 : get_lbp_for_compound_assignment_expr (
13602 : : AST::CompoundAssignmentExpr::ExprType expr_type)
13603 : : {
13604 : 1514 : switch (expr_type)
13605 : : {
13606 : : case CompoundAssignmentOperator::ADD:
13607 : : return LBP_PLUS;
13608 : : case CompoundAssignmentOperator::SUBTRACT:
13609 : : return LBP_MINUS;
13610 : : case CompoundAssignmentOperator::MULTIPLY:
13611 : : return LBP_MUL;
13612 : : case CompoundAssignmentOperator::DIVIDE:
13613 : : return LBP_DIV;
13614 : : case CompoundAssignmentOperator::MODULUS:
13615 : : return LBP_MOD;
13616 : : case CompoundAssignmentOperator::BITWISE_AND:
13617 : : return LBP_AMP;
13618 : : case CompoundAssignmentOperator::BITWISE_OR:
13619 : : return LBP_PIPE;
13620 : : case CompoundAssignmentOperator::BITWISE_XOR:
13621 : : return LBP_CARET;
13622 : : case CompoundAssignmentOperator::LEFT_SHIFT:
13623 : : return LBP_L_SHIFT;
13624 : : case CompoundAssignmentOperator::RIGHT_SHIFT:
13625 : : return LBP_R_SHIFT;
13626 : 0 : default:
13627 : : // WTF? should not happen, this is an error
13628 : 0 : rust_unreachable ();
13629 : :
13630 : : return LBP_PLUS;
13631 : : }
13632 : : }
13633 : :
13634 : : // Parses a compound assignment expression (with Pratt parsing).
13635 : : template <typename ManagedTokenSource>
13636 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13637 : 1514 : Parser<ManagedTokenSource>::parse_compound_assignment_expr (
13638 : : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13639 : : AST::CompoundAssignmentExpr::ExprType expr_type,
13640 : : ParseRestrictions restrictions)
13641 : : {
13642 : : // parse RHS (as tok has already been consumed in parse_expression)
13643 : 1514 : std::unique_ptr<AST::Expr> right
13644 : 1514 : = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
13645 : 3028 : AST::AttrVec (), restrictions);
13646 : 1514 : if (right == nullptr)
13647 : 0 : return nullptr;
13648 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13649 : :
13650 : : // TODO: check types. actually, do so during semantic analysis
13651 : 1514 : location_t locus = left->get_locus ();
13652 : :
13653 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13654 : 1514 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13655 : 1514 : expr_type, locus));
13656 : 1514 : }
13657 : :
13658 : : // Parses a binary add-assignment expression (with Pratt parsing).
13659 : : template <typename ManagedTokenSource>
13660 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13661 : 0 : Parser<ManagedTokenSource>::parse_plus_assig_expr (
13662 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13663 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13664 : : {
13665 : : // parse RHS (as tok has already been consumed in parse_expression)
13666 : 0 : std::unique_ptr<AST::Expr> right
13667 : 0 : = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
13668 : 0 : if (right == nullptr)
13669 : 0 : return nullptr;
13670 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13671 : :
13672 : : // TODO: check types. actually, do so during semantic analysis
13673 : 0 : location_t locus = left->get_locus ();
13674 : :
13675 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13676 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13677 : 0 : CompoundAssignmentOperator::ADD, locus));
13678 : 0 : }
13679 : :
13680 : : // Parses a binary minus-assignment expression (with Pratt parsing).
13681 : : template <typename ManagedTokenSource>
13682 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13683 : 0 : Parser<ManagedTokenSource>::parse_minus_assig_expr (
13684 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13685 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13686 : : {
13687 : : // parse RHS (as tok has already been consumed in parse_expression)
13688 : 0 : std::unique_ptr<AST::Expr> right
13689 : 0 : = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
13690 : 0 : if (right == nullptr)
13691 : 0 : return nullptr;
13692 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13693 : :
13694 : : // TODO: check types. actually, do so during semantic analysis
13695 : 0 : location_t locus = left->get_locus ();
13696 : :
13697 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13698 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13699 : : CompoundAssignmentOperator::SUBTRACT,
13700 : 0 : locus));
13701 : 0 : }
13702 : :
13703 : : // Parses a binary multiplication-assignment expression (with Pratt parsing).
13704 : : template <typename ManagedTokenSource>
13705 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13706 : 0 : Parser<ManagedTokenSource>::parse_mult_assig_expr (
13707 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13708 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13709 : : {
13710 : : // parse RHS (as tok has already been consumed in parse_expression)
13711 : 0 : std::unique_ptr<AST::Expr> right
13712 : 0 : = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
13713 : 0 : if (right == nullptr)
13714 : 0 : return nullptr;
13715 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13716 : :
13717 : : // TODO: check types. actually, do so during semantic analysis
13718 : 0 : location_t locus = left->get_locus ();
13719 : :
13720 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13721 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13722 : : CompoundAssignmentOperator::MULTIPLY,
13723 : 0 : locus));
13724 : 0 : }
13725 : :
13726 : : // Parses a binary division-assignment expression (with Pratt parsing).
13727 : : template <typename ManagedTokenSource>
13728 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13729 : 0 : Parser<ManagedTokenSource>::parse_div_assig_expr (
13730 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13731 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13732 : : {
13733 : : // parse RHS (as tok has already been consumed in parse_expression)
13734 : 0 : std::unique_ptr<AST::Expr> right
13735 : 0 : = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
13736 : 0 : if (right == nullptr)
13737 : 0 : return nullptr;
13738 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13739 : :
13740 : : // TODO: check types. actually, do so during semantic analysis
13741 : 0 : location_t locus = left->get_locus ();
13742 : :
13743 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13744 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13745 : : CompoundAssignmentOperator::DIVIDE,
13746 : 0 : locus));
13747 : 0 : }
13748 : :
13749 : : // Parses a binary modulo-assignment expression (with Pratt parsing).
13750 : : template <typename ManagedTokenSource>
13751 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13752 : 0 : Parser<ManagedTokenSource>::parse_mod_assig_expr (
13753 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13754 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13755 : : {
13756 : : // parse RHS (as tok has already been consumed in parse_expression)
13757 : 0 : std::unique_ptr<AST::Expr> right
13758 : 0 : = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
13759 : 0 : if (right == nullptr)
13760 : 0 : return nullptr;
13761 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13762 : :
13763 : : // TODO: check types. actually, do so during semantic analysis
13764 : 0 : location_t locus = left->get_locus ();
13765 : :
13766 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13767 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13768 : : CompoundAssignmentOperator::MODULUS,
13769 : 0 : locus));
13770 : 0 : }
13771 : :
13772 : : // Parses a binary and-assignment expression (with Pratt parsing).
13773 : : template <typename ManagedTokenSource>
13774 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13775 : 0 : Parser<ManagedTokenSource>::parse_and_assig_expr (
13776 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13777 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13778 : : {
13779 : : // parse RHS (as tok has already been consumed in parse_expression)
13780 : 0 : std::unique_ptr<AST::Expr> right
13781 : 0 : = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
13782 : 0 : if (right == nullptr)
13783 : 0 : return nullptr;
13784 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13785 : :
13786 : : // TODO: check types. actually, do so during semantic analysis
13787 : 0 : location_t locus = left->get_locus ();
13788 : :
13789 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13790 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13791 : : CompoundAssignmentOperator::BITWISE_AND,
13792 : 0 : locus));
13793 : 0 : }
13794 : :
13795 : : // Parses a binary or-assignment expression (with Pratt parsing).
13796 : : template <typename ManagedTokenSource>
13797 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13798 : 0 : Parser<ManagedTokenSource>::parse_or_assig_expr (
13799 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13800 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13801 : : {
13802 : : // parse RHS (as tok has already been consumed in parse_expression)
13803 : 0 : std::unique_ptr<AST::Expr> right
13804 : 0 : = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
13805 : 0 : if (right == nullptr)
13806 : 0 : return nullptr;
13807 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13808 : :
13809 : : // TODO: check types. actually, do so during semantic analysis
13810 : 0 : location_t locus = left->get_locus ();
13811 : :
13812 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13813 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13814 : : CompoundAssignmentOperator::BITWISE_OR,
13815 : 0 : locus));
13816 : 0 : }
13817 : :
13818 : : // Parses a binary xor-assignment expression (with Pratt parsing).
13819 : : template <typename ManagedTokenSource>
13820 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13821 : 0 : Parser<ManagedTokenSource>::parse_xor_assig_expr (
13822 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13823 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13824 : : {
13825 : : // parse RHS (as tok has already been consumed in parse_expression)
13826 : 0 : std::unique_ptr<AST::Expr> right
13827 : 0 : = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
13828 : 0 : if (right == nullptr)
13829 : 0 : return nullptr;
13830 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13831 : :
13832 : : // TODO: check types. actually, do so during semantic analysis
13833 : 0 : location_t locus = left->get_locus ();
13834 : :
13835 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13836 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13837 : : CompoundAssignmentOperator::BITWISE_XOR,
13838 : 0 : locus));
13839 : 0 : }
13840 : :
13841 : : // Parses a binary left shift-assignment expression (with Pratt parsing).
13842 : : template <typename ManagedTokenSource>
13843 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13844 : 0 : Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
13845 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13846 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13847 : : {
13848 : : // parse RHS (as tok has already been consumed in parse_expression)
13849 : 0 : std::unique_ptr<AST::Expr> right
13850 : 0 : = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
13851 : 0 : if (right == nullptr)
13852 : 0 : return nullptr;
13853 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13854 : :
13855 : : // TODO: check types. actually, do so during semantic analysis
13856 : 0 : location_t locus = left->get_locus ();
13857 : :
13858 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13859 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13860 : : CompoundAssignmentOperator::LEFT_SHIFT,
13861 : 0 : locus));
13862 : 0 : }
13863 : :
13864 : : // Parses a binary right shift-assignment expression (with Pratt parsing).
13865 : : template <typename ManagedTokenSource>
13866 : : std::unique_ptr<AST::CompoundAssignmentExpr>
13867 : 0 : Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
13868 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13869 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13870 : : {
13871 : : // parse RHS (as tok has already been consumed in parse_expression)
13872 : 0 : std::unique_ptr<AST::Expr> right
13873 : 0 : = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
13874 : 0 : if (right == nullptr)
13875 : 0 : return nullptr;
13876 : : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13877 : :
13878 : : // TODO: check types. actually, do so during semantic analysis
13879 : 0 : location_t locus = left->get_locus ();
13880 : :
13881 : : return std::unique_ptr<AST::CompoundAssignmentExpr> (
13882 : 0 : new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13883 : : CompoundAssignmentOperator::RIGHT_SHIFT,
13884 : 0 : locus));
13885 : 0 : }
13886 : :
13887 : : // Parses a postfix unary await expression (with Pratt parsing).
13888 : : template <typename ManagedTokenSource>
13889 : : std::unique_ptr<AST::AwaitExpr>
13890 : 0 : Parser<ManagedTokenSource>::parse_await_expr (
13891 : : const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
13892 : : AST::AttrVec outer_attrs)
13893 : : {
13894 : : /* skip "await" identifier (as "." has already been consumed in
13895 : : * parse_expression) this assumes that the identifier was already identified
13896 : : * as await */
13897 : 0 : if (!skip_token (IDENTIFIER))
13898 : : {
13899 : 0 : Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
13900 : : "- this is probably a deep issue");
13901 : 0 : add_error (std::move (error));
13902 : :
13903 : : // skip somewhere?
13904 : 0 : return nullptr;
13905 : 0 : }
13906 : :
13907 : : // TODO: check inside async block in semantic analysis
13908 : 0 : location_t locus = expr_to_await->get_locus ();
13909 : :
13910 : : return std::unique_ptr<AST::AwaitExpr> (
13911 : 0 : new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
13912 : 0 : locus));
13913 : : }
13914 : :
13915 : : /* Parses an exclusive range ('..') in left denotation position (i.e.
13916 : : * RangeFromExpr or RangeFromToExpr). */
13917 : : template <typename ManagedTokenSource>
13918 : : std::unique_ptr<AST::RangeExpr>
13919 : 356 : Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
13920 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13921 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13922 : : {
13923 : : // FIXME: this probably parses expressions accidently or whatever
13924 : : // try parsing RHS (as tok has already been consumed in parse_expression)
13925 : : // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
13926 : : // RangeFromToExpr.
13927 : 356 : restrictions.expr_can_be_null = true;
13928 : 356 : std::unique_ptr<AST::Expr> right
13929 : 356 : = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
13930 : :
13931 : 356 : location_t locus = left->get_locus ();
13932 : :
13933 : 356 : if (right == nullptr)
13934 : : {
13935 : : // range from expr
13936 : 65 : return std::unique_ptr<AST::RangeFromExpr> (
13937 : 65 : new AST::RangeFromExpr (std::move (left), locus));
13938 : : }
13939 : : else
13940 : : {
13941 : 291 : return std::unique_ptr<AST::RangeFromToExpr> (
13942 : 291 : new AST::RangeFromToExpr (std::move (left), std::move (right), locus));
13943 : : }
13944 : : // FIXME: make non-associative
13945 : 356 : }
13946 : :
13947 : : /* Parses an exclusive range ('..') in null denotation position (i.e.
13948 : : * RangeToExpr or RangeFullExpr). */
13949 : : template <typename ManagedTokenSource>
13950 : : std::unique_ptr<AST::RangeExpr>
13951 : 173 : Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
13952 : : const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
13953 : : {
13954 : 173 : auto restrictions = ParseRestrictions ();
13955 : 173 : restrictions.expr_can_be_null = true;
13956 : :
13957 : : // FIXME: this probably parses expressions accidently or whatever
13958 : : // try parsing RHS (as tok has already been consumed in parse_expression)
13959 : 173 : std::unique_ptr<AST::Expr> right
13960 : 173 : = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
13961 : :
13962 : 173 : location_t locus = tok->get_locus ();
13963 : :
13964 : 173 : if (right == nullptr)
13965 : : {
13966 : : // range from expr
13967 : 54 : return std::unique_ptr<AST::RangeFullExpr> (
13968 : 54 : new AST::RangeFullExpr (locus));
13969 : : }
13970 : : else
13971 : : {
13972 : 119 : return std::unique_ptr<AST::RangeToExpr> (
13973 : 119 : new AST::RangeToExpr (std::move (right), locus));
13974 : : }
13975 : : // FIXME: make non-associative
13976 : 173 : }
13977 : :
13978 : : // Parses a full binary range inclusive expression.
13979 : : template <typename ManagedTokenSource>
13980 : : std::unique_ptr<AST::RangeFromToInclExpr>
13981 : 13 : Parser<ManagedTokenSource>::parse_range_inclusive_expr (
13982 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13983 : : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13984 : : {
13985 : : // parse RHS (as tok has already been consumed in parse_expression)
13986 : 13 : std::unique_ptr<AST::Expr> right
13987 : 13 : = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
13988 : 13 : if (right == nullptr)
13989 : 0 : return nullptr;
13990 : : // FIXME: make non-associative
13991 : :
13992 : : // TODO: check types. actually, do so during semantic analysis
13993 : 13 : location_t locus = left->get_locus ();
13994 : :
13995 : : return std::unique_ptr<AST::RangeFromToInclExpr> (
13996 : 13 : new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus));
13997 : 13 : }
13998 : :
13999 : : // Parses an inclusive range-to prefix unary expression.
14000 : : template <typename ManagedTokenSource>
14001 : : std::unique_ptr<AST::RangeToInclExpr>
14002 : 0 : Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
14003 : : const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
14004 : : {
14005 : : // parse RHS (as tok has already been consumed in parse_expression)
14006 : 0 : std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ);
14007 : 0 : if (right == nullptr)
14008 : 0 : return nullptr;
14009 : : // FIXME: make non-associative
14010 : :
14011 : : // TODO: check types. actually, do so during semantic analysis
14012 : :
14013 : : return std::unique_ptr<AST::RangeToInclExpr> (
14014 : 0 : new AST::RangeToInclExpr (std::move (right), tok->get_locus ()));
14015 : 0 : }
14016 : :
14017 : : // Parses a pseudo-binary infix tuple index expression.
14018 : : template <typename ManagedTokenSource>
14019 : : std::unique_ptr<AST::TupleIndexExpr>
14020 : 8945 : Parser<ManagedTokenSource>::parse_tuple_index_expr (
14021 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
14022 : : AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14023 : : {
14024 : : // parse int literal (as token already skipped)
14025 : 8945 : const_TokenPtr index_tok = expect_token (INT_LITERAL);
14026 : 8945 : if (index_tok == nullptr)
14027 : : {
14028 : 0 : return nullptr;
14029 : : }
14030 : 17890 : std::string index = index_tok->get_str ();
14031 : :
14032 : : // convert to integer
14033 : 8945 : if (!index_tok->is_pure_decimal ())
14034 : : {
14035 : 27 : Error error (index_tok->get_locus (),
14036 : : "tuple index should be a pure decimal literal");
14037 : 27 : add_error (std::move (error));
14038 : 27 : }
14039 : 8945 : int index_int = atoi (index.c_str ());
14040 : :
14041 : 8945 : location_t locus = tuple_expr->get_locus ();
14042 : :
14043 : : return std::unique_ptr<AST::TupleIndexExpr> (
14044 : 8945 : new AST::TupleIndexExpr (std::move (tuple_expr), index_int,
14045 : 8945 : std::move (outer_attrs), locus));
14046 : 8945 : }
14047 : :
14048 : : // Parses a pseudo-binary infix array (or slice) index expression.
14049 : : template <typename ManagedTokenSource>
14050 : : std::unique_ptr<AST::ArrayIndexExpr>
14051 : 807 : Parser<ManagedTokenSource>::parse_index_expr (
14052 : : const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
14053 : : AST::AttrVec outer_attrs, ParseRestrictions)
14054 : : {
14055 : : // parse RHS (as tok has already been consumed in parse_expression)
14056 : : /*std::unique_ptr<AST::Expr> index_expr
14057 : : = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
14058 : : restrictions);*/
14059 : : // TODO: conceptually, should treat [] as brackets, so just parse all expr
14060 : 807 : std::unique_ptr<AST::Expr> index_expr = parse_expr ();
14061 : 807 : if (index_expr == nullptr)
14062 : 0 : return nullptr;
14063 : :
14064 : : // skip ']' at end of array
14065 : 807 : if (!skip_token (RIGHT_SQUARE))
14066 : : {
14067 : : // skip somewhere?
14068 : 0 : return nullptr;
14069 : : }
14070 : :
14071 : : // TODO: check types. actually, do so during semantic analysis
14072 : 807 : location_t locus = array_expr->get_locus ();
14073 : :
14074 : : return std::unique_ptr<AST::ArrayIndexExpr> (
14075 : 807 : new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr),
14076 : 807 : std::move (outer_attrs), locus));
14077 : 807 : }
14078 : :
14079 : : // Parses a pseudo-binary infix struct field access expression.
14080 : : template <typename ManagedTokenSource>
14081 : : std::unique_ptr<AST::FieldAccessExpr>
14082 : 7709 : Parser<ManagedTokenSource>::parse_field_access_expr (
14083 : : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
14084 : : AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14085 : : {
14086 : : /* get field name identifier (assume that this is a field access expr and
14087 : : * not await, for instance) */
14088 : 7709 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
14089 : 7709 : if (ident_tok == nullptr)
14090 : 0 : return nullptr;
14091 : :
14092 : 15418 : Identifier ident{ident_tok};
14093 : :
14094 : 7709 : location_t locus = struct_expr->get_locus ();
14095 : :
14096 : : // TODO: check types. actually, do so during semantic analysis
14097 : : return std::unique_ptr<AST::FieldAccessExpr> (
14098 : 7709 : new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident),
14099 : 7709 : std::move (outer_attrs), locus));
14100 : 7709 : }
14101 : :
14102 : : // Parses a pseudo-binary infix method call expression.
14103 : : template <typename ManagedTokenSource>
14104 : : std::unique_ptr<AST::MethodCallExpr>
14105 : 29605 : Parser<ManagedTokenSource>::parse_method_call_expr (
14106 : : const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
14107 : : AST::AttrVec outer_attrs, ParseRestrictions)
14108 : : {
14109 : : // parse path expr segment
14110 : 29605 : AST::PathExprSegment segment = parse_path_expr_segment ();
14111 : 29605 : if (segment.is_error ())
14112 : : {
14113 : 0 : Error error (tok->get_locus (),
14114 : : "failed to parse path expr segment of method call expr");
14115 : 0 : add_error (std::move (error));
14116 : :
14117 : 0 : return nullptr;
14118 : 0 : }
14119 : :
14120 : : // skip left parentheses
14121 : 29605 : if (!skip_token (LEFT_PAREN))
14122 : : {
14123 : 0 : return nullptr;
14124 : : }
14125 : :
14126 : : // parse method params (if they exist)
14127 : 29605 : std::vector<std::unique_ptr<AST::Expr>> params;
14128 : :
14129 : 29605 : const_TokenPtr t = lexer.peek_token ();
14130 : 35738 : while (t->get_id () != RIGHT_PAREN)
14131 : : {
14132 : 6133 : std::unique_ptr<AST::Expr> param = parse_expr ();
14133 : 6133 : if (param == nullptr)
14134 : : {
14135 : 0 : Error error (t->get_locus (),
14136 : : "failed to parse method param in method call");
14137 : 0 : add_error (std::move (error));
14138 : :
14139 : 0 : return nullptr;
14140 : 0 : }
14141 : 6133 : params.push_back (std::move (param));
14142 : :
14143 : 12266 : if (lexer.peek_token ()->get_id () != COMMA)
14144 : : break;
14145 : :
14146 : 418 : lexer.skip_token ();
14147 : 418 : t = lexer.peek_token ();
14148 : : }
14149 : :
14150 : : // skip right paren
14151 : 29605 : if (!skip_token (RIGHT_PAREN))
14152 : : {
14153 : 0 : return nullptr;
14154 : : }
14155 : :
14156 : : // TODO: check types. actually do so in semantic analysis pass.
14157 : 29605 : location_t locus = receiver_expr->get_locus ();
14158 : :
14159 : : return std::unique_ptr<AST::MethodCallExpr> (
14160 : 59210 : new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment),
14161 : : std::move (params), std::move (outer_attrs),
14162 : 29605 : locus));
14163 : 29605 : }
14164 : :
14165 : : // Parses a pseudo-binary infix function call expression.
14166 : : template <typename ManagedTokenSource>
14167 : : std::unique_ptr<AST::CallExpr>
14168 : 558 : Parser<ManagedTokenSource>::parse_function_call_expr (
14169 : : const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
14170 : : AST::AttrVec outer_attrs, ParseRestrictions)
14171 : : {
14172 : : // parse function params (if they exist)
14173 : 558 : std::vector<std::unique_ptr<AST::Expr>> params;
14174 : :
14175 : 558 : const_TokenPtr t = lexer.peek_token ();
14176 : 1062 : while (t->get_id () != RIGHT_PAREN)
14177 : : {
14178 : 504 : std::unique_ptr<AST::Expr> param = parse_expr ();
14179 : 504 : if (param == nullptr)
14180 : : {
14181 : 0 : Error error (t->get_locus (),
14182 : : "failed to parse function param in function call");
14183 : 0 : add_error (std::move (error));
14184 : :
14185 : 0 : return nullptr;
14186 : 0 : }
14187 : 504 : params.push_back (std::move (param));
14188 : :
14189 : 1008 : if (lexer.peek_token ()->get_id () != COMMA)
14190 : : break;
14191 : :
14192 : 107 : lexer.skip_token ();
14193 : 107 : t = lexer.peek_token ();
14194 : : }
14195 : :
14196 : : // skip ')' at end of param list
14197 : 558 : if (!skip_token (RIGHT_PAREN))
14198 : : {
14199 : : // skip somewhere?
14200 : 0 : return nullptr;
14201 : : }
14202 : :
14203 : : // TODO: check types. actually, do so during semantic analysis
14204 : 558 : location_t locus = function_expr->get_locus ();
14205 : :
14206 : : return std::unique_ptr<AST::CallExpr> (
14207 : 558 : new AST::CallExpr (std::move (function_expr), std::move (params),
14208 : 558 : std::move (outer_attrs), locus));
14209 : 558 : }
14210 : :
14211 : : /* Parses a macro invocation with a path in expression already parsed (but not
14212 : : * '!' token). */
14213 : : template <typename ManagedTokenSource>
14214 : : std::unique_ptr<AST::MacroInvocation>
14215 : 52545 : Parser<ManagedTokenSource>::parse_macro_invocation_partial (
14216 : : AST::PathInExpression path, AST::AttrVec outer_attrs,
14217 : : ParseRestrictions restrictions)
14218 : : {
14219 : : // macro invocation
14220 : 52545 : if (!skip_token (EXCLAM))
14221 : : {
14222 : 0 : return nullptr;
14223 : : }
14224 : :
14225 : : // convert PathInExpression to SimplePath - if this isn't possible, error
14226 : 52545 : AST::SimplePath converted_path = path.as_simple_path ();
14227 : 52545 : if (converted_path.is_empty ())
14228 : : {
14229 : 0 : Error error (lexer.peek_token ()->get_locus (),
14230 : : "failed to parse simple path in macro invocation");
14231 : 0 : add_error (std::move (error));
14232 : :
14233 : 0 : return nullptr;
14234 : 0 : }
14235 : :
14236 : 52545 : AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
14237 : :
14238 : 52545 : rust_debug ("successfully parsed macro invocation (via partial)");
14239 : :
14240 : 52545 : location_t macro_locus = converted_path.get_locus ();
14241 : :
14242 : 105090 : return AST::MacroInvocation::Regular (
14243 : 105090 : AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
14244 : 52545 : std::move (outer_attrs), macro_locus);
14245 : 52545 : }
14246 : :
14247 : : /* Parses a struct expr struct with a path in expression already parsed (but
14248 : : * not
14249 : : * '{' token). */
14250 : : template <typename ManagedTokenSource>
14251 : : std::unique_ptr<AST::StructExprStruct>
14252 : 1694 : Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
14253 : : AST::PathInExpression path, AST::AttrVec outer_attrs)
14254 : : {
14255 : : // assume struct expr struct (as struct-enum disambiguation requires name
14256 : : // lookup) again, make statement if final ';'
14257 : 1694 : if (!skip_token (LEFT_CURLY))
14258 : : {
14259 : 0 : return nullptr;
14260 : : }
14261 : :
14262 : : // parse inner attributes
14263 : 1694 : AST::AttrVec inner_attrs = parse_inner_attributes ();
14264 : :
14265 : : // branch based on next token
14266 : 1694 : const_TokenPtr t = lexer.peek_token ();
14267 : 1694 : location_t path_locus = path.get_locus ();
14268 : 1694 : switch (t->get_id ())
14269 : : {
14270 : 75 : case RIGHT_CURLY:
14271 : : // struct with no body
14272 : 75 : lexer.skip_token ();
14273 : :
14274 : : return std::unique_ptr<AST::StructExprStruct> (
14275 : 75 : new AST::StructExprStruct (std::move (path), std::move (inner_attrs),
14276 : 75 : std::move (outer_attrs), path_locus));
14277 : 1619 : case DOT_DOT:
14278 : : /* technically this would give a struct base-only struct, but this
14279 : : * algorithm should work too. As such, AST type not happening. */
14280 : : case IDENTIFIER:
14281 : : case HASH:
14282 : : case INT_LITERAL:
14283 : : {
14284 : : // struct with struct expr fields
14285 : :
14286 : : // parse struct expr fields
14287 : 1619 : std::vector<std::unique_ptr<AST::StructExprField>> fields;
14288 : :
14289 : 4479 : while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
14290 : : {
14291 : 2860 : std::unique_ptr<AST::StructExprField> field
14292 : : = parse_struct_expr_field ();
14293 : 2860 : if (field == nullptr)
14294 : : {
14295 : 0 : Error error (t->get_locus (),
14296 : : "failed to parse struct (or enum) expr field");
14297 : 0 : add_error (std::move (error));
14298 : :
14299 : 0 : return nullptr;
14300 : 0 : }
14301 : :
14302 : : // DEBUG:
14303 : 2860 : rust_debug ("struct/enum expr field validated to not be null");
14304 : :
14305 : 2860 : fields.push_back (std::move (field));
14306 : :
14307 : : // DEBUG:
14308 : 2860 : rust_debug ("struct/enum expr field pushed back");
14309 : :
14310 : 5720 : if (lexer.peek_token ()->get_id () != COMMA)
14311 : : {
14312 : : // DEBUG:
14313 : 1338 : rust_debug ("lack of comma detected in struct/enum expr "
14314 : : "fields - break");
14315 : : break;
14316 : : }
14317 : 1522 : lexer.skip_token ();
14318 : :
14319 : : // DEBUG:
14320 : 1522 : rust_debug ("struct/enum expr fields comma skipped ");
14321 : :
14322 : 1522 : t = lexer.peek_token ();
14323 : : }
14324 : :
14325 : : // DEBUG:
14326 : 1619 : rust_debug ("struct/enum expr about to parse struct base ");
14327 : :
14328 : : // parse struct base if it exists
14329 : : AST::StructBase struct_base = AST::StructBase::error ();
14330 : 3238 : if (lexer.peek_token ()->get_id () == DOT_DOT)
14331 : : {
14332 : 69 : location_t dot_dot_location = lexer.peek_token ()->get_locus ();
14333 : 69 : lexer.skip_token ();
14334 : :
14335 : : // parse required struct base expr
14336 : 69 : std::unique_ptr<AST::Expr> base_expr = parse_expr ();
14337 : 69 : if (base_expr == nullptr)
14338 : : {
14339 : 0 : Error error (lexer.peek_token ()->get_locus (),
14340 : : "failed to parse struct base expression in struct "
14341 : : "expression");
14342 : 0 : add_error (std::move (error));
14343 : :
14344 : 0 : return nullptr;
14345 : 0 : }
14346 : :
14347 : : // DEBUG:
14348 : 69 : rust_debug ("struct/enum expr - parsed and validated base expr");
14349 : :
14350 : : struct_base
14351 : 69 : = AST::StructBase (std::move (base_expr), dot_dot_location);
14352 : :
14353 : : // DEBUG:
14354 : 69 : rust_debug ("assigned struct base to new struct base ");
14355 : 69 : }
14356 : :
14357 : 1619 : if (!skip_token (RIGHT_CURLY))
14358 : : {
14359 : 0 : return nullptr;
14360 : : }
14361 : :
14362 : : // DEBUG:
14363 : 1619 : rust_debug (
14364 : : "struct/enum expr skipped right curly - done and ready to return");
14365 : :
14366 : 1619 : return std::unique_ptr<AST::StructExprStructFields> (
14367 : 1619 : new AST::StructExprStructFields (std::move (path), std::move (fields),
14368 : : path_locus, std::move (struct_base),
14369 : : std::move (inner_attrs),
14370 : 1619 : std::move (outer_attrs)));
14371 : 1619 : }
14372 : 0 : default:
14373 : 0 : add_error (
14374 : 0 : Error (t->get_locus (),
14375 : : "unrecognised token %qs in struct (or enum) expression - "
14376 : : "expected %<}%>, identifier, integer literal, or %<..%>",
14377 : : t->get_token_description ()));
14378 : :
14379 : 0 : return nullptr;
14380 : : }
14381 : 1694 : }
14382 : :
14383 : : /* Parses a struct expr tuple with a path in expression already parsed (but
14384 : : * not
14385 : : * '(' token).
14386 : : * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
14387 : : * A better solution would be to just get this to call that function directly.
14388 : : * */
14389 : : template <typename ManagedTokenSource>
14390 : : std::unique_ptr<AST::CallExpr>
14391 : 78744 : Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
14392 : : AST::PathInExpression path, AST::AttrVec outer_attrs)
14393 : : {
14394 : 78744 : if (!skip_token (LEFT_PAREN))
14395 : : {
14396 : 0 : return nullptr;
14397 : : }
14398 : :
14399 : 78744 : AST::AttrVec inner_attrs = parse_inner_attributes ();
14400 : :
14401 : 78744 : std::vector<std::unique_ptr<AST::Expr>> exprs;
14402 : :
14403 : 78744 : const_TokenPtr t = lexer.peek_token ();
14404 : 288893 : while (t->get_id () != RIGHT_PAREN)
14405 : : {
14406 : : // parse expression (required)
14407 : 210149 : std::unique_ptr<AST::Expr> expr = parse_expr ();
14408 : 210149 : if (expr == nullptr)
14409 : : {
14410 : 0 : Error error (t->get_locus (), "failed to parse expression in "
14411 : : "struct (or enum) expression tuple");
14412 : 0 : add_error (std::move (error));
14413 : :
14414 : 0 : return nullptr;
14415 : 0 : }
14416 : 210149 : exprs.push_back (std::move (expr));
14417 : :
14418 : 420298 : if (lexer.peek_token ()->get_id () != COMMA)
14419 : : break;
14420 : :
14421 : 142344 : lexer.skip_token ();
14422 : :
14423 : 142344 : t = lexer.peek_token ();
14424 : : }
14425 : :
14426 : 78744 : if (!skip_token (RIGHT_PAREN))
14427 : : {
14428 : 0 : return nullptr;
14429 : : }
14430 : :
14431 : 78744 : location_t path_locus = path.get_locus ();
14432 : :
14433 : 78744 : auto pathExpr = std::unique_ptr<AST::PathInExpression> (
14434 : 78744 : new AST::PathInExpression (std::move (path)));
14435 : :
14436 : : return std::unique_ptr<AST::CallExpr> (
14437 : 78744 : new AST::CallExpr (std::move (pathExpr), std::move (exprs),
14438 : 78744 : std::move (outer_attrs), path_locus));
14439 : 157488 : }
14440 : :
14441 : : // Parses a closure expression with pratt parsing (from null denotation).
14442 : : template <typename ManagedTokenSource>
14443 : : std::unique_ptr<AST::ClosureExpr>
14444 : 376 : Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
14445 : : AST::AttrVec outer_attrs)
14446 : : {
14447 : : // TODO: does this need pratt parsing (for precedence)? probably not, but
14448 : : // idk
14449 : 376 : location_t locus = tok->get_locus ();
14450 : 376 : bool has_move = false;
14451 : 376 : if (tok->get_id () == MOVE)
14452 : : {
14453 : 60 : has_move = true;
14454 : 60 : tok = lexer.peek_token ();
14455 : 60 : lexer.skip_token ();
14456 : : // skip token and reassign
14457 : : }
14458 : :
14459 : : // handle parameter list
14460 : 376 : std::vector<AST::ClosureParam> params;
14461 : :
14462 : 376 : switch (tok->get_id ())
14463 : : {
14464 : : case OR:
14465 : : // no parameters, don't skip token
14466 : : break;
14467 : 351 : case PIPE:
14468 : : {
14469 : : // actually may have parameters
14470 : : // don't skip token
14471 : 351 : const_TokenPtr t = lexer.peek_token ();
14472 : 785 : while (t->get_id () != PIPE)
14473 : : {
14474 : 434 : AST::ClosureParam param = parse_closure_param ();
14475 : 434 : if (param.is_error ())
14476 : : {
14477 : : // TODO is this really an error?
14478 : 0 : Error error (t->get_locus (), "could not parse closure param");
14479 : 0 : add_error (std::move (error));
14480 : :
14481 : 0 : return nullptr;
14482 : 0 : }
14483 : 434 : params.push_back (std::move (param));
14484 : :
14485 : 868 : if (lexer.peek_token ()->get_id () != COMMA)
14486 : : {
14487 : 702 : if (lexer.peek_token ()->get_id () == OR)
14488 : 1 : lexer.split_current_token (PIPE, PIPE);
14489 : : // not an error but means param list is done
14490 : : break;
14491 : : }
14492 : : // skip comma
14493 : 83 : lexer.skip_token ();
14494 : :
14495 : 166 : if (lexer.peek_token ()->get_id () == OR)
14496 : 0 : lexer.split_current_token (PIPE, PIPE);
14497 : :
14498 : 83 : t = lexer.peek_token ();
14499 : : }
14500 : :
14501 : 351 : if (!skip_token (PIPE))
14502 : : {
14503 : 0 : return nullptr;
14504 : : }
14505 : : break;
14506 : 351 : }
14507 : 0 : default:
14508 : 0 : add_error (Error (tok->get_locus (),
14509 : : "unexpected token %qs in closure expression - expected "
14510 : : "%<|%> or %<||%>",
14511 : : tok->get_token_description ()));
14512 : :
14513 : : // skip somewhere?
14514 : 0 : return nullptr;
14515 : : }
14516 : :
14517 : : // again branch based on next token
14518 : 376 : tok = lexer.peek_token ();
14519 : 376 : if (tok->get_id () == RETURN_TYPE)
14520 : : {
14521 : : // must be return type closure with block expr
14522 : :
14523 : : // skip "return type" token
14524 : 32 : lexer.skip_token ();
14525 : :
14526 : : // parse actual type, which is required
14527 : 32 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
14528 : 32 : if (type == nullptr)
14529 : : {
14530 : : // error
14531 : 0 : Error error (tok->get_locus (), "failed to parse type for closure");
14532 : 0 : add_error (std::move (error));
14533 : :
14534 : : // skip somewhere?
14535 : 0 : return nullptr;
14536 : 0 : }
14537 : :
14538 : : // parse block expr, which is required
14539 : 32 : std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
14540 : 32 : if (block == nullptr)
14541 : : {
14542 : : // error
14543 : 0 : Error error (lexer.peek_token ()->get_locus (),
14544 : : "failed to parse block expr in closure");
14545 : 0 : add_error (std::move (error));
14546 : :
14547 : : // skip somewhere?
14548 : 0 : return nullptr;
14549 : 0 : }
14550 : :
14551 : 32 : return std::unique_ptr<AST::ClosureExprInnerTyped> (
14552 : 32 : new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
14553 : : std::move (params), locus, has_move,
14554 : 32 : std::move (outer_attrs)));
14555 : 32 : }
14556 : : else
14557 : : {
14558 : : // must be expr-only closure
14559 : :
14560 : : // parse expr, which is required
14561 : 344 : std::unique_ptr<AST::Expr> expr = parse_expr ();
14562 : 344 : if (expr == nullptr)
14563 : : {
14564 : 0 : Error error (tok->get_locus (),
14565 : : "failed to parse expression in closure");
14566 : 0 : add_error (std::move (error));
14567 : :
14568 : : // skip somewhere?
14569 : 0 : return nullptr;
14570 : 0 : }
14571 : :
14572 : 344 : return std::unique_ptr<AST::ClosureExprInner> (
14573 : 344 : new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
14574 : 344 : has_move, std::move (outer_attrs)));
14575 : 344 : }
14576 : 376 : }
14577 : :
14578 : : // Returns true if the next token is END, ELSE, or EOF;
14579 : : template <typename ManagedTokenSource>
14580 : : bool
14581 : 0 : Parser<ManagedTokenSource>::done_end_or_else ()
14582 : : {
14583 : 0 : const_TokenPtr t = lexer.peek_token ();
14584 : 0 : return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
14585 : 0 : || t->get_id () == END_OF_FILE);
14586 : 0 : }
14587 : :
14588 : : // Returns true if the next token is END or EOF.
14589 : : template <typename ManagedTokenSource>
14590 : : bool
14591 : 0 : Parser<ManagedTokenSource>::done_end ()
14592 : : {
14593 : 0 : const_TokenPtr t = lexer.peek_token ();
14594 : 0 : return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
14595 : 0 : }
14596 : : } // namespace Rust
|