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