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 7895 : 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 7895 : const_TokenPtr tok = lexer.peek_token ();
75 7895 : switch (tok->get_id ())
76 : {
77 7647 : case RIGHT_ANGLE:
78 : // this is good - skip token
79 7647 : lexer.skip_token ();
80 7647 : 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 7895 : }
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 102397 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
118 : {
119 : // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
120 102397 : 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 8837 : case DOT:
149 17674 : if (lexer.peek_token (1)->get_id () == IDENTIFIER
150 16772 : && 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 74698 : default:
255 74698 : 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 4728 : Parser<ManagedTokenSource>::parse_items ()
272 : {
273 4728 : std::vector<std::unique_ptr<AST::Item>> items;
274 :
275 4728 : const_TokenPtr t = lexer.peek_token ();
276 23368 : while (t->get_id () != END_OF_FILE)
277 : {
278 18640 : auto item = parse_item (false);
279 18640 : if (!item)
280 79 : return Parse::Error::Items::make_malformed (std::move (items));
281 :
282 18561 : items.push_back (std::move (item.value ()));
283 :
284 18561 : 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 4649 : return items;
292 : #endif
293 4728 : }
294 :
295 : // Parses a crate (compilation unit) - entry point
296 : template <typename ManagedTokenSource>
297 : std::unique_ptr<AST::Crate>
298 4675 : Parser<ManagedTokenSource>::parse_crate ()
299 : {
300 : // parse inner attributes
301 4675 : AST::AttrVec inner_attrs = parse_inner_attributes ();
302 :
303 : // parse items
304 4675 : auto items
305 4675 : = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
306 :
307 : // emit all errors
308 4844 : for (const auto &error : error_table)
309 169 : error.emit ();
310 :
311 : return std::unique_ptr<AST::Crate> (
312 4675 : new AST::Crate (std::move (items), std::move (inner_attrs)));
313 4675 : }
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 498 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
319 : {
320 498 : const_TokenPtr t = lexer.peek_token ();
321 :
322 498 : if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
323 : {
324 496 : lexer.skip_token ();
325 496 : 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 498 : }
333 :
334 : template <typename ManagedTokenSource>
335 : bool
336 1506 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
337 : {
338 1506 : auto macro_name = lexer.peek_token (2)->get_id ();
339 :
340 1506 : bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
341 :
342 1506 : return t->get_str () == Values::WeakKeywords::MACRO_RULES
343 2446 : && 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 24071 : 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 24071 : AST::AttrVec outer_attrs = parse_outer_attributes ();
363 24071 : const_TokenPtr t = lexer.peek_token ();
364 :
365 24071 : 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 22707 : 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 22707 : auto vis_item = parse_vis_item (std::move (outer_attrs));
403 22707 : if (!vis_item)
404 : return Parse::Error::Item::make_malformed ();
405 22652 : return RType{std::move (vis_item)};
406 22707 : }
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 1354 : case IDENTIFIER:
421 : // TODO: ensure std::string and literal comparison works
422 2649 : if (t->get_str () == Values::WeakKeywords::UNION
423 1421 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
424 : {
425 67 : auto vis_item = parse_vis_item (std::move (outer_attrs));
426 67 : if (!vis_item)
427 : return Parse::Error::Item::make_malformed ();
428 67 : return RType{std::move (vis_item)};
429 : // or should this go straight to parsing union?
430 67 : }
431 2515 : else if (t->get_str () == Values::WeakKeywords::DEFAULT
432 1289 : && 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 2572 : else if (is_macro_rules_def (t))
440 : {
441 : // macro_rules! macro item
442 936 : auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
443 936 : if (!macro_rule_def)
444 : return Parse::Error::Item::make_malformed ();
445 923 : return RType{std::move (macro_rule_def)};
446 936 : }
447 700 : else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
448 699 : || lexer.peek_token (1)->get_id () == EXCLAM)
449 : {
450 : /* path (probably) or macro invocation, so probably a macro invocation
451 : * semi */
452 347 : auto macro_invocation_semi
453 347 : = parse_macro_invocation_semi (std::move (outer_attrs));
454 347 : if (!macro_invocation_semi)
455 : return Parse::Error::Item::make_malformed ();
456 346 : return RType{std::move (macro_invocation_semi)};
457 347 : }
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 24071 : }
471 :
472 : // Parses a VisItem (item that can have non-default visibility).
473 : template <typename ManagedTokenSource>
474 : std::unique_ptr<AST::VisItem>
475 23318 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
476 : {
477 : // parse visibility, which may or may not exist
478 23318 : auto vis_res = parse_visibility ();
479 23318 : if (!vis_res)
480 0 : return nullptr;
481 23318 : auto vis = vis_res.value ();
482 :
483 : // select VisItem to create depending on keyword
484 23318 : const_TokenPtr t = lexer.peek_token ();
485 :
486 23318 : switch (t->get_id ())
487 : {
488 1369 : case MOD:
489 1369 : return parse_module (std::move (vis), std::move (outer_attrs));
490 1514 : case EXTERN_KW:
491 : // lookahead to resolve syntactical production
492 1514 : t = lexer.peek_token (1);
493 :
494 1514 : 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 1487 : case STRING_LITERAL: // for specifying extern ABI
503 : // could be extern block or extern function, so more lookahead
504 1487 : t = lexer.peek_token (2);
505 :
506 1487 : switch (t->get_id ())
507 : {
508 4 : case FN_KW:
509 4 : return parse_function (std::move (vis), std::move (outer_attrs));
510 1483 : case LEFT_CURLY:
511 1483 : return parse_extern_block (std::move (vis),
512 1483 : 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 682 : case USE:
532 682 : return parse_use_decl (std::move (vis), std::move (outer_attrs));
533 6389 : case FN_KW:
534 6389 : 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 2699 : case STRUCT_KW:
538 2699 : return parse_struct (std::move (vis), std::move (outer_attrs));
539 549 : case ENUM_KW:
540 549 : 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 111 : case IDENTIFIER:
544 222 : if (t->get_str () == Values::WeakKeywords::UNION
545 222 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
546 : {
547 111 : 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 560 : case CONST:
555 : // lookahead to resolve syntactical production
556 560 : t = lexer.peek_token (1);
557 :
558 560 : switch (t->get_id ())
559 : {
560 476 : case IDENTIFIER:
561 : case UNDERSCORE:
562 476 : 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 68 : case STATIC_KW:
583 68 : return parse_static_item (std::move (vis), std::move (outer_attrs));
584 3719 : case AUTO:
585 : case TRAIT:
586 3719 : 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 23318 : }
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 945 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
662 : {
663 : // ensure that first token is identifier saying "macro_rules"
664 945 : const_TokenPtr t = lexer.peek_token ();
665 945 : if (t->get_id () != IDENTIFIER
666 945 : || 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 945 : lexer.skip_token ();
677 945 : location_t macro_locus = t->get_locus ();
678 :
679 945 : if (!skip_token (EXCLAM))
680 : {
681 : // skip after somewhere?
682 0 : return nullptr;
683 : }
684 :
685 : // parse macro name
686 945 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
687 945 : if (ident_tok == nullptr)
688 : {
689 1 : return nullptr;
690 : }
691 944 : Identifier rule_name{ident_tok};
692 :
693 : // DEBUG
694 944 : rust_debug ("in macro rules def, about to parse parens.");
695 :
696 : // save delim type to ensure it is reused later
697 944 : AST::DelimType delim_type = AST::PARENS;
698 :
699 : // Map tokens to DelimType
700 944 : t = lexer.peek_token ();
701 944 : 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 942 : case LEFT_CURLY:
710 942 : delim_type = AST::CURLY;
711 942 : 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 944 : lexer.skip_token ();
721 :
722 : // parse actual macro rules
723 944 : std::vector<AST::MacroRule> macro_rules;
724 :
725 : // must be at least one macro rule, so parse it
726 944 : AST::MacroRule initial_rule = parse_macro_rule ();
727 944 : 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 932 : macro_rules.push_back (std::move (initial_rule));
738 :
739 : // DEBUG
740 932 : rust_debug ("successfully pushed back initial macro rule");
741 :
742 932 : t = lexer.peek_token ();
743 : // parse macro rules
744 1060 : while (t->get_id () == SEMICOLON)
745 : {
746 : // skip semicolon
747 635 : lexer.skip_token ();
748 :
749 : // don't parse if end of macro rules
750 1270 : if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
751 : delim_type))
752 : {
753 : // DEBUG
754 507 : rust_debug (
755 : "broke out of parsing macro rules loop due to finding delim");
756 :
757 507 : break;
758 : }
759 :
760 : // try to parse next rule
761 128 : AST::MacroRule rule = parse_macro_rule ();
762 128 : 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 128 : macro_rules.push_back (std::move (rule));
772 :
773 : // DEBUG
774 128 : rust_debug ("successfully pushed back another macro rule");
775 :
776 128 : t = lexer.peek_token ();
777 : }
778 :
779 : // parse end delimiters
780 932 : t = lexer.peek_token ();
781 932 : if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
782 : {
783 : // tokens match opening delimiter, so skip.
784 932 : lexer.skip_token ();
785 :
786 932 : if (delim_type != AST::CURLY)
787 : {
788 : // skip semicolon at end of non-curly macro definitions
789 2 : 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 1864 : AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
801 : std::move (macro_rules),
802 932 : 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 2833 : }
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 42043 : Parser<ManagedTokenSource>::parse_visibility ()
989 : {
990 : // check for no visibility
991 84086 : if (lexer.peek_token ()->get_id () != PUB)
992 : {
993 33714 : return AST::Visibility::create_private ();
994 : }
995 :
996 8329 : auto vis_loc = lexer.peek_token ()->get_locus ();
997 8329 : lexer.skip_token ();
998 :
999 : // create simple pub visibility if
1000 : // - found no parentheses
1001 : // - found unit type `()`
1002 16658 : if (lexer.peek_token ()->get_id () != LEFT_PAREN
1003 8396 : || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
1004 : {
1005 8263 : 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 1370 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
1068 : AST::AttrVec outer_attrs)
1069 : {
1070 1370 : location_t locus = lexer.peek_token ()->get_locus ();
1071 :
1072 1370 : Unsafety safety = Unsafety::Normal;
1073 2740 : if (lexer.peek_token ()->get_id () == UNSAFE)
1074 : {
1075 1 : safety = Unsafety::Unsafe;
1076 1 : skip_token (UNSAFE);
1077 : }
1078 :
1079 1370 : skip_token (MOD);
1080 :
1081 1370 : const_TokenPtr module_name = expect_token (IDENTIFIER);
1082 1370 : if (module_name == nullptr)
1083 : {
1084 0 : return nullptr;
1085 : }
1086 1370 : Identifier name{module_name};
1087 :
1088 1370 : const_TokenPtr t = lexer.peek_token ();
1089 :
1090 1370 : 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 1232 : case LEFT_CURLY:
1101 : {
1102 1232 : lexer.skip_token ();
1103 :
1104 : // parse inner attributes
1105 1232 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1106 :
1107 1232 : std::string default_path = name.as_string ();
1108 :
1109 1232 : if (inline_module_stack.empty ())
1110 : {
1111 703 : std::string filename = lexer.get_filename ();
1112 703 : auto slash_idx = filename.rfind (file_separator);
1113 703 : if (slash_idx == std::string::npos)
1114 : slash_idx = 0;
1115 : else
1116 703 : slash_idx++;
1117 703 : filename = filename.substr (slash_idx);
1118 :
1119 703 : std::string subdir;
1120 703 : if (get_file_subdir (filename, subdir))
1121 703 : default_path = subdir + file_separator + name.as_string ();
1122 703 : }
1123 :
1124 1232 : std::string module_path_name
1125 : = extract_module_path (inner_attrs, outer_attrs, default_path);
1126 1232 : InlineModuleStackScope scope (*this, std::move (module_path_name));
1127 :
1128 : // parse items
1129 1232 : std::vector<std::unique_ptr<AST::Item>> items;
1130 1232 : const_TokenPtr tok = lexer.peek_token ();
1131 4072 : while (tok->get_id () != RIGHT_CURLY)
1132 : {
1133 2840 : auto item = parse_item (false);
1134 2840 : 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 2840 : items.push_back (std::move (item.value ()));
1144 :
1145 2840 : tok = lexer.peek_token ();
1146 : }
1147 :
1148 1232 : if (!skip_token (RIGHT_CURLY))
1149 : {
1150 : // skip somewhere?
1151 0 : return nullptr;
1152 : }
1153 :
1154 : return std::unique_ptr<AST::Module> (
1155 1232 : new AST::Module (std::move (name), locus, std::move (items),
1156 : std::move (vis), safety, std::move (inner_attrs),
1157 1232 : std::move (outer_attrs))); // module name?
1158 1232 : }
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 1370 : }
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 682 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
1270 : AST::AttrVec outer_attrs)
1271 : {
1272 682 : location_t locus = lexer.peek_token ()->get_locus ();
1273 682 : if (!skip_token (USE))
1274 : {
1275 0 : skip_after_semicolon ();
1276 0 : return nullptr;
1277 : }
1278 :
1279 : // parse use tree, which is required
1280 682 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1281 682 : 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 681 : if (!skip_token (SEMICOLON))
1292 : {
1293 0 : skip_after_semicolon ();
1294 0 : return nullptr;
1295 : }
1296 :
1297 : return std::unique_ptr<AST::UseDeclaration> (
1298 681 : new AST::UseDeclaration (std::move (use_tree), std::move (vis),
1299 681 : std::move (outer_attrs), locus));
1300 682 : }
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 1267 : 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 1267 : location_t locus = lexer.peek_token ()->get_locus ();
1333 :
1334 : // bool has_path = false;
1335 1267 : auto path = parse_simple_path ();
1336 :
1337 1267 : 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 1265 : const_TokenPtr t = lexer.peek_token ();
1431 :
1432 1265 : 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 1091 : 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 1091 : return std::unique_ptr<AST::UseTreeRebind> (
1478 3273 : new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
1479 1091 : 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 167 : skip_token ();
1491 167 : t = lexer.peek_token ();
1492 :
1493 167 : switch (t->get_id ())
1494 : {
1495 13 : case ASTERISK:
1496 : // glob UseTree type
1497 13 : lexer.skip_token ();
1498 :
1499 13 : return std::unique_ptr<AST::UseTreeGlob> (
1500 39 : new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
1501 13 : 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 1265 : }
1549 1267 : }
1550 :
1551 : // Parses a function (not a method).
1552 : template <typename ManagedTokenSource>
1553 : std::unique_ptr<AST::Function>
1554 11471 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
1555 : AST::AttrVec outer_attrs,
1556 : bool is_external)
1557 : {
1558 11471 : location_t locus = lexer.peek_token ()->get_locus ();
1559 : // Get qualifiers for function if they exist
1560 11471 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
1561 :
1562 11471 : skip_token (FN_KW);
1563 :
1564 : // Save function name token
1565 11471 : const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
1566 11471 : if (function_name_tok == nullptr)
1567 : {
1568 0 : skip_after_next_block ();
1569 0 : return nullptr;
1570 : }
1571 11471 : Identifier function_name{function_name_tok};
1572 :
1573 : // parse generic params - if exist
1574 11471 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1575 : = parse_generic_params_in_angles ();
1576 :
1577 11471 : 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 11471 : auto initial_param = parse_self_param ();
1589 :
1590 11471 : if (!initial_param.has_value ()
1591 11471 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
1592 0 : return nullptr;
1593 :
1594 13721 : 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 11471 : std::vector<std::unique_ptr<AST::Param>> function_params;
1599 :
1600 22942 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
1601 : function_params
1602 5139 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
1603 :
1604 11471 : if (initial_param.has_value ())
1605 2250 : function_params.insert (function_params.begin (),
1606 2250 : std::move (*initial_param));
1607 :
1608 11471 : 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 11471 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
1621 :
1622 : // parse where clause - if exists
1623 11471 : AST::WhereClause where_clause = parse_where_clause ();
1624 :
1625 11471 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
1626 22942 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1627 3931 : lexer.skip_token ();
1628 : else
1629 : {
1630 7540 : auto block_expr = parse_block_expr ();
1631 7540 : if (!block_expr)
1632 29 : return nullptr;
1633 7511 : body = std::move (block_expr.value ());
1634 7540 : }
1635 :
1636 : return std::unique_ptr<AST::Function> (
1637 30395 : 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 11442 : std::move (outer_attrs), locus, false, is_external));
1642 34413 : }
1643 :
1644 : // Parses function or method qualifiers (i.e. const, unsafe, and extern).
1645 : template <typename ManagedTokenSource>
1646 : AST::FunctionQualifiers
1647 18233 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
1648 : {
1649 18233 : Async async_status = Async::No;
1650 18233 : Const const_status = Const::No;
1651 18233 : Unsafety unsafe_status = Unsafety::Normal;
1652 18233 : bool has_extern = false;
1653 18233 : std::string abi;
1654 :
1655 18233 : const_TokenPtr t;
1656 : location_t locus;
1657 : // Check in order of const, unsafe, then extern
1658 54699 : for (int i = 0; i < 2; i++)
1659 : {
1660 36466 : t = lexer.peek_token ();
1661 36466 : locus = t->get_locus ();
1662 :
1663 36466 : 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 36466 : if (lexer.peek_token ()->get_id () == UNSAFE)
1680 : {
1681 495 : lexer.skip_token ();
1682 495 : unsafe_status = Unsafety::Unsafe;
1683 : }
1684 :
1685 36466 : if (lexer.peek_token ()->get_id () == EXTERN_KW)
1686 : {
1687 99 : lexer.skip_token ();
1688 99 : has_extern = true;
1689 :
1690 : // detect optional abi name
1691 99 : const_TokenPtr next_tok = lexer.peek_token ();
1692 99 : if (next_tok->get_id () == STRING_LITERAL)
1693 : {
1694 99 : lexer.skip_token ();
1695 99 : abi = next_tok->get_str ();
1696 : }
1697 99 : }
1698 :
1699 36466 : return AST::FunctionQualifiers (locus, async_status, const_status,
1700 18233 : unsafe_status, has_extern, std::move (abi));
1701 18233 : }
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 31897 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
1707 : {
1708 63794 : if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
1709 : {
1710 : // seems to be no generic params, so exit with empty vector
1711 27671 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
1712 : }
1713 4226 : lexer.skip_token ();
1714 :
1715 : // DEBUG:
1716 4226 : rust_debug ("skipped left angle in generic param");
1717 :
1718 4226 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1719 : = parse_generic_params (Parse::Utils::is_right_angle_tok);
1720 :
1721 : // DEBUG:
1722 4226 : rust_debug ("finished parsing actual generic params (i.e. inside angles)");
1723 :
1724 4226 : 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 4225 : return generic_params;
1734 4226 : }
1735 :
1736 : template <typename ManagedTokenSource>
1737 : template <typename EndTokenPred>
1738 : std::unique_ptr<AST::GenericParam>
1739 4623 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
1740 : {
1741 4623 : auto outer_attrs = parse_outer_attributes ();
1742 4623 : std::unique_ptr<AST::GenericParam> param;
1743 4623 : auto token = lexer.peek_token ();
1744 :
1745 4623 : 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 4265 : case IDENTIFIER:
1776 : {
1777 4265 : auto type_ident = token->get_str ();
1778 4265 : lexer.skip_token ();
1779 :
1780 4265 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
1781 8530 : 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 4265 : std::unique_ptr<AST::Type> type = nullptr;
1790 8530 : 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 4265 : param = std::unique_ptr<AST::TypeParam> (
1808 12795 : new AST::TypeParam (std::move (type_ident), token->get_locus (),
1809 : std::move (type_param_bounds), std::move (type),
1810 4265 : std::move (outer_attrs)));
1811 : break;
1812 4265 : }
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 4619 : return param;
1871 4623 : }
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 4226 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
1879 : {
1880 4226 : 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 4226 : AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
1888 :
1889 : // Did we parse a generic type param yet
1890 4226 : auto type_seen = false;
1891 : // Did we parse a const param with a default value yet
1892 4226 : auto const_with_default_seen = false;
1893 : // Did the user write a lifetime parameter after a type one
1894 4226 : auto order_error = false;
1895 : // Did the user write a const param with a default value after a type one
1896 4226 : auto const_with_default_order_error = false;
1897 :
1898 : // parse lifetime params
1899 22313 : while (!is_end_token (lexer.peek_token ()->get_id ()))
1900 : {
1901 4623 : auto param = parse_generic_param (is_end_token);
1902 4623 : if (param)
1903 : {
1904 4619 : if (param->get_kind () == AST::GenericParam::Kind::Type)
1905 : {
1906 4265 : type_seen = true;
1907 4265 : if (const_with_default_seen)
1908 4619 : 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 4619 : const_with_default_order_error = true;
1926 : }
1927 :
1928 4619 : generic_params.emplace_back (std::move (param));
1929 4619 : maybe_skip_token (COMMA);
1930 : }
1931 : else
1932 : break;
1933 : }
1934 :
1935 : // FIXME: Add reordering hint
1936 4226 : 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 4226 : 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 4226 : generic_params.shrink_to_fit ();
1952 4226 : return generic_params;
1953 4226 : }
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 10035 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
2305 : {
2306 10035 : std::vector<std::unique_ptr<AST::Param>> params;
2307 :
2308 20070 : if (is_end_token (lexer.peek_token ()->get_id ()))
2309 827 : return params;
2310 :
2311 9208 : auto initial_param = parse_function_param ();
2312 :
2313 : // Return empty parameter list if no parameter there
2314 9208 : if (initial_param == nullptr)
2315 : {
2316 : // TODO: is this an error?
2317 0 : return params;
2318 : }
2319 :
2320 9208 : 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 9208 : const_TokenPtr t = lexer.peek_token ();
2326 11463 : 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 9208 : params.shrink_to_fit ();
2353 9208 : return params;
2354 10035 : }
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 11463 : Parser<ManagedTokenSource>::parse_function_param ()
2361 : {
2362 : // parse outer attributes if they exist
2363 11463 : AST::AttrVec outer_attrs = parse_outer_attributes ();
2364 :
2365 : // TODO: should saved location be at start of outer attributes or pattern?
2366 11463 : location_t locus = lexer.peek_token ()->get_locus ();
2367 :
2368 22926 : 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 10636 : std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
2376 :
2377 : // create error function param if it doesn't exist
2378 10636 : if (param_pattern == nullptr)
2379 : {
2380 : // skip after something
2381 0 : return nullptr;
2382 : }
2383 :
2384 10636 : if (!skip_token (COLON))
2385 : {
2386 : // skip after something
2387 0 : return nullptr;
2388 : }
2389 :
2390 21272 : 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 10625 : std::unique_ptr<AST::Type> param_type = parse_type ();
2400 10625 : if (param_type == nullptr)
2401 : {
2402 0 : return nullptr;
2403 : }
2404 10625 : return std::make_unique<AST::FunctionParam> (
2405 21250 : AST::FunctionParam (std::move (param_pattern), std::move (param_type),
2406 10625 : std::move (outer_attrs), locus));
2407 10625 : }
2408 11463 : }
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 18187 : Parser<ManagedTokenSource>::parse_function_return_type ()
2415 : {
2416 36374 : if (lexer.peek_token ()->get_id () != RETURN_TYPE)
2417 5557 : return nullptr;
2418 :
2419 : // skip return type, as it now obviously exists
2420 12630 : lexer.skip_token ();
2421 :
2422 12630 : std::unique_ptr<AST::Type> type = parse_type ();
2423 :
2424 12630 : return type;
2425 12630 : }
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 31883 : Parser<ManagedTokenSource>::parse_where_clause ()
2434 : {
2435 31883 : const_TokenPtr where_tok = lexer.peek_token ();
2436 31883 : if (where_tok->get_id () != WHERE)
2437 : {
2438 : // where clause doesn't exist, so create empty one
2439 31594 : 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 2699 : 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 2699 : location_t locus = lexer.peek_token ()->get_locus ();
2976 2699 : skip_token (STRUCT_KW);
2977 :
2978 : // parse struct name
2979 2699 : const_TokenPtr name_tok = expect_token (IDENTIFIER);
2980 2699 : if (name_tok == nullptr)
2981 : {
2982 : // skip after somewhere?
2983 1 : return nullptr;
2984 : }
2985 2698 : Identifier struct_name{name_tok};
2986 :
2987 : // parse generic params, which may or may not exist
2988 2698 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2989 : = parse_generic_params_in_angles ();
2990 :
2991 : // branch on next token - determines whether proper struct or tuple struct
2992 5396 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
2993 : {
2994 : // tuple struct
2995 :
2996 : // skip left parenthesis
2997 990 : lexer.skip_token ();
2998 :
2999 : // parse tuple fields
3000 990 : std::vector<AST::TupleField> tuple_fields;
3001 : // Might be empty tuple for unit tuple struct.
3002 1980 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3003 23 : tuple_fields = std::vector<AST::TupleField> ();
3004 : else
3005 967 : tuple_fields = parse_tuple_fields ();
3006 :
3007 : // tuple parameters must have closing parenthesis
3008 990 : if (!skip_token (RIGHT_PAREN))
3009 : {
3010 1 : skip_after_semicolon ();
3011 1 : return nullptr;
3012 : }
3013 :
3014 : // parse where clause, which is optional
3015 989 : AST::WhereClause where_clause = parse_where_clause ();
3016 :
3017 989 : if (!skip_token (SEMICOLON))
3018 : {
3019 : // can't skip after semicolon because it's meant to be here
3020 0 : return nullptr;
3021 : }
3022 :
3023 989 : return std::unique_ptr<AST::TupleStruct> (
3024 989 : new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
3025 : std::move (generic_params),
3026 : std::move (where_clause), std::move (vis),
3027 989 : std::move (outer_attrs), locus));
3028 990 : }
3029 :
3030 : // assume it is a proper struct being parsed and continue outside of switch
3031 : // - label only here to suppress warning
3032 :
3033 : // parse where clause, which is optional
3034 1708 : AST::WhereClause where_clause = parse_where_clause ();
3035 :
3036 : // branch on next token - determines whether struct is a unit struct
3037 1708 : const_TokenPtr t = lexer.peek_token ();
3038 1708 : switch (t->get_id ())
3039 : {
3040 950 : case LEFT_CURLY:
3041 : {
3042 : // struct with body
3043 :
3044 : // skip curly bracket
3045 950 : lexer.skip_token ();
3046 :
3047 : // parse struct fields, if any
3048 950 : std::vector<AST::StructField> struct_fields
3049 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3050 :
3051 950 : if (!skip_token (RIGHT_CURLY))
3052 : {
3053 : // skip somewhere?
3054 0 : return nullptr;
3055 : }
3056 :
3057 950 : return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
3058 : std::move (struct_fields), std::move (struct_name),
3059 : std::move (generic_params), std::move (where_clause), false,
3060 950 : std::move (vis), std::move (outer_attrs), locus));
3061 950 : }
3062 757 : case SEMICOLON:
3063 : // unit struct declaration
3064 :
3065 757 : lexer.skip_token ();
3066 :
3067 757 : return std::unique_ptr<AST::StructStruct> (
3068 1514 : new AST::StructStruct (std::move (struct_name),
3069 : std::move (generic_params),
3070 : std::move (where_clause), std::move (vis),
3071 757 : std::move (outer_attrs), locus));
3072 1 : default:
3073 1 : add_error (Error (t->get_locus (),
3074 : "unexpected token %qs in struct declaration",
3075 : t->get_token_description ()));
3076 :
3077 : // skip somewhere?
3078 1 : return nullptr;
3079 : }
3080 2698 : }
3081 :
3082 : // Parses struct fields in struct declarations.
3083 : template <typename ManagedTokenSource>
3084 : std::vector<AST::StructField>
3085 0 : Parser<ManagedTokenSource>::parse_struct_fields ()
3086 : {
3087 0 : std::vector<AST::StructField> fields;
3088 :
3089 0 : AST::StructField initial_field = parse_struct_field ();
3090 :
3091 : // Return empty field list if no field there
3092 0 : if (initial_field.is_error ())
3093 : return fields;
3094 :
3095 0 : fields.push_back (std::move (initial_field));
3096 :
3097 0 : while (lexer.peek_token ()->get_id () == COMMA)
3098 : {
3099 0 : lexer.skip_token ();
3100 :
3101 0 : AST::StructField field = parse_struct_field ();
3102 :
3103 0 : if (field.is_error ())
3104 : {
3105 : // would occur with trailing comma, so allowed
3106 : break;
3107 : }
3108 :
3109 0 : fields.push_back (std::move (field));
3110 : }
3111 :
3112 0 : fields.shrink_to_fit ();
3113 : return fields;
3114 : // TODO: template if possible (parse_non_ptr_seq)
3115 0 : }
3116 :
3117 : // Parses struct fields in struct declarations.
3118 : template <typename ManagedTokenSource>
3119 : template <typename EndTokenPred>
3120 : std::vector<AST::StructField>
3121 1156 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
3122 : {
3123 1156 : std::vector<AST::StructField> fields;
3124 :
3125 1156 : AST::StructField initial_field = parse_struct_field ();
3126 :
3127 : // Return empty field list if no field there
3128 1156 : if (initial_field.is_error ())
3129 50 : return fields;
3130 :
3131 1106 : fields.push_back (std::move (initial_field));
3132 :
3133 4540 : while (lexer.peek_token ()->get_id () == COMMA)
3134 : {
3135 2085 : lexer.skip_token ();
3136 :
3137 4170 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3138 : break;
3139 :
3140 1164 : AST::StructField field = parse_struct_field ();
3141 1164 : if (field.is_error ())
3142 : {
3143 : /* TODO: should every field be ditched just because one couldn't be
3144 : * parsed? */
3145 0 : Error error (lexer.peek_token ()->get_locus (),
3146 : "failed to parse struct field in struct fields");
3147 0 : add_error (std::move (error));
3148 :
3149 0 : return {};
3150 0 : }
3151 :
3152 1164 : fields.push_back (std::move (field));
3153 : }
3154 :
3155 1106 : fields.shrink_to_fit ();
3156 1106 : return fields;
3157 : // TODO: template if possible (parse_non_ptr_seq)
3158 1156 : }
3159 :
3160 : // Parses a single struct field (in a struct definition). Does not parse
3161 : // commas.
3162 : template <typename ManagedTokenSource>
3163 : AST::StructField
3164 2320 : Parser<ManagedTokenSource>::parse_struct_field ()
3165 : {
3166 : // parse outer attributes, if they exist
3167 2320 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3168 :
3169 : // parse visibility, if it exists
3170 2320 : auto vis = parse_visibility ();
3171 2320 : if (!vis)
3172 0 : return AST::StructField::create_error ();
3173 :
3174 2320 : location_t locus = lexer.peek_token ()->get_locus ();
3175 :
3176 : // parse field name
3177 2320 : const_TokenPtr field_name_tok = lexer.peek_token ();
3178 2320 : if (field_name_tok->get_id () != IDENTIFIER)
3179 : {
3180 : // if not identifier, assumes there is no struct field and exits - not
3181 : // necessarily error
3182 50 : return AST::StructField::create_error ();
3183 : }
3184 2270 : Identifier field_name{field_name_tok};
3185 2270 : lexer.skip_token ();
3186 :
3187 2270 : if (!skip_token (COLON))
3188 : {
3189 : // skip after somewhere?
3190 0 : return AST::StructField::create_error ();
3191 : }
3192 :
3193 : // parse field type - this is required
3194 2270 : std::unique_ptr<AST::Type> field_type = parse_type ();
3195 2270 : if (field_type == nullptr)
3196 : {
3197 0 : Error error (lexer.peek_token ()->get_locus (),
3198 : "could not parse type in struct field definition");
3199 0 : add_error (std::move (error));
3200 :
3201 : // skip after somewhere
3202 0 : return AST::StructField::create_error ();
3203 0 : }
3204 :
3205 4540 : return AST::StructField (std::move (field_name), std::move (field_type),
3206 2270 : std::move (vis.value ()), locus,
3207 2270 : std::move (outer_attrs));
3208 9180 : }
3209 :
3210 : // Parses tuple fields in tuple/tuple struct declarations.
3211 : template <typename ManagedTokenSource>
3212 : std::vector<AST::TupleField>
3213 1392 : Parser<ManagedTokenSource>::parse_tuple_fields ()
3214 : {
3215 1392 : std::vector<AST::TupleField> fields;
3216 :
3217 1392 : AST::TupleField initial_field = parse_tuple_field ();
3218 :
3219 : // Return empty field list if no field there
3220 1392 : if (initial_field.is_error ())
3221 : {
3222 1 : return fields;
3223 : }
3224 :
3225 1391 : fields.push_back (std::move (initial_field));
3226 :
3227 : // maybe think of a better control structure here - do-while with an initial
3228 : // error state? basically, loop through field list until can't find any more
3229 : // params HACK: all current syntax uses of tuple fields have them ending
3230 : // with a right paren token
3231 1391 : const_TokenPtr t = lexer.peek_token ();
3232 2129 : while (t->get_id () == COMMA)
3233 : {
3234 : // skip comma if applies - e.g. trailing comma
3235 739 : lexer.skip_token ();
3236 :
3237 : // break out due to right paren if it exists
3238 1478 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3239 : {
3240 : break;
3241 : }
3242 :
3243 738 : AST::TupleField field = parse_tuple_field ();
3244 738 : if (field.is_error ())
3245 : {
3246 0 : Error error (lexer.peek_token ()->get_locus (),
3247 : "failed to parse tuple field in tuple fields");
3248 0 : add_error (std::move (error));
3249 :
3250 0 : return std::vector<AST::TupleField> ();
3251 0 : }
3252 :
3253 738 : fields.push_back (std::move (field));
3254 :
3255 738 : t = lexer.peek_token ();
3256 : }
3257 :
3258 1391 : fields.shrink_to_fit ();
3259 1391 : return fields;
3260 :
3261 : // TODO: this shares basically all code with function params and struct
3262 : // fields
3263 : // - templates?
3264 1392 : }
3265 :
3266 : /* Parses a single tuple struct field in a tuple struct definition. Does not
3267 : * parse commas. */
3268 : template <typename ManagedTokenSource>
3269 : AST::TupleField
3270 2130 : Parser<ManagedTokenSource>::parse_tuple_field ()
3271 : {
3272 : // parse outer attributes if they exist
3273 2130 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3274 :
3275 : // parse visibility if it exists
3276 2130 : auto visibility = parse_visibility ();
3277 2130 : if (!visibility)
3278 0 : return AST::TupleField::create_error ();
3279 :
3280 2130 : location_t locus = lexer.peek_token ()->get_locus ();
3281 :
3282 : // parse type, which is required
3283 2130 : std::unique_ptr<AST::Type> field_type = parse_type ();
3284 2130 : if (field_type == nullptr)
3285 : {
3286 : // error if null
3287 1 : Error error (lexer.peek_token ()->get_locus (),
3288 : "could not parse type in tuple struct field");
3289 1 : add_error (std::move (error));
3290 :
3291 : // skip after something
3292 1 : return AST::TupleField::create_error ();
3293 1 : }
3294 :
3295 2129 : return AST::TupleField (std::move (field_type),
3296 2129 : std::move (visibility.value ()), locus,
3297 2129 : std::move (outer_attrs));
3298 4260 : }
3299 :
3300 : // Parses a Rust "enum" tagged union item definition.
3301 : template <typename ManagedTokenSource>
3302 : std::unique_ptr<AST::Enum>
3303 549 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
3304 : AST::AttrVec outer_attrs)
3305 : {
3306 549 : location_t locus = lexer.peek_token ()->get_locus ();
3307 549 : skip_token (ENUM_KW);
3308 :
3309 : // parse enum name
3310 549 : const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
3311 549 : if (enum_name_tok == nullptr)
3312 1 : return nullptr;
3313 :
3314 548 : Identifier enum_name = {enum_name_tok};
3315 :
3316 : // parse generic params (of enum container, not enum variants) if they exist
3317 548 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3318 : = parse_generic_params_in_angles ();
3319 :
3320 : // parse where clause if it exists
3321 548 : AST::WhereClause where_clause = parse_where_clause ();
3322 :
3323 548 : if (!skip_token (LEFT_CURLY))
3324 : {
3325 0 : skip_after_end_block ();
3326 0 : return nullptr;
3327 : }
3328 :
3329 : // parse actual enum variant definitions
3330 548 : std::vector<std::unique_ptr<AST::EnumItem>> enum_items
3331 : = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
3332 :
3333 548 : if (!skip_token (RIGHT_CURLY))
3334 : {
3335 1 : skip_after_end_block ();
3336 1 : return nullptr;
3337 : }
3338 :
3339 : return std::unique_ptr<AST::Enum> (
3340 547 : new AST::Enum (std::move (enum_name), std::move (vis),
3341 : std::move (generic_params), std::move (where_clause),
3342 547 : std::move (enum_items), std::move (outer_attrs), locus));
3343 1096 : }
3344 :
3345 : // Parses the enum variants inside an enum definiton.
3346 : template <typename ManagedTokenSource>
3347 : std::vector<std::unique_ptr<AST::EnumItem>>
3348 0 : Parser<ManagedTokenSource>::parse_enum_items ()
3349 : {
3350 0 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3351 :
3352 0 : auto initial_item = parse_enum_item ();
3353 :
3354 : // Return empty item list if no field there
3355 0 : if (!initial_item)
3356 : return items;
3357 :
3358 0 : items.push_back (std::move (initial_item.value ()));
3359 :
3360 0 : while (lexer.peek_token ()->get_id () == COMMA)
3361 : {
3362 0 : lexer.skip_token ();
3363 :
3364 0 : auto item = parse_enum_item ();
3365 0 : if (!item)
3366 : {
3367 : // this would occur with a trailing comma, which is allowed
3368 : break;
3369 : }
3370 :
3371 0 : items.push_back (std::move (item.value ()));
3372 : }
3373 :
3374 0 : items.shrink_to_fit ();
3375 : return items;
3376 :
3377 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3378 0 : }
3379 :
3380 : // Parses the enum variants inside an enum definiton.
3381 : template <typename ManagedTokenSource>
3382 : template <typename EndTokenPred>
3383 : std::vector<std::unique_ptr<AST::EnumItem>>
3384 548 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
3385 : {
3386 548 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3387 :
3388 548 : auto initial_item = parse_enum_item ();
3389 :
3390 : // Return empty item list if no field there
3391 548 : if (!initial_item)
3392 15 : return items;
3393 :
3394 533 : items.push_back (std::move (initial_item.value ()));
3395 :
3396 2554 : while (lexer.peek_token ()->get_id () == COMMA)
3397 : {
3398 1244 : lexer.skip_token ();
3399 :
3400 2488 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3401 : break;
3402 :
3403 744 : auto item = parse_enum_item ();
3404 744 : if (!item)
3405 : {
3406 : /* TODO should this ignore all successfully parsed enum items just
3407 : * because one failed? */
3408 0 : Error error (lexer.peek_token ()->get_locus (),
3409 : "failed to parse enum item in enum items");
3410 0 : add_error (std::move (error));
3411 :
3412 0 : return {};
3413 0 : }
3414 :
3415 744 : items.push_back (std::move (item.value ()));
3416 : }
3417 :
3418 533 : items.shrink_to_fit ();
3419 533 : return items;
3420 :
3421 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3422 548 : }
3423 :
3424 : /* Parses a single enum variant item in an enum definition. Does not parse
3425 : * commas. */
3426 : template <typename ManagedTokenSource>
3427 : tl::expected<std::unique_ptr<AST::EnumItem>, Parse::Error::EnumVariant>
3428 1292 : Parser<ManagedTokenSource>::parse_enum_item ()
3429 : {
3430 : // parse outer attributes if they exist
3431 1292 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3432 :
3433 : // parse visibility, which may or may not exist
3434 1292 : auto vis_res = parse_visibility ();
3435 1292 : if (!vis_res)
3436 : return Parse::Error::EnumVariant::make_child_error ();
3437 1292 : auto vis = vis_res.value ();
3438 :
3439 : // parse name for enum item, which is required
3440 1292 : const_TokenPtr item_name_tok = lexer.peek_token ();
3441 1292 : if (item_name_tok->get_id () != IDENTIFIER)
3442 : {
3443 : // this may not be an error but it means there is no enum item here
3444 30 : return Parse::Error::EnumVariant::make_not_identifier (item_name_tok);
3445 : }
3446 1277 : lexer.skip_token ();
3447 1277 : Identifier item_name{item_name_tok};
3448 :
3449 : // branch based on next token
3450 1277 : const_TokenPtr t = lexer.peek_token ();
3451 1277 : switch (t->get_id ())
3452 : {
3453 443 : case LEFT_PAREN:
3454 : {
3455 : // tuple enum item
3456 443 : lexer.skip_token ();
3457 :
3458 443 : std::vector<AST::TupleField> tuple_fields;
3459 : // Might be empty tuple for unit tuple enum variant.
3460 886 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3461 18 : tuple_fields = std::vector<AST::TupleField> ();
3462 : else
3463 425 : tuple_fields = parse_tuple_fields ();
3464 :
3465 443 : if (!skip_token (RIGHT_PAREN))
3466 : {
3467 : // skip after somewhere
3468 : return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
3469 : }
3470 :
3471 443 : return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
3472 : std::move (item_name), std::move (vis), std::move (tuple_fields),
3473 443 : std::move (outer_attrs), item_name_tok->get_locus ()));
3474 443 : }
3475 95 : case LEFT_CURLY:
3476 : {
3477 : // struct enum item
3478 95 : lexer.skip_token ();
3479 :
3480 95 : std::vector<AST::StructField> struct_fields
3481 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3482 :
3483 95 : if (!skip_token (RIGHT_CURLY))
3484 : {
3485 : // skip after somewhere
3486 : return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
3487 : }
3488 :
3489 95 : return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
3490 : std::move (item_name), std::move (vis), std::move (struct_fields),
3491 95 : std::move (outer_attrs), item_name_tok->get_locus ()));
3492 95 : }
3493 278 : case EQUAL:
3494 : {
3495 : // discriminant enum item
3496 278 : lexer.skip_token ();
3497 :
3498 278 : auto discriminant_expr = parse_expr ();
3499 278 : if (!discriminant_expr)
3500 : return Parse::Error::EnumVariant::make_child_error ();
3501 :
3502 278 : return std::make_unique<AST::EnumItemDiscriminant> (
3503 : std::move (item_name), std::move (vis),
3504 278 : std::move (discriminant_expr.value ()), std::move (outer_attrs),
3505 556 : item_name_tok->get_locus ());
3506 278 : }
3507 461 : default:
3508 : // regular enum with just an identifier
3509 461 : return std::make_unique<AST::EnumItem> (std::move (item_name),
3510 : std::move (vis),
3511 : std::move (outer_attrs),
3512 461 : item_name_tok->get_locus ());
3513 : }
3514 3861 : }
3515 :
3516 : // Parses a C-style (and C-compat) untagged union declaration.
3517 : template <typename ManagedTokenSource>
3518 : std::unique_ptr<AST::Union>
3519 111 : Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
3520 : AST::AttrVec outer_attrs)
3521 : {
3522 : /* hack - "weak keyword" by finding identifier called "union" (lookahead in
3523 : * item switch) */
3524 111 : const_TokenPtr union_keyword = expect_token (IDENTIFIER);
3525 111 : rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
3526 111 : location_t locus = union_keyword->get_locus ();
3527 :
3528 : // parse actual union name
3529 111 : const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
3530 111 : if (union_name_tok == nullptr)
3531 : {
3532 0 : skip_after_next_block ();
3533 0 : return nullptr;
3534 : }
3535 111 : Identifier union_name{union_name_tok};
3536 :
3537 : // parse optional generic parameters
3538 111 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3539 : = parse_generic_params_in_angles ();
3540 :
3541 : // parse optional where clause
3542 111 : AST::WhereClause where_clause = parse_where_clause ();
3543 :
3544 111 : if (!skip_token (LEFT_CURLY))
3545 : {
3546 0 : skip_after_end_block ();
3547 0 : return nullptr;
3548 : }
3549 :
3550 : /* parse union inner items as "struct fields" because hey, syntax reuse.
3551 : * Spec said so. */
3552 111 : std::vector<AST::StructField> union_fields
3553 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3554 :
3555 111 : if (!skip_token (RIGHT_CURLY))
3556 : {
3557 : // skip after somewhere
3558 0 : return nullptr;
3559 : }
3560 :
3561 : return std::unique_ptr<AST::Union> (
3562 111 : new AST::Union (std::move (union_name), std::move (vis),
3563 : std::move (generic_params), std::move (where_clause),
3564 111 : std::move (union_fields), std::move (outer_attrs), locus));
3565 333 : }
3566 :
3567 : /* Parses a "constant item" (compile-time constant to maybe "inline"
3568 : * throughout the program - like constexpr). */
3569 : template <typename ManagedTokenSource>
3570 : std::unique_ptr<AST::ConstantItem>
3571 549 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
3572 : AST::AttrVec outer_attrs)
3573 : {
3574 549 : location_t locus = lexer.peek_token ()->get_locus ();
3575 549 : skip_token (CONST);
3576 :
3577 : /* get constant identifier - this is either a proper identifier or the _
3578 : * wildcard */
3579 549 : const_TokenPtr ident_tok = lexer.peek_token ();
3580 : // make default identifier the underscore wildcard one
3581 549 : std::string ident (Values::Keywords::UNDERSCORE);
3582 549 : switch (ident_tok->get_id ())
3583 : {
3584 547 : case IDENTIFIER:
3585 547 : ident = ident_tok->get_str ();
3586 547 : lexer.skip_token ();
3587 : break;
3588 2 : case UNDERSCORE:
3589 : // do nothing - identifier is already "_"
3590 2 : lexer.skip_token ();
3591 : break;
3592 0 : default:
3593 0 : add_error (
3594 0 : Error (ident_tok->get_locus (),
3595 : "expected item name (identifier or %<_%>) in constant item "
3596 : "declaration - found %qs",
3597 : ident_tok->get_token_description ()));
3598 :
3599 0 : skip_after_semicolon ();
3600 0 : return nullptr;
3601 : }
3602 :
3603 549 : if (!skip_token (COLON))
3604 : {
3605 0 : skip_after_semicolon ();
3606 0 : return nullptr;
3607 : }
3608 :
3609 : // parse constant type (required)
3610 549 : std::unique_ptr<AST::Type> type = parse_type ();
3611 :
3612 : // A const with no given expression value
3613 1098 : if (lexer.peek_token ()->get_id () == SEMICOLON)
3614 : {
3615 4 : lexer.skip_token ();
3616 : return std::unique_ptr<AST::ConstantItem> (
3617 8 : new AST::ConstantItem (std::move (ident), std::move (vis),
3618 : std::move (type), std::move (outer_attrs),
3619 4 : locus));
3620 : }
3621 :
3622 545 : if (!skip_token (EQUAL))
3623 : {
3624 0 : skip_after_semicolon ();
3625 0 : return nullptr;
3626 : }
3627 :
3628 : // parse constant expression (required)
3629 545 : auto expr = parse_expr ();
3630 545 : if (!expr)
3631 1 : return nullptr;
3632 :
3633 544 : if (!skip_token (SEMICOLON))
3634 : {
3635 : // skip somewhere?
3636 0 : return nullptr;
3637 : }
3638 :
3639 : return std::unique_ptr<AST::ConstantItem> (
3640 1088 : new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
3641 544 : std::move (expr.value ()), std::move (outer_attrs),
3642 544 : locus));
3643 1098 : }
3644 :
3645 : // Parses a "static item" (static storage item, with 'static lifetime).
3646 : template <typename ManagedTokenSource>
3647 : std::unique_ptr<AST::StaticItem>
3648 68 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
3649 : AST::AttrVec outer_attrs)
3650 : {
3651 68 : location_t locus = lexer.peek_token ()->get_locus ();
3652 68 : skip_token (STATIC_KW);
3653 :
3654 : // determine whether static item is mutable
3655 68 : bool is_mut = false;
3656 136 : if (lexer.peek_token ()->get_id () == MUT)
3657 : {
3658 4 : is_mut = true;
3659 4 : lexer.skip_token ();
3660 : }
3661 :
3662 68 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3663 68 : if (ident_tok == nullptr)
3664 1 : return nullptr;
3665 :
3666 67 : Identifier ident{ident_tok};
3667 :
3668 67 : if (!skip_token (COLON))
3669 : {
3670 1 : skip_after_semicolon ();
3671 1 : return nullptr;
3672 : }
3673 :
3674 : // parse static item type (required)
3675 66 : std::unique_ptr<AST::Type> type = parse_type ();
3676 :
3677 66 : if (!skip_token (EQUAL))
3678 : {
3679 0 : skip_after_semicolon ();
3680 0 : return nullptr;
3681 : }
3682 :
3683 : // parse static item expression (required)
3684 66 : auto expr = parse_expr ();
3685 66 : if (!expr)
3686 1 : return nullptr;
3687 :
3688 65 : if (!skip_token (SEMICOLON))
3689 : {
3690 : // skip after somewhere
3691 0 : return nullptr;
3692 : }
3693 :
3694 : return std::unique_ptr<AST::StaticItem> (
3695 130 : new AST::StaticItem (std::move (ident), is_mut, std::move (type),
3696 65 : std::move (expr.value ()), std::move (vis),
3697 65 : std::move (outer_attrs), locus));
3698 133 : }
3699 :
3700 : // Parses a trait definition item, including unsafe ones.
3701 : template <typename ManagedTokenSource>
3702 : std::unique_ptr<AST::Trait>
3703 3775 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
3704 : AST::AttrVec outer_attrs)
3705 : {
3706 3775 : location_t locus = lexer.peek_token ()->get_locus ();
3707 3775 : bool is_unsafe = false;
3708 3775 : bool is_auto_trait = false;
3709 :
3710 7550 : if (lexer.peek_token ()->get_id () == UNSAFE)
3711 : {
3712 56 : is_unsafe = true;
3713 56 : lexer.skip_token ();
3714 : }
3715 :
3716 7550 : if (lexer.peek_token ()->get_id () == AUTO)
3717 : {
3718 20 : is_auto_trait = true;
3719 20 : lexer.skip_token ();
3720 : }
3721 :
3722 3775 : skip_token (TRAIT);
3723 :
3724 : // parse trait name
3725 3775 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3726 3775 : if (ident_tok == nullptr)
3727 0 : return nullptr;
3728 :
3729 3775 : Identifier ident{ident_tok};
3730 :
3731 : // parse generic parameters (if they exist)
3732 3775 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3733 : = parse_generic_params_in_angles ();
3734 :
3735 : // create placeholder type param bounds in case they don't exist
3736 3775 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3737 :
3738 : // parse type param bounds (if they exist)
3739 7550 : if (lexer.peek_token ()->get_id () == COLON)
3740 : {
3741 538 : lexer.skip_token ();
3742 :
3743 538 : type_param_bounds = parse_type_param_bounds (
3744 72 : [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
3745 : // type_param_bounds = parse_type_param_bounds ();
3746 : }
3747 :
3748 : // parse where clause (if it exists)
3749 3775 : AST::WhereClause where_clause = parse_where_clause ();
3750 :
3751 3775 : if (!skip_token (LEFT_CURLY))
3752 : {
3753 0 : skip_after_end_block ();
3754 0 : return nullptr;
3755 : }
3756 :
3757 : // parse inner attrs (if they exist)
3758 3775 : AST::AttrVec inner_attrs = parse_inner_attributes ();
3759 :
3760 : // parse trait items
3761 3775 : std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
3762 :
3763 3775 : const_TokenPtr t = lexer.peek_token ();
3764 7137 : while (t->get_id () != RIGHT_CURLY)
3765 : {
3766 3362 : std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
3767 :
3768 3362 : if (trait_item == nullptr)
3769 : {
3770 0 : Error error (lexer.peek_token ()->get_locus (),
3771 : "failed to parse trait item in trait");
3772 0 : add_error (std::move (error));
3773 :
3774 0 : return nullptr;
3775 0 : }
3776 3362 : trait_items.push_back (std::move (trait_item));
3777 :
3778 3362 : t = lexer.peek_token ();
3779 : }
3780 :
3781 3775 : if (!skip_token (RIGHT_CURLY))
3782 : {
3783 : // skip after something
3784 0 : return nullptr;
3785 : }
3786 :
3787 3775 : trait_items.shrink_to_fit ();
3788 : return std::unique_ptr<AST::Trait> (
3789 3775 : new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
3790 : std::move (generic_params), std::move (type_param_bounds),
3791 : std::move (where_clause), std::move (trait_items),
3792 : std::move (vis), std::move (outer_attrs),
3793 3775 : std::move (inner_attrs), locus));
3794 7550 : }
3795 :
3796 : // Parses a trait item used inside traits (not trait, the Item).
3797 : template <typename ManagedTokenSource>
3798 : std::unique_ptr<AST::AssociatedItem>
3799 3364 : Parser<ManagedTokenSource>::parse_trait_item ()
3800 : {
3801 : // parse outer attributes (if they exist)
3802 3364 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3803 :
3804 3364 : auto vis_res = parse_visibility ();
3805 3364 : if (!vis_res)
3806 0 : return nullptr;
3807 :
3808 3364 : auto vis = vis_res.value ();
3809 :
3810 : // lookahead to determine what type of trait item to parse
3811 3364 : const_TokenPtr tok = lexer.peek_token ();
3812 3364 : switch (tok->get_id ())
3813 : {
3814 0 : case SUPER:
3815 : case SELF:
3816 : case CRATE:
3817 : case DOLLAR_SIGN:
3818 : // these seem to be SimplePath tokens, so this is a macro invocation
3819 : // semi
3820 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
3821 1 : case IDENTIFIER:
3822 2 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
3823 0 : return parse_function (std::move (vis), std::move (outer_attrs));
3824 : else
3825 2 : return parse_macro_invocation_semi (std::move (outer_attrs));
3826 748 : case TYPE:
3827 748 : return parse_trait_type (std::move (outer_attrs), vis);
3828 41 : case CONST:
3829 : // disambiguate with function qualifier
3830 82 : if (lexer.peek_token (1)->get_id () == IDENTIFIER)
3831 : {
3832 80 : return parse_trait_const (std::move (outer_attrs));
3833 : }
3834 : // else, fallthrough to function
3835 : // TODO: find out how to disable gcc "implicit fallthrough" error
3836 : gcc_fallthrough ();
3837 : case ASYNC:
3838 : case UNSAFE:
3839 : case EXTERN_KW:
3840 : case FN_KW:
3841 5150 : return parse_function (std::move (vis), std::move (outer_attrs));
3842 : default:
3843 : break;
3844 : }
3845 0 : add_error (Error (tok->get_locus (),
3846 : "unrecognised token %qs for item in trait",
3847 : tok->get_token_description ()));
3848 : // skip?
3849 0 : return nullptr;
3850 6728 : }
3851 :
3852 : // Parse a typedef trait item.
3853 : template <typename ManagedTokenSource>
3854 : std::unique_ptr<AST::TraitItemType>
3855 748 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
3856 : AST::Visibility vis)
3857 : {
3858 748 : location_t locus = lexer.peek_token ()->get_locus ();
3859 748 : skip_token (TYPE);
3860 :
3861 748 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3862 748 : if (ident_tok == nullptr)
3863 0 : return nullptr;
3864 :
3865 1496 : Identifier ident{ident_tok};
3866 :
3867 : // Parse optional generic parameters for GATs (Generic Associated Types)
3868 748 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
3869 1496 : if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
3870 : {
3871 9 : generic_params = parse_generic_params_in_angles ();
3872 : }
3873 :
3874 748 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
3875 :
3876 : // parse optional colon
3877 1496 : if (lexer.peek_token ()->get_id () == COLON)
3878 : {
3879 44 : lexer.skip_token ();
3880 :
3881 : // parse optional type param bounds
3882 : bounds
3883 44 : = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
3884 : // bounds = parse_type_param_bounds ();
3885 : }
3886 :
3887 748 : if (!skip_token (SEMICOLON))
3888 : {
3889 : // skip?
3890 0 : return nullptr;
3891 : }
3892 :
3893 : return std::unique_ptr<AST::TraitItemType> (
3894 748 : new AST::TraitItemType (std::move (ident), std::move (generic_params),
3895 : std::move (bounds), std::move (outer_attrs), vis,
3896 748 : locus));
3897 748 : }
3898 :
3899 : // Parses a constant trait item.
3900 : template <typename ManagedTokenSource>
3901 : std::unique_ptr<AST::ConstantItem>
3902 40 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
3903 : {
3904 40 : location_t locus = lexer.peek_token ()->get_locus ();
3905 40 : skip_token (CONST);
3906 :
3907 : // parse constant item name
3908 40 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3909 40 : if (ident_tok == nullptr)
3910 0 : return nullptr;
3911 :
3912 40 : Identifier ident{ident_tok};
3913 :
3914 40 : if (!skip_token (COLON))
3915 : {
3916 0 : skip_after_semicolon ();
3917 0 : return nullptr;
3918 : }
3919 :
3920 : // parse constant trait item type
3921 40 : std::unique_ptr<AST::Type> type = parse_type ();
3922 :
3923 : // parse constant trait body expression, if it exists
3924 40 : std::unique_ptr<AST::Expr> const_body = nullptr;
3925 80 : if (lexer.peek_token ()->get_id () == EQUAL)
3926 : {
3927 12 : lexer.skip_token ();
3928 :
3929 : // expression must exist, so parse it
3930 12 : auto expr = parse_expr ();
3931 12 : if (!expr)
3932 0 : return nullptr;
3933 12 : const_body = std::move (expr.value ());
3934 12 : }
3935 :
3936 40 : if (!skip_token (SEMICOLON))
3937 : {
3938 : // skip after something?
3939 0 : return nullptr;
3940 : }
3941 :
3942 120 : return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
3943 80 : std::move (ident), AST::Visibility::create_private (), std::move (type),
3944 40 : std::move (const_body), std::move (outer_attrs), locus));
3945 80 : }
3946 :
3947 : /* Parses a struct "impl" item (both inherent impl and trait impl can be
3948 : * parsed here), */
3949 : template <typename ManagedTokenSource>
3950 : std::unique_ptr<AST::Impl>
3951 5298 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
3952 : AST::AttrVec outer_attrs)
3953 : {
3954 : /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
3955 : * must be a trait impl. However, this isn't enough for full disambiguation,
3956 : * so don't branch here. */
3957 5298 : location_t locus = lexer.peek_token ()->get_locus ();
3958 5298 : bool is_unsafe = false;
3959 10596 : if (lexer.peek_token ()->get_id () == UNSAFE)
3960 : {
3961 67 : lexer.skip_token ();
3962 67 : is_unsafe = true;
3963 : }
3964 :
3965 5298 : if (!skip_token (IMPL))
3966 : {
3967 0 : skip_after_next_block ();
3968 0 : return nullptr;
3969 : }
3970 :
3971 : // parse generic params (shared by trait and inherent impls)
3972 5298 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3973 : = parse_generic_params_in_angles ();
3974 :
3975 : // Again, trait impl-only feature, but optional one, so can be used for
3976 : // branching yet.
3977 5298 : bool has_exclam = false;
3978 10596 : if (lexer.peek_token ()->get_id () == EXCLAM)
3979 : {
3980 6 : lexer.skip_token ();
3981 6 : has_exclam = true;
3982 : }
3983 :
3984 : /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
3985 : * doesn't parse too much and not work. */
3986 5298 : AST::TypePath type_path = parse_type_path ();
3987 10395 : if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
3988 : {
3989 : /* cannot parse type path (or not for token next, at least), so must be
3990 : * inherent impl */
3991 :
3992 : // hacky conversion of TypePath stack object to Type pointer
3993 984 : std::unique_ptr<AST::Type> type = nullptr;
3994 984 : if (!type_path.is_error ())
3995 783 : type = std::unique_ptr<AST::TypePath> (
3996 783 : new AST::TypePath (std::move (type_path)));
3997 : else
3998 201 : type = parse_type ();
3999 :
4000 : // Type is required, so error if null
4001 984 : if (type == nullptr)
4002 : {
4003 1 : Error error (lexer.peek_token ()->get_locus (),
4004 : "could not parse type in inherent impl");
4005 1 : add_error (std::move (error));
4006 :
4007 1 : skip_after_next_block ();
4008 1 : return nullptr;
4009 1 : }
4010 :
4011 : // parse optional where clause
4012 983 : AST::WhereClause where_clause = parse_where_clause ();
4013 :
4014 983 : if (!skip_token (LEFT_CURLY))
4015 : {
4016 : // TODO: does this still skip properly?
4017 0 : skip_after_end_block ();
4018 0 : return nullptr;
4019 : }
4020 :
4021 : // parse inner attributes (optional)
4022 983 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4023 :
4024 : // parse inherent impl items
4025 983 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4026 :
4027 983 : const_TokenPtr t = lexer.peek_token ();
4028 3761 : while (t->get_id () != RIGHT_CURLY)
4029 : {
4030 2788 : std::unique_ptr<AST::AssociatedItem> impl_item
4031 : = parse_inherent_impl_item ();
4032 :
4033 2788 : if (impl_item == nullptr)
4034 : {
4035 10 : Error error (
4036 10 : lexer.peek_token ()->get_locus (),
4037 : "failed to parse inherent impl item in inherent impl");
4038 10 : add_error (std::move (error));
4039 :
4040 10 : return nullptr;
4041 10 : }
4042 :
4043 2778 : impl_items.push_back (std::move (impl_item));
4044 :
4045 2778 : t = lexer.peek_token ();
4046 : }
4047 :
4048 973 : if (!skip_token (RIGHT_CURLY))
4049 : {
4050 : // skip somewhere
4051 0 : return nullptr;
4052 : }
4053 :
4054 : // DEBUG
4055 973 : rust_debug ("successfully parsed inherent impl");
4056 :
4057 973 : impl_items.shrink_to_fit ();
4058 :
4059 973 : return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
4060 : std::move (impl_items), std::move (generic_params), std::move (type),
4061 : std::move (where_clause), std::move (vis), std::move (inner_attrs),
4062 973 : std::move (outer_attrs), locus));
4063 984 : }
4064 : else
4065 : {
4066 : // type path must both be valid and next token is for, so trait impl
4067 4314 : if (!skip_token (FOR))
4068 : {
4069 0 : skip_after_next_block ();
4070 0 : return nullptr;
4071 : }
4072 :
4073 : // parse type
4074 4314 : std::unique_ptr<AST::Type> type = parse_type ();
4075 : // ensure type is included as it is required
4076 4314 : if (type == nullptr)
4077 : {
4078 0 : Error error (lexer.peek_token ()->get_locus (),
4079 : "could not parse type in trait impl");
4080 0 : add_error (std::move (error));
4081 :
4082 0 : skip_after_next_block ();
4083 0 : return nullptr;
4084 0 : }
4085 :
4086 : // parse optional where clause
4087 4314 : AST::WhereClause where_clause = parse_where_clause ();
4088 :
4089 4314 : if (!skip_token (LEFT_CURLY))
4090 : {
4091 : // TODO: does this still skip properly?
4092 0 : skip_after_end_block ();
4093 0 : return nullptr;
4094 : }
4095 :
4096 : // parse inner attributes (optional)
4097 4314 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4098 :
4099 : // parse trait impl items
4100 4314 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4101 :
4102 4314 : const_TokenPtr t = lexer.peek_token ();
4103 14602 : while (t->get_id () != RIGHT_CURLY)
4104 : {
4105 5145 : std::unique_ptr<AST::AssociatedItem> impl_item
4106 : = parse_trait_impl_item ();
4107 :
4108 5145 : if (impl_item == nullptr)
4109 : {
4110 1 : Error error (lexer.peek_token ()->get_locus (),
4111 : "failed to parse trait impl item in trait impl");
4112 1 : add_error (std::move (error));
4113 :
4114 1 : return nullptr;
4115 1 : }
4116 :
4117 5144 : impl_items.push_back (std::move (impl_item));
4118 :
4119 5144 : t = lexer.peek_token ();
4120 :
4121 : // DEBUG
4122 5144 : rust_debug ("successfully parsed a trait impl item");
4123 : }
4124 : // DEBUG
4125 4313 : rust_debug ("successfully finished trait impl items");
4126 :
4127 4313 : if (!skip_token (RIGHT_CURLY))
4128 : {
4129 : // skip somewhere
4130 0 : return nullptr;
4131 : }
4132 :
4133 : // DEBUG
4134 4313 : rust_debug ("successfully parsed trait impl");
4135 :
4136 4313 : impl_items.shrink_to_fit ();
4137 :
4138 4313 : return std::unique_ptr<AST::TraitImpl> (
4139 8626 : new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
4140 : std::move (impl_items), std::move (generic_params),
4141 : std::move (type), std::move (where_clause),
4142 : std::move (vis), std::move (inner_attrs),
4143 4313 : std::move (outer_attrs), locus));
4144 4314 : }
4145 5298 : }
4146 :
4147 : // Parses a single inherent impl item (item inside an inherent impl block).
4148 : template <typename ManagedTokenSource>
4149 : std::unique_ptr<AST::AssociatedItem>
4150 2790 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
4151 : {
4152 : // parse outer attributes (if they exist)
4153 2790 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4154 :
4155 : // TODO: cleanup - currently an unreadable mess
4156 :
4157 : // branch on next token:
4158 2790 : const_TokenPtr t = lexer.peek_token ();
4159 2790 : switch (t->get_id ())
4160 : {
4161 1 : case IDENTIFIER:
4162 : // FIXME: Arthur: Do we need to some lookahead here?
4163 2 : return parse_macro_invocation_semi (outer_attrs);
4164 2141 : case SUPER:
4165 : case SELF:
4166 : case CRATE:
4167 : case PUB:
4168 : {
4169 : // visibility, so not a macro invocation semi - must be constant,
4170 : // function, or method
4171 2141 : auto vis_res = parse_visibility ();
4172 2141 : if (!vis_res)
4173 0 : return nullptr;
4174 2141 : auto vis = vis_res.value ();
4175 :
4176 : // TODO: is a recursive call to parse_inherent_impl_item better?
4177 4282 : switch (lexer.peek_token ()->get_id ())
4178 : {
4179 1364 : case EXTERN_KW:
4180 : case UNSAFE:
4181 : case FN_KW:
4182 : // function or method
4183 2728 : return parse_inherent_impl_function_or_method (std::move (vis),
4184 : std::move (
4185 1364 : outer_attrs));
4186 777 : case CONST:
4187 : // lookahead to resolve production - could be function/method or
4188 : // const item
4189 777 : t = lexer.peek_token (1);
4190 :
4191 777 : switch (t->get_id ())
4192 : {
4193 1 : case IDENTIFIER:
4194 : case UNDERSCORE:
4195 2 : return parse_const_item (std::move (vis),
4196 1 : std::move (outer_attrs));
4197 776 : case UNSAFE:
4198 : case EXTERN_KW:
4199 : case FN_KW:
4200 1552 : return parse_inherent_impl_function_or_method (std::move (vis),
4201 : std::move (
4202 776 : outer_attrs));
4203 0 : default:
4204 0 : add_error (Error (t->get_locus (),
4205 : "unexpected token %qs in some sort of const "
4206 : "item in inherent impl",
4207 : t->get_token_description ()));
4208 :
4209 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4210 0 : return nullptr;
4211 : }
4212 0 : default:
4213 0 : add_error (
4214 0 : Error (t->get_locus (),
4215 : "unrecognised token %qs for item in inherent impl",
4216 : t->get_token_description ()));
4217 : // skip?
4218 0 : return nullptr;
4219 : }
4220 4282 : }
4221 608 : case ASYNC:
4222 : case EXTERN_KW:
4223 : case UNSAFE:
4224 : case FN_KW:
4225 : // function or method
4226 608 : return parse_inherent_impl_function_or_method (
4227 608 : AST::Visibility::create_private (), std::move (outer_attrs));
4228 40 : case CONST:
4229 : /* lookahead to resolve production - could be function/method or const
4230 : * item */
4231 40 : t = lexer.peek_token (1);
4232 :
4233 40 : switch (t->get_id ())
4234 : {
4235 40 : case IDENTIFIER:
4236 : case UNDERSCORE:
4237 80 : return parse_const_item (AST::Visibility::create_private (),
4238 40 : std::move (outer_attrs));
4239 0 : case UNSAFE:
4240 : case EXTERN_KW:
4241 : case FN_KW:
4242 0 : return parse_inherent_impl_function_or_method (
4243 0 : AST::Visibility::create_private (), std::move (outer_attrs));
4244 0 : default:
4245 0 : add_error (Error (t->get_locus (),
4246 : "unexpected token %qs in some sort of const item "
4247 : "in inherent impl",
4248 : t->get_token_description ()));
4249 :
4250 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4251 0 : return nullptr;
4252 : }
4253 : rust_unreachable ();
4254 0 : default:
4255 0 : add_error (Error (t->get_locus (),
4256 : "unrecognised token %qs for item in inherent impl",
4257 : t->get_token_description ()));
4258 :
4259 : // skip?
4260 0 : return nullptr;
4261 : }
4262 2790 : }
4263 :
4264 : /* For internal use only by parse_inherent_impl_item() - splits giant method
4265 : * into smaller ones and prevents duplication of logic. Strictly, this parses
4266 : * a function or method item inside an inherent impl item block. */
4267 : // TODO: make this a templated function with "return type" as type param -
4268 : // InherentImplItem is this specialisation of the template while TraitImplItem
4269 : // will be the other.
4270 : template <typename ManagedTokenSource>
4271 : std::unique_ptr<AST::AssociatedItem>
4272 2748 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
4273 : AST::Visibility vis, AST::AttrVec outer_attrs)
4274 : {
4275 2748 : location_t locus = lexer.peek_token ()->get_locus ();
4276 : // parse function or method qualifiers
4277 2748 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4278 :
4279 2748 : skip_token (FN_KW);
4280 :
4281 : // parse function or method name
4282 2748 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4283 2748 : if (ident_tok == nullptr)
4284 7 : return nullptr;
4285 :
4286 2741 : Identifier ident{ident_tok};
4287 :
4288 : // parse generic params
4289 2741 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4290 : = parse_generic_params_in_angles ();
4291 :
4292 2741 : if (!skip_token (LEFT_PAREN))
4293 : {
4294 : // skip after somewhere?
4295 0 : return nullptr;
4296 : }
4297 :
4298 : // now for function vs method disambiguation - method has opening "self"
4299 : // param
4300 2741 : auto initial_param = parse_self_param ();
4301 :
4302 2741 : if (!initial_param.has_value ()
4303 2741 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4304 3 : return nullptr;
4305 :
4306 : /* FIXME: ensure that self param doesn't accidently consume tokens for a
4307 : * function one idea is to lookahead up to 4 tokens to see whether self is
4308 : * one of them */
4309 2738 : bool is_method = false;
4310 2738 : if (initial_param.has_value ())
4311 : {
4312 1844 : if ((*initial_param)->is_self ())
4313 : is_method = true;
4314 :
4315 : /* skip comma so function and method regular params can be parsed in
4316 : * same way */
4317 3688 : if (lexer.peek_token ()->get_id () == COMMA)
4318 1193 : lexer.skip_token ();
4319 : }
4320 :
4321 : // parse trait function params
4322 2738 : std::vector<std::unique_ptr<AST::Param>> function_params
4323 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4324 :
4325 2738 : if (initial_param.has_value ())
4326 1844 : function_params.insert (function_params.begin (),
4327 1844 : std::move (*initial_param));
4328 :
4329 2738 : if (!skip_token (RIGHT_PAREN))
4330 : {
4331 0 : skip_after_end_block ();
4332 0 : return nullptr;
4333 : }
4334 :
4335 : // parse return type (optional)
4336 2738 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4337 :
4338 : // parse where clause (optional)
4339 2738 : AST::WhereClause where_clause = parse_where_clause ();
4340 :
4341 2738 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4342 5476 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4343 2 : lexer.skip_token ();
4344 : else
4345 : {
4346 2736 : auto result = parse_block_expr ();
4347 :
4348 2736 : if (!result)
4349 : {
4350 0 : Error error (
4351 0 : lexer.peek_token ()->get_locus (),
4352 : "could not parse definition in inherent impl %s definition",
4353 : is_method ? "method" : "function");
4354 0 : add_error (std::move (error));
4355 :
4356 0 : skip_after_end_block ();
4357 0 : return nullptr;
4358 0 : }
4359 2736 : body = std::move (result.value ());
4360 2736 : }
4361 :
4362 2738 : return std::unique_ptr<AST::Function> (
4363 10950 : new AST::Function (std::move (ident), std::move (qualifiers),
4364 : std::move (generic_params), std::move (function_params),
4365 : std::move (return_type), std::move (where_clause),
4366 : std::move (body), std::move (vis),
4367 2738 : std::move (outer_attrs), locus));
4368 8227 : }
4369 :
4370 : // Parses a single trait impl item (item inside a trait impl block).
4371 : template <typename ManagedTokenSource>
4372 : std::unique_ptr<AST::AssociatedItem>
4373 5248 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
4374 : {
4375 : // parse outer attributes (if they exist)
4376 5248 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4377 :
4378 5248 : auto vis_res = parse_visibility ();
4379 5248 : if (!vis_res)
4380 0 : return nullptr;
4381 5248 : auto visibility = vis_res.value ();
4382 :
4383 : // branch on next token:
4384 5248 : const_TokenPtr t = lexer.peek_token ();
4385 5248 : switch (t->get_id ())
4386 : {
4387 0 : case SUPER:
4388 : case SELF:
4389 : case CRATE:
4390 : case DOLLAR_SIGN:
4391 : // these seem to be SimplePath tokens, so this is a macro invocation
4392 : // semi
4393 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
4394 55 : case IDENTIFIER:
4395 110 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
4396 48 : return parse_trait_impl_function_or_method (visibility,
4397 24 : std::move (outer_attrs));
4398 : else
4399 62 : return parse_macro_invocation_semi (std::move (outer_attrs));
4400 1236 : case TYPE:
4401 2472 : return parse_type_alias (visibility, std::move (outer_attrs));
4402 3923 : case EXTERN_KW:
4403 : case UNSAFE:
4404 : case FN_KW:
4405 : // function or method
4406 7846 : return parse_trait_impl_function_or_method (visibility,
4407 3923 : std::move (outer_attrs));
4408 1 : case ASYNC:
4409 2 : return parse_async_item (visibility, std::move (outer_attrs));
4410 33 : case CONST:
4411 : // lookahead to resolve production - could be function/method or const
4412 : // item
4413 33 : t = lexer.peek_token (1);
4414 :
4415 33 : switch (t->get_id ())
4416 : {
4417 32 : case IDENTIFIER:
4418 : case UNDERSCORE:
4419 64 : return parse_const_item (visibility, std::move (outer_attrs));
4420 1 : case UNSAFE:
4421 : case EXTERN_KW:
4422 : case FN_KW:
4423 2 : return parse_trait_impl_function_or_method (visibility,
4424 1 : std::move (outer_attrs));
4425 0 : default:
4426 0 : add_error (Error (
4427 : t->get_locus (),
4428 : "unexpected token %qs in some sort of const item in trait impl",
4429 : t->get_token_description ()));
4430 :
4431 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4432 0 : return nullptr;
4433 : }
4434 : rust_unreachable ();
4435 : default:
4436 : break;
4437 : }
4438 0 : add_error (Error (t->get_locus (),
4439 : "unrecognised token %qs for item in trait impl",
4440 : t->get_token_description ()));
4441 :
4442 : // skip?
4443 0 : return nullptr;
4444 10496 : }
4445 :
4446 : /* For internal use only by parse_trait_impl_item() - splits giant method into
4447 : * smaller ones and prevents duplication of logic. Strictly, this parses a
4448 : * function or method item inside a trait impl item block. */
4449 : template <typename ManagedTokenSource>
4450 : std::unique_ptr<AST::AssociatedItem>
4451 3948 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
4452 : AST::Visibility vis, AST::AttrVec outer_attrs)
4453 : {
4454 : // this shares virtually all logic with
4455 : // parse_inherent_impl_function_or_method
4456 : // - template?
4457 3948 : location_t locus = lexer.peek_token ()->get_locus ();
4458 :
4459 3948 : auto is_default = false;
4460 3948 : auto t = lexer.peek_token ();
4461 3948 : if (t->get_id () == IDENTIFIER
4462 3948 : && t->get_str () == Values::WeakKeywords::DEFAULT)
4463 : {
4464 24 : is_default = true;
4465 24 : lexer.skip_token ();
4466 : }
4467 :
4468 : // parse function or method qualifiers
4469 3948 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4470 :
4471 3948 : skip_token (FN_KW);
4472 :
4473 : // parse function or method name
4474 3948 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4475 3948 : if (ident_tok == nullptr)
4476 : {
4477 0 : return nullptr;
4478 : }
4479 3948 : Identifier ident{ident_tok};
4480 :
4481 : // DEBUG:
4482 3948 : rust_debug (
4483 : "about to start parsing generic params in trait impl function or method");
4484 :
4485 : // parse generic params
4486 3948 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4487 : = parse_generic_params_in_angles ();
4488 :
4489 : // DEBUG:
4490 3948 : rust_debug (
4491 : "finished parsing generic params in trait impl function or method");
4492 :
4493 3948 : if (!skip_token (LEFT_PAREN))
4494 : {
4495 : // skip after somewhere?
4496 0 : return nullptr;
4497 : }
4498 :
4499 : // now for function vs method disambiguation - method has opening "self"
4500 : // param
4501 3948 : auto initial_param = parse_self_param ();
4502 :
4503 3948 : if (!initial_param.has_value ()
4504 3948 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4505 0 : return nullptr;
4506 :
4507 : // FIXME: ensure that self param doesn't accidently consume tokens for a
4508 : // function
4509 3948 : bool is_method = false;
4510 3948 : if (initial_param.has_value ())
4511 : {
4512 3708 : if ((*initial_param)->is_self ())
4513 : is_method = true;
4514 :
4515 : // skip comma so function and method regular params can be parsed in
4516 : // same way
4517 7416 : if (lexer.peek_token ()->get_id () == COMMA)
4518 : {
4519 2001 : lexer.skip_token ();
4520 : }
4521 :
4522 : // DEBUG
4523 3708 : rust_debug ("successfully parsed self param in method trait impl item");
4524 : }
4525 :
4526 : // DEBUG
4527 3948 : rust_debug (
4528 : "started to parse function params in function or method trait impl item");
4529 :
4530 : // parse trait function params (only if next token isn't right paren)
4531 3948 : std::vector<std::unique_ptr<AST::Param>> function_params;
4532 7896 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
4533 : {
4534 : function_params
4535 2158 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4536 :
4537 2158 : if (function_params.empty ())
4538 : {
4539 0 : Error error (
4540 0 : lexer.peek_token ()->get_locus (),
4541 : "failed to parse function params in trait impl %s definition",
4542 : is_method ? "method" : "function");
4543 0 : add_error (std::move (error));
4544 :
4545 0 : skip_after_next_block ();
4546 0 : return nullptr;
4547 0 : }
4548 : }
4549 :
4550 3948 : if (initial_param.has_value ())
4551 3708 : function_params.insert (function_params.begin (),
4552 3708 : std::move (*initial_param));
4553 :
4554 : // DEBUG
4555 3948 : rust_debug ("successfully parsed function params in function or method "
4556 : "trait impl item");
4557 :
4558 3948 : if (!skip_token (RIGHT_PAREN))
4559 : {
4560 0 : skip_after_next_block ();
4561 0 : return nullptr;
4562 : }
4563 :
4564 : // parse return type (optional)
4565 3948 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4566 :
4567 : // DEBUG
4568 3948 : rust_debug (
4569 : "successfully parsed return type in function or method trait impl item");
4570 :
4571 : // parse where clause (optional)
4572 3948 : AST::WhereClause where_clause = parse_where_clause ();
4573 :
4574 : // DEBUG
4575 3948 : rust_debug (
4576 : "successfully parsed where clause in function or method trait impl item");
4577 :
4578 : // parse function definition (in block) - semicolon not allowed
4579 3948 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4580 :
4581 7896 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4582 1 : lexer.skip_token ();
4583 : else
4584 : {
4585 3947 : auto result = parse_block_expr ();
4586 3947 : if (!result)
4587 : {
4588 1 : Error error (lexer.peek_token ()->get_locus (),
4589 : "could not parse definition in trait impl %s definition",
4590 : is_method ? "method" : "function");
4591 1 : add_error (std::move (error));
4592 :
4593 1 : skip_after_end_block ();
4594 1 : return nullptr;
4595 1 : }
4596 3946 : body = std::move (result.value ());
4597 3947 : }
4598 :
4599 3947 : return std::unique_ptr<AST::Function> (
4600 15787 : new AST::Function (std::move (ident), std::move (qualifiers),
4601 : std::move (generic_params), std::move (function_params),
4602 : std::move (return_type), std::move (where_clause),
4603 : std::move (body), std::move (vis),
4604 3947 : std::move (outer_attrs), locus, is_default));
4605 11844 : }
4606 :
4607 : // Parses an extern block of declarations.
4608 : template <typename ManagedTokenSource>
4609 : std::unique_ptr<AST::ExternBlock>
4610 1483 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
4611 : AST::AttrVec outer_attrs)
4612 : {
4613 1483 : location_t locus = lexer.peek_token ()->get_locus ();
4614 1483 : skip_token (EXTERN_KW);
4615 :
4616 : // detect optional abi name
4617 1483 : std::string abi;
4618 1483 : const_TokenPtr next_tok = lexer.peek_token ();
4619 1483 : if (next_tok->get_id () == STRING_LITERAL)
4620 : {
4621 1483 : lexer.skip_token ();
4622 1483 : abi = next_tok->get_str ();
4623 : }
4624 :
4625 1483 : if (!skip_token (LEFT_CURLY))
4626 : {
4627 0 : skip_after_end_block ();
4628 0 : return nullptr;
4629 : }
4630 :
4631 1483 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4632 :
4633 : // parse declarations inside extern block
4634 1483 : std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
4635 :
4636 1483 : const_TokenPtr t = lexer.peek_token ();
4637 3709 : while (t->get_id () != RIGHT_CURLY)
4638 : {
4639 2227 : std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
4640 :
4641 2227 : if (extern_item == nullptr)
4642 : {
4643 1 : Error error (t->get_locus (),
4644 : "failed to parse external item despite not reaching "
4645 : "end of extern block");
4646 1 : add_error (std::move (error));
4647 :
4648 1 : return nullptr;
4649 1 : }
4650 :
4651 2226 : extern_items.push_back (std::move (extern_item));
4652 :
4653 2226 : t = lexer.peek_token ();
4654 : }
4655 :
4656 1482 : if (!skip_token (RIGHT_CURLY))
4657 : {
4658 : // skip somewhere
4659 0 : return nullptr;
4660 : }
4661 :
4662 1482 : extern_items.shrink_to_fit ();
4663 :
4664 : return std::unique_ptr<AST::ExternBlock> (
4665 1482 : new AST::ExternBlock (std::move (abi), std::move (extern_items),
4666 : std::move (vis), std::move (inner_attrs),
4667 1482 : std::move (outer_attrs), locus));
4668 2966 : }
4669 :
4670 : // Parses a single extern block item (static or function declaration).
4671 : template <typename ManagedTokenSource>
4672 : std::unique_ptr<AST::ExternalItem>
4673 2230 : Parser<ManagedTokenSource>::parse_external_item ()
4674 : {
4675 : // parse optional outer attributes
4676 2230 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4677 :
4678 2230 : location_t locus = lexer.peek_token ()->get_locus ();
4679 :
4680 : // parse optional visibility
4681 2230 : auto vis_res = parse_visibility ();
4682 2230 : if (!vis_res)
4683 0 : return nullptr;
4684 2230 : auto vis = vis_res.value ();
4685 :
4686 2230 : const_TokenPtr t = lexer.peek_token ();
4687 2230 : switch (t->get_id ())
4688 : {
4689 2 : case IDENTIFIER:
4690 4 : return parse_macro_invocation_semi (outer_attrs);
4691 1 : case STATIC_KW:
4692 : {
4693 : // parse extern static item
4694 1 : lexer.skip_token ();
4695 :
4696 : // parse mut (optional)
4697 1 : bool has_mut = false;
4698 2 : if (lexer.peek_token ()->get_id () == MUT)
4699 : {
4700 0 : lexer.skip_token ();
4701 0 : has_mut = true;
4702 : }
4703 :
4704 : // parse identifier
4705 1 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4706 1 : if (ident_tok == nullptr)
4707 : {
4708 0 : skip_after_semicolon ();
4709 0 : return nullptr;
4710 : }
4711 1 : Identifier ident{ident_tok};
4712 :
4713 1 : if (!skip_token (COLON))
4714 : {
4715 0 : skip_after_semicolon ();
4716 0 : return nullptr;
4717 : }
4718 :
4719 : // parse type (required)
4720 1 : std::unique_ptr<AST::Type> type = parse_type ();
4721 1 : if (type == nullptr)
4722 : {
4723 0 : Error error (lexer.peek_token ()->get_locus (),
4724 : "failed to parse type in external static item");
4725 0 : add_error (std::move (error));
4726 :
4727 0 : skip_after_semicolon ();
4728 0 : return nullptr;
4729 0 : }
4730 :
4731 1 : if (!skip_token (SEMICOLON))
4732 : {
4733 : // skip after somewhere?
4734 0 : return nullptr;
4735 : }
4736 :
4737 1 : return std::unique_ptr<AST::ExternalStaticItem> (
4738 2 : new AST::ExternalStaticItem (std::move (ident), std::move (type),
4739 : has_mut, std::move (vis),
4740 1 : std::move (outer_attrs), locus));
4741 3 : }
4742 2223 : case FN_KW:
4743 4446 : return parse_function (std::move (vis), std::move (outer_attrs), true);
4744 :
4745 4 : case TYPE:
4746 4 : return parse_external_type_item (std::move (vis),
4747 4 : std::move (outer_attrs));
4748 0 : default:
4749 : // error
4750 0 : add_error (
4751 0 : Error (t->get_locus (),
4752 : "unrecognised token %qs in extern block item declaration",
4753 : t->get_token_description ()));
4754 :
4755 0 : skip_after_semicolon ();
4756 0 : return nullptr;
4757 : }
4758 4460 : }
4759 :
4760 : // Parses a statement (will further disambiguate any statement).
4761 : template <typename ManagedTokenSource>
4762 : std::unique_ptr<AST::Stmt>
4763 741 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
4764 : {
4765 : // quick exit for empty statement
4766 : // FIXME: Can we have empty statements without semicolons? Just nothing?
4767 741 : const_TokenPtr t = lexer.peek_token ();
4768 741 : if (t->get_id () == SEMICOLON)
4769 : {
4770 30 : lexer.skip_token ();
4771 30 : return std::unique_ptr<AST::EmptyStmt> (
4772 30 : new AST::EmptyStmt (t->get_locus ()));
4773 : }
4774 :
4775 : // parse outer attributes
4776 711 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4777 :
4778 : // parsing this will be annoying because of the many different possibilities
4779 : /* best may be just to copy paste in parse_item switch, and failing that try
4780 : * to parse outer attributes, and then pass them in to either a let
4781 : * statement or (fallback) expression statement. */
4782 : // FIXME: think of a way to do this without such a large switch?
4783 711 : t = lexer.peek_token ();
4784 711 : switch (t->get_id ())
4785 : {
4786 200 : case LET:
4787 : // let statement
4788 200 : return parse_let_stmt (std::move (outer_attrs), restrictions);
4789 186 : case PUB:
4790 : case MOD:
4791 : case EXTERN_KW:
4792 : case USE:
4793 : case FN_KW:
4794 : case TYPE:
4795 : case STRUCT_KW:
4796 : case ENUM_KW:
4797 : case CONST:
4798 : case STATIC_KW:
4799 : case AUTO:
4800 : case TRAIT:
4801 : case IMPL:
4802 : case MACRO:
4803 : /* TODO: implement union keyword but not really because of
4804 : * context-dependence crappy hack way to parse a union written below to
4805 : * separate it from the good code. */
4806 : // case UNION:
4807 : case UNSAFE: // maybe - unsafe traits are a thing
4808 : /* if any of these (should be all possible VisItem prefixes), parse a
4809 : * VisItem can't parse item because would require reparsing outer
4810 : * attributes */
4811 : // may also be unsafe block
4812 372 : if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
4813 : {
4814 1 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
4815 : }
4816 : else
4817 : {
4818 185 : return parse_vis_item (std::move (outer_attrs));
4819 : }
4820 : break;
4821 : // crappy hack to do union "keyword"
4822 220 : case IDENTIFIER:
4823 220 : if (t->get_str () == Values::WeakKeywords::UNION
4824 220 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
4825 : {
4826 0 : return parse_vis_item (std::move (outer_attrs));
4827 : // or should this go straight to parsing union?
4828 : }
4829 440 : else if (is_macro_rules_def (t))
4830 : {
4831 : // macro_rules! macro item
4832 2 : return parse_macro_rules_def (std::move (outer_attrs));
4833 : }
4834 : gcc_fallthrough ();
4835 : // TODO: find out how to disable gcc "implicit fallthrough" warning
4836 : default:
4837 : // fallback: expression statement
4838 323 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
4839 : break;
4840 : }
4841 711 : }
4842 :
4843 : // Parses a let statement.
4844 : template <typename ManagedTokenSource>
4845 : std::unique_ptr<AST::LetStmt>
4846 12943 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
4847 : ParseRestrictions restrictions)
4848 : {
4849 12943 : location_t locus = lexer.peek_token ()->get_locus ();
4850 12943 : skip_token (LET);
4851 :
4852 : // parse pattern (required)
4853 12943 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
4854 12943 : if (pattern == nullptr)
4855 : {
4856 0 : Error error (lexer.peek_token ()->get_locus (),
4857 : "failed to parse pattern in let statement");
4858 0 : add_error (std::move (error));
4859 :
4860 0 : skip_after_semicolon ();
4861 0 : return nullptr;
4862 0 : }
4863 :
4864 : // parse type declaration (optional)
4865 12943 : std::unique_ptr<AST::Type> type = nullptr;
4866 25886 : if (lexer.peek_token ()->get_id () == COLON)
4867 : {
4868 : // must have a type declaration
4869 2029 : lexer.skip_token ();
4870 :
4871 2029 : type = parse_type ();
4872 2029 : if (type == nullptr)
4873 : {
4874 0 : Error error (lexer.peek_token ()->get_locus (),
4875 : "failed to parse type in let statement");
4876 0 : add_error (std::move (error));
4877 :
4878 0 : skip_after_semicolon ();
4879 0 : return nullptr;
4880 0 : }
4881 : }
4882 :
4883 : // parse expression to set variable to (optional)
4884 12943 : std::unique_ptr<AST::Expr> expr = nullptr;
4885 25886 : if (lexer.peek_token ()->get_id () == EQUAL)
4886 : {
4887 : // must have an expression
4888 11890 : lexer.skip_token ();
4889 :
4890 11890 : auto expr_res = parse_expr ();
4891 11890 : if (!expr_res)
4892 : {
4893 22 : skip_after_semicolon ();
4894 22 : return nullptr;
4895 : }
4896 11868 : expr = std::move (expr_res.value ());
4897 11890 : }
4898 :
4899 12921 : tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
4900 12921 : if (maybe_skip_token (ELSE))
4901 : {
4902 5 : auto block_expr = parse_block_expr ();
4903 5 : if (block_expr)
4904 : else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
4905 10 : std::move (block_expr.value ())};
4906 : else
4907 : else_expr = tl::nullopt;
4908 5 : }
4909 :
4910 12921 : if (restrictions.consume_semi)
4911 : {
4912 : // `stmt` macro variables are parsed without a semicolon, but should be
4913 : // parsed as a full statement when interpolated. This should be handled
4914 : // by having the interpolated statement be distinguishable from normal
4915 : // tokens, e.g. by NT tokens.
4916 12776 : if (restrictions.allow_close_after_expr_stmt)
4917 55 : maybe_skip_token (SEMICOLON);
4918 12721 : else if (!skip_token (SEMICOLON))
4919 1 : return nullptr;
4920 : }
4921 :
4922 : return std::unique_ptr<AST::LetStmt> (
4923 25845 : new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
4924 12920 : std::move (else_expr), std::move (outer_attrs), locus));
4925 12943 : }
4926 :
4927 : template <typename ManagedTokenSource>
4928 : tl::optional<AST::GenericArg>
4929 3843 : Parser<ManagedTokenSource>::parse_generic_arg ()
4930 : {
4931 3843 : auto tok = lexer.peek_token ();
4932 3843 : std::unique_ptr<AST::Expr> expr = nullptr;
4933 :
4934 3843 : switch (tok->get_id ())
4935 : {
4936 2476 : case IDENTIFIER:
4937 : {
4938 : // This is a bit of a weird situation: With an identifier token, we
4939 : // could either have a valid type or a macro (FIXME: anything else?). So
4940 : // we need one bit of lookahead to differentiate if this is really
4941 2476 : auto next_tok = lexer.peek_token (1);
4942 2476 : if (next_tok->get_id () == LEFT_ANGLE
4943 2465 : || next_tok->get_id () == SCOPE_RESOLUTION
4944 4938 : || next_tok->get_id () == EXCLAM)
4945 : {
4946 22 : auto type = parse_type ();
4947 22 : if (type)
4948 22 : return AST::GenericArg::create_type (std::move (type));
4949 : else
4950 0 : return tl::nullopt;
4951 22 : }
4952 2454 : else if (next_tok->get_id () == COLON)
4953 : {
4954 1 : lexer.skip_token (); // skip ident
4955 1 : lexer.skip_token (); // skip colon
4956 :
4957 1 : auto tok = lexer.peek_token ();
4958 1 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
4959 : = parse_type_param_bounds ();
4960 :
4961 1 : auto type = std::unique_ptr<AST::TraitObjectType> (
4962 1 : new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
4963 : false));
4964 1 : if (type)
4965 1 : return AST::GenericArg::create_type (std::move (type));
4966 : else
4967 : return tl::nullopt;
4968 2 : }
4969 2453 : lexer.skip_token ();
4970 9812 : return AST::GenericArg::create_ambiguous (tok->get_str (),
4971 2453 : tok->get_locus ());
4972 2476 : }
4973 19 : case LEFT_CURLY:
4974 : {
4975 19 : auto res = parse_block_expr ();
4976 19 : if (res)
4977 19 : expr = std::move (res.value ());
4978 : else
4979 0 : return tl::nullopt;
4980 19 : }
4981 : break;
4982 91 : case MINUS:
4983 : case STRING_LITERAL:
4984 : case CHAR_LITERAL:
4985 : case INT_LITERAL:
4986 : case FLOAT_LITERAL:
4987 : case TRUE_LITERAL:
4988 : case FALSE_LITERAL:
4989 : {
4990 91 : auto res = parse_literal_expr ();
4991 91 : if (res)
4992 91 : expr = std::move (res.value ());
4993 : else
4994 0 : return tl::nullopt;
4995 91 : }
4996 : break;
4997 : // FIXME: Because of this, error reporting is garbage for const generic
4998 : // parameter's default values
4999 1257 : default:
5000 : {
5001 1257 : auto type = parse_type ();
5002 : // FIXME: Find a better way to do this?
5003 1257 : if (type)
5004 1256 : return AST::GenericArg::create_type (std::move (type));
5005 : else
5006 1 : return tl::nullopt;
5007 1257 : }
5008 : }
5009 :
5010 110 : if (!expr)
5011 0 : return tl::nullopt;
5012 :
5013 110 : return AST::GenericArg::create_const (std::move (expr));
5014 3843 : }
5015 :
5016 : // Parses the generic arguments in each path segment.
5017 : template <typename ManagedTokenSource>
5018 : AST::GenericArgs
5019 3643 : Parser<ManagedTokenSource>::parse_path_generic_args ()
5020 : {
5021 7286 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
5022 5 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
5023 :
5024 3643 : if (!skip_token (LEFT_ANGLE))
5025 : {
5026 : // skip after somewhere?
5027 0 : return AST::GenericArgs::create_empty ();
5028 : }
5029 :
5030 : // We need to parse all lifetimes, then parse types and const generics in
5031 : // any order.
5032 :
5033 : // try to parse lifetimes first
5034 3643 : std::vector<AST::Lifetime> lifetime_args;
5035 :
5036 3643 : const_TokenPtr t = lexer.peek_token ();
5037 3643 : location_t locus = t->get_locus ();
5038 7292 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5039 : {
5040 3649 : auto lifetime = parse_lifetime (false);
5041 3649 : if (!lifetime)
5042 : {
5043 : // not necessarily an error
5044 : break;
5045 : }
5046 :
5047 41 : lifetime_args.push_back (std::move (lifetime.value ()));
5048 :
5049 : // if next token isn't comma, then it must be end of list
5050 82 : if (lexer.peek_token ()->get_id () != COMMA)
5051 : {
5052 : break;
5053 : }
5054 : // skip comma
5055 7 : lexer.skip_token ();
5056 :
5057 7 : t = lexer.peek_token ();
5058 : }
5059 :
5060 : // try to parse types and const generics second
5061 3643 : std::vector<AST::GenericArg> generic_args;
5062 :
5063 : // TODO: think of better control structure
5064 3643 : t = lexer.peek_token ();
5065 11074 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5066 : {
5067 : // FIXME: Is it fine to break if there is one binding? Can't there be
5068 : // bindings in between types?
5069 :
5070 : // ensure not binding being parsed as type accidently
5071 6213 : if (t->get_id () == IDENTIFIER
5072 6442 : && lexer.peek_token (1)->get_id () == EQUAL)
5073 : break;
5074 :
5075 3823 : auto arg = parse_generic_arg ();
5076 3823 : if (arg)
5077 : {
5078 3823 : generic_args.emplace_back (std::move (arg.value ()));
5079 : }
5080 :
5081 : // FIXME: Do we need to break if we encounter an error?
5082 :
5083 : // if next token isn't comma, then it must be end of list
5084 7646 : if (lexer.peek_token ()->get_id () != COMMA)
5085 : break;
5086 :
5087 : // skip comma
5088 287 : lexer.skip_token ();
5089 287 : t = lexer.peek_token ();
5090 : }
5091 :
5092 : // try to parse bindings third
5093 3643 : std::vector<AST::GenericArgsBinding> binding_args;
5094 :
5095 : // TODO: think of better control structure
5096 3643 : t = lexer.peek_token ();
5097 3716 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5098 : {
5099 73 : AST::GenericArgsBinding binding = parse_generic_args_binding ();
5100 73 : if (binding.is_error ())
5101 : {
5102 : // not necessarily an error
5103 : break;
5104 : }
5105 :
5106 73 : binding_args.push_back (std::move (binding));
5107 :
5108 : // if next token isn't comma, then it must be end of list
5109 146 : if (lexer.peek_token ()->get_id () != COMMA)
5110 : {
5111 : break;
5112 : }
5113 : // skip comma
5114 1 : lexer.skip_token ();
5115 :
5116 1 : t = lexer.peek_token ();
5117 : }
5118 :
5119 : // skip any trailing commas
5120 7286 : if (lexer.peek_token ()->get_id () == COMMA)
5121 0 : lexer.skip_token ();
5122 :
5123 3643 : if (!skip_generics_right_angle ())
5124 0 : return AST::GenericArgs::create_empty ();
5125 :
5126 3643 : lifetime_args.shrink_to_fit ();
5127 3643 : generic_args.shrink_to_fit ();
5128 3643 : binding_args.shrink_to_fit ();
5129 :
5130 3643 : return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
5131 3643 : std::move (binding_args), locus);
5132 7286 : }
5133 :
5134 : // Parses a binding in a generic args path segment.
5135 : template <typename ManagedTokenSource>
5136 : AST::GenericArgsBinding
5137 73 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
5138 : {
5139 73 : const_TokenPtr ident_tok = lexer.peek_token ();
5140 73 : if (ident_tok->get_id () != IDENTIFIER)
5141 : {
5142 : // allow non error-inducing use
5143 : // skip somewhere?
5144 0 : return AST::GenericArgsBinding::create_error ();
5145 : }
5146 73 : lexer.skip_token ();
5147 73 : Identifier ident{ident_tok};
5148 :
5149 73 : if (!skip_token (EQUAL))
5150 : {
5151 : // skip after somewhere?
5152 0 : return AST::GenericArgsBinding::create_error ();
5153 : }
5154 :
5155 : // parse type (required)
5156 73 : std::unique_ptr<AST::Type> type = parse_type ();
5157 73 : if (type == nullptr)
5158 : {
5159 : // skip somewhere?
5160 0 : return AST::GenericArgsBinding::create_error ();
5161 : }
5162 :
5163 146 : return AST::GenericArgsBinding (std::move (ident), std::move (type),
5164 146 : ident_tok->get_locus ());
5165 146 : }
5166 :
5167 : // Parses a self param. Also handles self param not existing.
5168 : template <typename ManagedTokenSource>
5169 : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
5170 18160 : Parser<ManagedTokenSource>::parse_self_param ()
5171 : {
5172 18160 : bool has_reference = false;
5173 18160 : AST::Lifetime lifetime = AST::Lifetime::elided ();
5174 :
5175 18160 : location_t locus = lexer.peek_token ()->get_locus ();
5176 :
5177 : // TODO: Feels off, find a better way to clearly express this
5178 72640 : std::vector<std::vector<TokenId>> ptrs
5179 : = {{ASTERISK, SELF} /* *self */,
5180 : {ASTERISK, CONST, SELF} /* *const self */,
5181 : {ASTERISK, MUT, SELF} /* *mut self */};
5182 :
5183 72634 : for (auto &s : ptrs)
5184 : {
5185 : size_t i = 0;
5186 54488 : for (i = 0; i < s.size (); i++)
5187 108970 : if (lexer.peek_token (i)->get_id () != s[i])
5188 : break;
5189 54477 : if (i == s.size ())
5190 : {
5191 3 : Error error (lexer.peek_token ()->get_locus (),
5192 : "cannot pass %<self%> by raw pointer");
5193 3 : add_error (std::move (error));
5194 3 : return Parse::Error::Self::make_self_raw_pointer ();
5195 3 : }
5196 : }
5197 :
5198 : // Trying to find those patterns:
5199 : //
5200 : // &'lifetime mut self
5201 : // &'lifetime self
5202 : // & mut self
5203 : // & self
5204 : // mut self
5205 : // self
5206 : //
5207 : // If not found, it is probably a function, exit and let function parsing
5208 : // handle it.
5209 : bool is_self = false;
5210 108942 : for (size_t i = 0; i < 5; i++)
5211 181570 : if (lexer.peek_token (i)->get_id () == SELF)
5212 7807 : is_self = true;
5213 :
5214 18157 : if (!is_self)
5215 : return Parse::Error::Self::make_not_self ();
5216 :
5217 : // test if self is a reference parameter
5218 15608 : if (lexer.peek_token ()->get_id () == AMP)
5219 : {
5220 4638 : has_reference = true;
5221 4638 : lexer.skip_token ();
5222 :
5223 : // now test whether it has a lifetime
5224 9276 : if (lexer.peek_token ()->get_id () == LIFETIME)
5225 : {
5226 : // something went wrong somehow
5227 4 : if (auto parsed_lifetime = parse_lifetime (true))
5228 : {
5229 2 : lifetime = parsed_lifetime.value ();
5230 : }
5231 : else
5232 : {
5233 0 : Error error (lexer.peek_token ()->get_locus (),
5234 : "failed to parse lifetime in self param");
5235 0 : add_error (std::move (error));
5236 :
5237 : // skip after somewhere?
5238 0 : return Parse::Error::Self::make_parsing_error ();
5239 0 : }
5240 : }
5241 : }
5242 :
5243 : // test for mut
5244 7804 : bool has_mut = false;
5245 15608 : if (lexer.peek_token ()->get_id () == MUT)
5246 : {
5247 348 : has_mut = true;
5248 348 : lexer.skip_token ();
5249 : }
5250 :
5251 : // skip self token
5252 7804 : const_TokenPtr self_tok = lexer.peek_token ();
5253 7804 : if (self_tok->get_id () != SELF)
5254 : {
5255 : // skip after somewhere?
5256 : return Parse::Error::Self::make_not_self ();
5257 : }
5258 7802 : lexer.skip_token ();
5259 :
5260 : // parse optional type
5261 7802 : std::unique_ptr<AST::Type> type = nullptr;
5262 15604 : if (lexer.peek_token ()->get_id () == COLON)
5263 : {
5264 1 : lexer.skip_token ();
5265 :
5266 : // type is now required
5267 1 : type = parse_type ();
5268 1 : if (type == nullptr)
5269 : {
5270 0 : Error error (lexer.peek_token ()->get_locus (),
5271 : "could not parse type in self param");
5272 0 : add_error (std::move (error));
5273 :
5274 : // skip after somewhere?
5275 0 : return Parse::Error::Self::make_parsing_error ();
5276 0 : }
5277 : }
5278 :
5279 : // ensure that cannot have both type and reference
5280 7802 : if (type && has_reference)
5281 : {
5282 0 : Error error (
5283 0 : lexer.peek_token ()->get_locus (),
5284 : "cannot have both a reference and a type specified in a self param");
5285 0 : add_error (std::move (error));
5286 :
5287 : // skip after somewhere?
5288 0 : return Parse::Error::Self::make_parsing_error ();
5289 0 : }
5290 :
5291 7802 : if (has_reference)
5292 : {
5293 4638 : return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
5294 4638 : locus);
5295 : }
5296 : else
5297 : {
5298 : // note that type may be nullptr here and that's fine
5299 3164 : return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
5300 3164 : locus);
5301 : }
5302 25962 : }
5303 :
5304 : /* Parses an expression or macro statement. */
5305 : template <typename ManagedTokenSource>
5306 : std::unique_ptr<AST::Stmt>
5307 324 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
5308 : ParseRestrictions restrictions)
5309 : {
5310 324 : location_t locus = lexer.peek_token ()->get_locus ();
5311 :
5312 324 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
5313 :
5314 648 : switch (lexer.peek_token ()->get_id ())
5315 : {
5316 220 : case IDENTIFIER:
5317 : case CRATE:
5318 : case SUPER:
5319 : case SELF:
5320 : case SELF_ALIAS:
5321 : case DOLLAR_SIGN:
5322 : case SCOPE_RESOLUTION:
5323 : {
5324 220 : AST::PathInExpression path = parse_path_in_expression ();
5325 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
5326 220 : null_denotation;
5327 :
5328 440 : if (lexer.peek_token ()->get_id () == EXCLAM)
5329 : {
5330 61 : std::unique_ptr<AST::MacroInvocation> invoc
5331 122 : = parse_macro_invocation_partial (std::move (path),
5332 : std::move (outer_attrs));
5333 :
5334 61 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
5335 : {
5336 59 : invoc->add_semicolon ();
5337 : // Macro invocation with semicolon.
5338 59 : return invoc;
5339 : }
5340 :
5341 2 : TokenId after_macro = lexer.peek_token ()->get_id ();
5342 :
5343 2 : if (restrictions.allow_close_after_expr_stmt
5344 2 : && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
5345 : || after_macro == RIGHT_SQUARE))
5346 2 : return invoc;
5347 :
5348 0 : if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
5349 : == AST::CURLY
5350 0 : && after_macro != DOT && after_macro != QUESTION_MARK)
5351 : {
5352 0 : rust_debug ("braced macro statement");
5353 0 : return invoc;
5354 : }
5355 :
5356 0 : null_denotation = std::move (invoc);
5357 61 : }
5358 : else
5359 : {
5360 : null_denotation
5361 318 : = null_denotation_path (std::move (path), {}, restrictions);
5362 : }
5363 :
5364 636 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
5365 : std::move (outer_attrs), restrictions);
5366 : break;
5367 220 : }
5368 104 : default:
5369 104 : restrictions.expr_can_be_stmt = true;
5370 208 : expr = parse_expr (std::move (outer_attrs), restrictions);
5371 104 : break;
5372 : }
5373 :
5374 263 : if (!expr)
5375 : {
5376 : // expr is required, error
5377 0 : Error error (lexer.peek_token ()->get_locus (),
5378 : "failed to parse expr in expr statement");
5379 0 : add_error (std::move (error));
5380 :
5381 0 : skip_after_semicolon ();
5382 0 : return nullptr;
5383 0 : }
5384 :
5385 263 : bool has_semi = false;
5386 :
5387 263 : if (restrictions.consume_semi)
5388 : {
5389 249 : if (maybe_skip_token (SEMICOLON))
5390 : {
5391 138 : has_semi = true;
5392 : }
5393 111 : else if (expr.value ()->is_expr_without_block ())
5394 : {
5395 10 : if (restrictions.allow_close_after_expr_stmt)
5396 : {
5397 10 : TokenId id = lexer.peek_token ()->get_id ();
5398 10 : if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
5399 : {
5400 3 : expect_token (SEMICOLON);
5401 3 : return nullptr;
5402 : }
5403 : }
5404 : else
5405 : {
5406 0 : expect_token (SEMICOLON);
5407 0 : return nullptr;
5408 : }
5409 : }
5410 : }
5411 :
5412 260 : return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
5413 260 : has_semi);
5414 324 : }
5415 :
5416 : // Parses a loop label used in loop expressions.
5417 : template <typename ManagedTokenSource>
5418 : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
5419 40 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
5420 : {
5421 : // parse lifetime - if doesn't exist, assume no label
5422 40 : if (tok->get_id () != LIFETIME)
5423 : {
5424 : // not necessarily an error
5425 : return Parse::Error::LoopLabel::make_not_loop_label ();
5426 : }
5427 : /* FIXME: check for named lifetime requirement here? or check in semantic
5428 : * analysis phase? */
5429 40 : AST::Lifetime label = lifetime_from_token (tok);
5430 :
5431 40 : if (!skip_token (COLON))
5432 : {
5433 : // skip somewhere?
5434 40 : Parse::Error::LoopLabel::make_missing_colon ();
5435 : }
5436 :
5437 : return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
5438 40 : AST::LoopLabel (std::move (label), tok->get_locus ()));
5439 40 : }
5440 :
5441 : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
5442 : template <typename ManagedTokenSource>
5443 : AST::MatchArm
5444 2138 : Parser<ManagedTokenSource>::parse_match_arm ()
5445 : {
5446 : // parse optional outer attributes
5447 2138 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5448 :
5449 : // DEBUG
5450 2138 : rust_debug ("about to start parsing match arm patterns");
5451 :
5452 : // break early if find right curly
5453 4276 : if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
5454 : {
5455 : // not an error
5456 0 : return AST::MatchArm::create_error ();
5457 : }
5458 :
5459 : // parse match arm patterns - at least 1 is required
5460 2138 : std::unique_ptr<AST::Pattern> match_arm_pattern
5461 : = parse_match_arm_pattern (RIGHT_CURLY);
5462 2138 : if (match_arm_pattern == nullptr)
5463 : {
5464 0 : Error error (lexer.peek_token ()->get_locus (),
5465 : "failed to parse any patterns in match arm");
5466 0 : add_error (std::move (error));
5467 :
5468 : // skip somewhere?
5469 0 : return AST::MatchArm::create_error ();
5470 0 : }
5471 :
5472 : // DEBUG
5473 2138 : rust_debug ("successfully parsed match arm patterns");
5474 :
5475 : // parse match arm guard expr if it exists
5476 2138 : std::unique_ptr<AST::Expr> guard_expr = nullptr;
5477 4276 : if (lexer.peek_token ()->get_id () == IF)
5478 : {
5479 1 : lexer.skip_token ();
5480 :
5481 1 : auto guard_expr_res = parse_expr ();
5482 1 : if (!guard_expr_res)
5483 : {
5484 0 : Error error (lexer.peek_token ()->get_locus (),
5485 : "failed to parse guard expression in match arm");
5486 0 : add_error (std::move (error));
5487 :
5488 : // skip somewhere?
5489 0 : return AST::MatchArm::create_error ();
5490 0 : }
5491 1 : guard_expr = std::move (guard_expr_res.value ());
5492 1 : }
5493 :
5494 : // DEBUG
5495 2138 : rust_debug ("successfully parsed match arm");
5496 :
5497 4276 : return AST::MatchArm (std::move (match_arm_pattern),
5498 4276 : lexer.peek_token ()->get_locus (),
5499 2138 : std::move (guard_expr), std::move (outer_attrs));
5500 2138 : }
5501 :
5502 : /* Parses the patterns used in a match arm. End token id is the id of the
5503 : * token that would exist after the patterns are done (e.g. '}' for match
5504 : * expr, '=' for if let and while let). */
5505 : template <typename ManagedTokenSource>
5506 : std::unique_ptr<AST::Pattern>
5507 2173 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
5508 : {
5509 : // skip optional leading '|'
5510 4346 : if (lexer.peek_token ()->get_id () == PIPE)
5511 0 : lexer.skip_token ();
5512 : /* TODO: do I even need to store the result of this? can't be used.
5513 : * If semantically different, I need a wrapped "match arm patterns" object
5514 : * for this. */
5515 :
5516 2173 : std::unique_ptr<AST::Pattern> pattern;
5517 :
5518 : // quick break out if end_token_id
5519 4346 : if (lexer.peek_token ()->get_id () == end_token_id)
5520 1 : return pattern;
5521 :
5522 : // parse required pattern - if doesn't exist, return empty
5523 2172 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
5524 2172 : if (initial_pattern == nullptr)
5525 : {
5526 : // FIXME: should this be an error?
5527 0 : return pattern;
5528 : }
5529 :
5530 2172 : return initial_pattern;
5531 2173 : }
5532 :
5533 : // Parses a single parameter used in a closure definition.
5534 : template <typename ManagedTokenSource>
5535 : AST::ClosureParam
5536 72 : Parser<ManagedTokenSource>::parse_closure_param ()
5537 : {
5538 72 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5539 :
5540 : // parse pattern (which is required)
5541 72 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
5542 72 : if (pattern == nullptr)
5543 : {
5544 : // not necessarily an error
5545 0 : return AST::ClosureParam::create_error ();
5546 : }
5547 :
5548 : // parse optional type of param
5549 72 : std::unique_ptr<AST::Type> type = nullptr;
5550 144 : if (lexer.peek_token ()->get_id () == COLON)
5551 : {
5552 63 : lexer.skip_token ();
5553 :
5554 : // parse type, which is now required
5555 63 : type = parse_type ();
5556 63 : if (type == nullptr)
5557 : {
5558 0 : Error error (lexer.peek_token ()->get_locus (),
5559 : "failed to parse type in closure parameter");
5560 0 : add_error (std::move (error));
5561 :
5562 : // skip somewhere?
5563 0 : return AST::ClosureParam::create_error ();
5564 0 : }
5565 : }
5566 :
5567 72 : location_t loc = pattern->get_locus ();
5568 72 : return AST::ClosureParam (std::move (pattern), loc, std::move (type),
5569 72 : std::move (outer_attrs));
5570 72 : }
5571 :
5572 : // Parses a type (will further disambiguate any type).
5573 : template <typename ManagedTokenSource>
5574 : std::unique_ptr<AST::Type>
5575 43414 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
5576 : {
5577 : /* rules for all types:
5578 : * NeverType: '!'
5579 : * SliceType: '[' Type ']'
5580 : * InferredType: '_'
5581 : * MacroInvocation: SimplePath '!' DelimTokenTree
5582 : * ParenthesisedType: '(' Type ')'
5583 : * ImplTraitType: 'impl' TypeParamBounds
5584 : * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
5585 : * TypeParamBound Lifetime | TraitBound
5586 : * ImplTraitTypeOneBound: 'impl' TraitBound
5587 : * TraitObjectType: 'dyn'? TypeParamBounds
5588 : * TraitObjectTypeOneBound: 'dyn'? TraitBound
5589 : * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
5590 : * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
5591 : * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
5592 : * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
5593 : * 'unsafe'?
5594 : * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
5595 : * (
5596 : * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
5597 : * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
5598 : * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
5599 : * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
5600 : * TupleType: '(' Type etc. - regular tuple stuff. Also
5601 : * regular tuple vs parenthesised precedence
5602 : *
5603 : * Disambiguate between macro and type path via type path being parsed, and
5604 : * then if '!' found, convert type path to simple path for macro. Usual
5605 : * disambiguation for tuple vs parenthesised. For ImplTraitType and
5606 : * TraitObjectType individual disambiguations, they seem more like "special
5607 : * cases", so probably just try to parse the more general ImplTraitType or
5608 : * TraitObjectType and return OneBound versions if they satisfy those
5609 : * criteria. */
5610 :
5611 43414 : const_TokenPtr t = lexer.peek_token ();
5612 43414 : switch (t->get_id ())
5613 : {
5614 47 : case EXCLAM:
5615 : // never type - can't be macro as no path beforehand
5616 47 : lexer.skip_token ();
5617 47 : return std::unique_ptr<AST::NeverType> (
5618 47 : new AST::NeverType (t->get_locus ()));
5619 858 : case LEFT_SQUARE:
5620 : // slice type or array type - requires further disambiguation
5621 858 : return parse_slice_or_array_type ();
5622 309 : case LEFT_SHIFT:
5623 : case LEFT_ANGLE:
5624 : {
5625 : // qualified path in type
5626 309 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
5627 309 : if (path.is_error ())
5628 : {
5629 0 : if (save_errors)
5630 : {
5631 0 : Error error (t->get_locus (),
5632 : "failed to parse qualified path in type");
5633 0 : add_error (std::move (error));
5634 0 : }
5635 :
5636 0 : return nullptr;
5637 : }
5638 309 : return std::unique_ptr<AST::QualifiedPathInType> (
5639 309 : new AST::QualifiedPathInType (std::move (path)));
5640 309 : }
5641 104 : case UNDERSCORE:
5642 : // inferred type
5643 104 : lexer.skip_token ();
5644 104 : return std::unique_ptr<AST::InferredType> (
5645 104 : new AST::InferredType (t->get_locus ()));
5646 2728 : case ASTERISK:
5647 : // raw pointer type
5648 2728 : return parse_raw_pointer_type ();
5649 4290 : case AMP: // does this also include AMP_AMP?
5650 : case LOGICAL_AND:
5651 : // reference type
5652 4290 : return parse_reference_type ();
5653 0 : case LIFETIME:
5654 : {
5655 : /* probably a lifetime bound, so probably type param bounds in
5656 : * TraitObjectType */
5657 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5658 : = parse_type_param_bounds ();
5659 :
5660 0 : return std::unique_ptr<AST::TraitObjectType> (
5661 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5662 0 : false));
5663 0 : }
5664 34461 : case IDENTIFIER:
5665 : case SUPER:
5666 : case SELF:
5667 : case SELF_ALIAS:
5668 : case CRATE:
5669 : case DOLLAR_SIGN:
5670 : case SCOPE_RESOLUTION:
5671 : {
5672 : // macro invocation or type path - requires further disambiguation.
5673 : /* for parsing path component of each rule, perhaps parse it as a
5674 : * typepath and attempt conversion to simplepath if a trailing '!' is
5675 : * found */
5676 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
5677 : * with it, it is exactly the same as a TypePath syntactically, so
5678 : * this is a syntactical ambiguity. As such, the parser will parse it
5679 : * as a TypePath. This, however, does not prevent TraitObjectType from
5680 : * starting with a typepath. */
5681 :
5682 : // parse path as type path
5683 34461 : AST::TypePath path = parse_type_path ();
5684 34461 : if (path.is_error ())
5685 : {
5686 0 : if (save_errors)
5687 : {
5688 0 : Error error (t->get_locus (),
5689 : "failed to parse path as first component of type");
5690 0 : add_error (std::move (error));
5691 0 : }
5692 :
5693 0 : return nullptr;
5694 : }
5695 34461 : location_t locus = path.get_locus ();
5696 :
5697 : // branch on next token
5698 34461 : t = lexer.peek_token ();
5699 34461 : switch (t->get_id ())
5700 : {
5701 29 : case EXCLAM:
5702 : {
5703 : // macro invocation
5704 : // convert to simple path
5705 29 : AST::SimplePath macro_path = path.as_simple_path ();
5706 29 : if (macro_path.is_empty ())
5707 : {
5708 0 : if (save_errors)
5709 : {
5710 0 : Error error (t->get_locus (),
5711 : "failed to parse simple path in macro "
5712 : "invocation (for type)");
5713 0 : add_error (std::move (error));
5714 0 : }
5715 :
5716 0 : return nullptr;
5717 : }
5718 :
5719 29 : lexer.skip_token ();
5720 :
5721 29 : auto tok_tree = parse_delim_token_tree ();
5722 29 : if (!tok_tree)
5723 0 : return nullptr;
5724 :
5725 87 : return AST::MacroInvocation::Regular (
5726 58 : AST::MacroInvocData (std::move (macro_path),
5727 29 : std::move (tok_tree.value ())),
5728 29 : {}, locus);
5729 58 : }
5730 0 : case PLUS:
5731 : {
5732 : // type param bounds
5733 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5734 :
5735 : // convert type path to trait bound
5736 0 : std::unique_ptr<AST::TraitBound> path_bound (
5737 0 : new AST::TraitBound (std::move (path), locus, false, false));
5738 0 : bounds.push_back (std::move (path_bound));
5739 :
5740 : /* parse rest of bounds - FIXME: better way to find when to stop
5741 : * parsing */
5742 0 : while (t->get_id () == PLUS)
5743 : {
5744 0 : lexer.skip_token ();
5745 :
5746 : // parse bound if it exists - if not, assume end of sequence
5747 0 : std::unique_ptr<AST::TypeParamBound> bound
5748 : = parse_type_param_bound ();
5749 0 : if (bound == nullptr)
5750 : {
5751 : break;
5752 : }
5753 0 : bounds.push_back (std::move (bound));
5754 :
5755 0 : t = lexer.peek_token ();
5756 : }
5757 :
5758 0 : return std::unique_ptr<AST::TraitObjectType> (
5759 0 : new AST::TraitObjectType (std::move (bounds), locus, false));
5760 0 : }
5761 34432 : default:
5762 : // assume that this is a type path and not an error
5763 34432 : return std::unique_ptr<AST::TypePath> (
5764 34432 : new AST::TypePath (std::move (path)));
5765 : }
5766 34461 : }
5767 400 : case LEFT_PAREN:
5768 : /* tuple type or parenthesised type - requires further disambiguation
5769 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
5770 : * could be TraitObjectTypeOneBound or TraitObjectType */
5771 400 : return parse_paren_prefixed_type ();
5772 3 : case FOR:
5773 : // TraitObjectTypeOneBound or BareFunctionType
5774 3 : return parse_for_prefixed_type ();
5775 61 : case ASYNC:
5776 : case CONST:
5777 : case UNSAFE:
5778 : case EXTERN_KW:
5779 : case FN_KW:
5780 : // bare function type (with no for lifetimes)
5781 61 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
5782 120 : case IMPL:
5783 120 : lexer.skip_token ();
5784 240 : if (lexer.peek_token ()->get_id () == LIFETIME)
5785 : {
5786 : /* cannot be one bound because lifetime prevents it from being
5787 : * traitbound */
5788 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5789 : = parse_type_param_bounds ();
5790 :
5791 0 : return std::unique_ptr<AST::ImplTraitType> (
5792 0 : new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
5793 0 : }
5794 : else
5795 : {
5796 : // should be trait bound, so parse trait bound
5797 120 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
5798 120 : if (initial_bound == nullptr)
5799 : {
5800 0 : if (save_errors)
5801 : {
5802 0 : Error error (lexer.peek_token ()->get_locus (),
5803 : "failed to parse ImplTraitType initial bound");
5804 0 : add_error (std::move (error));
5805 0 : }
5806 :
5807 0 : return nullptr;
5808 : }
5809 :
5810 120 : location_t locus = t->get_locus ();
5811 :
5812 : // short cut if next token isn't '+'
5813 120 : t = lexer.peek_token ();
5814 120 : if (t->get_id () != PLUS)
5815 : {
5816 120 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
5817 120 : new AST::ImplTraitTypeOneBound (std::move (initial_bound),
5818 120 : locus));
5819 : }
5820 :
5821 : // parse additional type param bounds
5822 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5823 0 : bounds.push_back (std::move (initial_bound));
5824 0 : while (t->get_id () == PLUS)
5825 : {
5826 0 : lexer.skip_token ();
5827 :
5828 : // parse bound if it exists
5829 0 : std::unique_ptr<AST::TypeParamBound> bound
5830 : = parse_type_param_bound ();
5831 0 : if (bound == nullptr)
5832 : {
5833 : // not an error as trailing plus may exist
5834 : break;
5835 : }
5836 0 : bounds.push_back (std::move (bound));
5837 :
5838 0 : t = lexer.peek_token ();
5839 : }
5840 :
5841 0 : return std::unique_ptr<AST::ImplTraitType> (
5842 0 : new AST::ImplTraitType (std::move (bounds), locus));
5843 120 : }
5844 29 : case DYN:
5845 : case QUESTION_MARK:
5846 : {
5847 : // either TraitObjectType or TraitObjectTypeOneBound
5848 29 : bool has_dyn = false;
5849 29 : if (t->get_id () == DYN)
5850 : {
5851 29 : lexer.skip_token ();
5852 29 : has_dyn = true;
5853 : }
5854 :
5855 58 : if (lexer.peek_token ()->get_id () == LIFETIME)
5856 : {
5857 : /* cannot be one bound because lifetime prevents it from being
5858 : * traitbound */
5859 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5860 : = parse_type_param_bounds ();
5861 :
5862 0 : return std::unique_ptr<AST::TraitObjectType> (
5863 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5864 0 : has_dyn));
5865 0 : }
5866 : else
5867 : {
5868 : // should be trait bound, so parse trait bound
5869 29 : std::unique_ptr<AST::TraitBound> initial_bound
5870 : = parse_trait_bound ();
5871 29 : if (initial_bound == nullptr)
5872 : {
5873 2 : if (save_errors)
5874 : {
5875 2 : Error error (
5876 2 : lexer.peek_token ()->get_locus (),
5877 : "failed to parse TraitObjectType initial bound");
5878 2 : add_error (std::move (error));
5879 2 : }
5880 :
5881 2 : return nullptr;
5882 : }
5883 :
5884 : // short cut if next token isn't '+'
5885 27 : t = lexer.peek_token ();
5886 27 : if (t->get_id () != PLUS)
5887 : {
5888 : // convert trait bound to value object
5889 14 : AST::TraitBound value_bound (*initial_bound);
5890 :
5891 : // DEBUG: removed as unique ptr, so should auto delete
5892 : // delete initial_bound;
5893 :
5894 14 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
5895 28 : new AST::TraitObjectTypeOneBound (std::move (value_bound),
5896 14 : t->get_locus (), has_dyn));
5897 14 : }
5898 :
5899 : // parse additional type param bounds
5900 13 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5901 13 : bounds.push_back (std::move (initial_bound));
5902 33 : while (t->get_id () == PLUS)
5903 : {
5904 20 : lexer.skip_token ();
5905 :
5906 : // parse bound if it exists
5907 20 : std::unique_ptr<AST::TypeParamBound> bound
5908 : = parse_type_param_bound ();
5909 20 : if (bound == nullptr)
5910 : {
5911 : // not an error as trailing plus may exist
5912 : break;
5913 : }
5914 20 : bounds.push_back (std::move (bound));
5915 :
5916 20 : t = lexer.peek_token ();
5917 : }
5918 :
5919 13 : return std::unique_ptr<AST::TraitObjectType> (
5920 13 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5921 13 : has_dyn));
5922 29 : }
5923 : }
5924 4 : default:
5925 4 : if (save_errors)
5926 4 : add_error (Error (t->get_locus (), "unrecognised token %qs in type",
5927 : t->get_token_description ()));
5928 :
5929 4 : return nullptr;
5930 : }
5931 43414 : }
5932 :
5933 : /* Parses a type that has '(' as its first character. Returns a tuple type,
5934 : * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
5935 : * on following characters. */
5936 : template <typename ManagedTokenSource>
5937 : std::unique_ptr<AST::Type>
5938 400 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
5939 : {
5940 : /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
5941 : * a trait bound, not a parenthesised type, so that it can still be used in
5942 : * type param bounds. */
5943 :
5944 : /* NOTE: this implementation is really shit but I couldn't think of a better
5945 : * one. It requires essentially breaking polymorphism and downcasting via
5946 : * virtual method abuse, as it was copied from the rustc implementation (in
5947 : * which types are reified due to tagged union), after a more OOP attempt by
5948 : * me failed. */
5949 400 : location_t left_delim_locus = lexer.peek_token ()->get_locus ();
5950 :
5951 : // skip left delim
5952 400 : lexer.skip_token ();
5953 : /* while next token isn't close delim, parse comma-separated types, saving
5954 : * whether trailing comma happens */
5955 400 : const_TokenPtr t = lexer.peek_token ();
5956 400 : bool trailing_comma = true;
5957 400 : std::vector<std::unique_ptr<AST::Type>> types;
5958 :
5959 727 : while (t->get_id () != RIGHT_PAREN)
5960 : {
5961 632 : std::unique_ptr<AST::Type> type = parse_type ();
5962 632 : if (type == nullptr)
5963 : {
5964 0 : Error error (t->get_locus (),
5965 : "failed to parse type inside parentheses (probably "
5966 : "tuple or parenthesised)");
5967 0 : add_error (std::move (error));
5968 :
5969 0 : return nullptr;
5970 0 : }
5971 632 : types.push_back (std::move (type));
5972 :
5973 632 : t = lexer.peek_token ();
5974 632 : if (t->get_id () != COMMA)
5975 : {
5976 305 : trailing_comma = false;
5977 : break;
5978 : }
5979 327 : lexer.skip_token ();
5980 :
5981 327 : t = lexer.peek_token ();
5982 : }
5983 :
5984 400 : if (!skip_token (RIGHT_PAREN))
5985 : {
5986 0 : return nullptr;
5987 : }
5988 :
5989 : // if only one type and no trailing comma, then not a tuple type
5990 400 : if (types.size () == 1 && !trailing_comma)
5991 : {
5992 : // must be a TraitObjectType (with more than one bound)
5993 10 : if (lexer.peek_token ()->get_id () == PLUS)
5994 : {
5995 : // create type param bounds vector
5996 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5997 :
5998 : // HACK: convert type to traitbound and add to bounds
5999 0 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6000 0 : std::unique_ptr<AST::TraitBound> converted_bound (
6001 0 : released_ptr->to_trait_bound (true));
6002 0 : if (converted_bound == nullptr)
6003 : {
6004 0 : Error error (
6005 0 : lexer.peek_token ()->get_locus (),
6006 : "failed to hackily converted parsed type to trait bound");
6007 0 : add_error (std::move (error));
6008 :
6009 0 : return nullptr;
6010 0 : }
6011 0 : bounds.push_back (std::move (converted_bound));
6012 :
6013 0 : t = lexer.peek_token ();
6014 0 : while (t->get_id () == PLUS)
6015 : {
6016 0 : lexer.skip_token ();
6017 :
6018 : // attempt to parse typeparambound
6019 0 : std::unique_ptr<AST::TypeParamBound> bound
6020 : = parse_type_param_bound ();
6021 0 : if (bound == nullptr)
6022 : {
6023 : // not an error if null
6024 : break;
6025 : }
6026 0 : bounds.push_back (std::move (bound));
6027 :
6028 0 : t = lexer.peek_token ();
6029 : }
6030 :
6031 0 : return std::unique_ptr<AST::TraitObjectType> (
6032 0 : new AST::TraitObjectType (std::move (bounds), left_delim_locus,
6033 0 : false));
6034 0 : }
6035 : else
6036 : {
6037 : // release vector pointer
6038 5 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6039 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6040 : * type */
6041 5 : std::unique_ptr<AST::TraitBound> converted_bound (
6042 5 : released_ptr->to_trait_bound (true));
6043 5 : if (converted_bound == nullptr)
6044 : {
6045 : // parenthesised type
6046 5 : return std::unique_ptr<AST::ParenthesisedType> (
6047 5 : new AST::ParenthesisedType (std::move (released_ptr),
6048 5 : left_delim_locus));
6049 : }
6050 : else
6051 : {
6052 : // trait object type (one bound)
6053 :
6054 : // get value semantics trait bound
6055 0 : AST::TraitBound value_bound (*converted_bound);
6056 :
6057 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6058 0 : new AST::TraitObjectTypeOneBound (value_bound,
6059 0 : left_delim_locus));
6060 0 : }
6061 5 : }
6062 : }
6063 : else
6064 : {
6065 395 : return std::unique_ptr<AST::TupleType> (
6066 395 : new AST::TupleType (std::move (types), left_delim_locus));
6067 : }
6068 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6069 : * lost somehow */
6070 400 : }
6071 :
6072 : /* Parses a type that has 'for' as its first character. This means it has a
6073 : * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
6074 : * TraitObjectTypeOneBound depending on following characters. */
6075 : template <typename ManagedTokenSource>
6076 : std::unique_ptr<AST::Type>
6077 3 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
6078 : {
6079 3 : location_t for_locus = lexer.peek_token ()->get_locus ();
6080 : // parse for lifetimes in type
6081 3 : std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
6082 :
6083 : // branch on next token - either function or a trait type
6084 3 : const_TokenPtr t = lexer.peek_token ();
6085 3 : switch (t->get_id ())
6086 : {
6087 3 : case ASYNC:
6088 : case CONST:
6089 : case UNSAFE:
6090 : case EXTERN_KW:
6091 : case FN_KW:
6092 3 : return parse_bare_function_type (std::move (for_lifetimes));
6093 0 : case SCOPE_RESOLUTION:
6094 : case IDENTIFIER:
6095 : case SUPER:
6096 : case SELF:
6097 : case SELF_ALIAS:
6098 : case CRATE:
6099 : case DOLLAR_SIGN:
6100 : {
6101 : // path, so trait type
6102 :
6103 : // parse type path to finish parsing trait bound
6104 0 : AST::TypePath path = parse_type_path ();
6105 :
6106 0 : t = lexer.peek_token ();
6107 0 : if (t->get_id () != PLUS)
6108 : {
6109 : // must be one-bound trait type
6110 : // create trait bound value object
6111 0 : AST::TraitBound bound (std::move (path), for_locus, false, false,
6112 : std::move (for_lifetimes));
6113 :
6114 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6115 0 : new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
6116 0 : }
6117 :
6118 : /* more than one bound trait type (or at least parsed as it - could be
6119 : * trailing '+') create trait bound pointer and bounds */
6120 0 : std::unique_ptr<AST::TraitBound> initial_bound (
6121 0 : new AST::TraitBound (std::move (path), for_locus, false, false,
6122 : std::move (for_lifetimes)));
6123 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6124 0 : bounds.push_back (std::move (initial_bound));
6125 :
6126 0 : while (t->get_id () == PLUS)
6127 : {
6128 0 : lexer.skip_token ();
6129 :
6130 : // parse type param bound if it exists
6131 0 : std::unique_ptr<AST::TypeParamBound> bound
6132 : = parse_type_param_bound ();
6133 0 : if (bound == nullptr)
6134 : {
6135 : // not an error - e.g. trailing plus
6136 0 : return nullptr;
6137 : }
6138 0 : bounds.push_back (std::move (bound));
6139 :
6140 0 : t = lexer.peek_token ();
6141 : }
6142 :
6143 0 : return std::unique_ptr<AST::TraitObjectType> (
6144 0 : new AST::TraitObjectType (std::move (bounds), for_locus, false));
6145 0 : }
6146 0 : default:
6147 : // error
6148 0 : add_error (Error (t->get_locus (),
6149 : "unrecognised token %qs in bare function type or trait "
6150 : "object type or trait object type one bound",
6151 : t->get_token_description ()));
6152 :
6153 0 : return nullptr;
6154 : }
6155 3 : }
6156 :
6157 : // Parses a maybe named param used in bare function types.
6158 : template <typename ManagedTokenSource>
6159 : AST::MaybeNamedParam
6160 48 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
6161 : {
6162 : /* Basically guess that param is named if first token is identifier or
6163 : * underscore and second token is semicolon. This should probably have no
6164 : * exceptions. rustc uses backtracking to parse these, but at the time of
6165 : * writing gccrs has no backtracking capabilities. */
6166 48 : const_TokenPtr current = lexer.peek_token ();
6167 48 : const_TokenPtr next = lexer.peek_token (1);
6168 :
6169 48 : Identifier name;
6170 48 : AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
6171 :
6172 48 : if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
6173 : {
6174 : // named param
6175 1 : name = {current};
6176 1 : kind = AST::MaybeNamedParam::IDENTIFIER;
6177 1 : lexer.skip_token (1);
6178 : }
6179 47 : else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
6180 : {
6181 : // wildcard param
6182 12 : name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
6183 6 : kind = AST::MaybeNamedParam::WILDCARD;
6184 6 : lexer.skip_token (1);
6185 : }
6186 :
6187 : // parse type (required)
6188 48 : std::unique_ptr<AST::Type> type = parse_type ();
6189 48 : if (type == nullptr)
6190 : {
6191 0 : Error error (lexer.peek_token ()->get_locus (),
6192 : "failed to parse type in maybe named param");
6193 0 : add_error (std::move (error));
6194 :
6195 0 : return AST::MaybeNamedParam::create_error ();
6196 0 : }
6197 :
6198 96 : return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
6199 48 : std::move (outer_attrs), current->get_locus ());
6200 96 : }
6201 :
6202 : /* Parses a bare function type (with the given for lifetimes for convenience -
6203 : * does not parse them itself). */
6204 : template <typename ManagedTokenSource>
6205 : std::unique_ptr<AST::BareFunctionType>
6206 66 : Parser<ManagedTokenSource>::parse_bare_function_type (
6207 : std::vector<AST::LifetimeParam> for_lifetimes)
6208 : {
6209 : // TODO: pass in for lifetime location as param
6210 66 : location_t best_try_locus = lexer.peek_token ()->get_locus ();
6211 :
6212 66 : AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
6213 :
6214 66 : if (!skip_token (FN_KW))
6215 0 : return nullptr;
6216 :
6217 66 : if (!skip_token (LEFT_PAREN))
6218 0 : return nullptr;
6219 :
6220 : // parse function params, if they exist
6221 66 : std::vector<AST::MaybeNamedParam> params;
6222 66 : bool is_variadic = false;
6223 66 : AST::AttrVec variadic_attrs;
6224 :
6225 66 : const_TokenPtr t = lexer.peek_token ();
6226 120 : while (t->get_id () != RIGHT_PAREN)
6227 : {
6228 48 : AST::AttrVec temp_attrs = parse_outer_attributes ();
6229 :
6230 96 : if (lexer.peek_token ()->get_id () == ELLIPSIS)
6231 : {
6232 0 : lexer.skip_token ();
6233 0 : is_variadic = true;
6234 0 : variadic_attrs = std::move (temp_attrs);
6235 :
6236 0 : t = lexer.peek_token ();
6237 :
6238 0 : if (t->get_id () != RIGHT_PAREN)
6239 : {
6240 0 : Error error (t->get_locus (),
6241 : "expected right parentheses after variadic in maybe "
6242 : "named function "
6243 : "parameters, found %qs",
6244 : t->get_token_description ());
6245 0 : add_error (std::move (error));
6246 :
6247 0 : return nullptr;
6248 0 : }
6249 :
6250 : break;
6251 : }
6252 :
6253 48 : AST::MaybeNamedParam param
6254 48 : = parse_maybe_named_param (std::move (temp_attrs));
6255 48 : if (param.is_error ())
6256 : {
6257 0 : Error error (
6258 0 : lexer.peek_token ()->get_locus (),
6259 : "failed to parse maybe named param in bare function type");
6260 0 : add_error (std::move (error));
6261 :
6262 0 : return nullptr;
6263 0 : }
6264 48 : params.push_back (std::move (param));
6265 :
6266 96 : if (lexer.peek_token ()->get_id () != COMMA)
6267 : break;
6268 :
6269 6 : lexer.skip_token ();
6270 6 : t = lexer.peek_token ();
6271 : }
6272 :
6273 66 : if (!skip_token (RIGHT_PAREN))
6274 0 : return nullptr;
6275 :
6276 : // bare function return type, if exists
6277 66 : std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
6278 132 : if (lexer.peek_token ()->get_id () == RETURN_TYPE)
6279 : {
6280 53 : lexer.skip_token ();
6281 :
6282 : // parse required TypeNoBounds
6283 53 : return_type = parse_type_no_bounds ();
6284 53 : if (return_type == nullptr)
6285 : {
6286 0 : Error error (lexer.peek_token ()->get_locus (),
6287 : "failed to parse return type (type no bounds) in bare "
6288 : "function type");
6289 0 : add_error (std::move (error));
6290 :
6291 0 : return nullptr;
6292 0 : }
6293 : }
6294 :
6295 : return std::unique_ptr<AST::BareFunctionType> (
6296 66 : new AST::BareFunctionType (std::move (for_lifetimes),
6297 : std::move (qualifiers), std::move (params),
6298 : is_variadic, std::move (variadic_attrs),
6299 66 : std::move (return_type), best_try_locus));
6300 132 : }
6301 :
6302 : template <typename ManagedTokenSource>
6303 : std::unique_ptr<AST::ReferenceType>
6304 4314 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
6305 : {
6306 : // parse optional lifetime
6307 4314 : AST::Lifetime lifetime = AST::Lifetime::elided ();
6308 8628 : if (lexer.peek_token ()->get_id () == LIFETIME)
6309 : {
6310 468 : auto parsed_lifetime = parse_lifetime (true);
6311 468 : if (parsed_lifetime)
6312 : {
6313 468 : lifetime = parsed_lifetime.value ();
6314 : }
6315 : else
6316 : {
6317 0 : Error error (lexer.peek_token ()->get_locus (),
6318 : "failed to parse lifetime in reference type");
6319 0 : add_error (std::move (error));
6320 :
6321 0 : return nullptr;
6322 0 : }
6323 468 : }
6324 :
6325 4314 : bool is_mut = false;
6326 8628 : if (lexer.peek_token ()->get_id () == MUT)
6327 : {
6328 304 : lexer.skip_token ();
6329 304 : is_mut = true;
6330 : }
6331 :
6332 : // parse type no bounds, which is required
6333 4314 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6334 4314 : if (type == nullptr)
6335 : {
6336 0 : Error error (lexer.peek_token ()->get_locus (),
6337 : "failed to parse referenced type in reference type");
6338 0 : add_error (std::move (error));
6339 :
6340 0 : return nullptr;
6341 0 : }
6342 :
6343 : return std::unique_ptr<AST::ReferenceType> (
6344 12942 : new AST::ReferenceType (is_mut, std::move (type), locus,
6345 4314 : std::move (lifetime)));
6346 4314 : }
6347 :
6348 : // Parses a reference type (mutable or immutable, with given lifetime).
6349 : template <typename ManagedTokenSource>
6350 : std::unique_ptr<AST::ReferenceType>
6351 4314 : Parser<ManagedTokenSource>::parse_reference_type ()
6352 : {
6353 4314 : auto t = lexer.peek_token ();
6354 4314 : auto locus = t->get_locus ();
6355 :
6356 4314 : switch (t->get_id ())
6357 : {
6358 4300 : case AMP:
6359 4300 : skip_token (AMP);
6360 4300 : return parse_reference_type_inner (locus);
6361 14 : case LOGICAL_AND:
6362 14 : skip_token (LOGICAL_AND);
6363 : return std::unique_ptr<AST::ReferenceType> (
6364 42 : new AST::ReferenceType (false, parse_reference_type_inner (locus),
6365 14 : locus));
6366 0 : default:
6367 0 : rust_unreachable ();
6368 : }
6369 4314 : }
6370 :
6371 : // Parses a raw (unsafe) pointer type.
6372 : template <typename ManagedTokenSource>
6373 : std::unique_ptr<AST::RawPointerType>
6374 6540 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
6375 : {
6376 6540 : location_t locus = lexer.peek_token ()->get_locus ();
6377 6540 : skip_token (ASTERISK);
6378 :
6379 6540 : AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
6380 :
6381 : // branch on next token for pointer kind info
6382 6540 : const_TokenPtr t = lexer.peek_token ();
6383 6540 : switch (t->get_id ())
6384 : {
6385 721 : case MUT:
6386 721 : kind = AST::RawPointerType::MUT;
6387 721 : lexer.skip_token ();
6388 : break;
6389 5819 : case CONST:
6390 5819 : kind = AST::RawPointerType::CONST;
6391 5819 : lexer.skip_token ();
6392 : break;
6393 0 : default:
6394 0 : add_error (Error (t->get_locus (),
6395 : "unrecognised token %qs in raw pointer type",
6396 : t->get_token_description ()));
6397 :
6398 0 : return nullptr;
6399 : }
6400 :
6401 : // parse type no bounds (required)
6402 6540 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6403 6540 : if (type == nullptr)
6404 : {
6405 0 : Error error (lexer.peek_token ()->get_locus (),
6406 : "failed to parse pointed type of raw pointer type");
6407 0 : add_error (std::move (error));
6408 :
6409 0 : return nullptr;
6410 0 : }
6411 :
6412 : return std::unique_ptr<AST::RawPointerType> (
6413 6540 : new AST::RawPointerType (kind, std::move (type), locus));
6414 6540 : }
6415 :
6416 : /* Parses a slice or array type, depending on following arguments (as
6417 : * lookahead is not possible). */
6418 : template <typename ManagedTokenSource>
6419 : std::unique_ptr<AST::TypeNoBounds>
6420 1514 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
6421 : {
6422 1514 : location_t locus = lexer.peek_token ()->get_locus ();
6423 1514 : skip_token (LEFT_SQUARE);
6424 :
6425 : // parse inner type (required)
6426 1514 : std::unique_ptr<AST::Type> inner_type = parse_type ();
6427 1514 : if (inner_type == nullptr)
6428 : {
6429 0 : Error error (lexer.peek_token ()->get_locus (),
6430 : "failed to parse inner type in slice or array type");
6431 0 : add_error (std::move (error));
6432 :
6433 0 : return nullptr;
6434 0 : }
6435 :
6436 : // branch on next token
6437 1514 : const_TokenPtr t = lexer.peek_token ();
6438 1514 : switch (t->get_id ())
6439 : {
6440 842 : case RIGHT_SQUARE:
6441 : // slice type
6442 842 : lexer.skip_token ();
6443 :
6444 842 : return std::unique_ptr<AST::SliceType> (
6445 842 : new AST::SliceType (std::move (inner_type), locus));
6446 672 : case SEMICOLON:
6447 : {
6448 : // array type
6449 672 : lexer.skip_token ();
6450 :
6451 : // parse required array size expression
6452 672 : auto size = parse_anon_const ();
6453 :
6454 672 : if (!size)
6455 : {
6456 1 : Error error (lexer.peek_token ()->get_locus (),
6457 : "failed to parse size expression in array type");
6458 1 : add_error (std::move (error));
6459 :
6460 1 : return nullptr;
6461 1 : }
6462 :
6463 671 : if (!skip_token (RIGHT_SQUARE))
6464 : {
6465 0 : return nullptr;
6466 : }
6467 :
6468 671 : return std::unique_ptr<AST::ArrayType> (
6469 1331 : new AST::ArrayType (std::move (inner_type), std::move (*size),
6470 671 : locus));
6471 672 : }
6472 0 : default:
6473 : // error
6474 0 : add_error (
6475 0 : Error (t->get_locus (),
6476 : "unrecognised token %qs in slice or array type after inner type",
6477 : t->get_token_description ()));
6478 :
6479 0 : return nullptr;
6480 : }
6481 1514 : }
6482 :
6483 : // Parses a type, taking into account type boundary disambiguation.
6484 : template <typename ManagedTokenSource>
6485 : std::unique_ptr<AST::TypeNoBounds>
6486 16098 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
6487 : {
6488 16098 : const_TokenPtr t = lexer.peek_token ();
6489 16098 : switch (t->get_id ())
6490 : {
6491 1 : case EXCLAM:
6492 : // never type - can't be macro as no path beforehand
6493 1 : lexer.skip_token ();
6494 1 : return std::unique_ptr<AST::NeverType> (
6495 1 : new AST::NeverType (t->get_locus ()));
6496 656 : case LEFT_SQUARE:
6497 : // slice type or array type - requires further disambiguation
6498 656 : return parse_slice_or_array_type ();
6499 22 : case LEFT_SHIFT:
6500 : case LEFT_ANGLE:
6501 : {
6502 : // qualified path in type
6503 22 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
6504 22 : if (path.is_error ())
6505 : {
6506 0 : Error error (t->get_locus (),
6507 : "failed to parse qualified path in type");
6508 0 : add_error (std::move (error));
6509 :
6510 0 : return nullptr;
6511 0 : }
6512 22 : return std::unique_ptr<AST::QualifiedPathInType> (
6513 22 : new AST::QualifiedPathInType (std::move (path)));
6514 22 : }
6515 104 : case UNDERSCORE:
6516 : // inferred type
6517 104 : lexer.skip_token ();
6518 104 : return std::unique_ptr<AST::InferredType> (
6519 104 : new AST::InferredType (t->get_locus ()));
6520 3812 : case ASTERISK:
6521 : // raw pointer type
6522 3812 : return parse_raw_pointer_type ();
6523 24 : case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
6524 : case LOGICAL_AND:
6525 : // reference type
6526 24 : return parse_reference_type ();
6527 0 : case LIFETIME:
6528 : /* probably a lifetime bound, so probably type param bounds in
6529 : * TraitObjectType. this is not allowed, but detection here for error
6530 : * message */
6531 0 : add_error (Error (t->get_locus (),
6532 : "lifetime bounds (i.e. in type param bounds, in "
6533 : "TraitObjectType) are not allowed as TypeNoBounds"));
6534 :
6535 0 : return nullptr;
6536 11302 : case IDENTIFIER:
6537 : case SUPER:
6538 : case SELF:
6539 : case SELF_ALIAS:
6540 : case CRATE:
6541 : case DOLLAR_SIGN:
6542 : case SCOPE_RESOLUTION:
6543 : {
6544 : // macro invocation or type path - requires further disambiguation.
6545 : /* for parsing path component of each rule, perhaps parse it as a
6546 : * typepath and attempt conversion to simplepath if a trailing '!' is
6547 : * found */
6548 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
6549 : * with it, it is exactly the same as a TypePath syntactically, so
6550 : * this is a syntactical ambiguity. As such, the parser will parse it
6551 : * as a TypePath. This, however, does not prevent TraitObjectType from
6552 : * starting with a typepath. */
6553 :
6554 : // parse path as type path
6555 11302 : AST::TypePath path = parse_type_path ();
6556 11302 : if (path.is_error ())
6557 : {
6558 0 : Error error (
6559 : t->get_locus (),
6560 : "failed to parse path as first component of type no bounds");
6561 0 : add_error (std::move (error));
6562 :
6563 0 : return nullptr;
6564 0 : }
6565 11302 : location_t locus = path.get_locus ();
6566 :
6567 : // branch on next token
6568 11302 : t = lexer.peek_token ();
6569 11302 : switch (t->get_id ())
6570 : {
6571 1 : case EXCLAM:
6572 : {
6573 : // macro invocation
6574 : // convert to simple path
6575 1 : AST::SimplePath macro_path = path.as_simple_path ();
6576 1 : if (macro_path.is_empty ())
6577 : {
6578 0 : Error error (t->get_locus (),
6579 : "failed to parse simple path in macro "
6580 : "invocation (for type)");
6581 0 : add_error (std::move (error));
6582 :
6583 0 : return nullptr;
6584 0 : }
6585 :
6586 1 : lexer.skip_token ();
6587 :
6588 1 : auto tok_tree = parse_delim_token_tree ();
6589 1 : if (!tok_tree)
6590 0 : return nullptr;
6591 :
6592 3 : return AST::MacroInvocation::Regular (
6593 2 : AST::MacroInvocData (std::move (macro_path),
6594 1 : std::move (tok_tree.value ())),
6595 1 : {}, locus);
6596 2 : }
6597 11301 : default:
6598 : // assume that this is a type path and not an error
6599 11301 : return std::unique_ptr<AST::TypePath> (
6600 11301 : new AST::TypePath (std::move (path)));
6601 : }
6602 11302 : }
6603 18 : case LEFT_PAREN:
6604 : /* tuple type or parenthesised type - requires further disambiguation
6605 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
6606 : * could be TraitObjectTypeOneBound */
6607 18 : return parse_paren_prefixed_type_no_bounds ();
6608 2 : case FOR:
6609 : case ASYNC:
6610 : case CONST:
6611 : case UNSAFE:
6612 : case EXTERN_KW:
6613 : case FN_KW:
6614 : // bare function type (with no for lifetimes)
6615 2 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
6616 14 : case IMPL:
6617 14 : lexer.skip_token ();
6618 28 : if (lexer.peek_token ()->get_id () == LIFETIME)
6619 : {
6620 : /* cannot be one bound because lifetime prevents it from being
6621 : * traitbound not allowed as type no bounds, only here for error
6622 : * message */
6623 0 : Error error (
6624 0 : lexer.peek_token ()->get_locus (),
6625 : "lifetime (probably lifetime bound, in type param "
6626 : "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
6627 0 : add_error (std::move (error));
6628 :
6629 0 : return nullptr;
6630 0 : }
6631 : else
6632 : {
6633 : // should be trait bound, so parse trait bound
6634 14 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6635 14 : if (initial_bound == nullptr)
6636 : {
6637 0 : Error error (lexer.peek_token ()->get_locus (),
6638 : "failed to parse ImplTraitTypeOneBound bound");
6639 0 : add_error (std::move (error));
6640 :
6641 0 : return nullptr;
6642 0 : }
6643 :
6644 14 : location_t locus = t->get_locus ();
6645 :
6646 : // ensure not a trait with multiple bounds
6647 14 : t = lexer.peek_token ();
6648 14 : if (t->get_id () == PLUS)
6649 : {
6650 0 : Error error (t->get_locus (),
6651 : "plus after trait bound means an ImplTraitType, "
6652 : "which is not allowed as a TypeNoBounds");
6653 0 : add_error (std::move (error));
6654 :
6655 0 : return nullptr;
6656 0 : }
6657 :
6658 14 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6659 14 : new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
6660 14 : }
6661 143 : case DYN:
6662 : case QUESTION_MARK:
6663 : {
6664 : // either TraitObjectTypeOneBound
6665 143 : bool has_dyn = false;
6666 143 : if (t->get_id () == DYN)
6667 : {
6668 143 : lexer.skip_token ();
6669 143 : has_dyn = true;
6670 : }
6671 :
6672 286 : if (lexer.peek_token ()->get_id () == LIFETIME)
6673 : {
6674 : /* means that cannot be TraitObjectTypeOneBound - so here for
6675 : * error message */
6676 0 : Error error (lexer.peek_token ()->get_locus (),
6677 : "lifetime as bound in TraitObjectTypeOneBound "
6678 : "is not allowed, so cannot be TypeNoBounds");
6679 0 : add_error (std::move (error));
6680 :
6681 0 : return nullptr;
6682 0 : }
6683 :
6684 : // should be trait bound, so parse trait bound
6685 143 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6686 143 : if (initial_bound == nullptr)
6687 : {
6688 0 : Error error (
6689 0 : lexer.peek_token ()->get_locus (),
6690 : "failed to parse TraitObjectTypeOneBound initial bound");
6691 0 : add_error (std::move (error));
6692 :
6693 0 : return nullptr;
6694 0 : }
6695 :
6696 143 : location_t locus = t->get_locus ();
6697 :
6698 : // detect error with plus as next token
6699 143 : t = lexer.peek_token ();
6700 143 : if (t->get_id () == PLUS)
6701 : {
6702 0 : Error error (t->get_locus (),
6703 : "plus after trait bound means a TraitObjectType, "
6704 : "which is not allowed as a TypeNoBounds");
6705 0 : add_error (std::move (error));
6706 :
6707 0 : return nullptr;
6708 0 : }
6709 :
6710 : // convert trait bound to value object
6711 143 : AST::TraitBound value_bound (*initial_bound);
6712 :
6713 143 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6714 286 : new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
6715 143 : has_dyn));
6716 143 : }
6717 0 : default:
6718 0 : add_error (Error (t->get_locus (),
6719 : "unrecognised token %qs in type no bounds",
6720 : t->get_token_description ()));
6721 :
6722 0 : return nullptr;
6723 : }
6724 16098 : }
6725 :
6726 : // Parses a type no bounds beginning with '('.
6727 : template <typename ManagedTokenSource>
6728 : std::unique_ptr<AST::TypeNoBounds>
6729 18 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
6730 : {
6731 : /* NOTE: this could probably be parsed without the HACK solution of
6732 : * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
6733 :
6734 : /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
6735 : * considered a trait bound, not a parenthesised type, so that it can still
6736 : * be used in type param bounds. */
6737 :
6738 18 : location_t left_paren_locus = lexer.peek_token ()->get_locus ();
6739 :
6740 : // skip left delim
6741 18 : lexer.skip_token ();
6742 : /* while next token isn't close delim, parse comma-separated types, saving
6743 : * whether trailing comma happens */
6744 18 : const_TokenPtr t = lexer.peek_token ();
6745 18 : bool trailing_comma = true;
6746 18 : std::vector<std::unique_ptr<AST::Type>> types;
6747 :
6748 18 : while (t->get_id () != RIGHT_PAREN)
6749 : {
6750 2 : std::unique_ptr<AST::Type> type = parse_type ();
6751 2 : if (type == nullptr)
6752 : {
6753 0 : Error error (t->get_locus (),
6754 : "failed to parse type inside parentheses (probably "
6755 : "tuple or parenthesised)");
6756 0 : add_error (std::move (error));
6757 :
6758 0 : return nullptr;
6759 0 : }
6760 2 : types.push_back (std::move (type));
6761 :
6762 2 : t = lexer.peek_token ();
6763 2 : if (t->get_id () != COMMA)
6764 : {
6765 2 : trailing_comma = false;
6766 : break;
6767 : }
6768 0 : lexer.skip_token ();
6769 :
6770 0 : t = lexer.peek_token ();
6771 : }
6772 :
6773 18 : if (!skip_token (RIGHT_PAREN))
6774 : {
6775 0 : return nullptr;
6776 : }
6777 :
6778 : // if only one type and no trailing comma, then not a tuple type
6779 18 : if (types.size () == 1 && !trailing_comma)
6780 : {
6781 : // must be a TraitObjectType (with more than one bound)
6782 4 : if (lexer.peek_token ()->get_id () == PLUS)
6783 : {
6784 : // error - this is not allowed for type no bounds
6785 0 : Error error (lexer.peek_token ()->get_locus (),
6786 : "plus (implying TraitObjectType as type param "
6787 : "bounds) is not allowed in type no bounds");
6788 0 : add_error (std::move (error));
6789 :
6790 0 : return nullptr;
6791 0 : }
6792 : else
6793 : {
6794 : // release vector pointer
6795 2 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6796 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6797 : * type */
6798 2 : std::unique_ptr<AST::TraitBound> converted_bound (
6799 2 : released_ptr->to_trait_bound (true));
6800 2 : if (converted_bound == nullptr)
6801 : {
6802 : // parenthesised type
6803 2 : return std::unique_ptr<AST::ParenthesisedType> (
6804 2 : new AST::ParenthesisedType (std::move (released_ptr),
6805 2 : left_paren_locus));
6806 : }
6807 : else
6808 : {
6809 : // trait object type (one bound)
6810 :
6811 : // get value semantics trait bound
6812 0 : AST::TraitBound value_bound (*converted_bound);
6813 :
6814 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6815 0 : new AST::TraitObjectTypeOneBound (value_bound,
6816 0 : left_paren_locus));
6817 0 : }
6818 2 : }
6819 : }
6820 : else
6821 : {
6822 16 : return std::unique_ptr<AST::TupleType> (
6823 16 : new AST::TupleType (std::move (types), left_paren_locus));
6824 : }
6825 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6826 : * lost somehow */
6827 18 : }
6828 :
6829 : // Parses tuple struct items if they exist. Does not parse parentheses.
6830 : template <typename ManagedTokenSource>
6831 : std::unique_ptr<AST::TupleStructItems>
6832 924 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
6833 : {
6834 924 : std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
6835 :
6836 : // DEBUG
6837 924 : rust_debug ("started parsing tuple struct items");
6838 :
6839 : // check for '..' at front
6840 1848 : if (lexer.peek_token ()->get_id () == DOT_DOT)
6841 : {
6842 : // only parse upper patterns
6843 16 : lexer.skip_token ();
6844 :
6845 : // DEBUG
6846 16 : rust_debug ("'..' at front in tuple struct items detected");
6847 :
6848 16 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
6849 :
6850 16 : const_TokenPtr t = lexer.peek_token ();
6851 33 : while (t->get_id () == COMMA)
6852 : {
6853 17 : lexer.skip_token ();
6854 :
6855 : // break if right paren
6856 34 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
6857 : break;
6858 :
6859 : // parse pattern, which is now required
6860 17 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6861 17 : if (pattern == nullptr)
6862 : {
6863 0 : Error error (lexer.peek_token ()->get_locus (),
6864 : "failed to parse pattern in tuple struct items");
6865 0 : add_error (std::move (error));
6866 :
6867 0 : return nullptr;
6868 0 : }
6869 17 : upper_patterns.push_back (std::move (pattern));
6870 :
6871 17 : t = lexer.peek_token ();
6872 : }
6873 :
6874 : // DEBUG
6875 16 : rust_debug (
6876 : "finished parsing tuple struct items ranged (upper/none only)");
6877 :
6878 16 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
6879 16 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
6880 16 : std::move (upper_patterns)));
6881 16 : }
6882 :
6883 : // has at least some lower patterns
6884 908 : const_TokenPtr t = lexer.peek_token ();
6885 1863 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
6886 : {
6887 : // DEBUG
6888 955 : rust_debug ("about to parse pattern in tuple struct items");
6889 :
6890 : // parse pattern, which is required
6891 955 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6892 955 : if (pattern == nullptr)
6893 : {
6894 0 : Error error (t->get_locus (),
6895 : "failed to parse pattern in tuple struct items");
6896 0 : add_error (std::move (error));
6897 :
6898 0 : return nullptr;
6899 0 : }
6900 955 : lower_patterns.push_back (std::move (pattern));
6901 :
6902 : // DEBUG
6903 955 : rust_debug ("successfully parsed pattern in tuple struct items");
6904 :
6905 1910 : if (lexer.peek_token ()->get_id () != COMMA)
6906 : {
6907 : // DEBUG
6908 862 : rust_debug ("broke out of parsing patterns in tuple struct "
6909 : "items as no comma");
6910 :
6911 : break;
6912 : }
6913 93 : lexer.skip_token ();
6914 93 : t = lexer.peek_token ();
6915 : }
6916 :
6917 : // branch on next token
6918 908 : t = lexer.peek_token ();
6919 908 : switch (t->get_id ())
6920 : {
6921 884 : case RIGHT_PAREN:
6922 884 : return std::unique_ptr<AST::TupleStructItemsNoRest> (
6923 884 : new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
6924 23 : case DOT_DOT:
6925 : {
6926 : // has an upper range that must be parsed separately
6927 23 : lexer.skip_token ();
6928 :
6929 23 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
6930 :
6931 23 : t = lexer.peek_token ();
6932 25 : while (t->get_id () == COMMA)
6933 : {
6934 2 : lexer.skip_token ();
6935 :
6936 : // break if next token is right paren
6937 4 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
6938 : break;
6939 :
6940 : // parse pattern, which is required
6941 2 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6942 2 : if (pattern == nullptr)
6943 : {
6944 0 : Error error (lexer.peek_token ()->get_locus (),
6945 : "failed to parse pattern in tuple struct items");
6946 0 : add_error (std::move (error));
6947 :
6948 0 : return nullptr;
6949 0 : }
6950 2 : upper_patterns.push_back (std::move (pattern));
6951 :
6952 2 : t = lexer.peek_token ();
6953 : }
6954 :
6955 23 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
6956 23 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
6957 23 : std::move (upper_patterns)));
6958 23 : }
6959 1 : default:
6960 : // error
6961 1 : add_error (Error (t->get_locus (),
6962 : "unexpected token %qs in tuple struct items",
6963 : t->get_token_description ()));
6964 :
6965 1 : return nullptr;
6966 : }
6967 924 : }
6968 :
6969 : /* Parses a statement or expression (depending on whether a trailing semicolon
6970 : * exists). Useful for block expressions where it cannot be determined through
6971 : * lookahead whether it is a statement or expression to be parsed. */
6972 : template <typename ManagedTokenSource>
6973 : tl::expected<ExprOrStmt, Parse::Error::Node>
6974 38768 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
6975 : {
6976 : // quick exit for empty statement
6977 38768 : const_TokenPtr t = lexer.peek_token ();
6978 38768 : if (t->get_id () == SEMICOLON)
6979 : {
6980 18 : lexer.skip_token ();
6981 18 : std::unique_ptr<AST::EmptyStmt> stmt (
6982 18 : new AST::EmptyStmt (t->get_locus ()));
6983 36 : return ExprOrStmt (std::move (stmt));
6984 18 : }
6985 :
6986 : // parse outer attributes
6987 38750 : AST::AttrVec outer_attrs = parse_outer_attributes ();
6988 38750 : ParseRestrictions restrictions;
6989 38750 : restrictions.expr_can_be_stmt = true;
6990 :
6991 : // Defered child error checking: we need to check for a semicolon
6992 38750 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
6993 :
6994 : // parsing this will be annoying because of the many different possibilities
6995 : /* best may be just to copy paste in parse_item switch, and failing that try
6996 : * to parse outer attributes, and then pass them in to either a let
6997 : * statement or (fallback) expression statement. */
6998 : // FIXME: think of a way to do this without such a large switch?
6999 :
7000 : /* FIXME: for expressions at least, the only way that they can really be
7001 : * parsed properly in this way is if they don't support operators on them.
7002 : * They must be pratt-parsed otherwise. As such due to composability, only
7003 : * explicit statements will have special cases here. This should roughly
7004 : * correspond to "expr-with-block", but this warning is here in case it
7005 : * isn't the case. */
7006 38750 : t = lexer.peek_token ();
7007 38750 : switch (t->get_id ())
7008 : {
7009 12743 : case LET:
7010 : {
7011 : // let statement
7012 12743 : std::unique_ptr<AST::LetStmt> stmt (
7013 12743 : parse_let_stmt (std::move (outer_attrs)));
7014 25486 : return ExprOrStmt (std::move (stmt));
7015 12743 : }
7016 344 : case PUB:
7017 : case MOD:
7018 : case EXTERN_KW:
7019 : case USE:
7020 : case FN_KW:
7021 : case TYPE:
7022 : case STRUCT_KW:
7023 : case ENUM_KW:
7024 : case CONST:
7025 : case STATIC_KW:
7026 : case AUTO:
7027 : case TRAIT:
7028 : case IMPL:
7029 : {
7030 344 : std::unique_ptr<AST::VisItem> item (
7031 344 : parse_vis_item (std::move (outer_attrs)));
7032 688 : return ExprOrStmt (std::move (item));
7033 344 : }
7034 : /* TODO: implement union keyword but not really because of
7035 : * context-dependence crappy hack way to parse a union written below to
7036 : * separate it from the good code. */
7037 : // case UNION:
7038 3080 : case UNSAFE:
7039 : { // maybe - unsafe traits are a thing
7040 : /* if any of these (should be all possible VisItem prefixes), parse a
7041 : * VisItem - can't parse item because would require reparsing outer
7042 : * attributes */
7043 3080 : const_TokenPtr t2 = lexer.peek_token (1);
7044 3080 : switch (t2->get_id ())
7045 : {
7046 3066 : case LEFT_CURLY:
7047 : {
7048 : // unsafe block: parse as expression
7049 6132 : expr = parse_expr (std::move (outer_attrs), restrictions);
7050 : break;
7051 : }
7052 0 : case AUTO:
7053 : case TRAIT:
7054 : {
7055 : // unsafe trait
7056 0 : std::unique_ptr<AST::VisItem> item (
7057 0 : parse_vis_item (std::move (outer_attrs)));
7058 0 : return ExprOrStmt (std::move (item));
7059 0 : }
7060 14 : case EXTERN_KW:
7061 : case FN_KW:
7062 : {
7063 : // unsafe function
7064 14 : std::unique_ptr<AST::VisItem> item (
7065 14 : parse_vis_item (std::move (outer_attrs)));
7066 28 : return ExprOrStmt (std::move (item));
7067 14 : }
7068 0 : case IMPL:
7069 : {
7070 : // unsafe trait impl
7071 0 : std::unique_ptr<AST::VisItem> item (
7072 0 : parse_vis_item (std::move (outer_attrs)));
7073 0 : return ExprOrStmt (std::move (item));
7074 0 : }
7075 0 : default:
7076 0 : add_error (Error (t2->get_locus (),
7077 : "unrecognised token %qs after parsing unsafe - "
7078 : "expected beginning of expression or statement",
7079 : t->get_token_description ()));
7080 :
7081 : // skip somewhere?
7082 : return tl::unexpected<Parse::Error::Node> (
7083 0 : Parse::Error::Node::MALFORMED);
7084 : }
7085 : break;
7086 3080 : }
7087 : /* FIXME: this is either a macro invocation or macro invocation semi.
7088 : * start parsing to determine which one it is. */
7089 : // FIXME: old code there
7090 :
7091 : // crappy hack to do union "keyword"
7092 12268 : case IDENTIFIER:
7093 21908 : if (t->get_str () == Values::WeakKeywords::UNION
7094 12304 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
7095 : {
7096 1 : std::unique_ptr<AST::VisItem> item (
7097 1 : parse_vis_item (std::move (outer_attrs)));
7098 2 : return ExprOrStmt (std::move (item));
7099 : // or should this go straight to parsing union?
7100 1 : }
7101 21906 : else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
7102 12274 : && lexer.peek_token (1)->get_id () == EXCLAM)
7103 : {
7104 : // macro_rules! macro item
7105 7 : std::unique_ptr<AST::Item> item (
7106 7 : parse_macro_rules_def (std::move (outer_attrs)));
7107 14 : return ExprOrStmt (std::move (item));
7108 7 : }
7109 : gcc_fallthrough ();
7110 : case SUPER:
7111 : case SELF:
7112 : case SELF_ALIAS:
7113 : case CRATE:
7114 : case SCOPE_RESOLUTION:
7115 : case DOLLAR_SIGN:
7116 : {
7117 14716 : AST::PathInExpression path = parse_path_in_expression ();
7118 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
7119 14716 : null_denotation;
7120 :
7121 29432 : if (lexer.peek_token ()->get_id () == EXCLAM)
7122 : {
7123 590 : std::unique_ptr<AST::MacroInvocation> invoc
7124 1180 : = parse_macro_invocation_partial (std::move (path),
7125 : std::move (outer_attrs));
7126 590 : if (invoc == nullptr)
7127 : return tl::unexpected<Parse::Error::Node> (
7128 0 : Parse::Error::Node::CHILD_ERROR);
7129 :
7130 590 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7131 : {
7132 398 : invoc->add_semicolon ();
7133 : // Macro invocation with semicolon.
7134 398 : return ExprOrStmt (
7135 796 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7136 : }
7137 :
7138 384 : TokenId after_macro = lexer.peek_token ()->get_id ();
7139 :
7140 192 : AST::DelimType delim_type = invoc->get_invoc_data ()
7141 192 : .get_delim_tok_tree ()
7142 192 : .get_delim_type ();
7143 :
7144 192 : if (delim_type == AST::CURLY && after_macro != DOT
7145 6 : && after_macro != QUESTION_MARK)
7146 : {
7147 6 : rust_debug ("braced macro statement");
7148 6 : return ExprOrStmt (
7149 12 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7150 : }
7151 :
7152 186 : null_denotation = std::move (invoc);
7153 590 : }
7154 : else
7155 : {
7156 : null_denotation
7157 28252 : = null_denotation_path (std::move (path), {}, restrictions);
7158 : }
7159 :
7160 57244 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7161 : std::move (outer_attrs), restrictions);
7162 : break;
7163 14716 : }
7164 7859 : default:
7165 : /* expression statement or expression itself - parse
7166 : * expression then make it statement if semi afterwards */
7167 15688 : expr = parse_expr (std::move (outer_attrs), restrictions);
7168 7859 : break;
7169 : }
7170 :
7171 25237 : const_TokenPtr after_expr = lexer.peek_token ();
7172 25237 : if (after_expr->get_id () == SEMICOLON)
7173 : {
7174 : // must be expression statement
7175 7648 : lexer.skip_token ();
7176 :
7177 7648 : if (expr)
7178 : {
7179 7647 : return ExprOrStmt (
7180 15294 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7181 22941 : t->get_locus (), true));
7182 : }
7183 : else
7184 : {
7185 : return tl::unexpected<Parse::Error::Node> (
7186 1 : Parse::Error::Node::CHILD_ERROR);
7187 : }
7188 : }
7189 :
7190 17589 : if (expr)
7191 : {
7192 : // block expression statement.
7193 17558 : if (!expr.value ()->is_expr_without_block ()
7194 17558 : && after_expr->get_id () != RIGHT_CURLY)
7195 1581 : return ExprOrStmt (
7196 3162 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7197 4743 : t->get_locus (), false));
7198 :
7199 : // Check if expr_without_block is properly terminated
7200 15977 : if (expr.value ()->is_expr_without_block ()
7201 15977 : && after_expr->get_id () != RIGHT_CURLY)
7202 : {
7203 : // expr_without_block must be followed by ';' or '}'
7204 1 : Error error (after_expr->get_locus (),
7205 : "expected %<;%> or %<}%> after expression, found %qs",
7206 : after_expr->get_token_description ());
7207 1 : add_error (std::move (error));
7208 : return tl::unexpected<Parse::Error::Node> (
7209 1 : Parse::Error::Node::MALFORMED);
7210 1 : }
7211 : }
7212 :
7213 : // return expression
7214 16007 : if (expr)
7215 31952 : return ExprOrStmt (std::move (expr.value ()));
7216 : else
7217 31 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
7218 63987 : }
7219 :
7220 : } // namespace Rust
7221 :
7222 : #include "rust-parse-impl-utils.hxx"
7223 : #include "rust-parse-impl-attribute.hxx"
7224 : #include "rust-parse-impl-ttree.hxx"
7225 : #include "rust-parse-impl-macro.hxx"
7226 : #include "rust-parse-impl-path.hxx"
7227 : #include "rust-parse-impl-pattern.hxx"
7228 : #include "rust-parse-impl-expr.hxx"
|