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