Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : /* 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-keyword-values.h"
38 : #include "rust-edition.h"
39 : #include "rust-parse-error.h"
40 :
41 : #include "optional.h"
42 :
43 : namespace Rust {
44 :
45 : /* HACK-y special handling for skipping a right angle token at the end of
46 : * generic arguments.
47 : * Currently, this replaces the "current token" with one that is identical
48 : * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
49 : * for several reasons - it modifies the token stream to something that
50 : * actually doesn't make syntactic sense, it may not worked if the token
51 : * has already been skipped, etc. It was done because it would not
52 : * actually require inserting new items into the token stream (which I
53 : * thought would take more work to not mess up) and because I wasn't sure
54 : * if the "already seen right angle" flag in the parser would work
55 : * correctly.
56 : * Those two other approaches listed are in my opinion actually better
57 : * long-term - insertion is probably best as it reflects syntactically
58 : * what occurs. On the other hand, I need to do a code audit to make sure
59 : * that insertion doesn't mess anything up. So that's a FIXME. */
60 : template <typename ManagedTokenSource>
61 : bool
62 7893 : Parser<ManagedTokenSource>::skip_generics_right_angle ()
63 : {
64 : /* OK, new great idea. Have a lexer method called
65 : * "split_current_token(TokenType newLeft, TokenType newRight)", which is
66 : * called here with whatever arguments are appropriate. That lexer method
67 : * handles "replacing" the current token with the "newLeft" and "inserting"
68 : * the next token with the "newRight" (and creating a location, etc. for it)
69 : */
70 :
71 : /* HACK: special handling for right shift '>>', greater or equal '>=', and
72 : * right shift assig */
73 : // '>>='
74 7893 : const_TokenPtr tok = lexer.peek_token ();
75 7893 : switch (tok->get_id ())
76 : {
77 7645 : case RIGHT_ANGLE:
78 : // this is good - skip token
79 7645 : lexer.skip_token ();
80 7645 : return true;
81 247 : case RIGHT_SHIFT:
82 : {
83 : // new implementation that should be better
84 247 : lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
85 247 : lexer.skip_token ();
86 247 : return true;
87 : }
88 0 : case GREATER_OR_EQUAL:
89 : {
90 : // new implementation that should be better
91 0 : lexer.split_current_token (RIGHT_ANGLE, EQUAL);
92 0 : lexer.skip_token ();
93 0 : return true;
94 : }
95 0 : case RIGHT_SHIFT_EQ:
96 : {
97 : // new implementation that should be better
98 0 : lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
99 0 : lexer.skip_token ();
100 0 : return true;
101 : }
102 1 : default:
103 1 : add_error (Error (tok->get_locus (),
104 : "expected %<>%> at end of generic argument - found %qs",
105 : tok->get_token_description ()));
106 1 : return false;
107 : }
108 7893 : }
109 :
110 : /* Gets left binding power for specified token.
111 : * Not suitable for use at the moment or possibly ever because binding power
112 : * cannot be purely determined from operator token with Rust grammar - e.g.
113 : * method call and field access have
114 : * different left binding powers but the same operator token. */
115 : template <typename ManagedTokenSource>
116 : int
117 101918 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
118 : {
119 : // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
120 101918 : switch (token->get_id ())
121 : {
122 : /* TODO: issue here - distinguish between method calls and field access
123 : * somehow? Also would have to distinguish between paths and function
124 : * calls (:: operator), maybe more stuff. */
125 : /* Current plan for tackling LBP - don't do it based on token, use
126 : * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
127 : * and handle other expressions without it. rustc only considers
128 : * arithmetic, logical/relational, 'as',
129 : * '?=', ranges, colons, and assignment to have operator precedence and
130 : * associativity rules applicable. It then has
131 : * a separate "ExprPrecedence" that also includes binary operators. */
132 :
133 : // TODO: handle operator overloading - have a function replace the
134 : // operator?
135 :
136 : /*case DOT:
137 : return LBP_DOT;*/
138 :
139 0 : case SCOPE_RESOLUTION:
140 0 : rust_debug (
141 : "possible error - looked up LBP of scope resolution operator. should "
142 : "be handled elsewhere.");
143 0 : return LBP_PATH;
144 :
145 : /* Resolved by lookahead HACK that should work with current code. If next
146 : * token is identifier and token after that isn't parenthesised expression
147 : * list, it is a field reference. */
148 8785 : case DOT:
149 17570 : if (lexer.peek_token (1)->get_id () == IDENTIFIER
150 16668 : && lexer.peek_token (2)->get_id () != LEFT_PAREN)
151 : {
152 : return LBP_FIELD_EXPR;
153 : }
154 : return LBP_METHOD_CALL;
155 :
156 : case LEFT_PAREN:
157 : return LBP_FUNCTION_CALL;
158 :
159 : case LEFT_SQUARE:
160 : return LBP_ARRAY_REF;
161 :
162 : // postfix question mark (i.e. error propagation expression)
163 1 : case QUESTION_MARK:
164 1 : return LBP_QUESTION_MARK;
165 :
166 5288 : case AS:
167 5288 : return LBP_AS;
168 :
169 : case ASTERISK:
170 : return LBP_MUL;
171 : case DIV:
172 : return LBP_DIV;
173 : case PERCENT:
174 : return LBP_MOD;
175 :
176 : case PLUS:
177 : return LBP_PLUS;
178 : case MINUS:
179 : return LBP_MINUS;
180 :
181 : case LEFT_SHIFT:
182 : return LBP_L_SHIFT;
183 : case RIGHT_SHIFT:
184 : return LBP_R_SHIFT;
185 :
186 : // binary & operator
187 52 : case AMP:
188 52 : return LBP_AMP;
189 :
190 : // binary ^ operator
191 77 : case CARET:
192 77 : return LBP_CARET;
193 :
194 : // binary | operator
195 27 : case PIPE:
196 27 : return LBP_PIPE;
197 :
198 : case EQUAL_EQUAL:
199 : return LBP_EQUAL;
200 : case NOT_EQUAL:
201 : return LBP_NOT_EQUAL;
202 : case RIGHT_ANGLE:
203 : return LBP_GREATER_THAN;
204 : case GREATER_OR_EQUAL:
205 : return LBP_GREATER_EQUAL;
206 : case LEFT_ANGLE:
207 : return LBP_SMALLER_THAN;
208 : case LESS_OR_EQUAL:
209 : return LBP_SMALLER_EQUAL;
210 :
211 659 : case LOGICAL_AND:
212 659 : return LBP_LOGICAL_AND;
213 :
214 91 : case OR:
215 91 : return LBP_LOGICAL_OR;
216 :
217 : case DOT_DOT:
218 : return LBP_DOT_DOT;
219 :
220 : case DOT_DOT_EQ:
221 : return LBP_DOT_DOT_EQ;
222 :
223 : case EQUAL:
224 : return LBP_ASSIG;
225 : case PLUS_EQ:
226 : return LBP_PLUS_ASSIG;
227 : case MINUS_EQ:
228 : return LBP_MINUS_ASSIG;
229 : case ASTERISK_EQ:
230 : return LBP_MULT_ASSIG;
231 : case DIV_EQ:
232 : return LBP_DIV_ASSIG;
233 : case PERCENT_EQ:
234 : return LBP_MOD_ASSIG;
235 : case AMP_EQ:
236 : return LBP_AMP_ASSIG;
237 : case PIPE_EQ:
238 : return LBP_PIPE_ASSIG;
239 : case CARET_EQ:
240 : return LBP_CARET_ASSIG;
241 : case LEFT_SHIFT_EQ:
242 : return LBP_L_SHIFT_ASSIG;
243 : case RIGHT_SHIFT_EQ:
244 : return LBP_R_SHIFT_ASSIG;
245 :
246 : /* HACK: float literal due to lexer misidentifying a dot then an integer as
247 : * a float */
248 : case FLOAT_LITERAL:
249 : return LBP_FIELD_EXPR;
250 : // field expr is same as tuple expr in precedence, i imagine
251 : // TODO: is this needed anymore? lexer shouldn't do that anymore
252 :
253 : // anything that can't appear in an infix position is given lowest priority
254 74380 : default:
255 74380 : return LBP_LOWEST;
256 : }
257 : }
258 :
259 : // Returns true when current token is EOF.
260 : template <typename ManagedTokenSource>
261 : bool
262 0 : Parser<ManagedTokenSource>::done_end_of_file ()
263 : {
264 0 : return lexer.peek_token ()->get_id () == END_OF_FILE;
265 : }
266 :
267 : // Parses a sequence of items within a module or the implicit top-level module
268 : // in a crate
269 : template <typename ManagedTokenSource>
270 : tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
271 4711 : Parser<ManagedTokenSource>::parse_items ()
272 : {
273 4711 : std::vector<std::unique_ptr<AST::Item>> items;
274 :
275 4711 : const_TokenPtr t = lexer.peek_token ();
276 23306 : while (t->get_id () != END_OF_FILE)
277 : {
278 18595 : auto item = parse_item (false);
279 18595 : if (!item)
280 74 : return Parse::Error::Items::make_malformed (std::move (items));
281 :
282 18521 : items.push_back (std::move (item.value ()));
283 :
284 18521 : t = lexer.peek_token ();
285 : }
286 :
287 : // GCC 5->7 bug doesn't threat lvalue as an rvalue for the overload
288 : #if __GNUC__ <= 7
289 : return std::move (items);
290 : #else
291 4637 : return items;
292 : #endif
293 4711 : }
294 :
295 : // Parses a crate (compilation unit) - entry point
296 : template <typename ManagedTokenSource>
297 : std::unique_ptr<AST::Crate>
298 4658 : Parser<ManagedTokenSource>::parse_crate ()
299 : {
300 : // parse inner attributes
301 4658 : AST::AttrVec inner_attrs = parse_inner_attributes ();
302 :
303 : // parse items
304 4658 : auto items
305 4658 : = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
306 :
307 : // emit all errors
308 4822 : for (const auto &error : error_table)
309 164 : error.emit ();
310 :
311 : return std::unique_ptr<AST::Crate> (
312 4658 : new AST::Crate (std::move (items), std::move (inner_attrs)));
313 4658 : }
314 :
315 : // Parses an identifier/keyword as a Token
316 : template <typename ManagedTokenSource>
317 : tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Node>
318 497 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
319 : {
320 497 : const_TokenPtr t = lexer.peek_token ();
321 :
322 497 : if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
323 : {
324 495 : lexer.skip_token ();
325 495 : return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
326 : }
327 : else
328 : {
329 2 : add_error (Error (t->get_locus (), "expected keyword or identifier"));
330 2 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
331 : }
332 497 : }
333 :
334 : template <typename ManagedTokenSource>
335 : bool
336 1500 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
337 : {
338 1500 : auto macro_name = lexer.peek_token (2)->get_id ();
339 :
340 1500 : bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
341 :
342 1500 : return t->get_str () == Values::WeakKeywords::MACRO_RULES
343 2435 : && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
344 : }
345 :
346 : // Parses a single item
347 : template <typename ManagedTokenSource>
348 : tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
349 24019 : Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
350 : {
351 : // has a "called_from_statement" parameter for better error message handling
352 :
353 : // TODO: GCC 5 does not handle implicit return type correctly so we're forced
354 : // to specify it almost every time until the baseline GCC gets bumped.
355 : // Since this type is quite long and the code is dense we use an alias.
356 : //
357 : // When support for GCC 5 stops: remove this alias as well as the explicit
358 : // ctor calls.
359 : using RType = tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>;
360 :
361 : // parse outer attributes for item
362 24019 : AST::AttrVec outer_attrs = parse_outer_attributes ();
363 24019 : const_TokenPtr t = lexer.peek_token ();
364 :
365 24019 : switch (t->get_id ())
366 : {
367 7 : case END_OF_FILE:
368 : // not necessarily an error, unless we just read outer
369 : // attributes which needs to be attached
370 7 : if (!outer_attrs.empty ())
371 : {
372 0 : Rust::AST::Attribute attr = outer_attrs.back ();
373 0 : Error error (attr.get_locus (),
374 : "expected item after outer attribute or doc comment");
375 0 : add_error (std::move (error));
376 0 : }
377 : return Parse::Error::Item::make_end_of_file ();
378 :
379 22665 : case ASYNC:
380 : case PUB:
381 : case MOD:
382 : case EXTERN_KW:
383 : case USE:
384 : case FN_KW:
385 : case TYPE:
386 : case STRUCT_KW:
387 : case ENUM_KW:
388 : case CONST:
389 : case STATIC_KW:
390 : case AUTO:
391 : case TRAIT:
392 : case IMPL:
393 : case MACRO:
394 : /* TODO: implement union keyword but not really because of
395 : * context-dependence crappy hack way to parse a union written below to
396 : * separate it from the good code. */
397 : // case UNION:
398 : case UNSAFE: // maybe - unsafe traits are a thing
399 : // if any of these (should be all possible VisItem prefixes), parse a
400 : // VisItem
401 : {
402 22665 : auto vis_item = parse_vis_item (std::move (outer_attrs));
403 22665 : if (!vis_item)
404 : return Parse::Error::Item::make_malformed ();
405 22615 : return RType{std::move (vis_item)};
406 22665 : }
407 3 : case SUPER:
408 : case SELF:
409 : case CRATE:
410 : case DOLLAR_SIGN:
411 : // almost certainly macro invocation semi
412 : {
413 3 : auto macro_invoc_semi
414 3 : = parse_macro_invocation_semi (std::move (outer_attrs));
415 3 : if (!macro_invoc_semi)
416 : return Parse::Error::Item::make_malformed ();
417 3 : return RType{std::move (macro_invoc_semi)};
418 3 : }
419 : // crappy hack to do union "keyword"
420 1344 : case IDENTIFIER:
421 : // TODO: ensure std::string and literal comparison works
422 2629 : if (t->get_str () == Values::WeakKeywords::UNION
423 1407 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
424 : {
425 63 : auto vis_item = parse_vis_item (std::move (outer_attrs));
426 63 : if (!vis_item)
427 : return Parse::Error::Item::make_malformed ();
428 63 : return RType{std::move (vis_item)};
429 : // or should this go straight to parsing union?
430 63 : }
431 2503 : else if (t->get_str () == Values::WeakKeywords::DEFAULT
432 1283 : && lexer.peek_token (1)->get_id () != EXCLAM)
433 : {
434 1 : add_error (Error (t->get_locus (),
435 : "%qs is only allowed on items within %qs blocks",
436 : "default", "impl"));
437 : return Parse::Error::Item::make_malformed ();
438 : }
439 2560 : else if (is_macro_rules_def (t))
440 : {
441 : // macro_rules! macro item
442 931 : auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
443 931 : if (!macro_rule_def)
444 : return Parse::Error::Item::make_malformed ();
445 918 : return RType{std::move (macro_rule_def)};
446 931 : }
447 698 : else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
448 697 : || lexer.peek_token (1)->get_id () == EXCLAM)
449 : {
450 : /* path (probably) or macro invocation, so probably a macro invocation
451 : * semi */
452 346 : auto macro_invocation_semi
453 346 : = parse_macro_invocation_semi (std::move (outer_attrs));
454 346 : if (!macro_invocation_semi)
455 : return Parse::Error::Item::make_malformed ();
456 345 : return RType{std::move (macro_invocation_semi)};
457 346 : }
458 : gcc_fallthrough ();
459 : default:
460 : // otherwise unrecognised
461 6 : add_error (Error (t->get_locus (),
462 : "unrecognised token %qs for start of %s",
463 : t->get_token_description (),
464 : called_from_statement ? "statement" : "item"));
465 :
466 : // skip somewhere?
467 : return Parse::Error::Item::make_malformed ();
468 : break;
469 : }
470 24019 : }
471 :
472 : // Parses a VisItem (item that can have non-default visibility).
473 : template <typename ManagedTokenSource>
474 : std::unique_ptr<AST::VisItem>
475 23272 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
476 : {
477 : // parse visibility, which may or may not exist
478 23272 : auto vis_res = parse_visibility ();
479 23272 : if (!vis_res)
480 0 : return nullptr;
481 23272 : auto vis = vis_res.value ();
482 :
483 : // select VisItem to create depending on keyword
484 23272 : const_TokenPtr t = lexer.peek_token ();
485 :
486 23272 : switch (t->get_id ())
487 : {
488 1366 : case MOD:
489 1366 : return parse_module (std::move (vis), std::move (outer_attrs));
490 1510 : case EXTERN_KW:
491 : // lookahead to resolve syntactical production
492 1510 : t = lexer.peek_token (1);
493 :
494 1510 : switch (t->get_id ())
495 : {
496 27 : case CRATE:
497 27 : return parse_extern_crate (std::move (vis), std::move (outer_attrs));
498 0 : case FN_KW: // extern function
499 0 : return parse_function (std::move (vis), std::move (outer_attrs));
500 0 : case LEFT_CURLY: // extern block
501 0 : return parse_extern_block (std::move (vis), std::move (outer_attrs));
502 1483 : case STRING_LITERAL: // for specifying extern ABI
503 : // could be extern block or extern function, so more lookahead
504 1483 : t = lexer.peek_token (2);
505 :
506 1483 : switch (t->get_id ())
507 : {
508 2 : case FN_KW:
509 2 : return parse_function (std::move (vis), std::move (outer_attrs));
510 1481 : case LEFT_CURLY:
511 1481 : return parse_extern_block (std::move (vis),
512 1481 : std::move (outer_attrs));
513 0 : default:
514 0 : add_error (
515 0 : Error (t->get_locus (),
516 : "unexpected token %qs in some sort of extern production",
517 : t->get_token_description ()));
518 :
519 0 : lexer.skip_token (2); // TODO: is this right thing to do?
520 0 : return nullptr;
521 : }
522 0 : default:
523 0 : add_error (
524 0 : Error (t->get_locus (),
525 : "unexpected token %qs in some sort of extern production",
526 : t->get_token_description ()));
527 :
528 0 : lexer.skip_token (1); // TODO: is this right thing to do?
529 0 : return nullptr;
530 : }
531 679 : case USE:
532 679 : return parse_use_decl (std::move (vis), std::move (outer_attrs));
533 6377 : case FN_KW:
534 6377 : return parse_function (std::move (vis), std::move (outer_attrs));
535 62 : case TYPE:
536 62 : return parse_type_alias (std::move (vis), std::move (outer_attrs));
537 2691 : case STRUCT_KW:
538 2691 : return parse_struct (std::move (vis), std::move (outer_attrs));
539 547 : case ENUM_KW:
540 547 : return parse_enum (std::move (vis), std::move (outer_attrs));
541 : // TODO: implement union keyword but not really because of
542 : // context-dependence case UNION: crappy hack to do union "keyword"
543 107 : case IDENTIFIER:
544 214 : if (t->get_str () == Values::WeakKeywords::UNION
545 214 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
546 : {
547 107 : return parse_union (std::move (vis), std::move (outer_attrs));
548 : // or should item switch go straight to parsing union?
549 : }
550 : else
551 : {
552 : break;
553 : }
554 558 : case CONST:
555 : // lookahead to resolve syntactical production
556 558 : t = lexer.peek_token (1);
557 :
558 558 : switch (t->get_id ())
559 : {
560 474 : case IDENTIFIER:
561 : case UNDERSCORE:
562 474 : return parse_const_item (std::move (vis), std::move (outer_attrs));
563 1 : case ASYNC:
564 1 : return parse_async_item (std::move (vis), std::move (outer_attrs));
565 83 : case UNSAFE:
566 : case EXTERN_KW:
567 : case FN_KW:
568 83 : return parse_function (std::move (vis), std::move (outer_attrs));
569 0 : default:
570 0 : add_error (
571 0 : Error (t->get_locus (),
572 : "unexpected token %qs in some sort of const production",
573 : t->get_token_description ()));
574 :
575 0 : lexer.skip_token (1); // TODO: is this right thing to do?
576 0 : return nullptr;
577 : }
578 : // for async functions
579 2 : case ASYNC:
580 2 : return parse_async_item (std::move (vis), std::move (outer_attrs));
581 :
582 67 : case STATIC_KW:
583 67 : return parse_static_item (std::move (vis), std::move (outer_attrs));
584 3712 : case AUTO:
585 : case TRAIT:
586 3712 : return parse_trait (std::move (vis), std::move (outer_attrs));
587 5231 : case IMPL:
588 5231 : return parse_impl (std::move (vis), std::move (outer_attrs));
589 317 : case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
590 : // lookahead to resolve syntactical production
591 317 : t = lexer.peek_token (1);
592 :
593 317 : switch (t->get_id ())
594 : {
595 56 : case AUTO:
596 : case TRAIT:
597 56 : return parse_trait (std::move (vis), std::move (outer_attrs));
598 193 : case EXTERN_KW:
599 : case FN_KW:
600 193 : return parse_function (std::move (vis), std::move (outer_attrs));
601 67 : case IMPL:
602 67 : return parse_impl (std::move (vis), std::move (outer_attrs));
603 1 : case MOD:
604 1 : return parse_module (std::move (vis), std::move (outer_attrs));
605 0 : default:
606 0 : add_error (
607 0 : Error (t->get_locus (),
608 : "unexpected token %qs in some sort of unsafe production",
609 : t->get_token_description ()));
610 :
611 0 : lexer.skip_token (1); // TODO: is this right thing to do?
612 0 : return nullptr;
613 : }
614 45 : case MACRO:
615 45 : return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
616 : default:
617 : // otherwise vis item clearly doesn't exist, which is not an error
618 : // has a catch-all post-switch return to allow other breaks to occur
619 : break;
620 : }
621 1 : return nullptr;
622 23272 : }
623 :
624 : template <typename ManagedTokenSource>
625 : std::unique_ptr<AST::Function>
626 4 : Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
627 : AST::AttrVec outer_attrs)
628 : {
629 4 : auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
630 4 : const_TokenPtr t = lexer.peek_token (offset);
631 :
632 4 : if (get_rust_edition () == Edition::E2015)
633 : {
634 1 : add_error (Error (t->get_locus (), ErrorCode::E0670,
635 : "%<async fn%> is not permitted in Rust 2015"));
636 1 : add_error (
637 2 : Error::Hint (t->get_locus (),
638 : "to use %<async fn%>, switch to Rust 2018 or later"));
639 : }
640 :
641 4 : t = lexer.peek_token (offset + 1);
642 :
643 4 : switch (t->get_id ())
644 : {
645 4 : case UNSAFE:
646 : case FN_KW:
647 4 : return parse_function (std::move (vis), std::move (outer_attrs));
648 :
649 0 : default:
650 0 : add_error (
651 0 : Error (t->get_locus (), "expected item, found keyword %<async%>"));
652 :
653 0 : lexer.skip_token (1);
654 0 : return nullptr;
655 : }
656 4 : }
657 :
658 : // Parses a macro rules definition syntax extension whatever thing.
659 : template <typename ManagedTokenSource>
660 : std::unique_ptr<AST::MacroRulesDefinition>
661 940 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
662 : {
663 : // ensure that first token is identifier saying "macro_rules"
664 940 : const_TokenPtr t = lexer.peek_token ();
665 940 : if (t->get_id () != IDENTIFIER
666 940 : || t->get_str () != Values::WeakKeywords::MACRO_RULES)
667 : {
668 0 : Error error (
669 : t->get_locus (),
670 : "macro rules definition does not start with %<macro_rules%>");
671 0 : add_error (std::move (error));
672 :
673 : // skip after somewhere?
674 0 : return nullptr;
675 0 : }
676 940 : lexer.skip_token ();
677 940 : location_t macro_locus = t->get_locus ();
678 :
679 940 : if (!skip_token (EXCLAM))
680 : {
681 : // skip after somewhere?
682 0 : return nullptr;
683 : }
684 :
685 : // parse macro name
686 940 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
687 940 : if (ident_tok == nullptr)
688 : {
689 1 : return nullptr;
690 : }
691 939 : Identifier rule_name{ident_tok};
692 :
693 : // DEBUG
694 939 : rust_debug ("in macro rules def, about to parse parens.");
695 :
696 : // save delim type to ensure it is reused later
697 939 : AST::DelimType delim_type = AST::PARENS;
698 :
699 : // Map tokens to DelimType
700 939 : t = lexer.peek_token ();
701 939 : switch (t->get_id ())
702 : {
703 : case LEFT_PAREN:
704 : delim_type = AST::PARENS;
705 : break;
706 0 : case LEFT_SQUARE:
707 0 : delim_type = AST::SQUARE;
708 0 : break;
709 938 : case LEFT_CURLY:
710 938 : delim_type = AST::CURLY;
711 938 : break;
712 0 : default:
713 0 : add_error (Error (t->get_locus (),
714 : "unexpected token %qs - expecting delimiters (for a "
715 : "macro rules definition)",
716 : t->get_token_description ()));
717 :
718 0 : return nullptr;
719 : }
720 939 : lexer.skip_token ();
721 :
722 : // parse actual macro rules
723 939 : std::vector<AST::MacroRule> macro_rules;
724 :
725 : // must be at least one macro rule, so parse it
726 939 : AST::MacroRule initial_rule = parse_macro_rule ();
727 939 : if (initial_rule.is_error ())
728 : {
729 12 : Error error (lexer.peek_token ()->get_locus (),
730 : "required first macro rule in macro rules definition "
731 : "could not be parsed");
732 12 : add_error (std::move (error));
733 :
734 : // skip after somewhere?
735 12 : return nullptr;
736 12 : }
737 927 : macro_rules.push_back (std::move (initial_rule));
738 :
739 : // DEBUG
740 927 : rust_debug ("successfully pushed back initial macro rule");
741 :
742 927 : t = lexer.peek_token ();
743 : // parse macro rules
744 1052 : while (t->get_id () == SEMICOLON)
745 : {
746 : // skip semicolon
747 628 : lexer.skip_token ();
748 :
749 : // don't parse if end of macro rules
750 1256 : if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
751 : delim_type))
752 : {
753 : // DEBUG
754 503 : rust_debug (
755 : "broke out of parsing macro rules loop due to finding delim");
756 :
757 503 : break;
758 : }
759 :
760 : // try to parse next rule
761 125 : AST::MacroRule rule = parse_macro_rule ();
762 125 : if (rule.is_error ())
763 : {
764 0 : Error error (lexer.peek_token ()->get_locus (),
765 : "failed to parse macro rule in macro rules definition");
766 0 : add_error (std::move (error));
767 :
768 0 : return nullptr;
769 0 : }
770 :
771 125 : macro_rules.push_back (std::move (rule));
772 :
773 : // DEBUG
774 125 : rust_debug ("successfully pushed back another macro rule");
775 :
776 125 : t = lexer.peek_token ();
777 : }
778 :
779 : // parse end delimiters
780 927 : t = lexer.peek_token ();
781 927 : if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
782 : {
783 : // tokens match opening delimiter, so skip.
784 927 : lexer.skip_token ();
785 :
786 927 : if (delim_type != AST::CURLY)
787 : {
788 : // skip semicolon at end of non-curly macro definitions
789 1 : if (!skip_token (SEMICOLON))
790 : {
791 : // as this is the end, allow recovery (probably) - may change
792 : return std::unique_ptr<AST::MacroRulesDefinition> (
793 0 : AST::MacroRulesDefinition::mbe (
794 : std::move (rule_name), delim_type, std::move (macro_rules),
795 0 : std::move (outer_attrs), macro_locus));
796 : }
797 : }
798 :
799 : return std::unique_ptr<AST::MacroRulesDefinition> (
800 1854 : AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
801 : std::move (macro_rules),
802 927 : std::move (outer_attrs), macro_locus));
803 : }
804 : else
805 : {
806 : // tokens don't match opening delimiters, so produce error
807 0 : Error error (t->get_locus (),
808 : "unexpected token %qs - expecting closing delimiter %qs "
809 : "(for a macro rules definition)",
810 : t->get_token_description (),
811 : (delim_type == AST::PARENS
812 : ? ")"
813 : : (delim_type == AST::SQUARE ? "]" : "}")));
814 0 : add_error (std::move (error));
815 :
816 : /* return empty macro definiton despite possibly parsing mostly valid one
817 : * - TODO is this a good idea? */
818 0 : return nullptr;
819 0 : }
820 2818 : }
821 :
822 : // Parses a declarative macro 2.0 definition.
823 : template <typename ManagedTokenSource>
824 : std::unique_ptr<AST::MacroRulesDefinition>
825 45 : Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
826 : AST::AttrVec outer_attrs)
827 : {
828 : // ensure that first token is identifier saying "macro"
829 45 : const_TokenPtr t = lexer.peek_token ();
830 45 : if (t->get_id () != MACRO)
831 : {
832 0 : Error error (
833 : t->get_locus (),
834 : "declarative macro definition does not start with %<macro%>");
835 0 : add_error (std::move (error));
836 :
837 : // skip after somewhere?
838 0 : return nullptr;
839 0 : }
840 45 : lexer.skip_token ();
841 45 : location_t macro_locus = t->get_locus ();
842 :
843 : // parse macro name
844 45 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
845 45 : if (ident_tok == nullptr)
846 : {
847 0 : return nullptr;
848 : }
849 45 : Identifier rule_name{ident_tok};
850 :
851 45 : t = lexer.peek_token ();
852 45 : if (t->get_id () == LEFT_PAREN)
853 : {
854 : // single definiton of macro rule
855 : // e.g. `macro foo($e:expr) {}`
856 :
857 : // parse macro matcher
858 20 : location_t locus = lexer.peek_token ()->get_locus ();
859 20 : AST::MacroMatcher matcher = parse_macro_matcher ();
860 20 : if (matcher.is_error ())
861 0 : return nullptr;
862 :
863 : // check delimiter of macro matcher
864 20 : if (matcher.get_delim_type () != AST::DelimType::PARENS)
865 : {
866 0 : Error error (locus, "only parenthesis can be used for a macro "
867 : "matcher in declarative macro definition");
868 0 : add_error (std::move (error));
869 0 : return nullptr;
870 0 : }
871 :
872 20 : location_t transcriber_loc = lexer.peek_token ()->get_locus ();
873 20 : auto delim_tok_tree = parse_delim_token_tree ();
874 20 : if (!delim_tok_tree)
875 0 : return nullptr;
876 :
877 20 : AST::MacroTranscriber transcriber (delim_tok_tree.value (),
878 : transcriber_loc);
879 :
880 20 : if (transcriber.get_token_tree ().get_delim_type ()
881 : != AST::DelimType::CURLY)
882 : {
883 1 : Error error (transcriber_loc,
884 : "only braces can be used for a macro transcriber "
885 : "in declarative macro definition");
886 1 : add_error (std::move (error));
887 1 : return nullptr;
888 1 : }
889 :
890 19 : std::vector<AST::MacroRule> macro_rules;
891 19 : macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
892 : locus);
893 :
894 : return std::unique_ptr<AST::MacroRulesDefinition> (
895 38 : AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
896 : macro_rules,
897 : std::move (outer_attrs),
898 19 : macro_locus, vis));
899 59 : }
900 25 : else if (t->get_id () == LEFT_CURLY)
901 : {
902 : // multiple definitions of macro rule separated by comma
903 : // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
904 :
905 : // parse left curly
906 25 : const_TokenPtr left_curly = expect_token (LEFT_CURLY);
907 25 : if (left_curly == nullptr)
908 : {
909 0 : return nullptr;
910 : }
911 :
912 : // parse actual macro rules
913 25 : std::vector<AST::MacroRule> macro_rules;
914 :
915 : // must be at least one macro rule, so parse it
916 25 : AST::MacroRule initial_rule = parse_macro_rule ();
917 25 : if (initial_rule.is_error ())
918 : {
919 1 : Error error (
920 1 : lexer.peek_token ()->get_locus (),
921 : "required first macro rule in declarative macro definition "
922 : "could not be parsed");
923 1 : add_error (std::move (error));
924 :
925 : // skip after somewhere?
926 1 : return nullptr;
927 1 : }
928 24 : macro_rules.push_back (std::move (initial_rule));
929 :
930 24 : t = lexer.peek_token ();
931 : // parse macro rules
932 40 : while (t->get_id () == COMMA)
933 : {
934 : // skip comma
935 32 : lexer.skip_token ();
936 :
937 : // don't parse if end of macro rules
938 32 : if (Parse::Utils::token_id_matches_delims (
939 64 : lexer.peek_token ()->get_id (), AST::CURLY))
940 : {
941 : break;
942 : }
943 :
944 : // try to parse next rule
945 16 : AST::MacroRule rule = parse_macro_rule ();
946 16 : if (rule.is_error ())
947 : {
948 0 : Error error (
949 0 : lexer.peek_token ()->get_locus (),
950 : "failed to parse macro rule in declarative macro definition");
951 0 : add_error (std::move (error));
952 :
953 0 : return nullptr;
954 0 : }
955 :
956 16 : macro_rules.push_back (std::move (rule));
957 :
958 16 : t = lexer.peek_token ();
959 : }
960 :
961 : // parse right curly
962 24 : const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
963 24 : if (right_curly == nullptr)
964 : {
965 0 : return nullptr;
966 : }
967 :
968 : return std::unique_ptr<AST::MacroRulesDefinition> (
969 48 : AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
970 : std::move (macro_rules),
971 : std::move (outer_attrs),
972 24 : macro_locus, vis));
973 50 : }
974 : else
975 : {
976 0 : add_error (Error (t->get_locus (),
977 : "unexpected token %qs - expecting delimiters "
978 : "(for a declarative macro definiton)",
979 : t->get_token_description ()));
980 0 : return nullptr;
981 : }
982 90 : }
983 :
984 : /* Parses a visibility syntactical production (i.e. creating a non-default
985 : * visibility) */
986 : template <typename ManagedTokenSource>
987 : tl::expected<AST::Visibility, Parse::Error::Visibility>
988 41980 : Parser<ManagedTokenSource>::parse_visibility ()
989 : {
990 : // check for no visibility
991 83960 : if (lexer.peek_token ()->get_id () != PUB)
992 : {
993 33665 : return AST::Visibility::create_private ();
994 : }
995 :
996 8315 : auto vis_loc = lexer.peek_token ()->get_locus ();
997 8315 : lexer.skip_token ();
998 :
999 : // create simple pub visibility if
1000 : // - found no parentheses
1001 : // - found unit type `()`
1002 16630 : if (lexer.peek_token ()->get_id () != LEFT_PAREN
1003 8382 : || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
1004 : {
1005 8249 : return AST::Visibility::create_public (vis_loc);
1006 : // or whatever
1007 : }
1008 :
1009 66 : lexer.skip_token ();
1010 :
1011 66 : const_TokenPtr t = lexer.peek_token ();
1012 66 : auto path_loc = t->get_locus ();
1013 :
1014 66 : switch (t->get_id ())
1015 : {
1016 53 : case CRATE:
1017 53 : lexer.skip_token ();
1018 :
1019 53 : skip_token (RIGHT_PAREN);
1020 :
1021 53 : return AST::Visibility::create_crate (path_loc, vis_loc);
1022 0 : case SELF:
1023 0 : lexer.skip_token ();
1024 :
1025 0 : skip_token (RIGHT_PAREN);
1026 :
1027 0 : return AST::Visibility::create_self (path_loc, vis_loc);
1028 1 : case SUPER:
1029 1 : lexer.skip_token ();
1030 :
1031 1 : skip_token (RIGHT_PAREN);
1032 :
1033 1 : return AST::Visibility::create_super (path_loc, vis_loc);
1034 12 : case IN:
1035 : {
1036 12 : lexer.skip_token ();
1037 :
1038 : // parse the "in" path as well
1039 12 : auto path = parse_simple_path ();
1040 12 : if (!path)
1041 : {
1042 0 : Error error (lexer.peek_token ()->get_locus (),
1043 : "missing path in pub(in path) visibility");
1044 0 : add_error (std::move (error));
1045 :
1046 : // skip after somewhere?
1047 0 : return Parse::Error::Visibility::make_missing_path ();
1048 0 : }
1049 :
1050 12 : skip_token (RIGHT_PAREN);
1051 :
1052 24 : return AST::Visibility::create_in_path (std::move (path.value ()),
1053 12 : vis_loc);
1054 12 : }
1055 0 : default:
1056 0 : add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
1057 : t->get_token_description ()));
1058 :
1059 0 : lexer.skip_token ();
1060 : return Parse::Error::Visibility::make_malformed ();
1061 : }
1062 66 : }
1063 :
1064 : // Parses a module - either a bodied module or a module defined in another file.
1065 : template <typename ManagedTokenSource>
1066 : std::unique_ptr<AST::Module>
1067 1367 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
1068 : AST::AttrVec outer_attrs)
1069 : {
1070 1367 : location_t locus = lexer.peek_token ()->get_locus ();
1071 :
1072 1367 : Unsafety safety = Unsafety::Normal;
1073 2734 : if (lexer.peek_token ()->get_id () == UNSAFE)
1074 : {
1075 1 : safety = Unsafety::Unsafe;
1076 1 : skip_token (UNSAFE);
1077 : }
1078 :
1079 1367 : skip_token (MOD);
1080 :
1081 1367 : const_TokenPtr module_name = expect_token (IDENTIFIER);
1082 1367 : if (module_name == nullptr)
1083 : {
1084 0 : return nullptr;
1085 : }
1086 1367 : Identifier name{module_name};
1087 :
1088 1367 : const_TokenPtr t = lexer.peek_token ();
1089 :
1090 1367 : switch (t->get_id ())
1091 : {
1092 138 : case SEMICOLON:
1093 138 : lexer.skip_token ();
1094 :
1095 : // Construct an external module
1096 : return std::unique_ptr<AST::Module> (
1097 414 : new AST::Module (std::move (name), std::move (vis),
1098 : std::move (outer_attrs), locus, safety,
1099 414 : lexer.get_filename (), inline_module_stack));
1100 1229 : case LEFT_CURLY:
1101 : {
1102 1229 : lexer.skip_token ();
1103 :
1104 : // parse inner attributes
1105 1229 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1106 :
1107 1229 : std::string default_path = name.as_string ();
1108 :
1109 1229 : if (inline_module_stack.empty ())
1110 : {
1111 702 : std::string filename = lexer.get_filename ();
1112 702 : auto slash_idx = filename.rfind (file_separator);
1113 702 : if (slash_idx == std::string::npos)
1114 : slash_idx = 0;
1115 : else
1116 702 : slash_idx++;
1117 702 : filename = filename.substr (slash_idx);
1118 :
1119 702 : std::string subdir;
1120 702 : if (get_file_subdir (filename, subdir))
1121 702 : default_path = subdir + file_separator + name.as_string ();
1122 702 : }
1123 :
1124 1229 : std::string module_path_name
1125 : = extract_module_path (inner_attrs, outer_attrs, default_path);
1126 1229 : InlineModuleStackScope scope (*this, std::move (module_path_name));
1127 :
1128 : // parse items
1129 1229 : std::vector<std::unique_ptr<AST::Item>> items;
1130 1229 : const_TokenPtr tok = lexer.peek_token ();
1131 4063 : while (tok->get_id () != RIGHT_CURLY)
1132 : {
1133 2834 : auto item = parse_item (false);
1134 2834 : if (!item)
1135 : {
1136 0 : Error error (tok->get_locus (),
1137 : "failed to parse item in module");
1138 0 : add_error (std::move (error));
1139 :
1140 0 : return nullptr;
1141 0 : }
1142 :
1143 2834 : items.push_back (std::move (item.value ()));
1144 :
1145 2834 : tok = lexer.peek_token ();
1146 : }
1147 :
1148 1229 : if (!skip_token (RIGHT_CURLY))
1149 : {
1150 : // skip somewhere?
1151 0 : return nullptr;
1152 : }
1153 :
1154 : return std::unique_ptr<AST::Module> (
1155 1229 : new AST::Module (std::move (name), locus, std::move (items),
1156 : std::move (vis), safety, std::move (inner_attrs),
1157 1229 : std::move (outer_attrs))); // module name?
1158 1229 : }
1159 0 : default:
1160 0 : add_error (
1161 0 : Error (t->get_locus (),
1162 : "unexpected token %qs in module declaration/definition item",
1163 : t->get_token_description ()));
1164 :
1165 0 : lexer.skip_token ();
1166 0 : return nullptr;
1167 : }
1168 1367 : }
1169 :
1170 : // Parses an extern crate declaration (dependency on external crate)
1171 : template <typename ManagedTokenSource>
1172 : std::unique_ptr<AST::ExternCrate>
1173 27 : Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
1174 : AST::AttrVec outer_attrs)
1175 : {
1176 27 : location_t locus = lexer.peek_token ()->get_locus ();
1177 27 : if (!skip_token (EXTERN_KW))
1178 : {
1179 0 : skip_after_semicolon ();
1180 0 : return nullptr;
1181 : }
1182 :
1183 27 : if (!skip_token (CRATE))
1184 : {
1185 0 : skip_after_semicolon ();
1186 0 : return nullptr;
1187 : }
1188 :
1189 : /* parse crate reference name - this has its own syntactical rule in reference
1190 : * but seems to not be used elsewhere, so i'm putting it here */
1191 27 : const_TokenPtr crate_name_tok = lexer.peek_token ();
1192 27 : std::string crate_name;
1193 :
1194 27 : switch (crate_name_tok->get_id ())
1195 : {
1196 27 : case IDENTIFIER:
1197 27 : crate_name = crate_name_tok->get_str ();
1198 27 : lexer.skip_token ();
1199 : break;
1200 0 : case SELF:
1201 0 : crate_name = Values::Keywords::SELF;
1202 0 : lexer.skip_token ();
1203 : break;
1204 0 : default:
1205 0 : add_error (
1206 0 : Error (crate_name_tok->get_locus (),
1207 : "expecting crate name (identifier or %<self%>), found %qs",
1208 : crate_name_tok->get_token_description ()));
1209 :
1210 0 : skip_after_semicolon ();
1211 0 : return nullptr;
1212 : }
1213 :
1214 : // don't parse as clause if it doesn't exist
1215 54 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1216 : {
1217 27 : lexer.skip_token ();
1218 :
1219 : return std::unique_ptr<AST::ExternCrate> (
1220 27 : new AST::ExternCrate (std::move (crate_name), std::move (vis),
1221 27 : std::move (outer_attrs), locus));
1222 : }
1223 :
1224 : /* parse as clause - this also has its own syntactical rule in reference and
1225 : * also seems to not be used elsewhere, so including here again. */
1226 0 : if (!skip_token (AS))
1227 : {
1228 0 : skip_after_semicolon ();
1229 0 : return nullptr;
1230 : }
1231 :
1232 0 : const_TokenPtr as_name_tok = lexer.peek_token ();
1233 0 : std::string as_name;
1234 :
1235 0 : switch (as_name_tok->get_id ())
1236 : {
1237 0 : case IDENTIFIER:
1238 0 : as_name = as_name_tok->get_str ();
1239 0 : lexer.skip_token ();
1240 : break;
1241 0 : case UNDERSCORE:
1242 0 : as_name = Values::Keywords::UNDERSCORE;
1243 0 : lexer.skip_token ();
1244 : break;
1245 0 : default:
1246 0 : add_error (
1247 0 : Error (as_name_tok->get_locus (),
1248 : "expecting as clause name (identifier or %<_%>), found %qs",
1249 : as_name_tok->get_token_description ()));
1250 :
1251 0 : skip_after_semicolon ();
1252 0 : return nullptr;
1253 : }
1254 :
1255 0 : if (!skip_token (SEMICOLON))
1256 : {
1257 0 : skip_after_semicolon ();
1258 0 : return nullptr;
1259 : }
1260 :
1261 : return std::unique_ptr<AST::ExternCrate> (
1262 0 : new AST::ExternCrate (std::move (crate_name), std::move (vis),
1263 0 : std::move (outer_attrs), locus, std::move (as_name)));
1264 54 : }
1265 :
1266 : // Parses a use declaration.
1267 : template <typename ManagedTokenSource>
1268 : std::unique_ptr<AST::UseDeclaration>
1269 679 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
1270 : AST::AttrVec outer_attrs)
1271 : {
1272 679 : location_t locus = lexer.peek_token ()->get_locus ();
1273 679 : if (!skip_token (USE))
1274 : {
1275 0 : skip_after_semicolon ();
1276 0 : return nullptr;
1277 : }
1278 :
1279 : // parse use tree, which is required
1280 679 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1281 679 : if (use_tree == nullptr)
1282 : {
1283 1 : Error error (lexer.peek_token ()->get_locus (),
1284 : "could not parse use tree in use declaration");
1285 1 : add_error (std::move (error));
1286 :
1287 1 : skip_after_semicolon ();
1288 1 : return nullptr;
1289 1 : }
1290 :
1291 678 : if (!skip_token (SEMICOLON))
1292 : {
1293 0 : skip_after_semicolon ();
1294 0 : return nullptr;
1295 : }
1296 :
1297 : return std::unique_ptr<AST::UseDeclaration> (
1298 678 : new AST::UseDeclaration (std::move (use_tree), std::move (vis),
1299 678 : std::move (outer_attrs), locus));
1300 679 : }
1301 :
1302 : // Parses a use tree (which can be recursive and is actually a base class).
1303 : template <typename ManagedTokenSource>
1304 : std::unique_ptr<AST::UseTree>
1305 1264 : Parser<ManagedTokenSource>::parse_use_tree ()
1306 : {
1307 : /* potential syntax definitions in attempt to get algorithm:
1308 : * Glob:
1309 : * <- SimplePath :: *
1310 : * <- :: *
1311 : * <- *
1312 : * Nested tree thing:
1313 : * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
1314 : * <- :: COMPLICATED_INNER_TREE_THING }
1315 : * <- { COMPLICATED_INNER_TREE_THING }
1316 : * Rebind thing:
1317 : * <- SimplePath as IDENTIFIER
1318 : * <- SimplePath as _
1319 : * <- SimplePath
1320 : */
1321 :
1322 : /* current plan of attack: try to parse SimplePath first - if fails, one of
1323 : * top two then try parse :: - if fails, one of top two. Next is deciding
1324 : * character for top two. */
1325 :
1326 : /* Thus, parsing smaller parts of use tree may require feeding into function
1327 : * via parameters (or could handle all in this single function because other
1328 : * use tree types aren't recognised as separate in the spec) */
1329 :
1330 : // TODO: I think this function is too complex, probably should split it
1331 :
1332 1264 : location_t locus = lexer.peek_token ()->get_locus ();
1333 :
1334 : // bool has_path = false;
1335 1264 : auto path = parse_simple_path ();
1336 :
1337 1264 : if (!path)
1338 : {
1339 : // has no path, so must be glob or nested tree UseTree type
1340 :
1341 2 : bool is_global = false;
1342 :
1343 : // check for global scope resolution operator
1344 4 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
1345 : {
1346 0 : lexer.skip_token ();
1347 0 : is_global = true;
1348 : }
1349 :
1350 2 : const_TokenPtr t = lexer.peek_token ();
1351 2 : switch (t->get_id ())
1352 : {
1353 0 : case ASTERISK:
1354 : // glob UseTree type
1355 0 : lexer.skip_token ();
1356 :
1357 0 : if (is_global)
1358 0 : return std::unique_ptr<AST::UseTreeGlob> (
1359 0 : new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
1360 0 : AST::SimplePath::create_empty (), locus));
1361 : else
1362 0 : return std::unique_ptr<AST::UseTreeGlob> (
1363 0 : new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
1364 0 : AST::SimplePath::create_empty (), locus));
1365 2 : case LEFT_CURLY:
1366 : {
1367 : // nested tree UseTree type
1368 2 : lexer.skip_token ();
1369 :
1370 2 : std::vector<std::unique_ptr<AST::UseTree>> use_trees;
1371 :
1372 2 : const_TokenPtr t = lexer.peek_token ();
1373 5 : while (t->get_id () != RIGHT_CURLY)
1374 : {
1375 3 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1376 3 : if (use_tree == nullptr)
1377 : {
1378 : break;
1379 : }
1380 :
1381 3 : use_trees.push_back (std::move (use_tree));
1382 :
1383 6 : if (lexer.peek_token ()->get_id () != COMMA)
1384 : break;
1385 :
1386 1 : lexer.skip_token ();
1387 1 : t = lexer.peek_token ();
1388 : }
1389 :
1390 : // skip end curly delimiter
1391 2 : if (!skip_token (RIGHT_CURLY))
1392 : {
1393 : // skip after somewhere?
1394 0 : return nullptr;
1395 : }
1396 :
1397 2 : if (is_global)
1398 0 : return std::unique_ptr<AST::UseTreeList> (
1399 0 : new AST::UseTreeList (AST::UseTreeList::GLOBAL,
1400 0 : AST::SimplePath::create_empty (),
1401 0 : std::move (use_trees), locus));
1402 : else
1403 2 : return std::unique_ptr<AST::UseTreeList> (
1404 4 : new AST::UseTreeList (AST::UseTreeList::NO_PATH,
1405 4 : AST::SimplePath::create_empty (),
1406 2 : std::move (use_trees), locus));
1407 2 : }
1408 0 : case AS:
1409 : // this is not allowed
1410 0 : add_error (Error (
1411 : t->get_locus (),
1412 : "use declaration with rebind %<as%> requires a valid simple path - "
1413 : "none found"));
1414 :
1415 0 : skip_after_semicolon ();
1416 0 : return nullptr;
1417 0 : default:
1418 0 : add_error (Error (t->get_locus (),
1419 : "unexpected token %qs in use tree with "
1420 : "no valid simple path (i.e. list"
1421 : " or glob use tree)",
1422 : t->get_token_description ()));
1423 :
1424 0 : skip_after_semicolon ();
1425 0 : return nullptr;
1426 : }
1427 2 : }
1428 : else
1429 : {
1430 1262 : const_TokenPtr t = lexer.peek_token ();
1431 :
1432 1262 : switch (t->get_id ())
1433 : {
1434 6 : case AS:
1435 : {
1436 : // rebind UseTree type
1437 6 : lexer.skip_token ();
1438 :
1439 6 : const_TokenPtr t = lexer.peek_token ();
1440 6 : switch (t->get_id ())
1441 : {
1442 4 : case IDENTIFIER:
1443 : // skip lexer token
1444 4 : lexer.skip_token ();
1445 :
1446 4 : return std::unique_ptr<AST::UseTreeRebind> (
1447 12 : new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
1448 12 : std::move (path.value ()), locus, t));
1449 2 : case UNDERSCORE:
1450 : // skip lexer token
1451 2 : lexer.skip_token ();
1452 :
1453 2 : return std::unique_ptr<AST::UseTreeRebind> (
1454 6 : new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
1455 2 : std::move (path.value ()), locus,
1456 : {Values::Keywords::UNDERSCORE,
1457 2 : t->get_locus ()}));
1458 0 : default:
1459 0 : add_error (Error (
1460 : t->get_locus (),
1461 : "unexpected token %qs in use tree with as clause - expected "
1462 : "identifier or %<_%>",
1463 : t->get_token_description ()));
1464 :
1465 0 : skip_after_semicolon ();
1466 0 : return nullptr;
1467 : }
1468 6 : }
1469 1090 : case SEMICOLON:
1470 : // rebind UseTree type without rebinding - path only
1471 :
1472 : // don't skip semicolon - handled in parse_use_tree
1473 : // lexer.skip_token();
1474 : case COMMA:
1475 : case RIGHT_CURLY:
1476 : // this may occur in recursive calls - assume it is ok and ignore it
1477 1090 : return std::unique_ptr<AST::UseTreeRebind> (
1478 3270 : new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
1479 1090 : std::move (path.value ()), locus));
1480 : case SCOPE_RESOLUTION:
1481 : // keep going
1482 : break;
1483 1 : default:
1484 1 : add_error (Error (t->get_locus (),
1485 : "unexpected token %qs in use tree with valid path",
1486 : t->get_token_description ()));
1487 1 : return nullptr;
1488 : }
1489 :
1490 165 : skip_token ();
1491 165 : t = lexer.peek_token ();
1492 :
1493 165 : switch (t->get_id ())
1494 : {
1495 11 : case ASTERISK:
1496 : // glob UseTree type
1497 11 : lexer.skip_token ();
1498 :
1499 11 : return std::unique_ptr<AST::UseTreeGlob> (
1500 33 : new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
1501 11 : std::move (path.value ()), locus));
1502 154 : case LEFT_CURLY:
1503 : {
1504 : // nested tree UseTree type
1505 154 : lexer.skip_token ();
1506 :
1507 154 : std::vector<std::unique_ptr<AST::UseTree>> use_trees;
1508 :
1509 : // TODO: think of better control structure
1510 154 : const_TokenPtr t = lexer.peek_token ();
1511 736 : while (t->get_id () != RIGHT_CURLY)
1512 : {
1513 582 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1514 582 : if (use_tree == nullptr)
1515 : {
1516 : break;
1517 : }
1518 :
1519 582 : use_trees.push_back (std::move (use_tree));
1520 :
1521 1164 : if (lexer.peek_token ()->get_id () != COMMA)
1522 : break;
1523 :
1524 428 : lexer.skip_token ();
1525 428 : t = lexer.peek_token ();
1526 : }
1527 :
1528 : // skip end curly delimiter
1529 154 : if (!skip_token (RIGHT_CURLY))
1530 : {
1531 : // skip after somewhere?
1532 0 : return nullptr;
1533 : }
1534 :
1535 154 : return std::unique_ptr<AST::UseTreeList> (
1536 308 : new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
1537 154 : std::move (path.value ()),
1538 154 : std::move (use_trees), locus));
1539 154 : }
1540 0 : default:
1541 0 : add_error (Error (t->get_locus (),
1542 : "unexpected token %qs in use tree with valid path",
1543 : t->get_token_description ()));
1544 :
1545 : // skip_after_semicolon();
1546 0 : return nullptr;
1547 : }
1548 1262 : }
1549 1264 : }
1550 :
1551 : // Parses a function (not a method).
1552 : template <typename ManagedTokenSource>
1553 : std::unique_ptr<AST::Function>
1554 11454 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
1555 : AST::AttrVec outer_attrs,
1556 : bool is_external)
1557 : {
1558 11454 : location_t locus = lexer.peek_token ()->get_locus ();
1559 : // Get qualifiers for function if they exist
1560 11454 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
1561 :
1562 11454 : skip_token (FN_KW);
1563 :
1564 : // Save function name token
1565 11454 : const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
1566 11454 : if (function_name_tok == nullptr)
1567 : {
1568 0 : skip_after_next_block ();
1569 0 : return nullptr;
1570 : }
1571 11454 : Identifier function_name{function_name_tok};
1572 :
1573 : // parse generic params - if exist
1574 11454 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1575 : = parse_generic_params_in_angles ();
1576 :
1577 11454 : if (!skip_token (LEFT_PAREN))
1578 : {
1579 0 : Error error (lexer.peek_token ()->get_locus (),
1580 : "function declaration missing opening parentheses before "
1581 : "parameter list");
1582 0 : add_error (std::move (error));
1583 :
1584 0 : skip_after_next_block ();
1585 0 : return nullptr;
1586 0 : }
1587 :
1588 11454 : auto initial_param = parse_self_param ();
1589 :
1590 11454 : if (!initial_param.has_value ()
1591 11454 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
1592 0 : return nullptr;
1593 :
1594 13704 : if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
1595 1369 : skip_token ();
1596 :
1597 : // parse function parameters (only if next token isn't right paren)
1598 11454 : std::vector<std::unique_ptr<AST::Param>> function_params;
1599 :
1600 22908 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
1601 : function_params
1602 5137 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
1603 :
1604 11454 : if (initial_param.has_value ())
1605 2250 : function_params.insert (function_params.begin (),
1606 2250 : std::move (*initial_param));
1607 :
1608 11454 : if (!skip_token (RIGHT_PAREN))
1609 : {
1610 0 : Error error (lexer.peek_token ()->get_locus (),
1611 : "function declaration missing closing parentheses after "
1612 : "parameter list");
1613 0 : add_error (std::move (error));
1614 :
1615 0 : skip_after_next_block ();
1616 0 : return nullptr;
1617 0 : }
1618 :
1619 : // parse function return type - if exists
1620 11454 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
1621 :
1622 : // parse where clause - if exists
1623 11454 : AST::WhereClause where_clause = parse_where_clause ();
1624 :
1625 11454 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
1626 22908 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1627 3928 : lexer.skip_token ();
1628 : else
1629 : {
1630 7526 : auto block_expr = parse_block_expr ();
1631 7526 : if (!block_expr)
1632 28 : return nullptr;
1633 7498 : body = std::move (block_expr.value ());
1634 7526 : }
1635 :
1636 : return std::unique_ptr<AST::Function> (
1637 30350 : new AST::Function (std::move (function_name), std::move (qualifiers),
1638 : std::move (generic_params), std::move (function_params),
1639 : std::move (return_type), std::move (where_clause),
1640 : std::move (body), std::move (vis),
1641 11426 : std::move (outer_attrs), locus, false, is_external));
1642 34362 : }
1643 :
1644 : // Parses function or method qualifiers (i.e. const, unsafe, and extern).
1645 : template <typename ManagedTokenSource>
1646 : AST::FunctionQualifiers
1647 18216 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
1648 : {
1649 18216 : Async async_status = Async::No;
1650 18216 : Const const_status = Const::No;
1651 18216 : Unsafety unsafe_status = Unsafety::Normal;
1652 18216 : bool has_extern = false;
1653 18216 : std::string abi;
1654 :
1655 18216 : const_TokenPtr t;
1656 : location_t locus;
1657 : // Check in order of const, unsafe, then extern
1658 54648 : for (int i = 0; i < 2; i++)
1659 : {
1660 36432 : t = lexer.peek_token ();
1661 36432 : locus = t->get_locus ();
1662 :
1663 36432 : switch (t->get_id ())
1664 : {
1665 862 : case CONST:
1666 862 : lexer.skip_token ();
1667 862 : const_status = Const::Yes;
1668 862 : break;
1669 8 : case ASYNC:
1670 8 : lexer.skip_token ();
1671 8 : async_status = Async::Yes;
1672 8 : break;
1673 : default:
1674 : // const status is still none
1675 : break;
1676 : }
1677 : }
1678 :
1679 36432 : if (lexer.peek_token ()->get_id () == UNSAFE)
1680 : {
1681 495 : lexer.skip_token ();
1682 495 : unsafe_status = Unsafety::Unsafe;
1683 : }
1684 :
1685 36432 : if (lexer.peek_token ()->get_id () == EXTERN_KW)
1686 : {
1687 97 : lexer.skip_token ();
1688 97 : has_extern = true;
1689 :
1690 : // detect optional abi name
1691 97 : const_TokenPtr next_tok = lexer.peek_token ();
1692 97 : if (next_tok->get_id () == STRING_LITERAL)
1693 : {
1694 97 : lexer.skip_token ();
1695 97 : abi = next_tok->get_str ();
1696 : }
1697 97 : }
1698 :
1699 36432 : return AST::FunctionQualifiers (locus, async_status, const_status,
1700 18216 : unsafe_status, has_extern, std::move (abi));
1701 18216 : }
1702 :
1703 : // Parses generic (lifetime or type) params inside angle brackets (optional).
1704 : template <typename ManagedTokenSource>
1705 : std::vector<std::unique_ptr<AST::GenericParam>>
1706 31861 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
1707 : {
1708 63722 : if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
1709 : {
1710 : // seems to be no generic params, so exit with empty vector
1711 27637 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
1712 : }
1713 4224 : lexer.skip_token ();
1714 :
1715 : // DEBUG:
1716 4224 : rust_debug ("skipped left angle in generic param");
1717 :
1718 4224 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1719 : = parse_generic_params (Parse::Utils::is_right_angle_tok);
1720 :
1721 : // DEBUG:
1722 4224 : rust_debug ("finished parsing actual generic params (i.e. inside angles)");
1723 :
1724 4224 : if (!skip_generics_right_angle ())
1725 : {
1726 : // DEBUG
1727 1 : rust_debug ("failed to skip generics right angle - returning empty "
1728 : "generic params");
1729 :
1730 1 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
1731 : }
1732 :
1733 4223 : return generic_params;
1734 4224 : }
1735 :
1736 : template <typename ManagedTokenSource>
1737 : template <typename EndTokenPred>
1738 : std::unique_ptr<AST::GenericParam>
1739 4621 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
1740 : {
1741 4621 : auto outer_attrs = parse_outer_attributes ();
1742 4621 : std::unique_ptr<AST::GenericParam> param;
1743 4621 : auto token = lexer.peek_token ();
1744 :
1745 4621 : switch (token->get_id ())
1746 : {
1747 253 : case LIFETIME:
1748 : {
1749 253 : auto lifetime = parse_lifetime (false);
1750 253 : if (!lifetime)
1751 : {
1752 0 : Error error (token->get_locus (),
1753 : "failed to parse lifetime in generic parameter list");
1754 0 : add_error (std::move (error));
1755 :
1756 0 : return nullptr;
1757 0 : }
1758 :
1759 253 : std::vector<AST::Lifetime> lifetime_bounds;
1760 506 : if (lexer.peek_token ()->get_id () == COLON)
1761 : {
1762 1 : lexer.skip_token ();
1763 : // parse required bounds
1764 : lifetime_bounds
1765 1 : = parse_lifetime_bounds ([is_end_token] (TokenId id) {
1766 1 : return is_end_token (id) || id == COMMA;
1767 : });
1768 : }
1769 :
1770 506 : param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
1771 253 : std::move (lifetime.value ()), std::move (lifetime_bounds),
1772 253 : std::move (outer_attrs), token->get_locus ()));
1773 : break;
1774 506 : }
1775 4263 : case IDENTIFIER:
1776 : {
1777 4263 : auto type_ident = token->get_str ();
1778 4263 : lexer.skip_token ();
1779 :
1780 4263 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
1781 8526 : if (lexer.peek_token ()->get_id () == COLON)
1782 : {
1783 646 : lexer.skip_token ();
1784 :
1785 : // parse optional type param bounds
1786 646 : type_param_bounds = parse_type_param_bounds ();
1787 : }
1788 :
1789 4263 : std::unique_ptr<AST::Type> type = nullptr;
1790 8526 : if (lexer.peek_token ()->get_id () == EQUAL)
1791 : {
1792 362 : lexer.skip_token ();
1793 :
1794 : // parse required type
1795 362 : type = parse_type ();
1796 362 : if (!type)
1797 : {
1798 0 : Error error (
1799 0 : lexer.peek_token ()->get_locus (),
1800 : "failed to parse type in type param in generic params");
1801 0 : add_error (std::move (error));
1802 :
1803 0 : return nullptr;
1804 0 : }
1805 : }
1806 :
1807 4263 : param = std::unique_ptr<AST::TypeParam> (
1808 12789 : new AST::TypeParam (std::move (type_ident), token->get_locus (),
1809 : std::move (type_param_bounds), std::move (type),
1810 4263 : std::move (outer_attrs)));
1811 : break;
1812 4263 : }
1813 104 : case CONST:
1814 : {
1815 104 : lexer.skip_token ();
1816 :
1817 104 : auto name_token = expect_token (IDENTIFIER);
1818 :
1819 208 : if (!name_token || !expect_token (COLON))
1820 1 : return nullptr;
1821 :
1822 103 : auto type = parse_type ();
1823 103 : if (!type)
1824 1 : return nullptr;
1825 :
1826 : // optional default value
1827 102 : tl::optional<AST::GenericArg> default_expr = tl::nullopt;
1828 204 : if (lexer.peek_token ()->get_id () == EQUAL)
1829 : {
1830 20 : lexer.skip_token ();
1831 20 : auto tok = lexer.peek_token ();
1832 39 : default_expr = parse_generic_arg ();
1833 :
1834 20 : if (!default_expr)
1835 : {
1836 1 : Error error (tok->get_locus (),
1837 : "invalid token for start of default value for "
1838 : "const generic parameter: expected %<block%>, "
1839 : "%<identifier%> or %<literal%>, got %qs",
1840 : token_id_to_str (tok->get_id ()));
1841 :
1842 1 : add_error (std::move (error));
1843 1 : return nullptr;
1844 1 : }
1845 :
1846 : // At this point, we *know* that we are parsing a const
1847 : // expression
1848 19 : if (default_expr.value ().get_kind ()
1849 : == AST::GenericArg::Kind::Either)
1850 1 : default_expr = default_expr.value ().disambiguate_to_const ();
1851 20 : }
1852 :
1853 101 : param = std::unique_ptr<AST::ConstGenericParam> (
1854 423 : new AST::ConstGenericParam (name_token->get_str (), std::move (type),
1855 : default_expr, std::move (outer_attrs),
1856 101 : token->get_locus ()));
1857 :
1858 : break;
1859 207 : }
1860 1 : default:
1861 : // FIXME: Can we clean this last call with a method call?
1862 1 : Error error (token->get_locus (),
1863 : "unexpected token when parsing generic parameters: %qs",
1864 1 : token->as_string ().c_str ());
1865 1 : add_error (std::move (error));
1866 :
1867 1 : return nullptr;
1868 1 : }
1869 :
1870 4617 : return param;
1871 4621 : }
1872 :
1873 : /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
1874 : * always parse_generic_params_in_angles is what is wanted. */
1875 : template <typename ManagedTokenSource>
1876 : template <typename EndTokenPred>
1877 : std::vector<std::unique_ptr<AST::GenericParam>>
1878 4224 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
1879 : {
1880 4224 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
1881 :
1882 : /* can't parse lifetime and type params separately due to lookahead issues
1883 : * thus, parse them all here */
1884 :
1885 : /* HACK: used to retain attribute data if a lifetime param is tentatively
1886 : * parsed but it turns out to be type param */
1887 4224 : AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
1888 :
1889 : // Did we parse a generic type param yet
1890 4224 : auto type_seen = false;
1891 : // Did we parse a const param with a default value yet
1892 4224 : auto const_with_default_seen = false;
1893 : // Did the user write a lifetime parameter after a type one
1894 4224 : auto order_error = false;
1895 : // Did the user write a const param with a default value after a type one
1896 4224 : auto const_with_default_order_error = false;
1897 :
1898 : // parse lifetime params
1899 22303 : while (!is_end_token (lexer.peek_token ()->get_id ()))
1900 : {
1901 4621 : auto param = parse_generic_param (is_end_token);
1902 4621 : if (param)
1903 : {
1904 4617 : if (param->get_kind () == AST::GenericParam::Kind::Type)
1905 : {
1906 4263 : type_seen = true;
1907 4263 : if (const_with_default_seen)
1908 4617 : const_with_default_order_error = true;
1909 : }
1910 354 : else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
1911 354 : && type_seen)
1912 : {
1913 2 : order_error = true;
1914 2 : if (const_with_default_seen)
1915 0 : const_with_default_order_error = true;
1916 : }
1917 352 : else if (param->get_kind () == AST::GenericParam::Kind::Const)
1918 : {
1919 101 : type_seen = true;
1920 : AST::ConstGenericParam *const_param
1921 101 : = static_cast<AST::ConstGenericParam *> (param.get ());
1922 101 : if (const_param->has_default_value ())
1923 : const_with_default_seen = true;
1924 82 : else if (const_with_default_seen)
1925 4617 : const_with_default_order_error = true;
1926 : }
1927 :
1928 4617 : generic_params.emplace_back (std::move (param));
1929 4617 : maybe_skip_token (COMMA);
1930 : }
1931 : else
1932 : break;
1933 : }
1934 :
1935 : // FIXME: Add reordering hint
1936 4224 : if (order_error)
1937 : {
1938 2 : Error error (generic_params.front ()->get_locus (),
1939 : "invalid order for generic parameters: lifetime parameters "
1940 : "must be declared prior to type and const parameters");
1941 2 : add_error (std::move (error));
1942 2 : }
1943 4224 : if (const_with_default_order_error)
1944 : {
1945 1 : Error error (generic_params.front ()->get_locus (),
1946 : "invalid order for generic parameters: generic parameters "
1947 : "with a default must be trailing");
1948 1 : add_error (std::move (error));
1949 1 : }
1950 :
1951 4224 : generic_params.shrink_to_fit ();
1952 4224 : return generic_params;
1953 4224 : }
1954 :
1955 : /* Parses lifetime generic parameters (pointers). Will also consume any
1956 : * trailing comma. No extra checks for end token. */
1957 : template <typename ManagedTokenSource>
1958 : std::vector<std::unique_ptr<AST::LifetimeParam>>
1959 4 : Parser<ManagedTokenSource>::parse_lifetime_params ()
1960 : {
1961 4 : std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
1962 :
1963 12 : while (lexer.peek_token ()->get_id () != END_OF_FILE)
1964 : {
1965 4 : auto lifetime_param = parse_lifetime_param ();
1966 :
1967 4 : if (!lifetime_param)
1968 : {
1969 : // can't treat as error as only way to get out with trailing comma
1970 : break;
1971 : }
1972 :
1973 2 : lifetime_params.emplace_back (
1974 2 : new AST::LifetimeParam (std::move (lifetime_param.value ())));
1975 :
1976 4 : if (lexer.peek_token ()->get_id () != COMMA)
1977 : break;
1978 :
1979 : // skip commas, including trailing commas
1980 0 : lexer.skip_token ();
1981 : }
1982 :
1983 4 : lifetime_params.shrink_to_fit ();
1984 :
1985 4 : return lifetime_params;
1986 : }
1987 :
1988 : /* Parses lifetime generic parameters (pointers). Will also consume any
1989 : * trailing comma. Has extra is_end_token predicate checking. */
1990 : template <typename ManagedTokenSource>
1991 : template <typename EndTokenPred>
1992 : std::vector<std::unique_ptr<AST::LifetimeParam>>
1993 : Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
1994 : {
1995 : std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
1996 :
1997 : // if end_token is not specified, it defaults to EOF, so should work fine
1998 : while (!is_end_token (lexer.peek_token ()->get_id ()))
1999 : {
2000 : auto lifetime_param = parse_lifetime_param ();
2001 :
2002 : if (!lifetime_param)
2003 : {
2004 : /* TODO: is it worth throwing away all lifetime params just because
2005 : * one failed? */
2006 : Error error (lexer.peek_token ()->get_locus (),
2007 : "failed to parse lifetime param in lifetime params");
2008 : add_error (std::move (error));
2009 :
2010 : return {};
2011 : }
2012 :
2013 : lifetime_params.emplace_back (
2014 : new AST::LifetimeParam (std::move (lifetime_param)));
2015 :
2016 : if (lexer.peek_token ()->get_id () != COMMA)
2017 : break;
2018 :
2019 : // skip commas, including trailing commas
2020 : lexer.skip_token ();
2021 : }
2022 :
2023 : lifetime_params.shrink_to_fit ();
2024 :
2025 : return lifetime_params;
2026 : }
2027 :
2028 : /* Parses lifetime generic parameters (objects). Will also consume any
2029 : * trailing comma. No extra checks for end token.
2030 : * TODO: is this best solution? implements most of the same algorithm.
2031 : * TODO: seems to be unused, remove? */
2032 : template <typename ManagedTokenSource>
2033 : std::vector<AST::LifetimeParam>
2034 0 : Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
2035 : {
2036 0 : std::vector<AST::LifetimeParam> lifetime_params;
2037 :
2038 : // bad control structure as end token cannot be guaranteed
2039 0 : while (true)
2040 : {
2041 0 : auto lifetime_param = parse_lifetime_param ();
2042 :
2043 0 : if (!lifetime_param)
2044 : {
2045 : // not an error as only way to exit if trailing comma
2046 : break;
2047 : }
2048 :
2049 0 : lifetime_params.push_back (std::move (lifetime_param.value ()));
2050 :
2051 0 : if (lexer.peek_token ()->get_id () != COMMA)
2052 : break;
2053 :
2054 : // skip commas, including trailing commas
2055 0 : lexer.skip_token ();
2056 : }
2057 :
2058 0 : lifetime_params.shrink_to_fit ();
2059 :
2060 0 : return lifetime_params;
2061 : }
2062 :
2063 : /* Parses lifetime generic parameters (objects). Will also consume any
2064 : * trailing comma. Has extra is_end_token predicate checking.
2065 : * TODO: is this best solution? implements most of the same algorithm. */
2066 : template <typename ManagedTokenSource>
2067 : template <typename EndTokenPred>
2068 : std::vector<AST::LifetimeParam>
2069 26 : Parser<ManagedTokenSource>::parse_lifetime_params_objs (
2070 : EndTokenPred is_end_token)
2071 : {
2072 26 : std::vector<AST::LifetimeParam> lifetime_params;
2073 :
2074 78 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2075 : {
2076 26 : auto lifetime_param = parse_lifetime_param ();
2077 :
2078 26 : if (!lifetime_param)
2079 : {
2080 : /* TODO: is it worth throwing away all lifetime params just because
2081 : * one failed? */
2082 0 : Error error (lexer.peek_token ()->get_locus (),
2083 : "failed to parse lifetime param in lifetime params");
2084 0 : add_error (std::move (error));
2085 :
2086 0 : return {};
2087 0 : }
2088 :
2089 26 : lifetime_params.push_back (std::move (lifetime_param.value ()));
2090 :
2091 52 : if (lexer.peek_token ()->get_id () != COMMA)
2092 : break;
2093 :
2094 : // skip commas, including trailing commas
2095 0 : lexer.skip_token ();
2096 : }
2097 :
2098 26 : lifetime_params.shrink_to_fit ();
2099 :
2100 26 : return lifetime_params;
2101 26 : }
2102 :
2103 : /* Parses a sequence of a certain grammar rule in object form (not pointer or
2104 : * smart pointer), delimited by commas and ending when 'is_end_token' is
2105 : * satisfied (templated). Will also consume any trailing comma.
2106 : * FIXME: this cannot be used due to member function pointer problems (i.e.
2107 : * parsing_function cannot be specified properly) */
2108 : template <typename ManagedTokenSource>
2109 : template <typename ParseFunction, typename EndTokenPred>
2110 : auto
2111 : Parser<ManagedTokenSource>::parse_non_ptr_sequence (
2112 : ParseFunction parsing_function, EndTokenPred is_end_token,
2113 : std::string error_msg) -> std::vector<decltype (parsing_function ())>
2114 : {
2115 : std::vector<decltype (parsing_function ())> params;
2116 :
2117 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2118 : {
2119 : auto param = parsing_function ();
2120 :
2121 : if (param.is_error ())
2122 : {
2123 : // TODO: is it worth throwing away all params just because one
2124 : // failed?
2125 : Error error (lexer.peek_token ()->get_locus (),
2126 : std::move (error_msg));
2127 : add_error (std::move (error));
2128 :
2129 : return {};
2130 : }
2131 :
2132 : params.push_back (std::move (param));
2133 :
2134 : if (lexer.peek_token ()->get_id () != COMMA)
2135 : break;
2136 :
2137 : // skip commas, including trailing commas
2138 : lexer.skip_token ();
2139 : }
2140 :
2141 : params.shrink_to_fit ();
2142 :
2143 : return params;
2144 : }
2145 :
2146 : /* Parses a single lifetime generic parameter (not including comma). */
2147 : template <typename ManagedTokenSource>
2148 : tl::expected<AST::LifetimeParam, Parse::Error::LifetimeParam>
2149 30 : Parser<ManagedTokenSource>::parse_lifetime_param ()
2150 : {
2151 : // parse outer attributes, which are optional and may not exist
2152 30 : auto outer_attrs = parse_outer_attributes ();
2153 :
2154 : // save lifetime token - required
2155 30 : const_TokenPtr lifetime_tok = lexer.peek_token ();
2156 30 : if (lifetime_tok->get_id () != LIFETIME)
2157 : {
2158 : // if lifetime is missing, must not be a lifetime param, so return error
2159 : return Parse::Error::LifetimeParam::make_not_a_lifetime_param ();
2160 : }
2161 28 : lexer.skip_token ();
2162 56 : AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
2163 : lifetime_tok->get_locus ());
2164 :
2165 : // parse lifetime bounds, if it exists
2166 28 : std::vector<AST::Lifetime> lifetime_bounds;
2167 56 : if (lexer.peek_token ()->get_id () == COLON)
2168 : {
2169 : // parse lifetime bounds
2170 0 : lifetime_bounds = parse_lifetime_bounds ();
2171 : // TODO: have end token passed in?
2172 : }
2173 :
2174 56 : return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
2175 : std::move (outer_attrs),
2176 28 : lifetime_tok->get_locus ());
2177 58 : }
2178 :
2179 : // Parses type generic parameters. Will also consume any trailing comma.
2180 : template <typename ManagedTokenSource>
2181 : std::vector<std::unique_ptr<AST::TypeParam>>
2182 0 : Parser<ManagedTokenSource>::parse_type_params ()
2183 : {
2184 0 : std::vector<std::unique_ptr<AST::TypeParam>> type_params;
2185 :
2186 : // infinite loop with break on failure as no info on ending token
2187 0 : while (true)
2188 : {
2189 0 : std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
2190 :
2191 0 : if (type_param == nullptr)
2192 : {
2193 : // break if fails to parse
2194 : break;
2195 : }
2196 :
2197 0 : type_params.push_back (std::move (type_param));
2198 :
2199 0 : if (lexer.peek_token ()->get_id () != COMMA)
2200 : break;
2201 :
2202 : // skip commas, including trailing commas
2203 0 : lexer.skip_token ();
2204 : }
2205 :
2206 0 : type_params.shrink_to_fit ();
2207 0 : return type_params;
2208 : }
2209 :
2210 : // Parses type generic parameters. Will also consume any trailing comma.
2211 : template <typename ManagedTokenSource>
2212 : template <typename EndTokenPred>
2213 : std::vector<std::unique_ptr<AST::TypeParam>>
2214 : Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
2215 : {
2216 : std::vector<std::unique_ptr<AST::TypeParam>> type_params;
2217 :
2218 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2219 : {
2220 : std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
2221 :
2222 : if (type_param == nullptr)
2223 : {
2224 : Error error (lexer.peek_token ()->get_locus (),
2225 : "failed to parse type param in type params");
2226 : add_error (std::move (error));
2227 :
2228 : return {};
2229 : }
2230 :
2231 : type_params.push_back (std::move (type_param));
2232 :
2233 : if (lexer.peek_token ()->get_id () != COMMA)
2234 : break;
2235 :
2236 : // skip commas, including trailing commas
2237 : lexer.skip_token ();
2238 : }
2239 :
2240 : type_params.shrink_to_fit ();
2241 : return type_params;
2242 : /* TODO: this shares most code with parse_lifetime_params - good place to
2243 : * use template (i.e. parse_non_ptr_sequence if doable) */
2244 : }
2245 :
2246 : /* Parses a single type (generic) parameter, not including commas. May change
2247 : * to return value. */
2248 : template <typename ManagedTokenSource>
2249 : std::unique_ptr<AST::TypeParam>
2250 0 : Parser<ManagedTokenSource>::parse_type_param ()
2251 : {
2252 : // parse outer attributes, which are optional and may not exist
2253 0 : auto outer_attrs = parse_outer_attributes ();
2254 :
2255 0 : const_TokenPtr identifier_tok = lexer.peek_token ();
2256 0 : if (identifier_tok->get_id () != IDENTIFIER)
2257 : {
2258 : // return null as type param can't exist without this required
2259 : // identifier
2260 0 : return nullptr;
2261 : }
2262 0 : Identifier ident{identifier_tok};
2263 0 : lexer.skip_token ();
2264 :
2265 : // parse type param bounds (if they exist)
2266 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2267 0 : if (lexer.peek_token ()->get_id () == COLON)
2268 : {
2269 0 : lexer.skip_token ();
2270 :
2271 : // parse type param bounds, which may or may not exist
2272 0 : type_param_bounds = parse_type_param_bounds ();
2273 : }
2274 :
2275 : // parse type (if it exists)
2276 0 : std::unique_ptr<AST::Type> type = nullptr;
2277 0 : if (lexer.peek_token ()->get_id () == EQUAL)
2278 : {
2279 0 : lexer.skip_token ();
2280 :
2281 : // parse type (now required)
2282 0 : type = parse_type ();
2283 0 : if (type == nullptr)
2284 : {
2285 0 : Error error (lexer.peek_token ()->get_locus (),
2286 : "failed to parse type in type param");
2287 0 : add_error (std::move (error));
2288 :
2289 0 : return nullptr;
2290 0 : }
2291 : }
2292 :
2293 : return std::unique_ptr<AST::TypeParam> (
2294 0 : new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
2295 : std::move (type_param_bounds), std::move (type),
2296 0 : std::move (outer_attrs)));
2297 0 : }
2298 :
2299 : /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
2300 : * has end token handling. */
2301 : template <typename ManagedTokenSource>
2302 : template <typename EndTokenPred>
2303 : std::vector<std::unique_ptr<AST::Param>>
2304 10033 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
2305 : {
2306 10033 : std::vector<std::unique_ptr<AST::Param>> params;
2307 :
2308 20066 : if (is_end_token (lexer.peek_token ()->get_id ()))
2309 827 : return params;
2310 :
2311 9206 : auto initial_param = parse_function_param ();
2312 :
2313 : // Return empty parameter list if no parameter there
2314 9206 : if (initial_param == nullptr)
2315 : {
2316 : // TODO: is this an error?
2317 0 : return params;
2318 : }
2319 :
2320 9206 : params.push_back (std::move (initial_param));
2321 :
2322 : // maybe think of a better control structure here - do-while with an initial
2323 : // error state? basically, loop through parameter list until can't find any
2324 : // more params
2325 9206 : const_TokenPtr t = lexer.peek_token ();
2326 11461 : while (t->get_id () == COMMA)
2327 : {
2328 : // skip comma if applies
2329 2255 : lexer.skip_token ();
2330 :
2331 : // TODO: strictly speaking, shouldn't there be no trailing comma?
2332 4510 : if (is_end_token (lexer.peek_token ()->get_id ()))
2333 : break;
2334 :
2335 : // now, as right paren would break, function param is required
2336 2255 : auto param = parse_function_param ();
2337 2255 : if (param == nullptr)
2338 : {
2339 0 : Error error (lexer.peek_token ()->get_locus (),
2340 : "failed to parse function param (in function params)");
2341 0 : add_error (std::move (error));
2342 :
2343 : // skip somewhere?
2344 0 : return std::vector<std::unique_ptr<AST::Param>> ();
2345 0 : }
2346 :
2347 2255 : params.push_back (std::move (param));
2348 :
2349 2255 : t = lexer.peek_token ();
2350 : }
2351 :
2352 9206 : params.shrink_to_fit ();
2353 9206 : return params;
2354 10033 : }
2355 :
2356 : /* Parses a single regular (i.e. non-generic) parameter in a function or
2357 : * method, i.e. the "name: type" bit. Also handles it not existing. */
2358 : template <typename ManagedTokenSource>
2359 : std::unique_ptr<AST::Param>
2360 11461 : Parser<ManagedTokenSource>::parse_function_param ()
2361 : {
2362 : // parse outer attributes if they exist
2363 11461 : AST::AttrVec outer_attrs = parse_outer_attributes ();
2364 :
2365 : // TODO: should saved location be at start of outer attributes or pattern?
2366 11461 : location_t locus = lexer.peek_token ()->get_locus ();
2367 :
2368 22922 : if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
2369 : {
2370 827 : lexer.skip_token (); // Skip ellipsis
2371 827 : return std::make_unique<AST::VariadicParam> (
2372 1654 : AST::VariadicParam (std::move (outer_attrs), locus));
2373 : }
2374 :
2375 10634 : std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
2376 :
2377 : // create error function param if it doesn't exist
2378 10634 : if (param_pattern == nullptr)
2379 : {
2380 : // skip after something
2381 0 : return nullptr;
2382 : }
2383 :
2384 10634 : if (!skip_token (COLON))
2385 : {
2386 : // skip after something
2387 0 : return nullptr;
2388 : }
2389 :
2390 21268 : if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
2391 : {
2392 11 : lexer.skip_token (); // Skip ellipsis
2393 11 : return std::make_unique<AST::VariadicParam> (
2394 22 : AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
2395 11 : locus));
2396 : }
2397 : else
2398 : {
2399 10623 : std::unique_ptr<AST::Type> param_type = parse_type ();
2400 10623 : if (param_type == nullptr)
2401 : {
2402 0 : return nullptr;
2403 : }
2404 10623 : return std::make_unique<AST::FunctionParam> (
2405 21246 : AST::FunctionParam (std::move (param_pattern), std::move (param_type),
2406 10623 : std::move (outer_attrs), locus));
2407 10623 : }
2408 11461 : }
2409 :
2410 : /* Parses a function or method return type syntactical construction. Also
2411 : * handles a function return type not existing. */
2412 : template <typename ManagedTokenSource>
2413 : std::unique_ptr<AST::Type>
2414 18170 : Parser<ManagedTokenSource>::parse_function_return_type ()
2415 : {
2416 36340 : if (lexer.peek_token ()->get_id () != RETURN_TYPE)
2417 5545 : return nullptr;
2418 :
2419 : // skip return type, as it now obviously exists
2420 12625 : lexer.skip_token ();
2421 :
2422 12625 : std::unique_ptr<AST::Type> type = parse_type ();
2423 :
2424 12625 : return type;
2425 12625 : }
2426 :
2427 : /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
2428 : * a where clause not existing, in which it will return
2429 : * WhereClause::create_empty(), which can be checked via
2430 : * WhereClause::is_empty(). */
2431 : template <typename ManagedTokenSource>
2432 : AST::WhereClause
2433 31847 : Parser<ManagedTokenSource>::parse_where_clause ()
2434 : {
2435 31847 : const_TokenPtr where_tok = lexer.peek_token ();
2436 31847 : if (where_tok->get_id () != WHERE)
2437 : {
2438 : // where clause doesn't exist, so create empty one
2439 31558 : return AST::WhereClause::create_empty ();
2440 : }
2441 :
2442 289 : lexer.skip_token ();
2443 :
2444 : /* parse where clause items - this is not a separate rule in the reference
2445 : * so won't be here */
2446 289 : std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
2447 :
2448 289 : std::vector<AST::LifetimeParam> for_lifetimes;
2449 578 : if (lexer.peek_token ()->get_id () == FOR)
2450 1 : for_lifetimes = parse_for_lifetimes ();
2451 :
2452 : /* HACK: where clauses end with a right curly or semicolon or equals in all
2453 : * uses currently */
2454 289 : const_TokenPtr t = lexer.peek_token ();
2455 588 : while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
2456 580 : && t->get_id () != EQUAL)
2457 : {
2458 299 : std::unique_ptr<AST::WhereClauseItem> where_clause_item
2459 : = parse_where_clause_item (for_lifetimes);
2460 :
2461 299 : if (where_clause_item == nullptr)
2462 : {
2463 0 : Error error (t->get_locus (), "failed to parse where clause item");
2464 0 : add_error (std::move (error));
2465 :
2466 0 : return AST::WhereClause::create_empty ();
2467 0 : }
2468 :
2469 299 : where_clause_items.push_back (std::move (where_clause_item));
2470 :
2471 : // also skip comma if it exists
2472 598 : if (lexer.peek_token ()->get_id () != COMMA)
2473 : break;
2474 :
2475 291 : lexer.skip_token ();
2476 291 : t = lexer.peek_token ();
2477 : }
2478 :
2479 289 : where_clause_items.shrink_to_fit ();
2480 289 : return AST::WhereClause (std::move (where_clause_items));
2481 289 : }
2482 :
2483 : /* Parses a where clause item (lifetime or type bound). Does not parse any
2484 : * commas. */
2485 : template <typename ManagedTokenSource>
2486 : std::unique_ptr<AST::WhereClauseItem>
2487 299 : Parser<ManagedTokenSource>::parse_where_clause_item (
2488 : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
2489 : {
2490 : // shitty cheat way of determining lifetime or type bound - test for
2491 : // lifetime
2492 299 : const_TokenPtr t = lexer.peek_token ();
2493 :
2494 299 : if (t->get_id () == LIFETIME)
2495 2 : return parse_lifetime_where_clause_item ();
2496 : else
2497 297 : return parse_type_bound_where_clause_item (outer_for_lifetimes);
2498 299 : }
2499 :
2500 : // Parses a lifetime where clause item.
2501 : template <typename ManagedTokenSource>
2502 : std::unique_ptr<AST::LifetimeWhereClauseItem>
2503 2 : Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
2504 : {
2505 2 : auto parsed_lifetime = parse_lifetime (false);
2506 2 : if (!parsed_lifetime)
2507 : {
2508 : // TODO: error here?
2509 0 : return nullptr;
2510 : }
2511 2 : auto lifetime = parsed_lifetime.value ();
2512 :
2513 2 : if (!skip_token (COLON))
2514 : {
2515 : // TODO: skip after somewhere
2516 0 : return nullptr;
2517 : }
2518 :
2519 2 : std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
2520 : // TODO: have end token passed in?
2521 :
2522 2 : location_t locus = lifetime.get_locus ();
2523 :
2524 : return std::unique_ptr<AST::LifetimeWhereClauseItem> (
2525 2 : new AST::LifetimeWhereClauseItem (std::move (lifetime),
2526 2 : std::move (lifetime_bounds), locus));
2527 4 : }
2528 :
2529 : // Parses a type bound where clause item.
2530 : template <typename ManagedTokenSource>
2531 : std::unique_ptr<AST::TypeBoundWhereClauseItem>
2532 297 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
2533 : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
2534 : {
2535 297 : std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
2536 :
2537 297 : std::unique_ptr<AST::Type> type = parse_type ();
2538 297 : if (type == nullptr)
2539 : {
2540 0 : return nullptr;
2541 : }
2542 :
2543 297 : if (!skip_token (COLON))
2544 : {
2545 : // TODO: skip after somewhere
2546 0 : return nullptr;
2547 : }
2548 :
2549 594 : if (lexer.peek_token ()->get_id () == FOR)
2550 : {
2551 8 : auto for_lifetimes_inner = parse_for_lifetimes ();
2552 8 : for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
2553 : for_lifetimes_inner.end ());
2554 8 : }
2555 :
2556 : // parse type param bounds if they exist
2557 297 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
2558 : = parse_type_param_bounds ();
2559 :
2560 297 : location_t locus = lexer.peek_token ()->get_locus ();
2561 :
2562 : return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
2563 297 : new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
2564 : std::move (type),
2565 297 : std::move (type_param_bounds), locus));
2566 297 : }
2567 :
2568 : // Parses a for lifetimes clause, including the for keyword and angle
2569 : // brackets.
2570 : template <typename ManagedTokenSource>
2571 : std::vector<AST::LifetimeParam>
2572 26 : Parser<ManagedTokenSource>::parse_for_lifetimes ()
2573 : {
2574 26 : std::vector<AST::LifetimeParam> params;
2575 :
2576 26 : if (!skip_token (FOR))
2577 : {
2578 : // skip after somewhere?
2579 : return params;
2580 : }
2581 :
2582 26 : if (!skip_token (LEFT_ANGLE))
2583 : {
2584 : // skip after somewhere?
2585 : return params;
2586 : }
2587 :
2588 : /* cannot specify end token due to parsing problems with '>' tokens being
2589 : * nested */
2590 26 : params = parse_lifetime_params_objs (Parse::Utils::is_right_angle_tok);
2591 :
2592 26 : if (!skip_generics_right_angle ())
2593 : {
2594 : // DEBUG
2595 0 : rust_debug ("failed to skip generics right angle after (supposedly) "
2596 : "finished parsing where clause items");
2597 : // ok, well this gets called.
2598 :
2599 : // skip after somewhere?
2600 0 : return params;
2601 : }
2602 :
2603 : return params;
2604 : }
2605 :
2606 : // Parses type parameter bounds in where clause or generic arguments.
2607 : template <typename ManagedTokenSource>
2608 : std::vector<std::unique_ptr<AST::TypeParamBound>>
2609 944 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
2610 : {
2611 944 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2612 :
2613 944 : std::unique_ptr<AST::TypeParamBound> initial_bound
2614 : = parse_type_param_bound ();
2615 :
2616 : // quick exit if null
2617 944 : if (initial_bound == nullptr)
2618 : {
2619 : /* error? type param bounds must have at least one term, but are bounds
2620 : * optional? */
2621 : return type_param_bounds;
2622 : }
2623 944 : type_param_bounds.push_back (std::move (initial_bound));
2624 :
2625 1894 : while (lexer.peek_token ()->get_id () == PLUS)
2626 : {
2627 3 : lexer.skip_token ();
2628 :
2629 3 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
2630 3 : if (bound == nullptr)
2631 : {
2632 : /* not an error: bound is allowed to be null as trailing plus is
2633 : * allowed */
2634 : return type_param_bounds;
2635 : }
2636 :
2637 3 : type_param_bounds.push_back (std::move (bound));
2638 : }
2639 :
2640 944 : type_param_bounds.shrink_to_fit ();
2641 : return type_param_bounds;
2642 944 : }
2643 :
2644 : /* Parses type parameter bounds in where clause or generic arguments, with end
2645 : * token handling. */
2646 : template <typename ManagedTokenSource>
2647 : template <typename EndTokenPred>
2648 : std::vector<std::unique_ptr<AST::TypeParamBound>>
2649 582 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
2650 : {
2651 582 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2652 :
2653 582 : std::unique_ptr<AST::TypeParamBound> initial_bound
2654 : = parse_type_param_bound ();
2655 :
2656 : // quick exit if null
2657 582 : if (initial_bound == nullptr)
2658 : {
2659 : /* error? type param bounds must have at least one term, but are bounds
2660 : * optional? */
2661 0 : return type_param_bounds;
2662 : }
2663 582 : type_param_bounds.push_back (std::move (initial_bound));
2664 :
2665 1308 : while (lexer.peek_token ()->get_id () == PLUS)
2666 : {
2667 72 : lexer.skip_token ();
2668 :
2669 : // break if end token character
2670 144 : if (is_end_token (lexer.peek_token ()->get_id ()))
2671 : break;
2672 :
2673 72 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
2674 72 : if (bound == nullptr)
2675 : {
2676 : // TODO how wise is it to ditch all bounds if only one failed?
2677 0 : Error error (lexer.peek_token ()->get_locus (),
2678 : "failed to parse type param bound in type param bounds");
2679 0 : add_error (std::move (error));
2680 :
2681 0 : return {};
2682 0 : }
2683 :
2684 72 : type_param_bounds.push_back (std::move (bound));
2685 : }
2686 :
2687 582 : type_param_bounds.shrink_to_fit ();
2688 582 : return type_param_bounds;
2689 582 : }
2690 :
2691 : /* Parses a single type parameter bound in a where clause or generic argument.
2692 : * Does not parse the '+' between arguments. */
2693 : template <typename ManagedTokenSource>
2694 : std::unique_ptr<AST::TypeParamBound>
2695 1621 : Parser<ManagedTokenSource>::parse_type_param_bound ()
2696 : {
2697 : // shitty cheat way of determining lifetime or trait bound - test for
2698 : // lifetime
2699 1621 : const_TokenPtr t = lexer.peek_token ();
2700 1621 : switch (t->get_id ())
2701 : {
2702 12 : case LIFETIME:
2703 12 : return std::unique_ptr<AST::Lifetime> (
2704 24 : new AST::Lifetime (parse_lifetime (false).value ()));
2705 1609 : case LEFT_PAREN:
2706 : case QUESTION_MARK:
2707 : case FOR:
2708 : case IDENTIFIER:
2709 : case SUPER:
2710 : case SELF:
2711 : case SELF_ALIAS:
2712 : case CRATE:
2713 : case DOLLAR_SIGN:
2714 : case SCOPE_RESOLUTION:
2715 1609 : return parse_trait_bound ();
2716 0 : default:
2717 : // don't error - assume this is fine TODO
2718 0 : return nullptr;
2719 : }
2720 1621 : }
2721 :
2722 : // Parses a trait bound type param bound.
2723 : template <typename ManagedTokenSource>
2724 : std::unique_ptr<AST::TraitBound>
2725 1915 : Parser<ManagedTokenSource>::parse_trait_bound ()
2726 : {
2727 1915 : bool has_parens = false;
2728 1915 : bool has_question_mark = false;
2729 :
2730 3830 : location_t locus = lexer.peek_token ()->get_locus ();
2731 :
2732 : /* parse optional `for lifetimes`. */
2733 1915 : std::vector<AST::LifetimeParam> for_lifetimes;
2734 3830 : if (lexer.peek_token ()->get_id () == FOR)
2735 14 : for_lifetimes = parse_for_lifetimes ();
2736 :
2737 : // handle trait bound being in parentheses
2738 3830 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
2739 : {
2740 0 : has_parens = true;
2741 0 : lexer.skip_token ();
2742 : }
2743 :
2744 : // handle having question mark (optional)
2745 3830 : if (lexer.peek_token ()->get_id () == QUESTION_MARK)
2746 : {
2747 309 : has_question_mark = true;
2748 309 : lexer.skip_token ();
2749 : }
2750 :
2751 : // handle TypePath
2752 1915 : AST::TypePath type_path = parse_type_path ();
2753 1915 : if (type_path.is_error())
2754 2 : return nullptr;
2755 :
2756 : // handle closing parentheses
2757 1913 : if (has_parens)
2758 : {
2759 0 : if (!skip_token (RIGHT_PAREN))
2760 : {
2761 0 : return nullptr;
2762 : }
2763 : }
2764 :
2765 : return std::unique_ptr<AST::TraitBound> (
2766 1913 : new AST::TraitBound (std::move (type_path), locus, has_parens,
2767 1913 : has_question_mark, std::move (for_lifetimes)));
2768 1915 : }
2769 :
2770 : // Parses lifetime bounds.
2771 : template <typename ManagedTokenSource>
2772 : std::vector<AST::Lifetime>
2773 2 : Parser<ManagedTokenSource>::parse_lifetime_bounds ()
2774 : {
2775 2 : std::vector<AST::Lifetime> lifetime_bounds;
2776 :
2777 2 : while (true)
2778 : {
2779 2 : auto lifetime = parse_lifetime (false);
2780 :
2781 : // quick exit for parsing failure
2782 2 : if (!lifetime)
2783 : break;
2784 :
2785 2 : lifetime_bounds.push_back (std::move (lifetime.value ()));
2786 :
2787 : /* plus is maybe not allowed at end - spec defines it weirdly, so
2788 : * assuming allowed at end */
2789 4 : if (lexer.peek_token ()->get_id () != PLUS)
2790 : break;
2791 :
2792 0 : lexer.skip_token ();
2793 : }
2794 :
2795 2 : lifetime_bounds.shrink_to_fit ();
2796 2 : return lifetime_bounds;
2797 : }
2798 :
2799 : // Parses lifetime bounds, with added check for ending token.
2800 : template <typename ManagedTokenSource>
2801 : template <typename EndTokenPred>
2802 : std::vector<AST::Lifetime>
2803 1 : Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
2804 : {
2805 1 : std::vector<AST::Lifetime> lifetime_bounds;
2806 :
2807 4 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2808 : {
2809 1 : auto lifetime = parse_lifetime (false);
2810 :
2811 1 : if (!lifetime)
2812 : {
2813 : /* TODO: is it worth throwing away all lifetime bound info just
2814 : * because one failed? */
2815 0 : Error error (lexer.peek_token ()->get_locus (),
2816 : "failed to parse lifetime in lifetime bounds");
2817 0 : add_error (std::move (error));
2818 :
2819 0 : return {};
2820 0 : }
2821 :
2822 1 : lifetime_bounds.push_back (std::move (lifetime.value ()));
2823 :
2824 : /* plus is maybe not allowed at end - spec defines it weirdly, so
2825 : * assuming allowed at end */
2826 2 : if (lexer.peek_token ()->get_id () != PLUS)
2827 : break;
2828 :
2829 0 : lexer.skip_token ();
2830 : }
2831 :
2832 1 : lifetime_bounds.shrink_to_fit ();
2833 1 : return lifetime_bounds;
2834 1 : }
2835 :
2836 : /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
2837 : * existing. */
2838 : template <typename ManagedTokenSource>
2839 : tl::expected<AST::Lifetime, Parse::Error::Lifetime>
2840 4485 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
2841 : {
2842 4485 : const_TokenPtr lifetime_tok = lexer.peek_token ();
2843 4485 : if (lifetime_tok->get_id () != LIFETIME)
2844 : {
2845 3678 : if (allow_elided)
2846 : {
2847 0 : return AST::Lifetime::elided ();
2848 : }
2849 : else
2850 : {
2851 3678 : return tl::make_unexpected<Parse::Error::Lifetime> ({});
2852 : }
2853 : }
2854 807 : lexer.skip_token ();
2855 :
2856 1614 : return lifetime_from_token (lifetime_tok);
2857 4485 : }
2858 :
2859 : template <typename ManagedTokenSource>
2860 : AST::Lifetime
2861 847 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
2862 : {
2863 847 : location_t locus = tok->get_locus ();
2864 847 : std::string lifetime_ident = tok->get_str ();
2865 :
2866 847 : if (lifetime_ident == "static")
2867 : {
2868 85 : return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
2869 : }
2870 762 : else if (lifetime_ident == "_")
2871 : {
2872 : // Explicitly and implicitly elided lifetimes follow the same rules.
2873 43 : return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
2874 : }
2875 : else
2876 : {
2877 1438 : return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
2878 719 : locus);
2879 : }
2880 847 : }
2881 :
2882 : template <typename ManagedTokenSource>
2883 : std::unique_ptr<AST::ExternalTypeItem>
2884 4 : Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
2885 : AST::AttrVec outer_attrs)
2886 : {
2887 4 : location_t locus = lexer.peek_token ()->get_locus ();
2888 4 : skip_token (TYPE);
2889 :
2890 4 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
2891 4 : if (alias_name_tok == nullptr)
2892 : {
2893 0 : Error error (lexer.peek_token ()->get_locus (),
2894 : "could not parse identifier in external opaque type");
2895 0 : add_error (std::move (error));
2896 :
2897 0 : skip_after_semicolon ();
2898 0 : return nullptr;
2899 0 : }
2900 :
2901 4 : if (!skip_token (SEMICOLON))
2902 1 : return nullptr;
2903 :
2904 : return std::unique_ptr<AST::ExternalTypeItem> (
2905 9 : new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
2906 3 : std::move (outer_attrs), std::move (locus)));
2907 4 : }
2908 :
2909 : // Parses a "type alias" (typedef) item.
2910 : template <typename ManagedTokenSource>
2911 : std::unique_ptr<AST::TypeAlias>
2912 1298 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
2913 : AST::AttrVec outer_attrs)
2914 : {
2915 1298 : location_t locus = lexer.peek_token ()->get_locus ();
2916 1298 : skip_token (TYPE);
2917 :
2918 : // TODO: use this token for identifier when finished that
2919 1298 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
2920 1298 : if (alias_name_tok == nullptr)
2921 : {
2922 0 : Error error (lexer.peek_token ()->get_locus (),
2923 : "could not parse identifier in type alias");
2924 0 : add_error (std::move (error));
2925 :
2926 0 : skip_after_semicolon ();
2927 0 : return nullptr;
2928 0 : }
2929 1298 : Identifier alias_name{alias_name_tok};
2930 :
2931 : // parse generic params, which may not exist
2932 1298 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2933 : = parse_generic_params_in_angles ();
2934 :
2935 : // parse where clause, which may not exist
2936 1298 : AST::WhereClause where_clause = parse_where_clause ();
2937 :
2938 1298 : if (!skip_token (EQUAL))
2939 : {
2940 0 : skip_after_semicolon ();
2941 0 : return nullptr;
2942 : }
2943 :
2944 1298 : std::unique_ptr<AST::Type> type_to_alias = parse_type ();
2945 :
2946 1298 : if (!skip_token (SEMICOLON))
2947 : {
2948 : // should be skipping past this, not the next line
2949 0 : return nullptr;
2950 : }
2951 :
2952 : return std::unique_ptr<AST::TypeAlias> (
2953 1298 : new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
2954 : std::move (where_clause), std::move (type_to_alias),
2955 1298 : std::move (vis), std::move (outer_attrs), locus));
2956 2596 : }
2957 :
2958 : // Parse a struct item AST node.
2959 : template <typename ManagedTokenSource>
2960 : std::unique_ptr<AST::Struct>
2961 2691 : Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
2962 : AST::AttrVec outer_attrs)
2963 : {
2964 : /* TODO: determine best way to parse the proper struct vs tuple struct -
2965 : * share most of initial constructs so lookahead might be impossible, and if
2966 : * not probably too expensive. Best way is probably unified parsing for the
2967 : * initial parts and then pass them in as params to more derived functions.
2968 : * Alternatively, just parse everything in this one function - do this if
2969 : * function not too long. */
2970 :
2971 : /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
2972 : * struct_fields? '}' | ';' ) */
2973 : /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
2974 : * where_clause? ';' */
2975 2691 : location_t locus = lexer.peek_token ()->get_locus ();
2976 2691 : skip_token (STRUCT_KW);
2977 :
2978 : // parse struct name
2979 2691 : const_TokenPtr name_tok = expect_token (IDENTIFIER);
2980 2691 : if (name_tok == nullptr)
2981 : {
2982 0 : Error error (lexer.peek_token ()->get_locus (),
2983 : "could not parse struct or tuple struct identifier");
2984 0 : add_error (std::move (error));
2985 :
2986 : // skip after somewhere?
2987 0 : return nullptr;
2988 0 : }
2989 2691 : Identifier struct_name{name_tok};
2990 :
2991 : // parse generic params, which may or may not exist
2992 2691 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2993 : = parse_generic_params_in_angles ();
2994 :
2995 : // branch on next token - determines whether proper struct or tuple struct
2996 5382 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
2997 : {
2998 : // tuple struct
2999 :
3000 : // skip left parenthesis
3001 990 : lexer.skip_token ();
3002 :
3003 : // parse tuple fields
3004 990 : std::vector<AST::TupleField> tuple_fields;
3005 : // Might be empty tuple for unit tuple struct.
3006 1980 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3007 23 : tuple_fields = std::vector<AST::TupleField> ();
3008 : else
3009 967 : tuple_fields = parse_tuple_fields ();
3010 :
3011 : // tuple parameters must have closing parenthesis
3012 990 : if (!skip_token (RIGHT_PAREN))
3013 : {
3014 1 : skip_after_semicolon ();
3015 1 : return nullptr;
3016 : }
3017 :
3018 : // parse where clause, which is optional
3019 989 : AST::WhereClause where_clause = parse_where_clause ();
3020 :
3021 989 : if (!skip_token (SEMICOLON))
3022 : {
3023 : // can't skip after semicolon because it's meant to be here
3024 0 : return nullptr;
3025 : }
3026 :
3027 989 : return std::unique_ptr<AST::TupleStruct> (
3028 989 : new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
3029 : std::move (generic_params),
3030 : std::move (where_clause), std::move (vis),
3031 989 : std::move (outer_attrs), locus));
3032 990 : }
3033 :
3034 : // assume it is a proper struct being parsed and continue outside of switch
3035 : // - label only here to suppress warning
3036 :
3037 : // parse where clause, which is optional
3038 1701 : AST::WhereClause where_clause = parse_where_clause ();
3039 :
3040 : // branch on next token - determines whether struct is a unit struct
3041 1701 : const_TokenPtr t = lexer.peek_token ();
3042 1701 : switch (t->get_id ())
3043 : {
3044 945 : case LEFT_CURLY:
3045 : {
3046 : // struct with body
3047 :
3048 : // skip curly bracket
3049 945 : lexer.skip_token ();
3050 :
3051 : // parse struct fields, if any
3052 945 : std::vector<AST::StructField> struct_fields
3053 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3054 :
3055 945 : if (!skip_token (RIGHT_CURLY))
3056 : {
3057 : // skip somewhere?
3058 0 : return nullptr;
3059 : }
3060 :
3061 945 : return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
3062 : std::move (struct_fields), std::move (struct_name),
3063 : std::move (generic_params), std::move (where_clause), false,
3064 945 : std::move (vis), std::move (outer_attrs), locus));
3065 945 : }
3066 755 : case SEMICOLON:
3067 : // unit struct declaration
3068 :
3069 755 : lexer.skip_token ();
3070 :
3071 755 : return std::unique_ptr<AST::StructStruct> (
3072 1510 : new AST::StructStruct (std::move (struct_name),
3073 : std::move (generic_params),
3074 : std::move (where_clause), std::move (vis),
3075 755 : std::move (outer_attrs), locus));
3076 1 : default:
3077 1 : add_error (Error (t->get_locus (),
3078 : "unexpected token %qs in struct declaration",
3079 : t->get_token_description ()));
3080 :
3081 : // skip somewhere?
3082 1 : return nullptr;
3083 : }
3084 2691 : }
3085 :
3086 : // Parses struct fields in struct declarations.
3087 : template <typename ManagedTokenSource>
3088 : std::vector<AST::StructField>
3089 0 : Parser<ManagedTokenSource>::parse_struct_fields ()
3090 : {
3091 0 : std::vector<AST::StructField> fields;
3092 :
3093 0 : AST::StructField initial_field = parse_struct_field ();
3094 :
3095 : // Return empty field list if no field there
3096 0 : if (initial_field.is_error ())
3097 : return fields;
3098 :
3099 0 : fields.push_back (std::move (initial_field));
3100 :
3101 0 : while (lexer.peek_token ()->get_id () == COMMA)
3102 : {
3103 0 : lexer.skip_token ();
3104 :
3105 0 : AST::StructField field = parse_struct_field ();
3106 :
3107 0 : if (field.is_error ())
3108 : {
3109 : // would occur with trailing comma, so allowed
3110 : break;
3111 : }
3112 :
3113 0 : fields.push_back (std::move (field));
3114 : }
3115 :
3116 0 : fields.shrink_to_fit ();
3117 : return fields;
3118 : // TODO: template if possible (parse_non_ptr_seq)
3119 0 : }
3120 :
3121 : // Parses struct fields in struct declarations.
3122 : template <typename ManagedTokenSource>
3123 : template <typename EndTokenPred>
3124 : std::vector<AST::StructField>
3125 1147 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
3126 : {
3127 1147 : std::vector<AST::StructField> fields;
3128 :
3129 1147 : AST::StructField initial_field = parse_struct_field ();
3130 :
3131 : // Return empty field list if no field there
3132 1147 : if (initial_field.is_error ())
3133 45 : return fields;
3134 :
3135 1102 : fields.push_back (std::move (initial_field));
3136 :
3137 4524 : while (lexer.peek_token ()->get_id () == COMMA)
3138 : {
3139 2077 : lexer.skip_token ();
3140 :
3141 4154 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3142 : break;
3143 :
3144 1160 : AST::StructField field = parse_struct_field ();
3145 1160 : if (field.is_error ())
3146 : {
3147 : /* TODO: should every field be ditched just because one couldn't be
3148 : * parsed? */
3149 0 : Error error (lexer.peek_token ()->get_locus (),
3150 : "failed to parse struct field in struct fields");
3151 0 : add_error (std::move (error));
3152 :
3153 0 : return {};
3154 0 : }
3155 :
3156 1160 : fields.push_back (std::move (field));
3157 : }
3158 :
3159 1102 : fields.shrink_to_fit ();
3160 1102 : return fields;
3161 : // TODO: template if possible (parse_non_ptr_seq)
3162 1147 : }
3163 :
3164 : // Parses a single struct field (in a struct definition). Does not parse
3165 : // commas.
3166 : template <typename ManagedTokenSource>
3167 : AST::StructField
3168 2307 : Parser<ManagedTokenSource>::parse_struct_field ()
3169 : {
3170 : // parse outer attributes, if they exist
3171 2307 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3172 :
3173 : // parse visibility, if it exists
3174 2307 : auto vis = parse_visibility ();
3175 2307 : if (!vis)
3176 0 : return AST::StructField::create_error ();
3177 :
3178 2307 : location_t locus = lexer.peek_token ()->get_locus ();
3179 :
3180 : // parse field name
3181 2307 : const_TokenPtr field_name_tok = lexer.peek_token ();
3182 2307 : if (field_name_tok->get_id () != IDENTIFIER)
3183 : {
3184 : // if not identifier, assumes there is no struct field and exits - not
3185 : // necessarily error
3186 45 : return AST::StructField::create_error ();
3187 : }
3188 2262 : Identifier field_name{field_name_tok};
3189 2262 : lexer.skip_token ();
3190 :
3191 2262 : if (!skip_token (COLON))
3192 : {
3193 : // skip after somewhere?
3194 0 : return AST::StructField::create_error ();
3195 : }
3196 :
3197 : // parse field type - this is required
3198 2262 : std::unique_ptr<AST::Type> field_type = parse_type ();
3199 2262 : if (field_type == nullptr)
3200 : {
3201 0 : Error error (lexer.peek_token ()->get_locus (),
3202 : "could not parse type in struct field definition");
3203 0 : add_error (std::move (error));
3204 :
3205 : // skip after somewhere
3206 0 : return AST::StructField::create_error ();
3207 0 : }
3208 :
3209 4524 : return AST::StructField (std::move (field_name), std::move (field_type),
3210 2262 : std::move (vis.value ()), locus,
3211 2262 : std::move (outer_attrs));
3212 9138 : }
3213 :
3214 : // Parses tuple fields in tuple/tuple struct declarations.
3215 : template <typename ManagedTokenSource>
3216 : std::vector<AST::TupleField>
3217 1392 : Parser<ManagedTokenSource>::parse_tuple_fields ()
3218 : {
3219 1392 : std::vector<AST::TupleField> fields;
3220 :
3221 1392 : AST::TupleField initial_field = parse_tuple_field ();
3222 :
3223 : // Return empty field list if no field there
3224 1392 : if (initial_field.is_error ())
3225 : {
3226 1 : return fields;
3227 : }
3228 :
3229 1391 : fields.push_back (std::move (initial_field));
3230 :
3231 : // maybe think of a better control structure here - do-while with an initial
3232 : // error state? basically, loop through field list until can't find any more
3233 : // params HACK: all current syntax uses of tuple fields have them ending
3234 : // with a right paren token
3235 1391 : const_TokenPtr t = lexer.peek_token ();
3236 2129 : while (t->get_id () == COMMA)
3237 : {
3238 : // skip comma if applies - e.g. trailing comma
3239 739 : lexer.skip_token ();
3240 :
3241 : // break out due to right paren if it exists
3242 1478 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3243 : {
3244 : break;
3245 : }
3246 :
3247 738 : AST::TupleField field = parse_tuple_field ();
3248 738 : if (field.is_error ())
3249 : {
3250 0 : Error error (lexer.peek_token ()->get_locus (),
3251 : "failed to parse tuple field in tuple fields");
3252 0 : add_error (std::move (error));
3253 :
3254 0 : return std::vector<AST::TupleField> ();
3255 0 : }
3256 :
3257 738 : fields.push_back (std::move (field));
3258 :
3259 738 : t = lexer.peek_token ();
3260 : }
3261 :
3262 1391 : fields.shrink_to_fit ();
3263 1391 : return fields;
3264 :
3265 : // TODO: this shares basically all code with function params and struct
3266 : // fields
3267 : // - templates?
3268 1392 : }
3269 :
3270 : /* Parses a single tuple struct field in a tuple struct definition. Does not
3271 : * parse commas. */
3272 : template <typename ManagedTokenSource>
3273 : AST::TupleField
3274 2130 : Parser<ManagedTokenSource>::parse_tuple_field ()
3275 : {
3276 : // parse outer attributes if they exist
3277 2130 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3278 :
3279 : // parse visibility if it exists
3280 2130 : auto visibility = parse_visibility ();
3281 2130 : if (!visibility)
3282 0 : return AST::TupleField::create_error ();
3283 :
3284 2130 : location_t locus = lexer.peek_token ()->get_locus ();
3285 :
3286 : // parse type, which is required
3287 2130 : std::unique_ptr<AST::Type> field_type = parse_type ();
3288 2130 : if (field_type == nullptr)
3289 : {
3290 : // error if null
3291 1 : Error error (lexer.peek_token ()->get_locus (),
3292 : "could not parse type in tuple struct field");
3293 1 : add_error (std::move (error));
3294 :
3295 : // skip after something
3296 1 : return AST::TupleField::create_error ();
3297 1 : }
3298 :
3299 2129 : return AST::TupleField (std::move (field_type),
3300 2129 : std::move (visibility.value ()), locus,
3301 2129 : std::move (outer_attrs));
3302 4260 : }
3303 :
3304 : // Parses a Rust "enum" tagged union item definition.
3305 : template <typename ManagedTokenSource>
3306 : std::unique_ptr<AST::Enum>
3307 547 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
3308 : AST::AttrVec outer_attrs)
3309 : {
3310 547 : location_t locus = lexer.peek_token ()->get_locus ();
3311 547 : skip_token (ENUM_KW);
3312 :
3313 : // parse enum name
3314 547 : const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
3315 547 : if (enum_name_tok == nullptr)
3316 0 : return nullptr;
3317 :
3318 547 : Identifier enum_name = {enum_name_tok};
3319 :
3320 : // parse generic params (of enum container, not enum variants) if they exist
3321 547 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3322 : = parse_generic_params_in_angles ();
3323 :
3324 : // parse where clause if it exists
3325 547 : AST::WhereClause where_clause = parse_where_clause ();
3326 :
3327 547 : if (!skip_token (LEFT_CURLY))
3328 : {
3329 0 : skip_after_end_block ();
3330 0 : return nullptr;
3331 : }
3332 :
3333 : // parse actual enum variant definitions
3334 547 : std::vector<std::unique_ptr<AST::EnumItem>> enum_items
3335 : = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
3336 :
3337 547 : if (!skip_token (RIGHT_CURLY))
3338 : {
3339 0 : skip_after_end_block ();
3340 0 : return nullptr;
3341 : }
3342 :
3343 : return std::unique_ptr<AST::Enum> (
3344 547 : new AST::Enum (std::move (enum_name), std::move (vis),
3345 : std::move (generic_params), std::move (where_clause),
3346 547 : std::move (enum_items), std::move (outer_attrs), locus));
3347 1094 : }
3348 :
3349 : // Parses the enum variants inside an enum definiton.
3350 : template <typename ManagedTokenSource>
3351 : std::vector<std::unique_ptr<AST::EnumItem>>
3352 0 : Parser<ManagedTokenSource>::parse_enum_items ()
3353 : {
3354 0 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3355 :
3356 0 : std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
3357 :
3358 : // Return empty item list if no field there
3359 0 : if (initial_item == nullptr)
3360 : return items;
3361 :
3362 0 : items.push_back (std::move (initial_item));
3363 :
3364 0 : while (lexer.peek_token ()->get_id () == COMMA)
3365 : {
3366 0 : lexer.skip_token ();
3367 :
3368 0 : std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
3369 0 : if (item == nullptr)
3370 : {
3371 : // this would occur with a trailing comma, which is allowed
3372 : break;
3373 : }
3374 :
3375 0 : items.push_back (std::move (item));
3376 : }
3377 :
3378 0 : items.shrink_to_fit ();
3379 : return items;
3380 :
3381 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3382 0 : }
3383 :
3384 : // Parses the enum variants inside an enum definiton.
3385 : template <typename ManagedTokenSource>
3386 : template <typename EndTokenPred>
3387 : std::vector<std::unique_ptr<AST::EnumItem>>
3388 547 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
3389 : {
3390 547 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3391 :
3392 547 : std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
3393 :
3394 : // Return empty item list if no field there
3395 547 : if (initial_item == nullptr)
3396 14 : return items;
3397 :
3398 533 : items.push_back (std::move (initial_item));
3399 :
3400 2554 : while (lexer.peek_token ()->get_id () == COMMA)
3401 : {
3402 1244 : lexer.skip_token ();
3403 :
3404 2488 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3405 : break;
3406 :
3407 744 : std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
3408 744 : if (item == nullptr)
3409 : {
3410 : /* TODO should this ignore all successfully parsed enum items just
3411 : * because one failed? */
3412 0 : Error error (lexer.peek_token ()->get_locus (),
3413 : "failed to parse enum item in enum items");
3414 0 : add_error (std::move (error));
3415 :
3416 0 : return {};
3417 0 : }
3418 :
3419 744 : items.push_back (std::move (item));
3420 : }
3421 :
3422 533 : items.shrink_to_fit ();
3423 533 : return items;
3424 :
3425 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3426 547 : }
3427 :
3428 : /* Parses a single enum variant item in an enum definition. Does not parse
3429 : * commas. */
3430 : template <typename ManagedTokenSource>
3431 : std::unique_ptr<AST::EnumItem>
3432 1291 : Parser<ManagedTokenSource>::parse_enum_item ()
3433 : {
3434 : // parse outer attributes if they exist
3435 1291 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3436 :
3437 : // parse visibility, which may or may not exist
3438 1291 : auto vis_res = parse_visibility ();
3439 1291 : if (!vis_res)
3440 0 : return nullptr;
3441 1291 : auto vis = vis_res.value ();
3442 :
3443 : // parse name for enum item, which is required
3444 1291 : const_TokenPtr item_name_tok = lexer.peek_token ();
3445 1291 : if (item_name_tok->get_id () != IDENTIFIER)
3446 : {
3447 : // this may not be an error but it means there is no enum item here
3448 14 : return nullptr;
3449 : }
3450 1277 : lexer.skip_token ();
3451 1277 : Identifier item_name{item_name_tok};
3452 :
3453 : // branch based on next token
3454 1277 : const_TokenPtr t = lexer.peek_token ();
3455 1277 : switch (t->get_id ())
3456 : {
3457 443 : case LEFT_PAREN:
3458 : {
3459 : // tuple enum item
3460 443 : lexer.skip_token ();
3461 :
3462 443 : std::vector<AST::TupleField> tuple_fields;
3463 : // Might be empty tuple for unit tuple enum variant.
3464 886 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3465 18 : tuple_fields = std::vector<AST::TupleField> ();
3466 : else
3467 425 : tuple_fields = parse_tuple_fields ();
3468 :
3469 443 : if (!skip_token (RIGHT_PAREN))
3470 : {
3471 : // skip after somewhere
3472 0 : return nullptr;
3473 : }
3474 :
3475 443 : return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
3476 : std::move (item_name), std::move (vis), std::move (tuple_fields),
3477 443 : std::move (outer_attrs), item_name_tok->get_locus ()));
3478 443 : }
3479 95 : case LEFT_CURLY:
3480 : {
3481 : // struct enum item
3482 95 : lexer.skip_token ();
3483 :
3484 95 : std::vector<AST::StructField> struct_fields
3485 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3486 :
3487 95 : if (!skip_token (RIGHT_CURLY))
3488 : {
3489 : // skip after somewhere
3490 0 : return nullptr;
3491 : }
3492 :
3493 95 : return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
3494 : std::move (item_name), std::move (vis), std::move (struct_fields),
3495 95 : std::move (outer_attrs), item_name_tok->get_locus ()));
3496 95 : }
3497 278 : case EQUAL:
3498 : {
3499 : // discriminant enum item
3500 278 : lexer.skip_token ();
3501 :
3502 278 : auto discriminant_expr = parse_expr ();
3503 278 : if (!discriminant_expr)
3504 0 : return nullptr;
3505 :
3506 278 : return std::unique_ptr<AST::EnumItemDiscriminant> (
3507 556 : new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
3508 278 : std::move (discriminant_expr.value ()),
3509 : std::move (outer_attrs),
3510 278 : item_name_tok->get_locus ()));
3511 278 : }
3512 461 : default:
3513 : // regular enum with just an identifier
3514 : return std::unique_ptr<AST::EnumItem> (
3515 461 : new AST::EnumItem (std::move (item_name), std::move (vis),
3516 : std::move (outer_attrs),
3517 461 : item_name_tok->get_locus ()));
3518 : }
3519 3859 : }
3520 :
3521 : // Parses a C-style (and C-compat) untagged union declaration.
3522 : template <typename ManagedTokenSource>
3523 : std::unique_ptr<AST::Union>
3524 107 : Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
3525 : AST::AttrVec outer_attrs)
3526 : {
3527 : /* hack - "weak keyword" by finding identifier called "union" (lookahead in
3528 : * item switch) */
3529 107 : const_TokenPtr union_keyword = expect_token (IDENTIFIER);
3530 107 : rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
3531 107 : location_t locus = union_keyword->get_locus ();
3532 :
3533 : // parse actual union name
3534 107 : const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
3535 107 : if (union_name_tok == nullptr)
3536 : {
3537 0 : skip_after_next_block ();
3538 0 : return nullptr;
3539 : }
3540 107 : Identifier union_name{union_name_tok};
3541 :
3542 : // parse optional generic parameters
3543 107 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3544 : = parse_generic_params_in_angles ();
3545 :
3546 : // parse optional where clause
3547 107 : AST::WhereClause where_clause = parse_where_clause ();
3548 :
3549 107 : if (!skip_token (LEFT_CURLY))
3550 : {
3551 0 : skip_after_end_block ();
3552 0 : return nullptr;
3553 : }
3554 :
3555 : /* parse union inner items as "struct fields" because hey, syntax reuse.
3556 : * Spec said so. */
3557 107 : std::vector<AST::StructField> union_fields
3558 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3559 :
3560 107 : if (!skip_token (RIGHT_CURLY))
3561 : {
3562 : // skip after somewhere
3563 0 : return nullptr;
3564 : }
3565 :
3566 : return std::unique_ptr<AST::Union> (
3567 107 : new AST::Union (std::move (union_name), std::move (vis),
3568 : std::move (generic_params), std::move (where_clause),
3569 107 : std::move (union_fields), std::move (outer_attrs), locus));
3570 321 : }
3571 :
3572 : /* Parses a "constant item" (compile-time constant to maybe "inline"
3573 : * throughout the program - like constexpr). */
3574 : template <typename ManagedTokenSource>
3575 : std::unique_ptr<AST::ConstantItem>
3576 547 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
3577 : AST::AttrVec outer_attrs)
3578 : {
3579 547 : location_t locus = lexer.peek_token ()->get_locus ();
3580 547 : skip_token (CONST);
3581 :
3582 : /* get constant identifier - this is either a proper identifier or the _
3583 : * wildcard */
3584 547 : const_TokenPtr ident_tok = lexer.peek_token ();
3585 : // make default identifier the underscore wildcard one
3586 547 : std::string ident (Values::Keywords::UNDERSCORE);
3587 547 : switch (ident_tok->get_id ())
3588 : {
3589 547 : case IDENTIFIER:
3590 547 : ident = ident_tok->get_str ();
3591 547 : lexer.skip_token ();
3592 : break;
3593 0 : case UNDERSCORE:
3594 : // do nothing - identifier is already "_"
3595 0 : lexer.skip_token ();
3596 : break;
3597 0 : default:
3598 0 : add_error (
3599 0 : Error (ident_tok->get_locus (),
3600 : "expected item name (identifier or %<_%>) in constant item "
3601 : "declaration - found %qs",
3602 : ident_tok->get_token_description ()));
3603 :
3604 0 : skip_after_semicolon ();
3605 0 : return nullptr;
3606 : }
3607 :
3608 547 : if (!skip_token (COLON))
3609 : {
3610 0 : skip_after_semicolon ();
3611 0 : return nullptr;
3612 : }
3613 :
3614 : // parse constant type (required)
3615 547 : std::unique_ptr<AST::Type> type = parse_type ();
3616 :
3617 : // A const with no given expression value
3618 1094 : if (lexer.peek_token ()->get_id () == SEMICOLON)
3619 : {
3620 4 : lexer.skip_token ();
3621 : return std::unique_ptr<AST::ConstantItem> (
3622 8 : new AST::ConstantItem (std::move (ident), std::move (vis),
3623 : std::move (type), std::move (outer_attrs),
3624 4 : locus));
3625 : }
3626 :
3627 543 : if (!skip_token (EQUAL))
3628 : {
3629 0 : skip_after_semicolon ();
3630 0 : return nullptr;
3631 : }
3632 :
3633 : // parse constant expression (required)
3634 543 : auto expr = parse_expr ();
3635 543 : if (!expr)
3636 1 : return nullptr;
3637 :
3638 542 : if (!skip_token (SEMICOLON))
3639 : {
3640 : // skip somewhere?
3641 0 : return nullptr;
3642 : }
3643 :
3644 : return std::unique_ptr<AST::ConstantItem> (
3645 1084 : new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
3646 542 : std::move (expr.value ()), std::move (outer_attrs),
3647 542 : locus));
3648 1094 : }
3649 :
3650 : // Parses a "static item" (static storage item, with 'static lifetime).
3651 : template <typename ManagedTokenSource>
3652 : std::unique_ptr<AST::StaticItem>
3653 67 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
3654 : AST::AttrVec outer_attrs)
3655 : {
3656 67 : location_t locus = lexer.peek_token ()->get_locus ();
3657 67 : skip_token (STATIC_KW);
3658 :
3659 : // determine whether static item is mutable
3660 67 : bool is_mut = false;
3661 134 : if (lexer.peek_token ()->get_id () == MUT)
3662 : {
3663 4 : is_mut = true;
3664 4 : lexer.skip_token ();
3665 : }
3666 :
3667 67 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3668 67 : if (ident_tok == nullptr)
3669 0 : return nullptr;
3670 :
3671 67 : Identifier ident{ident_tok};
3672 :
3673 67 : if (!skip_token (COLON))
3674 : {
3675 1 : skip_after_semicolon ();
3676 1 : return nullptr;
3677 : }
3678 :
3679 : // parse static item type (required)
3680 66 : std::unique_ptr<AST::Type> type = parse_type ();
3681 :
3682 66 : if (!skip_token (EQUAL))
3683 : {
3684 0 : skip_after_semicolon ();
3685 0 : return nullptr;
3686 : }
3687 :
3688 : // parse static item expression (required)
3689 66 : auto expr = parse_expr ();
3690 66 : if (!expr)
3691 1 : return nullptr;
3692 :
3693 65 : if (!skip_token (SEMICOLON))
3694 : {
3695 : // skip after somewhere
3696 0 : return nullptr;
3697 : }
3698 :
3699 : return std::unique_ptr<AST::StaticItem> (
3700 130 : new AST::StaticItem (std::move (ident), is_mut, std::move (type),
3701 65 : std::move (expr.value ()), std::move (vis),
3702 65 : std::move (outer_attrs), locus));
3703 133 : }
3704 :
3705 : // Parses a trait definition item, including unsafe ones.
3706 : template <typename ManagedTokenSource>
3707 : std::unique_ptr<AST::Trait>
3708 3768 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
3709 : AST::AttrVec outer_attrs)
3710 : {
3711 3768 : location_t locus = lexer.peek_token ()->get_locus ();
3712 3768 : bool is_unsafe = false;
3713 3768 : bool is_auto_trait = false;
3714 :
3715 7536 : if (lexer.peek_token ()->get_id () == UNSAFE)
3716 : {
3717 56 : is_unsafe = true;
3718 56 : lexer.skip_token ();
3719 : }
3720 :
3721 7536 : if (lexer.peek_token ()->get_id () == AUTO)
3722 : {
3723 20 : is_auto_trait = true;
3724 20 : lexer.skip_token ();
3725 : }
3726 :
3727 3768 : skip_token (TRAIT);
3728 :
3729 : // parse trait name
3730 3768 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3731 3768 : if (ident_tok == nullptr)
3732 0 : return nullptr;
3733 :
3734 3768 : Identifier ident{ident_tok};
3735 :
3736 : // parse generic parameters (if they exist)
3737 3768 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3738 : = parse_generic_params_in_angles ();
3739 :
3740 : // create placeholder type param bounds in case they don't exist
3741 3768 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3742 :
3743 : // parse type param bounds (if they exist)
3744 7536 : if (lexer.peek_token ()->get_id () == COLON)
3745 : {
3746 538 : lexer.skip_token ();
3747 :
3748 538 : type_param_bounds = parse_type_param_bounds (
3749 72 : [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
3750 : // type_param_bounds = parse_type_param_bounds ();
3751 : }
3752 :
3753 : // parse where clause (if it exists)
3754 3768 : AST::WhereClause where_clause = parse_where_clause ();
3755 :
3756 3768 : if (!skip_token (LEFT_CURLY))
3757 : {
3758 0 : skip_after_end_block ();
3759 0 : return nullptr;
3760 : }
3761 :
3762 : // parse inner attrs (if they exist)
3763 3768 : AST::AttrVec inner_attrs = parse_inner_attributes ();
3764 :
3765 : // parse trait items
3766 3768 : std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
3767 :
3768 3768 : const_TokenPtr t = lexer.peek_token ();
3769 7130 : while (t->get_id () != RIGHT_CURLY)
3770 : {
3771 3362 : std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
3772 :
3773 3362 : if (trait_item == nullptr)
3774 : {
3775 0 : Error error (lexer.peek_token ()->get_locus (),
3776 : "failed to parse trait item in trait");
3777 0 : add_error (std::move (error));
3778 :
3779 0 : return nullptr;
3780 0 : }
3781 3362 : trait_items.push_back (std::move (trait_item));
3782 :
3783 3362 : t = lexer.peek_token ();
3784 : }
3785 :
3786 3768 : if (!skip_token (RIGHT_CURLY))
3787 : {
3788 : // skip after something
3789 0 : return nullptr;
3790 : }
3791 :
3792 3768 : trait_items.shrink_to_fit ();
3793 : return std::unique_ptr<AST::Trait> (
3794 3768 : new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
3795 : std::move (generic_params), std::move (type_param_bounds),
3796 : std::move (where_clause), std::move (trait_items),
3797 : std::move (vis), std::move (outer_attrs),
3798 3768 : std::move (inner_attrs), locus));
3799 7536 : }
3800 :
3801 : // Parses a trait item used inside traits (not trait, the Item).
3802 : template <typename ManagedTokenSource>
3803 : std::unique_ptr<AST::AssociatedItem>
3804 3364 : Parser<ManagedTokenSource>::parse_trait_item ()
3805 : {
3806 : // parse outer attributes (if they exist)
3807 3364 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3808 :
3809 3364 : auto vis_res = parse_visibility ();
3810 3364 : if (!vis_res)
3811 0 : return nullptr;
3812 :
3813 3364 : auto vis = vis_res.value ();
3814 :
3815 : // lookahead to determine what type of trait item to parse
3816 3364 : const_TokenPtr tok = lexer.peek_token ();
3817 3364 : switch (tok->get_id ())
3818 : {
3819 0 : case SUPER:
3820 : case SELF:
3821 : case CRATE:
3822 : case DOLLAR_SIGN:
3823 : // these seem to be SimplePath tokens, so this is a macro invocation
3824 : // semi
3825 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
3826 1 : case IDENTIFIER:
3827 2 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
3828 0 : return parse_function (std::move (vis), std::move (outer_attrs));
3829 : else
3830 2 : return parse_macro_invocation_semi (std::move (outer_attrs));
3831 748 : case TYPE:
3832 748 : return parse_trait_type (std::move (outer_attrs), vis);
3833 41 : case CONST:
3834 : // disambiguate with function qualifier
3835 82 : if (lexer.peek_token (1)->get_id () == IDENTIFIER)
3836 : {
3837 80 : return parse_trait_const (std::move (outer_attrs));
3838 : }
3839 : // else, fallthrough to function
3840 : // TODO: find out how to disable gcc "implicit fallthrough" error
3841 : gcc_fallthrough ();
3842 : case ASYNC:
3843 : case UNSAFE:
3844 : case EXTERN_KW:
3845 : case FN_KW:
3846 5150 : return parse_function (std::move (vis), std::move (outer_attrs));
3847 : default:
3848 : break;
3849 : }
3850 0 : add_error (Error (tok->get_locus (),
3851 : "unrecognised token %qs for item in trait",
3852 : tok->get_token_description ()));
3853 : // skip?
3854 0 : return nullptr;
3855 6728 : }
3856 :
3857 : // Parse a typedef trait item.
3858 : template <typename ManagedTokenSource>
3859 : std::unique_ptr<AST::TraitItemType>
3860 748 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
3861 : AST::Visibility vis)
3862 : {
3863 748 : location_t locus = lexer.peek_token ()->get_locus ();
3864 748 : skip_token (TYPE);
3865 :
3866 748 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3867 748 : if (ident_tok == nullptr)
3868 0 : return nullptr;
3869 :
3870 1496 : Identifier ident{ident_tok};
3871 :
3872 : // Parse optional generic parameters for GATs (Generic Associated Types)
3873 748 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
3874 1496 : if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
3875 : {
3876 9 : generic_params = parse_generic_params_in_angles ();
3877 : }
3878 :
3879 748 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
3880 :
3881 : // parse optional colon
3882 1496 : if (lexer.peek_token ()->get_id () == COLON)
3883 : {
3884 44 : lexer.skip_token ();
3885 :
3886 : // parse optional type param bounds
3887 : bounds
3888 44 : = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
3889 : // bounds = parse_type_param_bounds ();
3890 : }
3891 :
3892 748 : if (!skip_token (SEMICOLON))
3893 : {
3894 : // skip?
3895 0 : return nullptr;
3896 : }
3897 :
3898 : return std::unique_ptr<AST::TraitItemType> (
3899 748 : new AST::TraitItemType (std::move (ident), std::move (generic_params),
3900 : std::move (bounds), std::move (outer_attrs), vis,
3901 748 : locus));
3902 748 : }
3903 :
3904 : // Parses a constant trait item.
3905 : template <typename ManagedTokenSource>
3906 : std::unique_ptr<AST::ConstantItem>
3907 40 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
3908 : {
3909 40 : location_t locus = lexer.peek_token ()->get_locus ();
3910 40 : skip_token (CONST);
3911 :
3912 : // parse constant item name
3913 40 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3914 40 : if (ident_tok == nullptr)
3915 0 : return nullptr;
3916 :
3917 40 : Identifier ident{ident_tok};
3918 :
3919 40 : if (!skip_token (COLON))
3920 : {
3921 0 : skip_after_semicolon ();
3922 0 : return nullptr;
3923 : }
3924 :
3925 : // parse constant trait item type
3926 40 : std::unique_ptr<AST::Type> type = parse_type ();
3927 :
3928 : // parse constant trait body expression, if it exists
3929 40 : std::unique_ptr<AST::Expr> const_body = nullptr;
3930 80 : if (lexer.peek_token ()->get_id () == EQUAL)
3931 : {
3932 12 : lexer.skip_token ();
3933 :
3934 : // expression must exist, so parse it
3935 12 : auto expr = parse_expr ();
3936 12 : if (!expr)
3937 0 : return nullptr;
3938 12 : const_body = std::move (expr.value ());
3939 12 : }
3940 :
3941 40 : if (!skip_token (SEMICOLON))
3942 : {
3943 : // skip after something?
3944 0 : return nullptr;
3945 : }
3946 :
3947 120 : return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
3948 80 : std::move (ident), AST::Visibility::create_private (), std::move (type),
3949 40 : std::move (const_body), std::move (outer_attrs), locus));
3950 80 : }
3951 :
3952 : /* Parses a struct "impl" item (both inherent impl and trait impl can be
3953 : * parsed here), */
3954 : template <typename ManagedTokenSource>
3955 : std::unique_ptr<AST::Impl>
3956 5298 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
3957 : AST::AttrVec outer_attrs)
3958 : {
3959 : /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
3960 : * must be a trait impl. However, this isn't enough for full disambiguation,
3961 : * so don't branch here. */
3962 5298 : location_t locus = lexer.peek_token ()->get_locus ();
3963 5298 : bool is_unsafe = false;
3964 10596 : if (lexer.peek_token ()->get_id () == UNSAFE)
3965 : {
3966 67 : lexer.skip_token ();
3967 67 : is_unsafe = true;
3968 : }
3969 :
3970 5298 : if (!skip_token (IMPL))
3971 : {
3972 0 : skip_after_next_block ();
3973 0 : return nullptr;
3974 : }
3975 :
3976 : // parse generic params (shared by trait and inherent impls)
3977 5298 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3978 : = parse_generic_params_in_angles ();
3979 :
3980 : // Again, trait impl-only feature, but optional one, so can be used for
3981 : // branching yet.
3982 5298 : bool has_exclam = false;
3983 10596 : if (lexer.peek_token ()->get_id () == EXCLAM)
3984 : {
3985 6 : lexer.skip_token ();
3986 6 : has_exclam = true;
3987 : }
3988 :
3989 : /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
3990 : * doesn't parse too much and not work. */
3991 5298 : AST::TypePath type_path = parse_type_path ();
3992 10395 : if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
3993 : {
3994 : /* cannot parse type path (or not for token next, at least), so must be
3995 : * inherent impl */
3996 :
3997 : // hacky conversion of TypePath stack object to Type pointer
3998 984 : std::unique_ptr<AST::Type> type = nullptr;
3999 984 : if (!type_path.is_error ())
4000 783 : type = std::unique_ptr<AST::TypePath> (
4001 783 : new AST::TypePath (std::move (type_path)));
4002 : else
4003 201 : type = parse_type ();
4004 :
4005 : // Type is required, so error if null
4006 984 : if (type == nullptr)
4007 : {
4008 1 : Error error (lexer.peek_token ()->get_locus (),
4009 : "could not parse type in inherent impl");
4010 1 : add_error (std::move (error));
4011 :
4012 1 : skip_after_next_block ();
4013 1 : return nullptr;
4014 1 : }
4015 :
4016 : // parse optional where clause
4017 983 : AST::WhereClause where_clause = parse_where_clause ();
4018 :
4019 983 : if (!skip_token (LEFT_CURLY))
4020 : {
4021 : // TODO: does this still skip properly?
4022 0 : skip_after_end_block ();
4023 0 : return nullptr;
4024 : }
4025 :
4026 : // parse inner attributes (optional)
4027 983 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4028 :
4029 : // parse inherent impl items
4030 983 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4031 :
4032 983 : const_TokenPtr t = lexer.peek_token ();
4033 3761 : while (t->get_id () != RIGHT_CURLY)
4034 : {
4035 2788 : std::unique_ptr<AST::AssociatedItem> impl_item
4036 : = parse_inherent_impl_item ();
4037 :
4038 2788 : if (impl_item == nullptr)
4039 : {
4040 10 : Error error (
4041 10 : lexer.peek_token ()->get_locus (),
4042 : "failed to parse inherent impl item in inherent impl");
4043 10 : add_error (std::move (error));
4044 :
4045 10 : return nullptr;
4046 10 : }
4047 :
4048 2778 : impl_items.push_back (std::move (impl_item));
4049 :
4050 2778 : t = lexer.peek_token ();
4051 : }
4052 :
4053 973 : if (!skip_token (RIGHT_CURLY))
4054 : {
4055 : // skip somewhere
4056 0 : return nullptr;
4057 : }
4058 :
4059 : // DEBUG
4060 973 : rust_debug ("successfully parsed inherent impl");
4061 :
4062 973 : impl_items.shrink_to_fit ();
4063 :
4064 973 : return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
4065 : std::move (impl_items), std::move (generic_params), std::move (type),
4066 : std::move (where_clause), std::move (vis), std::move (inner_attrs),
4067 973 : std::move (outer_attrs), locus));
4068 984 : }
4069 : else
4070 : {
4071 : // type path must both be valid and next token is for, so trait impl
4072 4314 : if (!skip_token (FOR))
4073 : {
4074 0 : skip_after_next_block ();
4075 0 : return nullptr;
4076 : }
4077 :
4078 : // parse type
4079 4314 : std::unique_ptr<AST::Type> type = parse_type ();
4080 : // ensure type is included as it is required
4081 4314 : if (type == nullptr)
4082 : {
4083 0 : Error error (lexer.peek_token ()->get_locus (),
4084 : "could not parse type in trait impl");
4085 0 : add_error (std::move (error));
4086 :
4087 0 : skip_after_next_block ();
4088 0 : return nullptr;
4089 0 : }
4090 :
4091 : // parse optional where clause
4092 4314 : AST::WhereClause where_clause = parse_where_clause ();
4093 :
4094 4314 : if (!skip_token (LEFT_CURLY))
4095 : {
4096 : // TODO: does this still skip properly?
4097 0 : skip_after_end_block ();
4098 0 : return nullptr;
4099 : }
4100 :
4101 : // parse inner attributes (optional)
4102 4314 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4103 :
4104 : // parse trait impl items
4105 4314 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4106 :
4107 4314 : const_TokenPtr t = lexer.peek_token ();
4108 14602 : while (t->get_id () != RIGHT_CURLY)
4109 : {
4110 5145 : std::unique_ptr<AST::AssociatedItem> impl_item
4111 : = parse_trait_impl_item ();
4112 :
4113 5145 : if (impl_item == nullptr)
4114 : {
4115 1 : Error error (lexer.peek_token ()->get_locus (),
4116 : "failed to parse trait impl item in trait impl");
4117 1 : add_error (std::move (error));
4118 :
4119 1 : return nullptr;
4120 1 : }
4121 :
4122 5144 : impl_items.push_back (std::move (impl_item));
4123 :
4124 5144 : t = lexer.peek_token ();
4125 :
4126 : // DEBUG
4127 5144 : rust_debug ("successfully parsed a trait impl item");
4128 : }
4129 : // DEBUG
4130 4313 : rust_debug ("successfully finished trait impl items");
4131 :
4132 4313 : if (!skip_token (RIGHT_CURLY))
4133 : {
4134 : // skip somewhere
4135 0 : return nullptr;
4136 : }
4137 :
4138 : // DEBUG
4139 4313 : rust_debug ("successfully parsed trait impl");
4140 :
4141 4313 : impl_items.shrink_to_fit ();
4142 :
4143 4313 : return std::unique_ptr<AST::TraitImpl> (
4144 8626 : new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
4145 : std::move (impl_items), std::move (generic_params),
4146 : std::move (type), std::move (where_clause),
4147 : std::move (vis), std::move (inner_attrs),
4148 4313 : std::move (outer_attrs), locus));
4149 4314 : }
4150 5298 : }
4151 :
4152 : // Parses a single inherent impl item (item inside an inherent impl block).
4153 : template <typename ManagedTokenSource>
4154 : std::unique_ptr<AST::AssociatedItem>
4155 2790 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
4156 : {
4157 : // parse outer attributes (if they exist)
4158 2790 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4159 :
4160 : // TODO: cleanup - currently an unreadable mess
4161 :
4162 : // branch on next token:
4163 2790 : const_TokenPtr t = lexer.peek_token ();
4164 2790 : switch (t->get_id ())
4165 : {
4166 1 : case IDENTIFIER:
4167 : // FIXME: Arthur: Do we need to some lookahead here?
4168 2 : return parse_macro_invocation_semi (outer_attrs);
4169 2141 : case SUPER:
4170 : case SELF:
4171 : case CRATE:
4172 : case PUB:
4173 : {
4174 : // visibility, so not a macro invocation semi - must be constant,
4175 : // function, or method
4176 2141 : auto vis_res = parse_visibility ();
4177 2141 : if (!vis_res)
4178 0 : return nullptr;
4179 2141 : auto vis = vis_res.value ();
4180 :
4181 : // TODO: is a recursive call to parse_inherent_impl_item better?
4182 4282 : switch (lexer.peek_token ()->get_id ())
4183 : {
4184 1364 : case EXTERN_KW:
4185 : case UNSAFE:
4186 : case FN_KW:
4187 : // function or method
4188 2728 : return parse_inherent_impl_function_or_method (std::move (vis),
4189 : std::move (
4190 1364 : outer_attrs));
4191 777 : case CONST:
4192 : // lookahead to resolve production - could be function/method or
4193 : // const item
4194 777 : t = lexer.peek_token (1);
4195 :
4196 777 : switch (t->get_id ())
4197 : {
4198 1 : case IDENTIFIER:
4199 : case UNDERSCORE:
4200 2 : return parse_const_item (std::move (vis),
4201 1 : std::move (outer_attrs));
4202 776 : case UNSAFE:
4203 : case EXTERN_KW:
4204 : case FN_KW:
4205 1552 : return parse_inherent_impl_function_or_method (std::move (vis),
4206 : std::move (
4207 776 : outer_attrs));
4208 0 : default:
4209 0 : add_error (Error (t->get_locus (),
4210 : "unexpected token %qs in some sort of const "
4211 : "item in inherent impl",
4212 : t->get_token_description ()));
4213 :
4214 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4215 0 : return nullptr;
4216 : }
4217 0 : default:
4218 0 : add_error (
4219 0 : Error (t->get_locus (),
4220 : "unrecognised token %qs for item in inherent impl",
4221 : t->get_token_description ()));
4222 : // skip?
4223 0 : return nullptr;
4224 : }
4225 4282 : }
4226 608 : case ASYNC:
4227 : case EXTERN_KW:
4228 : case UNSAFE:
4229 : case FN_KW:
4230 : // function or method
4231 608 : return parse_inherent_impl_function_or_method (
4232 608 : AST::Visibility::create_private (), std::move (outer_attrs));
4233 40 : case CONST:
4234 : /* lookahead to resolve production - could be function/method or const
4235 : * item */
4236 40 : t = lexer.peek_token (1);
4237 :
4238 40 : switch (t->get_id ())
4239 : {
4240 40 : case IDENTIFIER:
4241 : case UNDERSCORE:
4242 80 : return parse_const_item (AST::Visibility::create_private (),
4243 40 : std::move (outer_attrs));
4244 0 : case UNSAFE:
4245 : case EXTERN_KW:
4246 : case FN_KW:
4247 0 : return parse_inherent_impl_function_or_method (
4248 0 : AST::Visibility::create_private (), std::move (outer_attrs));
4249 0 : default:
4250 0 : add_error (Error (t->get_locus (),
4251 : "unexpected token %qs in some sort of const item "
4252 : "in inherent impl",
4253 : t->get_token_description ()));
4254 :
4255 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4256 0 : return nullptr;
4257 : }
4258 : rust_unreachable ();
4259 0 : default:
4260 0 : add_error (Error (t->get_locus (),
4261 : "unrecognised token %qs for item in inherent impl",
4262 : t->get_token_description ()));
4263 :
4264 : // skip?
4265 0 : return nullptr;
4266 : }
4267 2790 : }
4268 :
4269 : /* For internal use only by parse_inherent_impl_item() - splits giant method
4270 : * into smaller ones and prevents duplication of logic. Strictly, this parses
4271 : * a function or method item inside an inherent impl item block. */
4272 : // TODO: make this a templated function with "return type" as type param -
4273 : // InherentImplItem is this specialisation of the template while TraitImplItem
4274 : // will be the other.
4275 : template <typename ManagedTokenSource>
4276 : std::unique_ptr<AST::AssociatedItem>
4277 2748 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
4278 : AST::Visibility vis, AST::AttrVec outer_attrs)
4279 : {
4280 2748 : location_t locus = lexer.peek_token ()->get_locus ();
4281 : // parse function or method qualifiers
4282 2748 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4283 :
4284 2748 : skip_token (FN_KW);
4285 :
4286 : // parse function or method name
4287 2748 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4288 2748 : if (ident_tok == nullptr)
4289 7 : return nullptr;
4290 :
4291 2741 : Identifier ident{ident_tok};
4292 :
4293 : // parse generic params
4294 2741 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4295 : = parse_generic_params_in_angles ();
4296 :
4297 2741 : if (!skip_token (LEFT_PAREN))
4298 : {
4299 : // skip after somewhere?
4300 0 : return nullptr;
4301 : }
4302 :
4303 : // now for function vs method disambiguation - method has opening "self"
4304 : // param
4305 2741 : auto initial_param = parse_self_param ();
4306 :
4307 2741 : if (!initial_param.has_value ()
4308 2741 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4309 3 : return nullptr;
4310 :
4311 : /* FIXME: ensure that self param doesn't accidently consume tokens for a
4312 : * function one idea is to lookahead up to 4 tokens to see whether self is
4313 : * one of them */
4314 2738 : bool is_method = false;
4315 2738 : if (initial_param.has_value ())
4316 : {
4317 1844 : if ((*initial_param)->is_self ())
4318 : is_method = true;
4319 :
4320 : /* skip comma so function and method regular params can be parsed in
4321 : * same way */
4322 3688 : if (lexer.peek_token ()->get_id () == COMMA)
4323 1193 : lexer.skip_token ();
4324 : }
4325 :
4326 : // parse trait function params
4327 2738 : std::vector<std::unique_ptr<AST::Param>> function_params
4328 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4329 :
4330 2738 : if (initial_param.has_value ())
4331 1844 : function_params.insert (function_params.begin (),
4332 1844 : std::move (*initial_param));
4333 :
4334 2738 : if (!skip_token (RIGHT_PAREN))
4335 : {
4336 0 : skip_after_end_block ();
4337 0 : return nullptr;
4338 : }
4339 :
4340 : // parse return type (optional)
4341 2738 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4342 :
4343 : // parse where clause (optional)
4344 2738 : AST::WhereClause where_clause = parse_where_clause ();
4345 :
4346 2738 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4347 5476 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4348 2 : lexer.skip_token ();
4349 : else
4350 : {
4351 2736 : auto result = parse_block_expr ();
4352 :
4353 2736 : if (!result)
4354 : {
4355 0 : Error error (
4356 0 : lexer.peek_token ()->get_locus (),
4357 : "could not parse definition in inherent impl %s definition",
4358 : is_method ? "method" : "function");
4359 0 : add_error (std::move (error));
4360 :
4361 0 : skip_after_end_block ();
4362 0 : return nullptr;
4363 0 : }
4364 2736 : body = std::move (result.value ());
4365 2736 : }
4366 :
4367 2738 : return std::unique_ptr<AST::Function> (
4368 10950 : new AST::Function (std::move (ident), std::move (qualifiers),
4369 : std::move (generic_params), std::move (function_params),
4370 : std::move (return_type), std::move (where_clause),
4371 : std::move (body), std::move (vis),
4372 2738 : std::move (outer_attrs), locus));
4373 8227 : }
4374 :
4375 : // Parses a single trait impl item (item inside a trait impl block).
4376 : template <typename ManagedTokenSource>
4377 : std::unique_ptr<AST::AssociatedItem>
4378 5248 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
4379 : {
4380 : // parse outer attributes (if they exist)
4381 5248 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4382 :
4383 5248 : auto vis_res = parse_visibility ();
4384 5248 : if (!vis_res)
4385 0 : return nullptr;
4386 5248 : auto visibility = vis_res.value ();
4387 :
4388 : // branch on next token:
4389 5248 : const_TokenPtr t = lexer.peek_token ();
4390 5248 : switch (t->get_id ())
4391 : {
4392 0 : case SUPER:
4393 : case SELF:
4394 : case CRATE:
4395 : case DOLLAR_SIGN:
4396 : // these seem to be SimplePath tokens, so this is a macro invocation
4397 : // semi
4398 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
4399 55 : case IDENTIFIER:
4400 110 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
4401 48 : return parse_trait_impl_function_or_method (visibility,
4402 24 : std::move (outer_attrs));
4403 : else
4404 62 : return parse_macro_invocation_semi (std::move (outer_attrs));
4405 1236 : case TYPE:
4406 2472 : return parse_type_alias (visibility, std::move (outer_attrs));
4407 3923 : case EXTERN_KW:
4408 : case UNSAFE:
4409 : case FN_KW:
4410 : // function or method
4411 7846 : return parse_trait_impl_function_or_method (visibility,
4412 3923 : std::move (outer_attrs));
4413 1 : case ASYNC:
4414 2 : return parse_async_item (visibility, std::move (outer_attrs));
4415 33 : case CONST:
4416 : // lookahead to resolve production - could be function/method or const
4417 : // item
4418 33 : t = lexer.peek_token (1);
4419 :
4420 33 : switch (t->get_id ())
4421 : {
4422 32 : case IDENTIFIER:
4423 : case UNDERSCORE:
4424 64 : return parse_const_item (visibility, std::move (outer_attrs));
4425 1 : case UNSAFE:
4426 : case EXTERN_KW:
4427 : case FN_KW:
4428 2 : return parse_trait_impl_function_or_method (visibility,
4429 1 : std::move (outer_attrs));
4430 0 : default:
4431 0 : add_error (Error (
4432 : t->get_locus (),
4433 : "unexpected token %qs in some sort of const item in trait impl",
4434 : t->get_token_description ()));
4435 :
4436 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4437 0 : return nullptr;
4438 : }
4439 : rust_unreachable ();
4440 : default:
4441 : break;
4442 : }
4443 0 : add_error (Error (t->get_locus (),
4444 : "unrecognised token %qs for item in trait impl",
4445 : t->get_token_description ()));
4446 :
4447 : // skip?
4448 0 : return nullptr;
4449 10496 : }
4450 :
4451 : /* For internal use only by parse_trait_impl_item() - splits giant method into
4452 : * smaller ones and prevents duplication of logic. Strictly, this parses a
4453 : * function or method item inside a trait impl item block. */
4454 : template <typename ManagedTokenSource>
4455 : std::unique_ptr<AST::AssociatedItem>
4456 3948 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
4457 : AST::Visibility vis, AST::AttrVec outer_attrs)
4458 : {
4459 : // this shares virtually all logic with
4460 : // parse_inherent_impl_function_or_method
4461 : // - template?
4462 3948 : location_t locus = lexer.peek_token ()->get_locus ();
4463 :
4464 3948 : auto is_default = false;
4465 3948 : auto t = lexer.peek_token ();
4466 3948 : if (t->get_id () == IDENTIFIER
4467 3948 : && t->get_str () == Values::WeakKeywords::DEFAULT)
4468 : {
4469 24 : is_default = true;
4470 24 : lexer.skip_token ();
4471 : }
4472 :
4473 : // parse function or method qualifiers
4474 3948 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4475 :
4476 3948 : skip_token (FN_KW);
4477 :
4478 : // parse function or method name
4479 3948 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4480 3948 : if (ident_tok == nullptr)
4481 : {
4482 0 : return nullptr;
4483 : }
4484 3948 : Identifier ident{ident_tok};
4485 :
4486 : // DEBUG:
4487 3948 : rust_debug (
4488 : "about to start parsing generic params in trait impl function or method");
4489 :
4490 : // parse generic params
4491 3948 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4492 : = parse_generic_params_in_angles ();
4493 :
4494 : // DEBUG:
4495 3948 : rust_debug (
4496 : "finished parsing generic params in trait impl function or method");
4497 :
4498 3948 : if (!skip_token (LEFT_PAREN))
4499 : {
4500 : // skip after somewhere?
4501 0 : return nullptr;
4502 : }
4503 :
4504 : // now for function vs method disambiguation - method has opening "self"
4505 : // param
4506 3948 : auto initial_param = parse_self_param ();
4507 :
4508 3948 : if (!initial_param.has_value ()
4509 3948 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4510 0 : return nullptr;
4511 :
4512 : // FIXME: ensure that self param doesn't accidently consume tokens for a
4513 : // function
4514 3948 : bool is_method = false;
4515 3948 : if (initial_param.has_value ())
4516 : {
4517 3708 : if ((*initial_param)->is_self ())
4518 : is_method = true;
4519 :
4520 : // skip comma so function and method regular params can be parsed in
4521 : // same way
4522 7416 : if (lexer.peek_token ()->get_id () == COMMA)
4523 : {
4524 2001 : lexer.skip_token ();
4525 : }
4526 :
4527 : // DEBUG
4528 3708 : rust_debug ("successfully parsed self param in method trait impl item");
4529 : }
4530 :
4531 : // DEBUG
4532 3948 : rust_debug (
4533 : "started to parse function params in function or method trait impl item");
4534 :
4535 : // parse trait function params (only if next token isn't right paren)
4536 3948 : std::vector<std::unique_ptr<AST::Param>> function_params;
4537 7896 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
4538 : {
4539 : function_params
4540 2158 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4541 :
4542 2158 : if (function_params.empty ())
4543 : {
4544 0 : Error error (
4545 0 : lexer.peek_token ()->get_locus (),
4546 : "failed to parse function params in trait impl %s definition",
4547 : is_method ? "method" : "function");
4548 0 : add_error (std::move (error));
4549 :
4550 0 : skip_after_next_block ();
4551 0 : return nullptr;
4552 0 : }
4553 : }
4554 :
4555 3948 : if (initial_param.has_value ())
4556 3708 : function_params.insert (function_params.begin (),
4557 3708 : std::move (*initial_param));
4558 :
4559 : // DEBUG
4560 3948 : rust_debug ("successfully parsed function params in function or method "
4561 : "trait impl item");
4562 :
4563 3948 : if (!skip_token (RIGHT_PAREN))
4564 : {
4565 0 : skip_after_next_block ();
4566 0 : return nullptr;
4567 : }
4568 :
4569 : // parse return type (optional)
4570 3948 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4571 :
4572 : // DEBUG
4573 3948 : rust_debug (
4574 : "successfully parsed return type in function or method trait impl item");
4575 :
4576 : // parse where clause (optional)
4577 3948 : AST::WhereClause where_clause = parse_where_clause ();
4578 :
4579 : // DEBUG
4580 3948 : rust_debug (
4581 : "successfully parsed where clause in function or method trait impl item");
4582 :
4583 : // parse function definition (in block) - semicolon not allowed
4584 3948 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4585 :
4586 7896 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4587 1 : lexer.skip_token ();
4588 : else
4589 : {
4590 3947 : auto result = parse_block_expr ();
4591 3947 : if (!result)
4592 : {
4593 1 : Error error (lexer.peek_token ()->get_locus (),
4594 : "could not parse definition in trait impl %s definition",
4595 : is_method ? "method" : "function");
4596 1 : add_error (std::move (error));
4597 :
4598 1 : skip_after_end_block ();
4599 1 : return nullptr;
4600 1 : }
4601 3946 : body = std::move (result.value ());
4602 3947 : }
4603 :
4604 3947 : return std::unique_ptr<AST::Function> (
4605 15787 : new AST::Function (std::move (ident), std::move (qualifiers),
4606 : std::move (generic_params), std::move (function_params),
4607 : std::move (return_type), std::move (where_clause),
4608 : std::move (body), std::move (vis),
4609 3947 : std::move (outer_attrs), locus, is_default));
4610 11844 : }
4611 :
4612 : // Parses an extern block of declarations.
4613 : template <typename ManagedTokenSource>
4614 : std::unique_ptr<AST::ExternBlock>
4615 1481 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
4616 : AST::AttrVec outer_attrs)
4617 : {
4618 1481 : location_t locus = lexer.peek_token ()->get_locus ();
4619 1481 : skip_token (EXTERN_KW);
4620 :
4621 : // detect optional abi name
4622 1481 : std::string abi;
4623 1481 : const_TokenPtr next_tok = lexer.peek_token ();
4624 1481 : if (next_tok->get_id () == STRING_LITERAL)
4625 : {
4626 1481 : lexer.skip_token ();
4627 1481 : abi = next_tok->get_str ();
4628 : }
4629 :
4630 1481 : if (!skip_token (LEFT_CURLY))
4631 : {
4632 0 : skip_after_end_block ();
4633 0 : return nullptr;
4634 : }
4635 :
4636 1481 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4637 :
4638 : // parse declarations inside extern block
4639 1481 : std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
4640 :
4641 1481 : const_TokenPtr t = lexer.peek_token ();
4642 3704 : while (t->get_id () != RIGHT_CURLY)
4643 : {
4644 2224 : std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
4645 :
4646 2224 : if (extern_item == nullptr)
4647 : {
4648 1 : Error error (t->get_locus (),
4649 : "failed to parse external item despite not reaching "
4650 : "end of extern block");
4651 1 : add_error (std::move (error));
4652 :
4653 1 : return nullptr;
4654 1 : }
4655 :
4656 2223 : extern_items.push_back (std::move (extern_item));
4657 :
4658 2223 : t = lexer.peek_token ();
4659 : }
4660 :
4661 1480 : if (!skip_token (RIGHT_CURLY))
4662 : {
4663 : // skip somewhere
4664 0 : return nullptr;
4665 : }
4666 :
4667 1480 : extern_items.shrink_to_fit ();
4668 :
4669 : return std::unique_ptr<AST::ExternBlock> (
4670 1480 : new AST::ExternBlock (std::move (abi), std::move (extern_items),
4671 : std::move (vis), std::move (inner_attrs),
4672 1480 : std::move (outer_attrs), locus));
4673 2962 : }
4674 :
4675 : // Parses a single extern block item (static or function declaration).
4676 : template <typename ManagedTokenSource>
4677 : std::unique_ptr<AST::ExternalItem>
4678 2227 : Parser<ManagedTokenSource>::parse_external_item ()
4679 : {
4680 : // parse optional outer attributes
4681 2227 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4682 :
4683 2227 : location_t locus = lexer.peek_token ()->get_locus ();
4684 :
4685 : // parse optional visibility
4686 2227 : auto vis_res = parse_visibility ();
4687 2227 : if (!vis_res)
4688 0 : return nullptr;
4689 2227 : auto vis = vis_res.value ();
4690 :
4691 2227 : const_TokenPtr t = lexer.peek_token ();
4692 2227 : switch (t->get_id ())
4693 : {
4694 2 : case IDENTIFIER:
4695 4 : return parse_macro_invocation_semi (outer_attrs);
4696 1 : case STATIC_KW:
4697 : {
4698 : // parse extern static item
4699 1 : lexer.skip_token ();
4700 :
4701 : // parse mut (optional)
4702 1 : bool has_mut = false;
4703 2 : if (lexer.peek_token ()->get_id () == MUT)
4704 : {
4705 0 : lexer.skip_token ();
4706 0 : has_mut = true;
4707 : }
4708 :
4709 : // parse identifier
4710 1 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4711 1 : if (ident_tok == nullptr)
4712 : {
4713 0 : skip_after_semicolon ();
4714 0 : return nullptr;
4715 : }
4716 1 : Identifier ident{ident_tok};
4717 :
4718 1 : if (!skip_token (COLON))
4719 : {
4720 0 : skip_after_semicolon ();
4721 0 : return nullptr;
4722 : }
4723 :
4724 : // parse type (required)
4725 1 : std::unique_ptr<AST::Type> type = parse_type ();
4726 1 : if (type == nullptr)
4727 : {
4728 0 : Error error (lexer.peek_token ()->get_locus (),
4729 : "failed to parse type in external static item");
4730 0 : add_error (std::move (error));
4731 :
4732 0 : skip_after_semicolon ();
4733 0 : return nullptr;
4734 0 : }
4735 :
4736 1 : if (!skip_token (SEMICOLON))
4737 : {
4738 : // skip after somewhere?
4739 0 : return nullptr;
4740 : }
4741 :
4742 1 : return std::unique_ptr<AST::ExternalStaticItem> (
4743 2 : new AST::ExternalStaticItem (std::move (ident), std::move (type),
4744 : has_mut, std::move (vis),
4745 1 : std::move (outer_attrs), locus));
4746 3 : }
4747 2220 : case FN_KW:
4748 4440 : return parse_function (std::move (vis), std::move (outer_attrs), true);
4749 :
4750 4 : case TYPE:
4751 4 : return parse_external_type_item (std::move (vis),
4752 4 : std::move (outer_attrs));
4753 0 : default:
4754 : // error
4755 0 : add_error (
4756 0 : Error (t->get_locus (),
4757 : "unrecognised token %qs in extern block item declaration",
4758 : t->get_token_description ()));
4759 :
4760 0 : skip_after_semicolon ();
4761 0 : return nullptr;
4762 : }
4763 4454 : }
4764 :
4765 : // Parses a statement (will further disambiguate any statement).
4766 : template <typename ManagedTokenSource>
4767 : std::unique_ptr<AST::Stmt>
4768 741 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
4769 : {
4770 : // quick exit for empty statement
4771 : // FIXME: Can we have empty statements without semicolons? Just nothing?
4772 741 : const_TokenPtr t = lexer.peek_token ();
4773 741 : if (t->get_id () == SEMICOLON)
4774 : {
4775 30 : lexer.skip_token ();
4776 30 : return std::unique_ptr<AST::EmptyStmt> (
4777 30 : new AST::EmptyStmt (t->get_locus ()));
4778 : }
4779 :
4780 : // parse outer attributes
4781 711 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4782 :
4783 : // parsing this will be annoying because of the many different possibilities
4784 : /* best may be just to copy paste in parse_item switch, and failing that try
4785 : * to parse outer attributes, and then pass them in to either a let
4786 : * statement or (fallback) expression statement. */
4787 : // FIXME: think of a way to do this without such a large switch?
4788 711 : t = lexer.peek_token ();
4789 711 : switch (t->get_id ())
4790 : {
4791 200 : case LET:
4792 : // let statement
4793 200 : return parse_let_stmt (std::move (outer_attrs), restrictions);
4794 186 : case PUB:
4795 : case MOD:
4796 : case EXTERN_KW:
4797 : case USE:
4798 : case FN_KW:
4799 : case TYPE:
4800 : case STRUCT_KW:
4801 : case ENUM_KW:
4802 : case CONST:
4803 : case STATIC_KW:
4804 : case AUTO:
4805 : case TRAIT:
4806 : case IMPL:
4807 : case MACRO:
4808 : /* TODO: implement union keyword but not really because of
4809 : * context-dependence crappy hack way to parse a union written below to
4810 : * separate it from the good code. */
4811 : // case UNION:
4812 : case UNSAFE: // maybe - unsafe traits are a thing
4813 : /* if any of these (should be all possible VisItem prefixes), parse a
4814 : * VisItem can't parse item because would require reparsing outer
4815 : * attributes */
4816 : // may also be unsafe block
4817 372 : if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
4818 : {
4819 1 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
4820 : }
4821 : else
4822 : {
4823 185 : return parse_vis_item (std::move (outer_attrs));
4824 : }
4825 : break;
4826 : // crappy hack to do union "keyword"
4827 220 : case IDENTIFIER:
4828 220 : if (t->get_str () == Values::WeakKeywords::UNION
4829 220 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
4830 : {
4831 0 : return parse_vis_item (std::move (outer_attrs));
4832 : // or should this go straight to parsing union?
4833 : }
4834 440 : else if (is_macro_rules_def (t))
4835 : {
4836 : // macro_rules! macro item
4837 2 : return parse_macro_rules_def (std::move (outer_attrs));
4838 : }
4839 : gcc_fallthrough ();
4840 : // TODO: find out how to disable gcc "implicit fallthrough" warning
4841 : default:
4842 : // fallback: expression statement
4843 323 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
4844 : break;
4845 : }
4846 711 : }
4847 :
4848 : // Parses a let statement.
4849 : template <typename ManagedTokenSource>
4850 : std::unique_ptr<AST::LetStmt>
4851 12925 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
4852 : ParseRestrictions restrictions)
4853 : {
4854 12925 : location_t locus = lexer.peek_token ()->get_locus ();
4855 12925 : skip_token (LET);
4856 :
4857 : // parse pattern (required)
4858 12925 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
4859 12925 : if (pattern == nullptr)
4860 : {
4861 0 : Error error (lexer.peek_token ()->get_locus (),
4862 : "failed to parse pattern in let statement");
4863 0 : add_error (std::move (error));
4864 :
4865 0 : skip_after_semicolon ();
4866 0 : return nullptr;
4867 0 : }
4868 :
4869 : // parse type declaration (optional)
4870 12925 : std::unique_ptr<AST::Type> type = nullptr;
4871 25850 : if (lexer.peek_token ()->get_id () == COLON)
4872 : {
4873 : // must have a type declaration
4874 2027 : lexer.skip_token ();
4875 :
4876 2027 : type = parse_type ();
4877 2027 : if (type == nullptr)
4878 : {
4879 0 : Error error (lexer.peek_token ()->get_locus (),
4880 : "failed to parse type in let statement");
4881 0 : add_error (std::move (error));
4882 :
4883 0 : skip_after_semicolon ();
4884 0 : return nullptr;
4885 0 : }
4886 : }
4887 :
4888 : // parse expression to set variable to (optional)
4889 12925 : std::unique_ptr<AST::Expr> expr = nullptr;
4890 25850 : if (lexer.peek_token ()->get_id () == EQUAL)
4891 : {
4892 : // must have an expression
4893 11872 : lexer.skip_token ();
4894 :
4895 11872 : auto expr_res = parse_expr ();
4896 11872 : if (!expr_res)
4897 : {
4898 22 : skip_after_semicolon ();
4899 22 : return nullptr;
4900 : }
4901 11850 : expr = std::move (expr_res.value ());
4902 11872 : }
4903 :
4904 12903 : tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
4905 12903 : if (maybe_skip_token (ELSE))
4906 : {
4907 5 : auto block_expr = parse_block_expr ();
4908 5 : if (block_expr)
4909 : else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
4910 10 : std::move (block_expr.value ())};
4911 : else
4912 : else_expr = tl::nullopt;
4913 5 : }
4914 :
4915 12903 : if (restrictions.consume_semi)
4916 : {
4917 : // `stmt` macro variables are parsed without a semicolon, but should be
4918 : // parsed as a full statement when interpolated. This should be handled
4919 : // by having the interpolated statement be distinguishable from normal
4920 : // tokens, e.g. by NT tokens.
4921 12758 : if (restrictions.allow_close_after_expr_stmt)
4922 55 : maybe_skip_token (SEMICOLON);
4923 12703 : else if (!skip_token (SEMICOLON))
4924 1 : return nullptr;
4925 : }
4926 :
4927 : return std::unique_ptr<AST::LetStmt> (
4928 25809 : new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
4929 12902 : std::move (else_expr), std::move (outer_attrs), locus));
4930 12925 : }
4931 :
4932 : template <typename ManagedTokenSource>
4933 : tl::optional<AST::GenericArg>
4934 3843 : Parser<ManagedTokenSource>::parse_generic_arg ()
4935 : {
4936 3843 : auto tok = lexer.peek_token ();
4937 3843 : std::unique_ptr<AST::Expr> expr = nullptr;
4938 :
4939 3843 : switch (tok->get_id ())
4940 : {
4941 2476 : case IDENTIFIER:
4942 : {
4943 : // This is a bit of a weird situation: With an identifier token, we
4944 : // could either have a valid type or a macro (FIXME: anything else?). So
4945 : // we need one bit of lookahead to differentiate if this is really
4946 2476 : auto next_tok = lexer.peek_token (1);
4947 2476 : if (next_tok->get_id () == LEFT_ANGLE
4948 2465 : || next_tok->get_id () == SCOPE_RESOLUTION
4949 4938 : || next_tok->get_id () == EXCLAM)
4950 : {
4951 22 : auto type = parse_type ();
4952 22 : if (type)
4953 22 : return AST::GenericArg::create_type (std::move (type));
4954 : else
4955 0 : return tl::nullopt;
4956 22 : }
4957 2454 : else if (next_tok->get_id () == COLON)
4958 : {
4959 1 : lexer.skip_token (); // skip ident
4960 1 : lexer.skip_token (); // skip colon
4961 :
4962 1 : auto tok = lexer.peek_token ();
4963 1 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
4964 : = parse_type_param_bounds ();
4965 :
4966 1 : auto type = std::unique_ptr<AST::TraitObjectType> (
4967 1 : new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
4968 : false));
4969 1 : if (type)
4970 1 : return AST::GenericArg::create_type (std::move (type));
4971 : else
4972 : return tl::nullopt;
4973 2 : }
4974 2453 : lexer.skip_token ();
4975 9812 : return AST::GenericArg::create_ambiguous (tok->get_str (),
4976 2453 : tok->get_locus ());
4977 2476 : }
4978 19 : case LEFT_CURLY:
4979 : {
4980 19 : auto res = parse_block_expr ();
4981 19 : if (res)
4982 19 : expr = std::move (res.value ());
4983 : else
4984 0 : return tl::nullopt;
4985 19 : }
4986 : break;
4987 91 : case MINUS:
4988 : case STRING_LITERAL:
4989 : case CHAR_LITERAL:
4990 : case INT_LITERAL:
4991 : case FLOAT_LITERAL:
4992 : case TRUE_LITERAL:
4993 : case FALSE_LITERAL:
4994 : {
4995 91 : auto res = parse_literal_expr ();
4996 91 : if (res)
4997 91 : expr = std::move (res.value ());
4998 : else
4999 0 : return tl::nullopt;
5000 91 : }
5001 : break;
5002 : // FIXME: Because of this, error reporting is garbage for const generic
5003 : // parameter's default values
5004 1257 : default:
5005 : {
5006 1257 : auto type = parse_type ();
5007 : // FIXME: Find a better way to do this?
5008 1257 : if (type)
5009 1256 : return AST::GenericArg::create_type (std::move (type));
5010 : else
5011 1 : return tl::nullopt;
5012 1257 : }
5013 : }
5014 :
5015 110 : if (!expr)
5016 0 : return tl::nullopt;
5017 :
5018 110 : return AST::GenericArg::create_const (std::move (expr));
5019 3843 : }
5020 :
5021 : // Parses the generic arguments in each path segment.
5022 : template <typename ManagedTokenSource>
5023 : AST::GenericArgs
5024 3643 : Parser<ManagedTokenSource>::parse_path_generic_args ()
5025 : {
5026 7286 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
5027 5 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
5028 :
5029 3643 : if (!skip_token (LEFT_ANGLE))
5030 : {
5031 : // skip after somewhere?
5032 0 : return AST::GenericArgs::create_empty ();
5033 : }
5034 :
5035 : // We need to parse all lifetimes, then parse types and const generics in
5036 : // any order.
5037 :
5038 : // try to parse lifetimes first
5039 3643 : std::vector<AST::Lifetime> lifetime_args;
5040 :
5041 3643 : const_TokenPtr t = lexer.peek_token ();
5042 3643 : location_t locus = t->get_locus ();
5043 7292 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5044 : {
5045 3649 : auto lifetime = parse_lifetime (false);
5046 3649 : if (!lifetime)
5047 : {
5048 : // not necessarily an error
5049 : break;
5050 : }
5051 :
5052 41 : lifetime_args.push_back (std::move (lifetime.value ()));
5053 :
5054 : // if next token isn't comma, then it must be end of list
5055 82 : if (lexer.peek_token ()->get_id () != COMMA)
5056 : {
5057 : break;
5058 : }
5059 : // skip comma
5060 7 : lexer.skip_token ();
5061 :
5062 7 : t = lexer.peek_token ();
5063 : }
5064 :
5065 : // try to parse types and const generics second
5066 3643 : std::vector<AST::GenericArg> generic_args;
5067 :
5068 : // TODO: think of better control structure
5069 3643 : t = lexer.peek_token ();
5070 11074 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5071 : {
5072 : // FIXME: Is it fine to break if there is one binding? Can't there be
5073 : // bindings in between types?
5074 :
5075 : // ensure not binding being parsed as type accidently
5076 6213 : if (t->get_id () == IDENTIFIER
5077 6442 : && lexer.peek_token (1)->get_id () == EQUAL)
5078 : break;
5079 :
5080 3823 : auto arg = parse_generic_arg ();
5081 3823 : if (arg)
5082 : {
5083 3823 : generic_args.emplace_back (std::move (arg.value ()));
5084 : }
5085 :
5086 : // FIXME: Do we need to break if we encounter an error?
5087 :
5088 : // if next token isn't comma, then it must be end of list
5089 7646 : if (lexer.peek_token ()->get_id () != COMMA)
5090 : break;
5091 :
5092 : // skip comma
5093 287 : lexer.skip_token ();
5094 287 : t = lexer.peek_token ();
5095 : }
5096 :
5097 : // try to parse bindings third
5098 3643 : std::vector<AST::GenericArgsBinding> binding_args;
5099 :
5100 : // TODO: think of better control structure
5101 3643 : t = lexer.peek_token ();
5102 3716 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5103 : {
5104 73 : AST::GenericArgsBinding binding = parse_generic_args_binding ();
5105 73 : if (binding.is_error ())
5106 : {
5107 : // not necessarily an error
5108 : break;
5109 : }
5110 :
5111 73 : binding_args.push_back (std::move (binding));
5112 :
5113 : // if next token isn't comma, then it must be end of list
5114 146 : if (lexer.peek_token ()->get_id () != COMMA)
5115 : {
5116 : break;
5117 : }
5118 : // skip comma
5119 1 : lexer.skip_token ();
5120 :
5121 1 : t = lexer.peek_token ();
5122 : }
5123 :
5124 : // skip any trailing commas
5125 7286 : if (lexer.peek_token ()->get_id () == COMMA)
5126 0 : lexer.skip_token ();
5127 :
5128 3643 : if (!skip_generics_right_angle ())
5129 0 : return AST::GenericArgs::create_empty ();
5130 :
5131 3643 : lifetime_args.shrink_to_fit ();
5132 3643 : generic_args.shrink_to_fit ();
5133 3643 : binding_args.shrink_to_fit ();
5134 :
5135 3643 : return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
5136 3643 : std::move (binding_args), locus);
5137 7286 : }
5138 :
5139 : // Parses a binding in a generic args path segment.
5140 : template <typename ManagedTokenSource>
5141 : AST::GenericArgsBinding
5142 73 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
5143 : {
5144 73 : const_TokenPtr ident_tok = lexer.peek_token ();
5145 73 : if (ident_tok->get_id () != IDENTIFIER)
5146 : {
5147 : // allow non error-inducing use
5148 : // skip somewhere?
5149 0 : return AST::GenericArgsBinding::create_error ();
5150 : }
5151 73 : lexer.skip_token ();
5152 73 : Identifier ident{ident_tok};
5153 :
5154 73 : if (!skip_token (EQUAL))
5155 : {
5156 : // skip after somewhere?
5157 0 : return AST::GenericArgsBinding::create_error ();
5158 : }
5159 :
5160 : // parse type (required)
5161 73 : std::unique_ptr<AST::Type> type = parse_type ();
5162 73 : if (type == nullptr)
5163 : {
5164 : // skip somewhere?
5165 0 : return AST::GenericArgsBinding::create_error ();
5166 : }
5167 :
5168 146 : return AST::GenericArgsBinding (std::move (ident), std::move (type),
5169 146 : ident_tok->get_locus ());
5170 146 : }
5171 :
5172 : // Parses a self param. Also handles self param not existing.
5173 : template <typename ManagedTokenSource>
5174 : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
5175 18143 : Parser<ManagedTokenSource>::parse_self_param ()
5176 : {
5177 18143 : bool has_reference = false;
5178 18143 : AST::Lifetime lifetime = AST::Lifetime::elided ();
5179 :
5180 18143 : location_t locus = lexer.peek_token ()->get_locus ();
5181 :
5182 : // TODO: Feels off, find a better way to clearly express this
5183 72572 : std::vector<std::vector<TokenId>> ptrs
5184 : = {{ASTERISK, SELF} /* *self */,
5185 : {ASTERISK, CONST, SELF} /* *const self */,
5186 : {ASTERISK, MUT, SELF} /* *mut self */};
5187 :
5188 72566 : for (auto &s : ptrs)
5189 : {
5190 : size_t i = 0;
5191 54437 : for (i = 0; i < s.size (); i++)
5192 108868 : if (lexer.peek_token (i)->get_id () != s[i])
5193 : break;
5194 54426 : if (i == s.size ())
5195 : {
5196 3 : Error error (lexer.peek_token ()->get_locus (),
5197 : "cannot pass %<self%> by raw pointer");
5198 3 : add_error (std::move (error));
5199 3 : return Parse::Error::Self::make_self_raw_pointer ();
5200 3 : }
5201 : }
5202 :
5203 : // Trying to find those patterns:
5204 : //
5205 : // &'lifetime mut self
5206 : // &'lifetime self
5207 : // & mut self
5208 : // & self
5209 : // mut self
5210 : // self
5211 : //
5212 : // If not found, it is probably a function, exit and let function parsing
5213 : // handle it.
5214 : bool is_self = false;
5215 108840 : for (size_t i = 0; i < 5; i++)
5216 181400 : if (lexer.peek_token (i)->get_id () == SELF)
5217 7807 : is_self = true;
5218 :
5219 18140 : if (!is_self)
5220 : return Parse::Error::Self::make_not_self ();
5221 :
5222 : // test if self is a reference parameter
5223 15608 : if (lexer.peek_token ()->get_id () == AMP)
5224 : {
5225 4638 : has_reference = true;
5226 4638 : lexer.skip_token ();
5227 :
5228 : // now test whether it has a lifetime
5229 9276 : if (lexer.peek_token ()->get_id () == LIFETIME)
5230 : {
5231 : // something went wrong somehow
5232 4 : if (auto parsed_lifetime = parse_lifetime (true))
5233 : {
5234 2 : lifetime = parsed_lifetime.value ();
5235 : }
5236 : else
5237 : {
5238 0 : Error error (lexer.peek_token ()->get_locus (),
5239 : "failed to parse lifetime in self param");
5240 0 : add_error (std::move (error));
5241 :
5242 : // skip after somewhere?
5243 0 : return Parse::Error::Self::make_parsing_error ();
5244 0 : }
5245 : }
5246 : }
5247 :
5248 : // test for mut
5249 7804 : bool has_mut = false;
5250 15608 : if (lexer.peek_token ()->get_id () == MUT)
5251 : {
5252 348 : has_mut = true;
5253 348 : lexer.skip_token ();
5254 : }
5255 :
5256 : // skip self token
5257 7804 : const_TokenPtr self_tok = lexer.peek_token ();
5258 7804 : if (self_tok->get_id () != SELF)
5259 : {
5260 : // skip after somewhere?
5261 : return Parse::Error::Self::make_not_self ();
5262 : }
5263 7802 : lexer.skip_token ();
5264 :
5265 : // parse optional type
5266 7802 : std::unique_ptr<AST::Type> type = nullptr;
5267 15604 : if (lexer.peek_token ()->get_id () == COLON)
5268 : {
5269 1 : lexer.skip_token ();
5270 :
5271 : // type is now required
5272 1 : type = parse_type ();
5273 1 : if (type == nullptr)
5274 : {
5275 0 : Error error (lexer.peek_token ()->get_locus (),
5276 : "could not parse type in self param");
5277 0 : add_error (std::move (error));
5278 :
5279 : // skip after somewhere?
5280 0 : return Parse::Error::Self::make_parsing_error ();
5281 0 : }
5282 : }
5283 :
5284 : // ensure that cannot have both type and reference
5285 7802 : if (type && has_reference)
5286 : {
5287 0 : Error error (
5288 0 : lexer.peek_token ()->get_locus (),
5289 : "cannot have both a reference and a type specified in a self param");
5290 0 : add_error (std::move (error));
5291 :
5292 : // skip after somewhere?
5293 0 : return Parse::Error::Self::make_parsing_error ();
5294 0 : }
5295 :
5296 7802 : if (has_reference)
5297 : {
5298 4638 : return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
5299 4638 : locus);
5300 : }
5301 : else
5302 : {
5303 : // note that type may be nullptr here and that's fine
5304 3164 : return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
5305 3164 : locus);
5306 : }
5307 25945 : }
5308 :
5309 : /* Parses an expression or macro statement. */
5310 : template <typename ManagedTokenSource>
5311 : std::unique_ptr<AST::Stmt>
5312 324 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
5313 : ParseRestrictions restrictions)
5314 : {
5315 324 : location_t locus = lexer.peek_token ()->get_locus ();
5316 :
5317 324 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
5318 :
5319 648 : switch (lexer.peek_token ()->get_id ())
5320 : {
5321 220 : case IDENTIFIER:
5322 : case CRATE:
5323 : case SUPER:
5324 : case SELF:
5325 : case SELF_ALIAS:
5326 : case DOLLAR_SIGN:
5327 : case SCOPE_RESOLUTION:
5328 : {
5329 220 : AST::PathInExpression path = parse_path_in_expression ();
5330 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
5331 220 : null_denotation;
5332 :
5333 440 : if (lexer.peek_token ()->get_id () == EXCLAM)
5334 : {
5335 61 : std::unique_ptr<AST::MacroInvocation> invoc
5336 122 : = parse_macro_invocation_partial (std::move (path),
5337 : std::move (outer_attrs));
5338 :
5339 61 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
5340 : {
5341 59 : invoc->add_semicolon ();
5342 : // Macro invocation with semicolon.
5343 59 : return invoc;
5344 : }
5345 :
5346 2 : TokenId after_macro = lexer.peek_token ()->get_id ();
5347 :
5348 2 : if (restrictions.allow_close_after_expr_stmt
5349 2 : && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
5350 : || after_macro == RIGHT_SQUARE))
5351 2 : return invoc;
5352 :
5353 0 : if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
5354 : == AST::CURLY
5355 0 : && after_macro != DOT && after_macro != QUESTION_MARK)
5356 : {
5357 0 : rust_debug ("braced macro statement");
5358 0 : return invoc;
5359 : }
5360 :
5361 0 : null_denotation = std::move (invoc);
5362 61 : }
5363 : else
5364 : {
5365 : null_denotation
5366 318 : = null_denotation_path (std::move (path), {}, restrictions);
5367 : }
5368 :
5369 636 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
5370 : std::move (outer_attrs), restrictions);
5371 : break;
5372 220 : }
5373 104 : default:
5374 104 : restrictions.expr_can_be_stmt = true;
5375 208 : expr = parse_expr (std::move (outer_attrs), restrictions);
5376 104 : break;
5377 : }
5378 :
5379 263 : if (!expr)
5380 : {
5381 : // expr is required, error
5382 0 : Error error (lexer.peek_token ()->get_locus (),
5383 : "failed to parse expr in expr statement");
5384 0 : add_error (std::move (error));
5385 :
5386 0 : skip_after_semicolon ();
5387 0 : return nullptr;
5388 0 : }
5389 :
5390 263 : bool has_semi = false;
5391 :
5392 263 : if (restrictions.consume_semi)
5393 : {
5394 249 : if (maybe_skip_token (SEMICOLON))
5395 : {
5396 138 : has_semi = true;
5397 : }
5398 111 : else if (expr.value ()->is_expr_without_block ())
5399 : {
5400 10 : if (restrictions.allow_close_after_expr_stmt)
5401 : {
5402 10 : TokenId id = lexer.peek_token ()->get_id ();
5403 10 : if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
5404 : {
5405 3 : expect_token (SEMICOLON);
5406 3 : return nullptr;
5407 : }
5408 : }
5409 : else
5410 : {
5411 0 : expect_token (SEMICOLON);
5412 0 : return nullptr;
5413 : }
5414 : }
5415 : }
5416 :
5417 260 : return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
5418 260 : has_semi);
5419 324 : }
5420 :
5421 : // Parses a loop label used in loop expressions.
5422 : template <typename ManagedTokenSource>
5423 : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
5424 40 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
5425 : {
5426 : // parse lifetime - if doesn't exist, assume no label
5427 40 : if (tok->get_id () != LIFETIME)
5428 : {
5429 : // not necessarily an error
5430 : return Parse::Error::LoopLabel::make_not_loop_label ();
5431 : }
5432 : /* FIXME: check for named lifetime requirement here? or check in semantic
5433 : * analysis phase? */
5434 40 : AST::Lifetime label = lifetime_from_token (tok);
5435 :
5436 40 : if (!skip_token (COLON))
5437 : {
5438 : // skip somewhere?
5439 40 : Parse::Error::LoopLabel::make_missing_colon ();
5440 : }
5441 :
5442 : return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
5443 40 : AST::LoopLabel (std::move (label), tok->get_locus ()));
5444 40 : }
5445 :
5446 : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
5447 : template <typename ManagedTokenSource>
5448 : AST::MatchArm
5449 2136 : Parser<ManagedTokenSource>::parse_match_arm ()
5450 : {
5451 : // parse optional outer attributes
5452 2136 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5453 :
5454 : // DEBUG
5455 2136 : rust_debug ("about to start parsing match arm patterns");
5456 :
5457 : // break early if find right curly
5458 4272 : if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
5459 : {
5460 : // not an error
5461 0 : return AST::MatchArm::create_error ();
5462 : }
5463 :
5464 : // parse match arm patterns - at least 1 is required
5465 2136 : std::unique_ptr<AST::Pattern> match_arm_pattern
5466 : = parse_match_arm_pattern (RIGHT_CURLY);
5467 2136 : if (match_arm_pattern == nullptr)
5468 : {
5469 0 : Error error (lexer.peek_token ()->get_locus (),
5470 : "failed to parse any patterns in match arm");
5471 0 : add_error (std::move (error));
5472 :
5473 : // skip somewhere?
5474 0 : return AST::MatchArm::create_error ();
5475 0 : }
5476 :
5477 : // DEBUG
5478 2136 : rust_debug ("successfully parsed match arm patterns");
5479 :
5480 : // parse match arm guard expr if it exists
5481 2136 : std::unique_ptr<AST::Expr> guard_expr = nullptr;
5482 4272 : if (lexer.peek_token ()->get_id () == IF)
5483 : {
5484 1 : lexer.skip_token ();
5485 :
5486 1 : auto guard_expr_res = parse_expr ();
5487 1 : if (!guard_expr_res)
5488 : {
5489 0 : Error error (lexer.peek_token ()->get_locus (),
5490 : "failed to parse guard expression in match arm");
5491 0 : add_error (std::move (error));
5492 :
5493 : // skip somewhere?
5494 0 : return AST::MatchArm::create_error ();
5495 0 : }
5496 1 : guard_expr = std::move (guard_expr_res.value ());
5497 1 : }
5498 :
5499 : // DEBUG
5500 2136 : rust_debug ("successfully parsed match arm");
5501 :
5502 4272 : return AST::MatchArm (std::move (match_arm_pattern),
5503 4272 : lexer.peek_token ()->get_locus (),
5504 2136 : std::move (guard_expr), std::move (outer_attrs));
5505 2136 : }
5506 :
5507 : /* Parses the patterns used in a match arm. End token id is the id of the
5508 : * token that would exist after the patterns are done (e.g. '}' for match
5509 : * expr, '=' for if let and while let). */
5510 : template <typename ManagedTokenSource>
5511 : std::unique_ptr<AST::Pattern>
5512 2171 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
5513 : {
5514 : // skip optional leading '|'
5515 4342 : if (lexer.peek_token ()->get_id () == PIPE)
5516 0 : lexer.skip_token ();
5517 : /* TODO: do I even need to store the result of this? can't be used.
5518 : * If semantically different, I need a wrapped "match arm patterns" object
5519 : * for this. */
5520 :
5521 2171 : std::unique_ptr<AST::Pattern> pattern;
5522 :
5523 : // quick break out if end_token_id
5524 4342 : if (lexer.peek_token ()->get_id () == end_token_id)
5525 1 : return pattern;
5526 :
5527 : // parse required pattern - if doesn't exist, return empty
5528 2170 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
5529 2170 : if (initial_pattern == nullptr)
5530 : {
5531 : // FIXME: should this be an error?
5532 0 : return pattern;
5533 : }
5534 :
5535 2170 : return initial_pattern;
5536 2171 : }
5537 :
5538 : // Parses a single parameter used in a closure definition.
5539 : template <typename ManagedTokenSource>
5540 : AST::ClosureParam
5541 72 : Parser<ManagedTokenSource>::parse_closure_param ()
5542 : {
5543 72 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5544 :
5545 : // parse pattern (which is required)
5546 72 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
5547 72 : if (pattern == nullptr)
5548 : {
5549 : // not necessarily an error
5550 0 : return AST::ClosureParam::create_error ();
5551 : }
5552 :
5553 : // parse optional type of param
5554 72 : std::unique_ptr<AST::Type> type = nullptr;
5555 144 : if (lexer.peek_token ()->get_id () == COLON)
5556 : {
5557 63 : lexer.skip_token ();
5558 :
5559 : // parse type, which is now required
5560 63 : type = parse_type ();
5561 63 : if (type == nullptr)
5562 : {
5563 0 : Error error (lexer.peek_token ()->get_locus (),
5564 : "failed to parse type in closure parameter");
5565 0 : add_error (std::move (error));
5566 :
5567 : // skip somewhere?
5568 0 : return AST::ClosureParam::create_error ();
5569 0 : }
5570 : }
5571 :
5572 72 : location_t loc = pattern->get_locus ();
5573 72 : return AST::ClosureParam (std::move (pattern), loc, std::move (type),
5574 72 : std::move (outer_attrs));
5575 72 : }
5576 :
5577 : // Parses a type (will further disambiguate any type).
5578 : template <typename ManagedTokenSource>
5579 : std::unique_ptr<AST::Type>
5580 43391 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
5581 : {
5582 : /* rules for all types:
5583 : * NeverType: '!'
5584 : * SliceType: '[' Type ']'
5585 : * InferredType: '_'
5586 : * MacroInvocation: SimplePath '!' DelimTokenTree
5587 : * ParenthesisedType: '(' Type ')'
5588 : * ImplTraitType: 'impl' TypeParamBounds
5589 : * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
5590 : * TypeParamBound Lifetime | TraitBound
5591 : * ImplTraitTypeOneBound: 'impl' TraitBound
5592 : * TraitObjectType: 'dyn'? TypeParamBounds
5593 : * TraitObjectTypeOneBound: 'dyn'? TraitBound
5594 : * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
5595 : * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
5596 : * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
5597 : * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
5598 : * 'unsafe'?
5599 : * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
5600 : * (
5601 : * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
5602 : * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
5603 : * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
5604 : * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
5605 : * TupleType: '(' Type etc. - regular tuple stuff. Also
5606 : * regular tuple vs parenthesised precedence
5607 : *
5608 : * Disambiguate between macro and type path via type path being parsed, and
5609 : * then if '!' found, convert type path to simple path for macro. Usual
5610 : * disambiguation for tuple vs parenthesised. For ImplTraitType and
5611 : * TraitObjectType individual disambiguations, they seem more like "special
5612 : * cases", so probably just try to parse the more general ImplTraitType or
5613 : * TraitObjectType and return OneBound versions if they satisfy those
5614 : * criteria. */
5615 :
5616 43391 : const_TokenPtr t = lexer.peek_token ();
5617 43391 : switch (t->get_id ())
5618 : {
5619 46 : case EXCLAM:
5620 : // never type - can't be macro as no path beforehand
5621 46 : lexer.skip_token ();
5622 46 : return std::unique_ptr<AST::NeverType> (
5623 46 : new AST::NeverType (t->get_locus ()));
5624 854 : case LEFT_SQUARE:
5625 : // slice type or array type - requires further disambiguation
5626 854 : return parse_slice_or_array_type ();
5627 309 : case LEFT_SHIFT:
5628 : case LEFT_ANGLE:
5629 : {
5630 : // qualified path in type
5631 309 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
5632 309 : if (path.is_error ())
5633 : {
5634 0 : if (save_errors)
5635 : {
5636 0 : Error error (t->get_locus (),
5637 : "failed to parse qualified path in type");
5638 0 : add_error (std::move (error));
5639 0 : }
5640 :
5641 0 : return nullptr;
5642 : }
5643 309 : return std::unique_ptr<AST::QualifiedPathInType> (
5644 309 : new AST::QualifiedPathInType (std::move (path)));
5645 309 : }
5646 104 : case UNDERSCORE:
5647 : // inferred type
5648 104 : lexer.skip_token ();
5649 104 : return std::unique_ptr<AST::InferredType> (
5650 104 : new AST::InferredType (t->get_locus ()));
5651 2728 : case ASTERISK:
5652 : // raw pointer type
5653 2728 : return parse_raw_pointer_type ();
5654 4290 : case AMP: // does this also include AMP_AMP?
5655 : case LOGICAL_AND:
5656 : // reference type
5657 4290 : return parse_reference_type ();
5658 0 : case LIFETIME:
5659 : {
5660 : /* probably a lifetime bound, so probably type param bounds in
5661 : * TraitObjectType */
5662 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5663 : = parse_type_param_bounds ();
5664 :
5665 0 : return std::unique_ptr<AST::TraitObjectType> (
5666 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5667 0 : false));
5668 0 : }
5669 34447 : case IDENTIFIER:
5670 : case SUPER:
5671 : case SELF:
5672 : case SELF_ALIAS:
5673 : case CRATE:
5674 : case DOLLAR_SIGN:
5675 : case SCOPE_RESOLUTION:
5676 : {
5677 : // macro invocation or type path - requires further disambiguation.
5678 : /* for parsing path component of each rule, perhaps parse it as a
5679 : * typepath and attempt conversion to simplepath if a trailing '!' is
5680 : * found */
5681 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
5682 : * with it, it is exactly the same as a TypePath syntactically, so
5683 : * this is a syntactical ambiguity. As such, the parser will parse it
5684 : * as a TypePath. This, however, does not prevent TraitObjectType from
5685 : * starting with a typepath. */
5686 :
5687 : // parse path as type path
5688 34447 : AST::TypePath path = parse_type_path ();
5689 34447 : if (path.is_error ())
5690 : {
5691 0 : if (save_errors)
5692 : {
5693 0 : Error error (t->get_locus (),
5694 : "failed to parse path as first component of type");
5695 0 : add_error (std::move (error));
5696 0 : }
5697 :
5698 0 : return nullptr;
5699 : }
5700 34447 : location_t locus = path.get_locus ();
5701 :
5702 : // branch on next token
5703 34447 : t = lexer.peek_token ();
5704 34447 : switch (t->get_id ())
5705 : {
5706 29 : case EXCLAM:
5707 : {
5708 : // macro invocation
5709 : // convert to simple path
5710 29 : AST::SimplePath macro_path = path.as_simple_path ();
5711 29 : if (macro_path.is_empty ())
5712 : {
5713 0 : if (save_errors)
5714 : {
5715 0 : Error error (t->get_locus (),
5716 : "failed to parse simple path in macro "
5717 : "invocation (for type)");
5718 0 : add_error (std::move (error));
5719 0 : }
5720 :
5721 0 : return nullptr;
5722 : }
5723 :
5724 29 : lexer.skip_token ();
5725 :
5726 29 : auto tok_tree = parse_delim_token_tree ();
5727 29 : if (!tok_tree)
5728 0 : return nullptr;
5729 :
5730 87 : return AST::MacroInvocation::Regular (
5731 58 : AST::MacroInvocData (std::move (macro_path),
5732 29 : std::move (tok_tree.value ())),
5733 29 : {}, locus);
5734 58 : }
5735 0 : case PLUS:
5736 : {
5737 : // type param bounds
5738 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5739 :
5740 : // convert type path to trait bound
5741 0 : std::unique_ptr<AST::TraitBound> path_bound (
5742 0 : new AST::TraitBound (std::move (path), locus, false, false));
5743 0 : bounds.push_back (std::move (path_bound));
5744 :
5745 : /* parse rest of bounds - FIXME: better way to find when to stop
5746 : * parsing */
5747 0 : while (t->get_id () == PLUS)
5748 : {
5749 0 : lexer.skip_token ();
5750 :
5751 : // parse bound if it exists - if not, assume end of sequence
5752 0 : std::unique_ptr<AST::TypeParamBound> bound
5753 : = parse_type_param_bound ();
5754 0 : if (bound == nullptr)
5755 : {
5756 : break;
5757 : }
5758 0 : bounds.push_back (std::move (bound));
5759 :
5760 0 : t = lexer.peek_token ();
5761 : }
5762 :
5763 0 : return std::unique_ptr<AST::TraitObjectType> (
5764 0 : new AST::TraitObjectType (std::move (bounds), locus, false));
5765 0 : }
5766 34418 : default:
5767 : // assume that this is a type path and not an error
5768 34418 : return std::unique_ptr<AST::TypePath> (
5769 34418 : new AST::TypePath (std::move (path)));
5770 : }
5771 34447 : }
5772 396 : case LEFT_PAREN:
5773 : /* tuple type or parenthesised type - requires further disambiguation
5774 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
5775 : * could be TraitObjectTypeOneBound or TraitObjectType */
5776 396 : return parse_paren_prefixed_type ();
5777 3 : case FOR:
5778 : // TraitObjectTypeOneBound or BareFunctionType
5779 3 : return parse_for_prefixed_type ();
5780 61 : case ASYNC:
5781 : case CONST:
5782 : case UNSAFE:
5783 : case EXTERN_KW:
5784 : case FN_KW:
5785 : // bare function type (with no for lifetimes)
5786 61 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
5787 120 : case IMPL:
5788 120 : lexer.skip_token ();
5789 240 : if (lexer.peek_token ()->get_id () == LIFETIME)
5790 : {
5791 : /* cannot be one bound because lifetime prevents it from being
5792 : * traitbound */
5793 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5794 : = parse_type_param_bounds ();
5795 :
5796 0 : return std::unique_ptr<AST::ImplTraitType> (
5797 0 : new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
5798 0 : }
5799 : else
5800 : {
5801 : // should be trait bound, so parse trait bound
5802 120 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
5803 120 : if (initial_bound == nullptr)
5804 : {
5805 0 : if (save_errors)
5806 : {
5807 0 : Error error (lexer.peek_token ()->get_locus (),
5808 : "failed to parse ImplTraitType initial bound");
5809 0 : add_error (std::move (error));
5810 0 : }
5811 :
5812 0 : return nullptr;
5813 : }
5814 :
5815 120 : location_t locus = t->get_locus ();
5816 :
5817 : // short cut if next token isn't '+'
5818 120 : t = lexer.peek_token ();
5819 120 : if (t->get_id () != PLUS)
5820 : {
5821 120 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
5822 120 : new AST::ImplTraitTypeOneBound (std::move (initial_bound),
5823 120 : locus));
5824 : }
5825 :
5826 : // parse additional type param bounds
5827 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5828 0 : bounds.push_back (std::move (initial_bound));
5829 0 : while (t->get_id () == PLUS)
5830 : {
5831 0 : lexer.skip_token ();
5832 :
5833 : // parse bound if it exists
5834 0 : std::unique_ptr<AST::TypeParamBound> bound
5835 : = parse_type_param_bound ();
5836 0 : if (bound == nullptr)
5837 : {
5838 : // not an error as trailing plus may exist
5839 : break;
5840 : }
5841 0 : bounds.push_back (std::move (bound));
5842 :
5843 0 : t = lexer.peek_token ();
5844 : }
5845 :
5846 0 : return std::unique_ptr<AST::ImplTraitType> (
5847 0 : new AST::ImplTraitType (std::move (bounds), locus));
5848 120 : }
5849 29 : case DYN:
5850 : case QUESTION_MARK:
5851 : {
5852 : // either TraitObjectType or TraitObjectTypeOneBound
5853 29 : bool has_dyn = false;
5854 29 : if (t->get_id () == DYN)
5855 : {
5856 29 : lexer.skip_token ();
5857 29 : has_dyn = true;
5858 : }
5859 :
5860 58 : if (lexer.peek_token ()->get_id () == LIFETIME)
5861 : {
5862 : /* cannot be one bound because lifetime prevents it from being
5863 : * traitbound */
5864 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5865 : = parse_type_param_bounds ();
5866 :
5867 0 : return std::unique_ptr<AST::TraitObjectType> (
5868 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5869 0 : has_dyn));
5870 0 : }
5871 : else
5872 : {
5873 : // should be trait bound, so parse trait bound
5874 29 : std::unique_ptr<AST::TraitBound> initial_bound
5875 : = parse_trait_bound ();
5876 29 : if (initial_bound == nullptr)
5877 : {
5878 2 : if (save_errors)
5879 : {
5880 2 : Error error (
5881 2 : lexer.peek_token ()->get_locus (),
5882 : "failed to parse TraitObjectType initial bound");
5883 2 : add_error (std::move (error));
5884 2 : }
5885 :
5886 2 : return nullptr;
5887 : }
5888 :
5889 : // short cut if next token isn't '+'
5890 27 : t = lexer.peek_token ();
5891 27 : if (t->get_id () != PLUS)
5892 : {
5893 : // convert trait bound to value object
5894 14 : AST::TraitBound value_bound (*initial_bound);
5895 :
5896 : // DEBUG: removed as unique ptr, so should auto delete
5897 : // delete initial_bound;
5898 :
5899 14 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
5900 28 : new AST::TraitObjectTypeOneBound (std::move (value_bound),
5901 14 : t->get_locus (), has_dyn));
5902 14 : }
5903 :
5904 : // parse additional type param bounds
5905 13 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5906 13 : bounds.push_back (std::move (initial_bound));
5907 33 : while (t->get_id () == PLUS)
5908 : {
5909 20 : lexer.skip_token ();
5910 :
5911 : // parse bound if it exists
5912 20 : std::unique_ptr<AST::TypeParamBound> bound
5913 : = parse_type_param_bound ();
5914 20 : if (bound == nullptr)
5915 : {
5916 : // not an error as trailing plus may exist
5917 : break;
5918 : }
5919 20 : bounds.push_back (std::move (bound));
5920 :
5921 20 : t = lexer.peek_token ();
5922 : }
5923 :
5924 13 : return std::unique_ptr<AST::TraitObjectType> (
5925 13 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5926 13 : has_dyn));
5927 29 : }
5928 : }
5929 4 : default:
5930 4 : if (save_errors)
5931 4 : add_error (Error (t->get_locus (), "unrecognised token %qs in type",
5932 : t->get_token_description ()));
5933 :
5934 4 : return nullptr;
5935 : }
5936 43391 : }
5937 :
5938 : /* Parses a type that has '(' as its first character. Returns a tuple type,
5939 : * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
5940 : * on following characters. */
5941 : template <typename ManagedTokenSource>
5942 : std::unique_ptr<AST::Type>
5943 396 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
5944 : {
5945 : /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
5946 : * a trait bound, not a parenthesised type, so that it can still be used in
5947 : * type param bounds. */
5948 :
5949 : /* NOTE: this implementation is really shit but I couldn't think of a better
5950 : * one. It requires essentially breaking polymorphism and downcasting via
5951 : * virtual method abuse, as it was copied from the rustc implementation (in
5952 : * which types are reified due to tagged union), after a more OOP attempt by
5953 : * me failed. */
5954 396 : location_t left_delim_locus = lexer.peek_token ()->get_locus ();
5955 :
5956 : // skip left delim
5957 396 : lexer.skip_token ();
5958 : /* while next token isn't close delim, parse comma-separated types, saving
5959 : * whether trailing comma happens */
5960 396 : const_TokenPtr t = lexer.peek_token ();
5961 396 : bool trailing_comma = true;
5962 396 : std::vector<std::unique_ptr<AST::Type>> types;
5963 :
5964 723 : while (t->get_id () != RIGHT_PAREN)
5965 : {
5966 632 : std::unique_ptr<AST::Type> type = parse_type ();
5967 632 : if (type == nullptr)
5968 : {
5969 0 : Error error (t->get_locus (),
5970 : "failed to parse type inside parentheses (probably "
5971 : "tuple or parenthesised)");
5972 0 : add_error (std::move (error));
5973 :
5974 0 : return nullptr;
5975 0 : }
5976 632 : types.push_back (std::move (type));
5977 :
5978 632 : t = lexer.peek_token ();
5979 632 : if (t->get_id () != COMMA)
5980 : {
5981 305 : trailing_comma = false;
5982 : break;
5983 : }
5984 327 : lexer.skip_token ();
5985 :
5986 327 : t = lexer.peek_token ();
5987 : }
5988 :
5989 396 : if (!skip_token (RIGHT_PAREN))
5990 : {
5991 0 : return nullptr;
5992 : }
5993 :
5994 : // if only one type and no trailing comma, then not a tuple type
5995 396 : if (types.size () == 1 && !trailing_comma)
5996 : {
5997 : // must be a TraitObjectType (with more than one bound)
5998 10 : if (lexer.peek_token ()->get_id () == PLUS)
5999 : {
6000 : // create type param bounds vector
6001 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6002 :
6003 : // HACK: convert type to traitbound and add to bounds
6004 0 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6005 0 : std::unique_ptr<AST::TraitBound> converted_bound (
6006 0 : released_ptr->to_trait_bound (true));
6007 0 : if (converted_bound == nullptr)
6008 : {
6009 0 : Error error (
6010 0 : lexer.peek_token ()->get_locus (),
6011 : "failed to hackily converted parsed type to trait bound");
6012 0 : add_error (std::move (error));
6013 :
6014 0 : return nullptr;
6015 0 : }
6016 0 : bounds.push_back (std::move (converted_bound));
6017 :
6018 0 : t = lexer.peek_token ();
6019 0 : while (t->get_id () == PLUS)
6020 : {
6021 0 : lexer.skip_token ();
6022 :
6023 : // attempt to parse typeparambound
6024 0 : std::unique_ptr<AST::TypeParamBound> bound
6025 : = parse_type_param_bound ();
6026 0 : if (bound == nullptr)
6027 : {
6028 : // not an error if null
6029 : break;
6030 : }
6031 0 : bounds.push_back (std::move (bound));
6032 :
6033 0 : t = lexer.peek_token ();
6034 : }
6035 :
6036 0 : return std::unique_ptr<AST::TraitObjectType> (
6037 0 : new AST::TraitObjectType (std::move (bounds), left_delim_locus,
6038 0 : false));
6039 0 : }
6040 : else
6041 : {
6042 : // release vector pointer
6043 5 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6044 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6045 : * type */
6046 5 : std::unique_ptr<AST::TraitBound> converted_bound (
6047 5 : released_ptr->to_trait_bound (true));
6048 5 : if (converted_bound == nullptr)
6049 : {
6050 : // parenthesised type
6051 5 : return std::unique_ptr<AST::ParenthesisedType> (
6052 5 : new AST::ParenthesisedType (std::move (released_ptr),
6053 5 : left_delim_locus));
6054 : }
6055 : else
6056 : {
6057 : // trait object type (one bound)
6058 :
6059 : // get value semantics trait bound
6060 0 : AST::TraitBound value_bound (*converted_bound);
6061 :
6062 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6063 0 : new AST::TraitObjectTypeOneBound (value_bound,
6064 0 : left_delim_locus));
6065 0 : }
6066 5 : }
6067 : }
6068 : else
6069 : {
6070 391 : return std::unique_ptr<AST::TupleType> (
6071 391 : new AST::TupleType (std::move (types), left_delim_locus));
6072 : }
6073 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6074 : * lost somehow */
6075 396 : }
6076 :
6077 : /* Parses a type that has 'for' as its first character. This means it has a
6078 : * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
6079 : * TraitObjectTypeOneBound depending on following characters. */
6080 : template <typename ManagedTokenSource>
6081 : std::unique_ptr<AST::Type>
6082 3 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
6083 : {
6084 3 : location_t for_locus = lexer.peek_token ()->get_locus ();
6085 : // parse for lifetimes in type
6086 3 : std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
6087 :
6088 : // branch on next token - either function or a trait type
6089 3 : const_TokenPtr t = lexer.peek_token ();
6090 3 : switch (t->get_id ())
6091 : {
6092 3 : case ASYNC:
6093 : case CONST:
6094 : case UNSAFE:
6095 : case EXTERN_KW:
6096 : case FN_KW:
6097 3 : return parse_bare_function_type (std::move (for_lifetimes));
6098 0 : case SCOPE_RESOLUTION:
6099 : case IDENTIFIER:
6100 : case SUPER:
6101 : case SELF:
6102 : case SELF_ALIAS:
6103 : case CRATE:
6104 : case DOLLAR_SIGN:
6105 : {
6106 : // path, so trait type
6107 :
6108 : // parse type path to finish parsing trait bound
6109 0 : AST::TypePath path = parse_type_path ();
6110 :
6111 0 : t = lexer.peek_token ();
6112 0 : if (t->get_id () != PLUS)
6113 : {
6114 : // must be one-bound trait type
6115 : // create trait bound value object
6116 0 : AST::TraitBound bound (std::move (path), for_locus, false, false,
6117 : std::move (for_lifetimes));
6118 :
6119 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6120 0 : new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
6121 0 : }
6122 :
6123 : /* more than one bound trait type (or at least parsed as it - could be
6124 : * trailing '+') create trait bound pointer and bounds */
6125 0 : std::unique_ptr<AST::TraitBound> initial_bound (
6126 0 : new AST::TraitBound (std::move (path), for_locus, false, false,
6127 : std::move (for_lifetimes)));
6128 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6129 0 : bounds.push_back (std::move (initial_bound));
6130 :
6131 0 : while (t->get_id () == PLUS)
6132 : {
6133 0 : lexer.skip_token ();
6134 :
6135 : // parse type param bound if it exists
6136 0 : std::unique_ptr<AST::TypeParamBound> bound
6137 : = parse_type_param_bound ();
6138 0 : if (bound == nullptr)
6139 : {
6140 : // not an error - e.g. trailing plus
6141 0 : return nullptr;
6142 : }
6143 0 : bounds.push_back (std::move (bound));
6144 :
6145 0 : t = lexer.peek_token ();
6146 : }
6147 :
6148 0 : return std::unique_ptr<AST::TraitObjectType> (
6149 0 : new AST::TraitObjectType (std::move (bounds), for_locus, false));
6150 0 : }
6151 0 : default:
6152 : // error
6153 0 : add_error (Error (t->get_locus (),
6154 : "unrecognised token %qs in bare function type or trait "
6155 : "object type or trait object type one bound",
6156 : t->get_token_description ()));
6157 :
6158 0 : return nullptr;
6159 : }
6160 3 : }
6161 :
6162 : // Parses a maybe named param used in bare function types.
6163 : template <typename ManagedTokenSource>
6164 : AST::MaybeNamedParam
6165 48 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
6166 : {
6167 : /* Basically guess that param is named if first token is identifier or
6168 : * underscore and second token is semicolon. This should probably have no
6169 : * exceptions. rustc uses backtracking to parse these, but at the time of
6170 : * writing gccrs has no backtracking capabilities. */
6171 48 : const_TokenPtr current = lexer.peek_token ();
6172 48 : const_TokenPtr next = lexer.peek_token (1);
6173 :
6174 48 : Identifier name;
6175 48 : AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
6176 :
6177 48 : if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
6178 : {
6179 : // named param
6180 1 : name = {current};
6181 1 : kind = AST::MaybeNamedParam::IDENTIFIER;
6182 1 : lexer.skip_token (1);
6183 : }
6184 47 : else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
6185 : {
6186 : // wildcard param
6187 12 : name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
6188 6 : kind = AST::MaybeNamedParam::WILDCARD;
6189 6 : lexer.skip_token (1);
6190 : }
6191 :
6192 : // parse type (required)
6193 48 : std::unique_ptr<AST::Type> type = parse_type ();
6194 48 : if (type == nullptr)
6195 : {
6196 0 : Error error (lexer.peek_token ()->get_locus (),
6197 : "failed to parse type in maybe named param");
6198 0 : add_error (std::move (error));
6199 :
6200 0 : return AST::MaybeNamedParam::create_error ();
6201 0 : }
6202 :
6203 96 : return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
6204 48 : std::move (outer_attrs), current->get_locus ());
6205 96 : }
6206 :
6207 : /* Parses a bare function type (with the given for lifetimes for convenience -
6208 : * does not parse them itself). */
6209 : template <typename ManagedTokenSource>
6210 : std::unique_ptr<AST::BareFunctionType>
6211 66 : Parser<ManagedTokenSource>::parse_bare_function_type (
6212 : std::vector<AST::LifetimeParam> for_lifetimes)
6213 : {
6214 : // TODO: pass in for lifetime location as param
6215 66 : location_t best_try_locus = lexer.peek_token ()->get_locus ();
6216 :
6217 66 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
6218 :
6219 66 : if (!skip_token (FN_KW))
6220 0 : return nullptr;
6221 :
6222 66 : if (!skip_token (LEFT_PAREN))
6223 0 : return nullptr;
6224 :
6225 : // parse function params, if they exist
6226 66 : std::vector<AST::MaybeNamedParam> params;
6227 66 : bool is_variadic = false;
6228 66 : AST::AttrVec variadic_attrs;
6229 :
6230 66 : const_TokenPtr t = lexer.peek_token ();
6231 120 : while (t->get_id () != RIGHT_PAREN)
6232 : {
6233 48 : AST::AttrVec temp_attrs = parse_outer_attributes ();
6234 :
6235 96 : if (lexer.peek_token ()->get_id () == ELLIPSIS)
6236 : {
6237 0 : lexer.skip_token ();
6238 0 : is_variadic = true;
6239 0 : variadic_attrs = std::move (temp_attrs);
6240 :
6241 0 : t = lexer.peek_token ();
6242 :
6243 0 : if (t->get_id () != RIGHT_PAREN)
6244 : {
6245 0 : Error error (t->get_locus (),
6246 : "expected right parentheses after variadic in maybe "
6247 : "named function "
6248 : "parameters, found %qs",
6249 : t->get_token_description ());
6250 0 : add_error (std::move (error));
6251 :
6252 0 : return nullptr;
6253 0 : }
6254 :
6255 : break;
6256 : }
6257 :
6258 48 : AST::MaybeNamedParam param
6259 48 : = parse_maybe_named_param (std::move (temp_attrs));
6260 48 : if (param.is_error ())
6261 : {
6262 0 : Error error (
6263 0 : lexer.peek_token ()->get_locus (),
6264 : "failed to parse maybe named param in bare function type");
6265 0 : add_error (std::move (error));
6266 :
6267 0 : return nullptr;
6268 0 : }
6269 48 : params.push_back (std::move (param));
6270 :
6271 96 : if (lexer.peek_token ()->get_id () != COMMA)
6272 : break;
6273 :
6274 6 : lexer.skip_token ();
6275 6 : t = lexer.peek_token ();
6276 : }
6277 :
6278 66 : if (!skip_token (RIGHT_PAREN))
6279 0 : return nullptr;
6280 :
6281 : // bare function return type, if exists
6282 66 : std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
6283 132 : if (lexer.peek_token ()->get_id () == RETURN_TYPE)
6284 : {
6285 53 : lexer.skip_token ();
6286 :
6287 : // parse required TypeNoBounds
6288 53 : return_type = parse_type_no_bounds ();
6289 53 : if (return_type == nullptr)
6290 : {
6291 0 : Error error (lexer.peek_token ()->get_locus (),
6292 : "failed to parse return type (type no bounds) in bare "
6293 : "function type");
6294 0 : add_error (std::move (error));
6295 :
6296 0 : return nullptr;
6297 0 : }
6298 : }
6299 :
6300 : return std::unique_ptr<AST::BareFunctionType> (
6301 66 : new AST::BareFunctionType (std::move (for_lifetimes),
6302 : std::move (qualifiers), std::move (params),
6303 : is_variadic, std::move (variadic_attrs),
6304 66 : std::move (return_type), best_try_locus));
6305 132 : }
6306 :
6307 : template <typename ManagedTokenSource>
6308 : std::unique_ptr<AST::ReferenceType>
6309 4314 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
6310 : {
6311 : // parse optional lifetime
6312 4314 : AST::Lifetime lifetime = AST::Lifetime::elided ();
6313 8628 : if (lexer.peek_token ()->get_id () == LIFETIME)
6314 : {
6315 468 : auto parsed_lifetime = parse_lifetime (true);
6316 468 : if (parsed_lifetime)
6317 : {
6318 468 : lifetime = parsed_lifetime.value ();
6319 : }
6320 : else
6321 : {
6322 0 : Error error (lexer.peek_token ()->get_locus (),
6323 : "failed to parse lifetime in reference type");
6324 0 : add_error (std::move (error));
6325 :
6326 0 : return nullptr;
6327 0 : }
6328 468 : }
6329 :
6330 4314 : bool is_mut = false;
6331 8628 : if (lexer.peek_token ()->get_id () == MUT)
6332 : {
6333 304 : lexer.skip_token ();
6334 304 : is_mut = true;
6335 : }
6336 :
6337 : // parse type no bounds, which is required
6338 4314 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6339 4314 : if (type == nullptr)
6340 : {
6341 0 : Error error (lexer.peek_token ()->get_locus (),
6342 : "failed to parse referenced type in reference type");
6343 0 : add_error (std::move (error));
6344 :
6345 0 : return nullptr;
6346 0 : }
6347 :
6348 : return std::unique_ptr<AST::ReferenceType> (
6349 12942 : new AST::ReferenceType (is_mut, std::move (type), locus,
6350 4314 : std::move (lifetime)));
6351 4314 : }
6352 :
6353 : // Parses a reference type (mutable or immutable, with given lifetime).
6354 : template <typename ManagedTokenSource>
6355 : std::unique_ptr<AST::ReferenceType>
6356 4314 : Parser<ManagedTokenSource>::parse_reference_type ()
6357 : {
6358 4314 : auto t = lexer.peek_token ();
6359 4314 : auto locus = t->get_locus ();
6360 :
6361 4314 : switch (t->get_id ())
6362 : {
6363 4300 : case AMP:
6364 4300 : skip_token (AMP);
6365 4300 : return parse_reference_type_inner (locus);
6366 14 : case LOGICAL_AND:
6367 14 : skip_token (LOGICAL_AND);
6368 : return std::unique_ptr<AST::ReferenceType> (
6369 42 : new AST::ReferenceType (false, parse_reference_type_inner (locus),
6370 14 : locus));
6371 0 : default:
6372 0 : rust_unreachable ();
6373 : }
6374 4314 : }
6375 :
6376 : // Parses a raw (unsafe) pointer type.
6377 : template <typename ManagedTokenSource>
6378 : std::unique_ptr<AST::RawPointerType>
6379 6540 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
6380 : {
6381 6540 : location_t locus = lexer.peek_token ()->get_locus ();
6382 6540 : skip_token (ASTERISK);
6383 :
6384 6540 : AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
6385 :
6386 : // branch on next token for pointer kind info
6387 6540 : const_TokenPtr t = lexer.peek_token ();
6388 6540 : switch (t->get_id ())
6389 : {
6390 721 : case MUT:
6391 721 : kind = AST::RawPointerType::MUT;
6392 721 : lexer.skip_token ();
6393 : break;
6394 5819 : case CONST:
6395 5819 : kind = AST::RawPointerType::CONST;
6396 5819 : lexer.skip_token ();
6397 : break;
6398 0 : default:
6399 0 : add_error (Error (t->get_locus (),
6400 : "unrecognised token %qs in raw pointer type",
6401 : t->get_token_description ()));
6402 :
6403 0 : return nullptr;
6404 : }
6405 :
6406 : // parse type no bounds (required)
6407 6540 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6408 6540 : if (type == nullptr)
6409 : {
6410 0 : Error error (lexer.peek_token ()->get_locus (),
6411 : "failed to parse pointed type of raw pointer type");
6412 0 : add_error (std::move (error));
6413 :
6414 0 : return nullptr;
6415 0 : }
6416 :
6417 : return std::unique_ptr<AST::RawPointerType> (
6418 6540 : new AST::RawPointerType (kind, std::move (type), locus));
6419 6540 : }
6420 :
6421 : /* Parses a slice or array type, depending on following arguments (as
6422 : * lookahead is not possible). */
6423 : template <typename ManagedTokenSource>
6424 : std::unique_ptr<AST::TypeNoBounds>
6425 1510 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
6426 : {
6427 1510 : location_t locus = lexer.peek_token ()->get_locus ();
6428 1510 : skip_token (LEFT_SQUARE);
6429 :
6430 : // parse inner type (required)
6431 1510 : std::unique_ptr<AST::Type> inner_type = parse_type ();
6432 1510 : if (inner_type == nullptr)
6433 : {
6434 0 : Error error (lexer.peek_token ()->get_locus (),
6435 : "failed to parse inner type in slice or array type");
6436 0 : add_error (std::move (error));
6437 :
6438 0 : return nullptr;
6439 0 : }
6440 :
6441 : // branch on next token
6442 1510 : const_TokenPtr t = lexer.peek_token ();
6443 1510 : switch (t->get_id ())
6444 : {
6445 842 : case RIGHT_SQUARE:
6446 : // slice type
6447 842 : lexer.skip_token ();
6448 :
6449 842 : return std::unique_ptr<AST::SliceType> (
6450 842 : new AST::SliceType (std::move (inner_type), locus));
6451 668 : case SEMICOLON:
6452 : {
6453 : // array type
6454 668 : lexer.skip_token ();
6455 :
6456 : // parse required array size expression
6457 668 : auto size = parse_anon_const ();
6458 :
6459 668 : if (!size)
6460 : {
6461 1 : Error error (lexer.peek_token ()->get_locus (),
6462 : "failed to parse size expression in array type");
6463 1 : add_error (std::move (error));
6464 :
6465 1 : return nullptr;
6466 1 : }
6467 :
6468 667 : if (!skip_token (RIGHT_SQUARE))
6469 : {
6470 0 : return nullptr;
6471 : }
6472 :
6473 667 : return std::unique_ptr<AST::ArrayType> (
6474 1323 : new AST::ArrayType (std::move (inner_type), std::move (*size),
6475 667 : locus));
6476 668 : }
6477 0 : default:
6478 : // error
6479 0 : add_error (
6480 0 : Error (t->get_locus (),
6481 : "unrecognised token %qs in slice or array type after inner type",
6482 : t->get_token_description ()));
6483 :
6484 0 : return nullptr;
6485 : }
6486 1510 : }
6487 :
6488 : // Parses a type, taking into account type boundary disambiguation.
6489 : template <typename ManagedTokenSource>
6490 : std::unique_ptr<AST::TypeNoBounds>
6491 16098 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
6492 : {
6493 16098 : const_TokenPtr t = lexer.peek_token ();
6494 16098 : switch (t->get_id ())
6495 : {
6496 1 : case EXCLAM:
6497 : // never type - can't be macro as no path beforehand
6498 1 : lexer.skip_token ();
6499 1 : return std::unique_ptr<AST::NeverType> (
6500 1 : new AST::NeverType (t->get_locus ()));
6501 656 : case LEFT_SQUARE:
6502 : // slice type or array type - requires further disambiguation
6503 656 : return parse_slice_or_array_type ();
6504 22 : case LEFT_SHIFT:
6505 : case LEFT_ANGLE:
6506 : {
6507 : // qualified path in type
6508 22 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
6509 22 : if (path.is_error ())
6510 : {
6511 0 : Error error (t->get_locus (),
6512 : "failed to parse qualified path in type");
6513 0 : add_error (std::move (error));
6514 :
6515 0 : return nullptr;
6516 0 : }
6517 22 : return std::unique_ptr<AST::QualifiedPathInType> (
6518 22 : new AST::QualifiedPathInType (std::move (path)));
6519 22 : }
6520 104 : case UNDERSCORE:
6521 : // inferred type
6522 104 : lexer.skip_token ();
6523 104 : return std::unique_ptr<AST::InferredType> (
6524 104 : new AST::InferredType (t->get_locus ()));
6525 3812 : case ASTERISK:
6526 : // raw pointer type
6527 3812 : return parse_raw_pointer_type ();
6528 24 : case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
6529 : case LOGICAL_AND:
6530 : // reference type
6531 24 : return parse_reference_type ();
6532 0 : case LIFETIME:
6533 : /* probably a lifetime bound, so probably type param bounds in
6534 : * TraitObjectType. this is not allowed, but detection here for error
6535 : * message */
6536 0 : add_error (Error (t->get_locus (),
6537 : "lifetime bounds (i.e. in type param bounds, in "
6538 : "TraitObjectType) are not allowed as TypeNoBounds"));
6539 :
6540 0 : return nullptr;
6541 11302 : case IDENTIFIER:
6542 : case SUPER:
6543 : case SELF:
6544 : case SELF_ALIAS:
6545 : case CRATE:
6546 : case DOLLAR_SIGN:
6547 : case SCOPE_RESOLUTION:
6548 : {
6549 : // macro invocation or type path - requires further disambiguation.
6550 : /* for parsing path component of each rule, perhaps parse it as a
6551 : * typepath and attempt conversion to simplepath if a trailing '!' is
6552 : * found */
6553 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
6554 : * with it, it is exactly the same as a TypePath syntactically, so
6555 : * this is a syntactical ambiguity. As such, the parser will parse it
6556 : * as a TypePath. This, however, does not prevent TraitObjectType from
6557 : * starting with a typepath. */
6558 :
6559 : // parse path as type path
6560 11302 : AST::TypePath path = parse_type_path ();
6561 11302 : if (path.is_error ())
6562 : {
6563 0 : Error error (
6564 : t->get_locus (),
6565 : "failed to parse path as first component of type no bounds");
6566 0 : add_error (std::move (error));
6567 :
6568 0 : return nullptr;
6569 0 : }
6570 11302 : location_t locus = path.get_locus ();
6571 :
6572 : // branch on next token
6573 11302 : t = lexer.peek_token ();
6574 11302 : switch (t->get_id ())
6575 : {
6576 1 : case EXCLAM:
6577 : {
6578 : // macro invocation
6579 : // convert to simple path
6580 1 : AST::SimplePath macro_path = path.as_simple_path ();
6581 1 : if (macro_path.is_empty ())
6582 : {
6583 0 : Error error (t->get_locus (),
6584 : "failed to parse simple path in macro "
6585 : "invocation (for type)");
6586 0 : add_error (std::move (error));
6587 :
6588 0 : return nullptr;
6589 0 : }
6590 :
6591 1 : lexer.skip_token ();
6592 :
6593 1 : auto tok_tree = parse_delim_token_tree ();
6594 1 : if (!tok_tree)
6595 0 : return nullptr;
6596 :
6597 3 : return AST::MacroInvocation::Regular (
6598 2 : AST::MacroInvocData (std::move (macro_path),
6599 1 : std::move (tok_tree.value ())),
6600 1 : {}, locus);
6601 2 : }
6602 11301 : default:
6603 : // assume that this is a type path and not an error
6604 11301 : return std::unique_ptr<AST::TypePath> (
6605 11301 : new AST::TypePath (std::move (path)));
6606 : }
6607 11302 : }
6608 18 : case LEFT_PAREN:
6609 : /* tuple type or parenthesised type - requires further disambiguation
6610 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
6611 : * could be TraitObjectTypeOneBound */
6612 18 : return parse_paren_prefixed_type_no_bounds ();
6613 2 : case FOR:
6614 : case ASYNC:
6615 : case CONST:
6616 : case UNSAFE:
6617 : case EXTERN_KW:
6618 : case FN_KW:
6619 : // bare function type (with no for lifetimes)
6620 2 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
6621 14 : case IMPL:
6622 14 : lexer.skip_token ();
6623 28 : if (lexer.peek_token ()->get_id () == LIFETIME)
6624 : {
6625 : /* cannot be one bound because lifetime prevents it from being
6626 : * traitbound not allowed as type no bounds, only here for error
6627 : * message */
6628 0 : Error error (
6629 0 : lexer.peek_token ()->get_locus (),
6630 : "lifetime (probably lifetime bound, in type param "
6631 : "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
6632 0 : add_error (std::move (error));
6633 :
6634 0 : return nullptr;
6635 0 : }
6636 : else
6637 : {
6638 : // should be trait bound, so parse trait bound
6639 14 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6640 14 : if (initial_bound == nullptr)
6641 : {
6642 0 : Error error (lexer.peek_token ()->get_locus (),
6643 : "failed to parse ImplTraitTypeOneBound bound");
6644 0 : add_error (std::move (error));
6645 :
6646 0 : return nullptr;
6647 0 : }
6648 :
6649 14 : location_t locus = t->get_locus ();
6650 :
6651 : // ensure not a trait with multiple bounds
6652 14 : t = lexer.peek_token ();
6653 14 : if (t->get_id () == PLUS)
6654 : {
6655 0 : Error error (t->get_locus (),
6656 : "plus after trait bound means an ImplTraitType, "
6657 : "which is not allowed as a TypeNoBounds");
6658 0 : add_error (std::move (error));
6659 :
6660 0 : return nullptr;
6661 0 : }
6662 :
6663 14 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6664 14 : new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
6665 14 : }
6666 143 : case DYN:
6667 : case QUESTION_MARK:
6668 : {
6669 : // either TraitObjectTypeOneBound
6670 143 : bool has_dyn = false;
6671 143 : if (t->get_id () == DYN)
6672 : {
6673 143 : lexer.skip_token ();
6674 143 : has_dyn = true;
6675 : }
6676 :
6677 286 : if (lexer.peek_token ()->get_id () == LIFETIME)
6678 : {
6679 : /* means that cannot be TraitObjectTypeOneBound - so here for
6680 : * error message */
6681 0 : Error error (lexer.peek_token ()->get_locus (),
6682 : "lifetime as bound in TraitObjectTypeOneBound "
6683 : "is not allowed, so cannot be TypeNoBounds");
6684 0 : add_error (std::move (error));
6685 :
6686 0 : return nullptr;
6687 0 : }
6688 :
6689 : // should be trait bound, so parse trait bound
6690 143 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6691 143 : if (initial_bound == nullptr)
6692 : {
6693 0 : Error error (
6694 0 : lexer.peek_token ()->get_locus (),
6695 : "failed to parse TraitObjectTypeOneBound initial bound");
6696 0 : add_error (std::move (error));
6697 :
6698 0 : return nullptr;
6699 0 : }
6700 :
6701 143 : location_t locus = t->get_locus ();
6702 :
6703 : // detect error with plus as next token
6704 143 : t = lexer.peek_token ();
6705 143 : if (t->get_id () == PLUS)
6706 : {
6707 0 : Error error (t->get_locus (),
6708 : "plus after trait bound means a TraitObjectType, "
6709 : "which is not allowed as a TypeNoBounds");
6710 0 : add_error (std::move (error));
6711 :
6712 0 : return nullptr;
6713 0 : }
6714 :
6715 : // convert trait bound to value object
6716 143 : AST::TraitBound value_bound (*initial_bound);
6717 :
6718 143 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6719 286 : new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
6720 143 : has_dyn));
6721 143 : }
6722 0 : default:
6723 0 : add_error (Error (t->get_locus (),
6724 : "unrecognised token %qs in type no bounds",
6725 : t->get_token_description ()));
6726 :
6727 0 : return nullptr;
6728 : }
6729 16098 : }
6730 :
6731 : // Parses a type no bounds beginning with '('.
6732 : template <typename ManagedTokenSource>
6733 : std::unique_ptr<AST::TypeNoBounds>
6734 18 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
6735 : {
6736 : /* NOTE: this could probably be parsed without the HACK solution of
6737 : * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
6738 :
6739 : /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
6740 : * considered a trait bound, not a parenthesised type, so that it can still
6741 : * be used in type param bounds. */
6742 :
6743 18 : location_t left_paren_locus = lexer.peek_token ()->get_locus ();
6744 :
6745 : // skip left delim
6746 18 : lexer.skip_token ();
6747 : /* while next token isn't close delim, parse comma-separated types, saving
6748 : * whether trailing comma happens */
6749 18 : const_TokenPtr t = lexer.peek_token ();
6750 18 : bool trailing_comma = true;
6751 18 : std::vector<std::unique_ptr<AST::Type>> types;
6752 :
6753 18 : while (t->get_id () != RIGHT_PAREN)
6754 : {
6755 2 : std::unique_ptr<AST::Type> type = parse_type ();
6756 2 : if (type == nullptr)
6757 : {
6758 0 : Error error (t->get_locus (),
6759 : "failed to parse type inside parentheses (probably "
6760 : "tuple or parenthesised)");
6761 0 : add_error (std::move (error));
6762 :
6763 0 : return nullptr;
6764 0 : }
6765 2 : types.push_back (std::move (type));
6766 :
6767 2 : t = lexer.peek_token ();
6768 2 : if (t->get_id () != COMMA)
6769 : {
6770 2 : trailing_comma = false;
6771 : break;
6772 : }
6773 0 : lexer.skip_token ();
6774 :
6775 0 : t = lexer.peek_token ();
6776 : }
6777 :
6778 18 : if (!skip_token (RIGHT_PAREN))
6779 : {
6780 0 : return nullptr;
6781 : }
6782 :
6783 : // if only one type and no trailing comma, then not a tuple type
6784 18 : if (types.size () == 1 && !trailing_comma)
6785 : {
6786 : // must be a TraitObjectType (with more than one bound)
6787 4 : if (lexer.peek_token ()->get_id () == PLUS)
6788 : {
6789 : // error - this is not allowed for type no bounds
6790 0 : Error error (lexer.peek_token ()->get_locus (),
6791 : "plus (implying TraitObjectType as type param "
6792 : "bounds) is not allowed in type no bounds");
6793 0 : add_error (std::move (error));
6794 :
6795 0 : return nullptr;
6796 0 : }
6797 : else
6798 : {
6799 : // release vector pointer
6800 2 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6801 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6802 : * type */
6803 2 : std::unique_ptr<AST::TraitBound> converted_bound (
6804 2 : released_ptr->to_trait_bound (true));
6805 2 : if (converted_bound == nullptr)
6806 : {
6807 : // parenthesised type
6808 2 : return std::unique_ptr<AST::ParenthesisedType> (
6809 2 : new AST::ParenthesisedType (std::move (released_ptr),
6810 2 : left_paren_locus));
6811 : }
6812 : else
6813 : {
6814 : // trait object type (one bound)
6815 :
6816 : // get value semantics trait bound
6817 0 : AST::TraitBound value_bound (*converted_bound);
6818 :
6819 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6820 0 : new AST::TraitObjectTypeOneBound (value_bound,
6821 0 : left_paren_locus));
6822 0 : }
6823 2 : }
6824 : }
6825 : else
6826 : {
6827 16 : return std::unique_ptr<AST::TupleType> (
6828 16 : new AST::TupleType (std::move (types), left_paren_locus));
6829 : }
6830 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6831 : * lost somehow */
6832 18 : }
6833 :
6834 : // Parses tuple struct items if they exist. Does not parse parentheses.
6835 : template <typename ManagedTokenSource>
6836 : std::unique_ptr<AST::TupleStructItems>
6837 924 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
6838 : {
6839 924 : std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
6840 :
6841 : // DEBUG
6842 924 : rust_debug ("started parsing tuple struct items");
6843 :
6844 : // check for '..' at front
6845 1848 : if (lexer.peek_token ()->get_id () == DOT_DOT)
6846 : {
6847 : // only parse upper patterns
6848 16 : lexer.skip_token ();
6849 :
6850 : // DEBUG
6851 16 : rust_debug ("'..' at front in tuple struct items detected");
6852 :
6853 16 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
6854 :
6855 16 : const_TokenPtr t = lexer.peek_token ();
6856 33 : while (t->get_id () == COMMA)
6857 : {
6858 17 : lexer.skip_token ();
6859 :
6860 : // break if right paren
6861 34 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
6862 : break;
6863 :
6864 : // parse pattern, which is now required
6865 17 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6866 17 : if (pattern == nullptr)
6867 : {
6868 0 : Error error (lexer.peek_token ()->get_locus (),
6869 : "failed to parse pattern in tuple struct items");
6870 0 : add_error (std::move (error));
6871 :
6872 0 : return nullptr;
6873 0 : }
6874 17 : upper_patterns.push_back (std::move (pattern));
6875 :
6876 17 : t = lexer.peek_token ();
6877 : }
6878 :
6879 : // DEBUG
6880 16 : rust_debug (
6881 : "finished parsing tuple struct items ranged (upper/none only)");
6882 :
6883 16 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
6884 16 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
6885 16 : std::move (upper_patterns)));
6886 16 : }
6887 :
6888 : // has at least some lower patterns
6889 908 : const_TokenPtr t = lexer.peek_token ();
6890 1863 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
6891 : {
6892 : // DEBUG
6893 955 : rust_debug ("about to parse pattern in tuple struct items");
6894 :
6895 : // parse pattern, which is required
6896 955 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6897 955 : if (pattern == nullptr)
6898 : {
6899 0 : Error error (t->get_locus (),
6900 : "failed to parse pattern in tuple struct items");
6901 0 : add_error (std::move (error));
6902 :
6903 0 : return nullptr;
6904 0 : }
6905 955 : lower_patterns.push_back (std::move (pattern));
6906 :
6907 : // DEBUG
6908 955 : rust_debug ("successfully parsed pattern in tuple struct items");
6909 :
6910 1910 : if (lexer.peek_token ()->get_id () != COMMA)
6911 : {
6912 : // DEBUG
6913 862 : rust_debug ("broke out of parsing patterns in tuple struct "
6914 : "items as no comma");
6915 :
6916 : break;
6917 : }
6918 93 : lexer.skip_token ();
6919 93 : t = lexer.peek_token ();
6920 : }
6921 :
6922 : // branch on next token
6923 908 : t = lexer.peek_token ();
6924 908 : switch (t->get_id ())
6925 : {
6926 884 : case RIGHT_PAREN:
6927 884 : return std::unique_ptr<AST::TupleStructItemsNoRest> (
6928 884 : new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
6929 23 : case DOT_DOT:
6930 : {
6931 : // has an upper range that must be parsed separately
6932 23 : lexer.skip_token ();
6933 :
6934 23 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
6935 :
6936 23 : t = lexer.peek_token ();
6937 25 : while (t->get_id () == COMMA)
6938 : {
6939 2 : lexer.skip_token ();
6940 :
6941 : // break if next token is right paren
6942 4 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
6943 : break;
6944 :
6945 : // parse pattern, which is required
6946 2 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6947 2 : if (pattern == nullptr)
6948 : {
6949 0 : Error error (lexer.peek_token ()->get_locus (),
6950 : "failed to parse pattern in tuple struct items");
6951 0 : add_error (std::move (error));
6952 :
6953 0 : return nullptr;
6954 0 : }
6955 2 : upper_patterns.push_back (std::move (pattern));
6956 :
6957 2 : t = lexer.peek_token ();
6958 : }
6959 :
6960 23 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
6961 23 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
6962 23 : std::move (upper_patterns)));
6963 23 : }
6964 1 : default:
6965 : // error
6966 1 : add_error (Error (t->get_locus (),
6967 : "unexpected token %qs in tuple struct items",
6968 : t->get_token_description ()));
6969 :
6970 1 : return nullptr;
6971 : }
6972 924 : }
6973 :
6974 : /* Parses a statement or expression (depending on whether a trailing semicolon
6975 : * exists). Useful for block expressions where it cannot be determined through
6976 : * lookahead whether it is a statement or expression to be parsed. */
6977 : template <typename ManagedTokenSource>
6978 : tl::expected<ExprOrStmt, Parse::Error::Node>
6979 38626 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
6980 : {
6981 : // quick exit for empty statement
6982 38626 : const_TokenPtr t = lexer.peek_token ();
6983 38626 : if (t->get_id () == SEMICOLON)
6984 : {
6985 18 : lexer.skip_token ();
6986 18 : std::unique_ptr<AST::EmptyStmt> stmt (
6987 18 : new AST::EmptyStmt (t->get_locus ()));
6988 36 : return ExprOrStmt (std::move (stmt));
6989 18 : }
6990 :
6991 : // parse outer attributes
6992 38608 : AST::AttrVec outer_attrs = parse_outer_attributes ();
6993 38608 : ParseRestrictions restrictions;
6994 38608 : restrictions.expr_can_be_stmt = true;
6995 :
6996 : // Defered child error checking: we need to check for a semicolon
6997 38608 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
6998 :
6999 : // parsing this will be annoying because of the many different possibilities
7000 : /* best may be just to copy paste in parse_item switch, and failing that try
7001 : * to parse outer attributes, and then pass them in to either a let
7002 : * statement or (fallback) expression statement. */
7003 : // FIXME: think of a way to do this without such a large switch?
7004 :
7005 : /* FIXME: for expressions at least, the only way that they can really be
7006 : * parsed properly in this way is if they don't support operators on them.
7007 : * They must be pratt-parsed otherwise. As such due to composability, only
7008 : * explicit statements will have special cases here. This should roughly
7009 : * correspond to "expr-with-block", but this warning is here in case it
7010 : * isn't the case. */
7011 38608 : t = lexer.peek_token ();
7012 38608 : switch (t->get_id ())
7013 : {
7014 12725 : case LET:
7015 : {
7016 : // let statement
7017 12725 : std::unique_ptr<AST::LetStmt> stmt (
7018 12725 : parse_let_stmt (std::move (outer_attrs)));
7019 25450 : return ExprOrStmt (std::move (stmt));
7020 12725 : }
7021 344 : case PUB:
7022 : case MOD:
7023 : case EXTERN_KW:
7024 : case USE:
7025 : case FN_KW:
7026 : case TYPE:
7027 : case STRUCT_KW:
7028 : case ENUM_KW:
7029 : case CONST:
7030 : case STATIC_KW:
7031 : case AUTO:
7032 : case TRAIT:
7033 : case IMPL:
7034 : {
7035 344 : std::unique_ptr<AST::VisItem> item (
7036 344 : parse_vis_item (std::move (outer_attrs)));
7037 688 : return ExprOrStmt (std::move (item));
7038 344 : }
7039 : /* TODO: implement union keyword but not really because of
7040 : * context-dependence crappy hack way to parse a union written below to
7041 : * separate it from the good code. */
7042 : // case UNION:
7043 3076 : case UNSAFE:
7044 : { // maybe - unsafe traits are a thing
7045 : /* if any of these (should be all possible VisItem prefixes), parse a
7046 : * VisItem - can't parse item because would require reparsing outer
7047 : * attributes */
7048 3076 : const_TokenPtr t2 = lexer.peek_token (1);
7049 3076 : switch (t2->get_id ())
7050 : {
7051 3062 : case LEFT_CURLY:
7052 : {
7053 : // unsafe block: parse as expression
7054 6124 : expr = parse_expr (std::move (outer_attrs), restrictions);
7055 : break;
7056 : }
7057 0 : case AUTO:
7058 : case TRAIT:
7059 : {
7060 : // unsafe trait
7061 0 : std::unique_ptr<AST::VisItem> item (
7062 0 : parse_vis_item (std::move (outer_attrs)));
7063 0 : return ExprOrStmt (std::move (item));
7064 0 : }
7065 14 : case EXTERN_KW:
7066 : case FN_KW:
7067 : {
7068 : // unsafe function
7069 14 : std::unique_ptr<AST::VisItem> item (
7070 14 : parse_vis_item (std::move (outer_attrs)));
7071 28 : return ExprOrStmt (std::move (item));
7072 14 : }
7073 0 : case IMPL:
7074 : {
7075 : // unsafe trait impl
7076 0 : std::unique_ptr<AST::VisItem> item (
7077 0 : parse_vis_item (std::move (outer_attrs)));
7078 0 : return ExprOrStmt (std::move (item));
7079 0 : }
7080 0 : default:
7081 0 : add_error (Error (t2->get_locus (),
7082 : "unrecognised token %qs after parsing unsafe - "
7083 : "expected beginning of expression or statement",
7084 : t->get_token_description ()));
7085 :
7086 : // skip somewhere?
7087 : return tl::unexpected<Parse::Error::Node> (
7088 0 : Parse::Error::Node::MALFORMED);
7089 : }
7090 : break;
7091 3076 : }
7092 : /* FIXME: this is either a macro invocation or macro invocation semi.
7093 : * start parsing to determine which one it is. */
7094 : // FIXME: old code there
7095 :
7096 : // crappy hack to do union "keyword"
7097 12203 : case IDENTIFIER:
7098 21778 : if (t->get_str () == Values::WeakKeywords::UNION
7099 12239 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
7100 : {
7101 1 : std::unique_ptr<AST::VisItem> item (
7102 1 : parse_vis_item (std::move (outer_attrs)));
7103 2 : return ExprOrStmt (std::move (item));
7104 : // or should this go straight to parsing union?
7105 1 : }
7106 21776 : else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
7107 12209 : && lexer.peek_token (1)->get_id () == EXCLAM)
7108 : {
7109 : // macro_rules! macro item
7110 7 : std::unique_ptr<AST::Item> item (
7111 7 : parse_macro_rules_def (std::move (outer_attrs)));
7112 14 : return ExprOrStmt (std::move (item));
7113 7 : }
7114 : gcc_fallthrough ();
7115 : case SUPER:
7116 : case SELF:
7117 : case SELF_ALIAS:
7118 : case CRATE:
7119 : case SCOPE_RESOLUTION:
7120 : case DOLLAR_SIGN:
7121 : {
7122 14651 : AST::PathInExpression path = parse_path_in_expression ();
7123 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
7124 14651 : null_denotation;
7125 :
7126 29302 : if (lexer.peek_token ()->get_id () == EXCLAM)
7127 : {
7128 590 : std::unique_ptr<AST::MacroInvocation> invoc
7129 1180 : = parse_macro_invocation_partial (std::move (path),
7130 : std::move (outer_attrs));
7131 590 : if (invoc == nullptr)
7132 : return tl::unexpected<Parse::Error::Node> (
7133 0 : Parse::Error::Node::CHILD_ERROR);
7134 :
7135 590 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7136 : {
7137 398 : invoc->add_semicolon ();
7138 : // Macro invocation with semicolon.
7139 398 : return ExprOrStmt (
7140 796 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7141 : }
7142 :
7143 384 : TokenId after_macro = lexer.peek_token ()->get_id ();
7144 :
7145 192 : AST::DelimType delim_type = invoc->get_invoc_data ()
7146 192 : .get_delim_tok_tree ()
7147 192 : .get_delim_type ();
7148 :
7149 192 : if (delim_type == AST::CURLY && after_macro != DOT
7150 6 : && after_macro != QUESTION_MARK)
7151 : {
7152 6 : rust_debug ("braced macro statement");
7153 6 : return ExprOrStmt (
7154 12 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7155 : }
7156 :
7157 186 : null_denotation = std::move (invoc);
7158 590 : }
7159 : else
7160 : {
7161 : null_denotation
7162 28122 : = null_denotation_path (std::move (path), {}, restrictions);
7163 : }
7164 :
7165 56984 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7166 : std::move (outer_attrs), restrictions);
7167 : break;
7168 14651 : }
7169 7804 : default:
7170 : /* expression statement or expression itself - parse
7171 : * expression then make it statement if semi afterwards */
7172 15579 : expr = parse_expr (std::move (outer_attrs), restrictions);
7173 7804 : break;
7174 : }
7175 :
7176 25113 : const_TokenPtr after_expr = lexer.peek_token ();
7177 25113 : if (after_expr->get_id () == SEMICOLON)
7178 : {
7179 : // must be expression statement
7180 7584 : lexer.skip_token ();
7181 :
7182 7584 : if (expr)
7183 : {
7184 7583 : return ExprOrStmt (
7185 15166 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7186 22749 : t->get_locus (), true));
7187 : }
7188 : else
7189 : {
7190 : return tl::unexpected<Parse::Error::Node> (
7191 1 : Parse::Error::Node::CHILD_ERROR);
7192 : }
7193 : }
7194 :
7195 17529 : if (expr)
7196 : {
7197 : // block expression statement.
7198 17499 : if (!expr.value ()->is_expr_without_block ()
7199 17499 : && after_expr->get_id () != RIGHT_CURLY)
7200 1533 : return ExprOrStmt (
7201 3066 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7202 4599 : t->get_locus (), false));
7203 :
7204 : // Check if expr_without_block is properly terminated
7205 15966 : if (expr.value ()->is_expr_without_block ()
7206 15966 : && after_expr->get_id () != RIGHT_CURLY)
7207 : {
7208 : // expr_without_block must be followed by ';' or '}'
7209 1 : Error error (after_expr->get_locus (),
7210 : "expected %<;%> or %<}%> after expression, found %qs",
7211 : after_expr->get_token_description ());
7212 1 : add_error (std::move (error));
7213 : return tl::unexpected<Parse::Error::Node> (
7214 1 : Parse::Error::Node::MALFORMED);
7215 1 : }
7216 : }
7217 :
7218 : // return expression
7219 15995 : if (expr)
7220 31930 : return ExprOrStmt (std::move (expr.value ()));
7221 : else
7222 30 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
7223 63721 : }
7224 :
7225 : } // namespace Rust
7226 :
7227 : #include "rust-parse-impl-utils.hxx"
7228 : #include "rust-parse-impl-attribute.hxx"
7229 : #include "rust-parse-impl-ttree.hxx"
7230 : #include "rust-parse-impl-macro.hxx"
7231 : #include "rust-parse-impl-path.hxx"
7232 : #include "rust-parse-impl-pattern.hxx"
7233 : #include "rust-parse-impl-expr.hxx"
|