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 32118 : 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 32118 : const_TokenPtr tok = lexer.peek_token ();
75 32118 : switch (tok->get_id ())
76 : {
77 28132 : case RIGHT_ANGLE:
78 : // this is good - skip token
79 28132 : lexer.skip_token ();
80 28132 : return true;
81 3985 : case RIGHT_SHIFT:
82 : {
83 : // new implementation that should be better
84 3985 : lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
85 3985 : lexer.skip_token ();
86 3985 : 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 32118 : }
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 893030 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
118 : {
119 : // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
120 893030 : 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 : 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 51629 : case DOT:
149 103258 : if (lexer.peek_token (1)->get_id () == IDENTIFIER
150 94199 : && 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 250 : case QUESTION_MARK:
164 250 : return LBP_QUESTION_MARK;
165 :
166 10833 : case AS:
167 10833 : 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 4380 : case AMP:
188 4380 : return LBP_AMP;
189 :
190 : // binary ^ operator
191 164 : case CARET:
192 164 : return LBP_CARET;
193 :
194 : // binary | operator
195 3249 : case PIPE:
196 3249 : 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 1436 : case LOGICAL_AND:
212 1436 : return LBP_LOGICAL_AND;
213 :
214 615 : case OR:
215 615 : 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 779935 : default:
255 779935 : 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 5453 : Parser<ManagedTokenSource>::parse_items ()
272 : {
273 5453 : std::vector<std::unique_ptr<AST::Item>> items;
274 :
275 5453 : const_TokenPtr t = lexer.peek_token ();
276 33041 : while (t->get_id () != END_OF_FILE)
277 : {
278 27588 : auto item = parse_item (false);
279 27588 : if (!item)
280 84 : return Parse::Error::Items::make_malformed (std::move (items));
281 :
282 27504 : items.push_back (std::move (item.value ()));
283 :
284 27504 : 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 5369 : return items;
292 : #endif
293 5453 : }
294 :
295 : // Parses a crate (compilation unit) - entry point
296 : template <typename ManagedTokenSource>
297 : std::unique_ptr<AST::Crate>
298 5164 : Parser<ManagedTokenSource>::parse_crate ()
299 : {
300 : // parse inner attributes
301 5164 : AST::AttrVec inner_attrs = parse_inner_attributes ();
302 :
303 : // parse items
304 10328 : auto items
305 5164 : = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
306 :
307 : // emit all errors
308 5349 : for (const auto &error : error_table)
309 185 : error.emit ();
310 :
311 : return std::unique_ptr<AST::Crate> (
312 5164 : new AST::Crate (std::move (items), std::move (inner_attrs)));
313 5164 : }
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 13406 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
319 : {
320 13406 : const_TokenPtr t = lexer.peek_token ();
321 :
322 13406 : if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
323 : {
324 13391 : lexer.skip_token ();
325 13391 : return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
326 : }
327 : else
328 : {
329 15 : add_error (Error (t->get_locus (), "expected keyword or identifier"));
330 15 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
331 : }
332 13406 : }
333 :
334 : template <typename ManagedTokenSource>
335 : bool
336 5458 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
337 : {
338 5458 : auto macro_name = lexer.peek_token (2)->get_id ();
339 :
340 5458 : bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
341 :
342 5458 : return t->get_str () == Values::WeakKeywords::MACRO_RULES
343 5466 : && 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 44457 : 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 44457 : AST::AttrVec outer_attrs = parse_outer_attributes ();
363 44457 : const_TokenPtr t = lexer.peek_token ();
364 :
365 44457 : 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 39188 : 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 39188 : auto vis_item = parse_vis_item (std::move (outer_attrs));
403 39188 : if (!vis_item)
404 62 : return Parse::Error::Item::make_malformed ();
405 39126 : return RType{std::move (vis_item)};
406 39188 : }
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 5259 : case IDENTIFIER:
421 : // TODO: ensure std::string and literal comparison works
422 5259 : if (t->get_str () == Values::WeakKeywords::UNION
423 5326 : && 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 5192 : else if (t->get_str () == Values::WeakKeywords::DEFAULT
432 5194 : && 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 10382 : else if (is_macro_rules_def (t))
439 : {
440 : // macro_rules! macro item
441 1251 : auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
442 1251 : if (!macro_rule_def)
443 13 : return Parse::Error::Item::make_malformed ();
444 1238 : return RType{std::move (macro_rule_def)};
445 1251 : }
446 7880 : else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
447 7879 : || lexer.peek_token (1)->get_id () == EXCLAM)
448 : {
449 : /* path (probably) or macro invocation, so probably a macro invocation
450 : * semi */
451 3937 : auto macro_invocation_semi
452 3937 : = parse_macro_invocation_semi (std::move (outer_attrs));
453 3937 : if (!macro_invocation_semi)
454 1 : return Parse::Error::Item::make_malformed ();
455 3936 : return RType{std::move (macro_invocation_semi)};
456 3937 : }
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 44457 : }
470 :
471 : // Parses a VisItem (item that can have non-default visibility).
472 : template <typename ManagedTokenSource>
473 : std::unique_ptr<AST::VisItem>
474 40431 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
475 : {
476 : // parse visibility, which may or may not exist
477 40431 : auto vis_res = parse_visibility ();
478 40431 : if (!vis_res)
479 0 : return nullptr;
480 40431 : auto vis = vis_res.value ();
481 :
482 : // select VisItem to create depending on keyword
483 40431 : const_TokenPtr t = lexer.peek_token ();
484 :
485 40431 : switch (t->get_id ())
486 : {
487 1813 : case MOD:
488 1813 : return parse_module (std::move (vis), std::move (outer_attrs));
489 1851 : case EXTERN_KW:
490 : // lookahead to resolve syntactical production
491 1851 : t = lexer.peek_token (1);
492 :
493 1851 : switch (t->get_id ())
494 : {
495 70 : case CRATE:
496 70 : 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 1780 : case STRING_LITERAL: // for specifying extern ABI
502 : // could be extern block or extern function, so more lookahead
503 1780 : t = lexer.peek_token (2);
504 :
505 1780 : switch (t->get_id ())
506 : {
507 4 : case FN_KW:
508 4 : return parse_function (std::move (vis), std::move (outer_attrs));
509 1776 : case LEFT_CURLY:
510 1776 : return parse_extern_block (std::move (vis),
511 1776 : 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 2049 : case USE:
531 2049 : return parse_use_decl (std::move (vis), std::move (outer_attrs));
532 7323 : case FN_KW:
533 7323 : return parse_function (std::move (vis), std::move (outer_attrs));
534 111 : case TYPE:
535 111 : return parse_type_alias (std::move (vis), std::move (outer_attrs));
536 3821 : case STRUCT_KW:
537 3821 : return parse_struct (std::move (vis), std::move (outer_attrs));
538 656 : case ENUM_KW:
539 656 : 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 117 : case IDENTIFIER:
543 117 : if (t->get_str () == Values::WeakKeywords::UNION
544 233 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
545 : {
546 116 : 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 1199 : case CONST:
557 : // lookahead to resolve syntactical production
558 1199 : t = lexer.peek_token (1);
559 :
560 1199 : switch (t->get_id ())
561 : {
562 1075 : case IDENTIFIER:
563 : case UNDERSCORE:
564 1075 : 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 123 : case UNSAFE:
568 : case EXTERN_KW:
569 : case FN_KW:
570 123 : 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 4418 : case AUTO:
587 : case TRAIT:
588 4418 : return parse_trait (std::move (vis), std::move (outer_attrs));
589 12769 : case IMPL:
590 12769 : return parse_impl (std::move (vis), std::move (outer_attrs));
591 4114 : case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
592 : // lookahead to resolve syntactical production
593 4114 : t = lexer.peek_token (1);
594 :
595 4114 : switch (t->get_id ())
596 : {
597 84 : case AUTO:
598 : case TRAIT:
599 84 : return parse_trait (std::move (vis), std::move (outer_attrs));
600 3732 : case EXTERN_KW:
601 : case FN_KW:
602 3732 : return parse_function (std::move (vis), std::move (outer_attrs));
603 296 : case IMPL:
604 296 : 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 73 : case MACRO:
617 73 : 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 40431 : }
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 1770 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
664 : {
665 : // ensure that first token is identifier saying "macro_rules"
666 1770 : const_TokenPtr t = lexer.peek_token ();
667 1770 : if (t->get_id () != IDENTIFIER
668 1770 : || 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 1770 : lexer.skip_token ();
679 1770 : location_t macro_locus = t->get_locus ();
680 :
681 1770 : if (!skip_token (EXCLAM))
682 : {
683 : // skip after somewhere?
684 0 : return nullptr;
685 : }
686 :
687 : // parse macro name
688 1770 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
689 1770 : if (ident_tok == nullptr)
690 : {
691 1 : return nullptr;
692 : }
693 3538 : Identifier rule_name{ident_tok};
694 :
695 : // DEBUG
696 1769 : rust_debug ("in macro rules def, about to parse parens.");
697 :
698 : // save delim type to ensure it is reused later
699 1769 : AST::DelimType delim_type = AST::PARENS;
700 :
701 : // Map tokens to DelimType
702 1769 : t = lexer.peek_token ();
703 1769 : 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 1767 : case LEFT_CURLY:
712 1767 : delim_type = AST::CURLY;
713 1767 : 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 1769 : lexer.skip_token ();
723 :
724 : // parse actual macro rules
725 1769 : std::vector<AST::MacroRule> macro_rules;
726 :
727 : // must be at least one macro rule, so parse it
728 1769 : AST::MacroRule initial_rule = parse_macro_rule ();
729 1769 : 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 1757 : macro_rules.push_back (std::move (initial_rule));
740 :
741 : // DEBUG
742 1757 : rust_debug ("successfully pushed back initial macro rule");
743 :
744 1757 : t = lexer.peek_token ();
745 : // parse macro rules
746 1929 : while (t->get_id () == SEMICOLON)
747 : {
748 : // skip semicolon
749 1324 : lexer.skip_token ();
750 :
751 : // don't parse if end of macro rules
752 2648 : if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
753 : delim_type))
754 : {
755 : // DEBUG
756 1152 : rust_debug (
757 : "broke out of parsing macro rules loop due to finding delim");
758 :
759 1152 : break;
760 : }
761 :
762 : // try to parse next rule
763 172 : AST::MacroRule rule = parse_macro_rule ();
764 172 : 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 172 : macro_rules.push_back (std::move (rule));
774 :
775 : // DEBUG
776 172 : rust_debug ("successfully pushed back another macro rule");
777 :
778 172 : t = lexer.peek_token ();
779 : }
780 :
781 : // parse end delimiters
782 1757 : t = lexer.peek_token ();
783 1757 : if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
784 : {
785 : // tokens match opening delimiter, so skip.
786 1757 : lexer.skip_token ();
787 :
788 1757 : 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 3514 : AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
803 : std::move (macro_rules),
804 1757 : 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 5308 : }
823 :
824 : // Parses a declarative macro 2.0 definition.
825 : template <typename ManagedTokenSource>
826 : std::unique_ptr<AST::MacroRulesDefinition>
827 73 : 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 73 : const_TokenPtr t = lexer.peek_token ();
832 73 : 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 73 : lexer.skip_token ();
843 73 : location_t macro_locus = t->get_locus ();
844 :
845 : // parse macro name
846 73 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
847 73 : if (ident_tok == nullptr)
848 : {
849 0 : return nullptr;
850 : }
851 146 : Identifier rule_name{ident_tok};
852 :
853 73 : t = lexer.peek_token ();
854 73 : 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 48 : location_t locus = lexer.peek_token ()->get_locus ();
861 48 : AST::MacroMatcher matcher = parse_macro_matcher ();
862 48 : if (matcher.is_error ())
863 0 : return nullptr;
864 :
865 : // check delimiter of macro matcher
866 48 : 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 48 : location_t transcriber_loc = lexer.peek_token ()->get_locus ();
875 48 : auto delim_tok_tree = parse_delim_token_tree ();
876 48 : if (!delim_tok_tree)
877 0 : return nullptr;
878 :
879 48 : AST::MacroTranscriber transcriber (delim_tok_tree.value (),
880 : transcriber_loc);
881 :
882 48 : 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 47 : std::vector<AST::MacroRule> macro_rules;
893 47 : macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
894 : locus);
895 :
896 : return std::unique_ptr<AST::MacroRulesDefinition> (
897 94 : AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
898 : macro_rules,
899 : std::move (outer_attrs),
900 47 : macro_locus, vis));
901 143 : }
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 146 : }
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 77131 : Parser<ManagedTokenSource>::parse_visibility ()
991 : {
992 : // check for no visibility
993 154262 : if (lexer.peek_token ()->get_id () != PUB)
994 : {
995 60138 : return AST::Visibility::create_private ();
996 : }
997 :
998 16993 : auto vis_loc = lexer.peek_token ()->get_locus ();
999 16993 : lexer.skip_token ();
1000 :
1001 : // create simple pub visibility if
1002 : // - found no parentheses
1003 : // - found unit type `()`
1004 33986 : if (lexer.peek_token ()->get_id () != LEFT_PAREN
1005 17409 : || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
1006 : {
1007 16578 : return AST::Visibility::create_public (vis_loc);
1008 : // or whatever
1009 : }
1010 :
1011 415 : lexer.skip_token ();
1012 :
1013 415 : const_TokenPtr t = lexer.peek_token ();
1014 415 : auto path_loc = t->get_locus ();
1015 :
1016 415 : switch (t->get_id ())
1017 : {
1018 280 : case CRATE:
1019 280 : lexer.skip_token ();
1020 :
1021 280 : skip_token (RIGHT_PAREN);
1022 :
1023 280 : 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 115 : case SUPER:
1031 115 : lexer.skip_token ();
1032 :
1033 115 : skip_token (RIGHT_PAREN);
1034 :
1035 115 : 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 415 : }
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 1814 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
1070 : AST::AttrVec outer_attrs)
1071 : {
1072 1814 : location_t locus = lexer.peek_token ()->get_locus ();
1073 :
1074 1814 : Unsafety safety = Unsafety::Normal;
1075 3628 : if (lexer.peek_token ()->get_id () == UNSAFE)
1076 : {
1077 1 : safety = Unsafety::Unsafe;
1078 1 : skip_token (UNSAFE);
1079 : }
1080 :
1081 1814 : skip_token (MOD);
1082 :
1083 1814 : const_TokenPtr module_name = expect_token (IDENTIFIER);
1084 1814 : if (module_name == nullptr)
1085 : {
1086 0 : return nullptr;
1087 : }
1088 3628 : Identifier name{module_name};
1089 :
1090 1814 : const_TokenPtr t = lexer.peek_token ();
1091 :
1092 1814 : switch (t->get_id ())
1093 : {
1094 335 : case SEMICOLON:
1095 335 : lexer.skip_token ();
1096 :
1097 : // Construct an external module
1098 : return std::unique_ptr<AST::Module> (
1099 1005 : new AST::Module (std::move (name), std::move (vis),
1100 : std::move (outer_attrs), locus, safety,
1101 1005 : lexer.get_filename (), inline_module_stack));
1102 1479 : case LEFT_CURLY:
1103 : {
1104 1479 : lexer.skip_token ();
1105 :
1106 : // parse inner attributes
1107 1479 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1108 :
1109 1479 : std::string default_path = name.as_string ();
1110 :
1111 1479 : if (inline_module_stack.empty ())
1112 : {
1113 1058 : std::string filename = lexer.get_filename ();
1114 1058 : auto slash_idx = filename.rfind (file_separator);
1115 1058 : if (slash_idx == std::string::npos)
1116 : slash_idx = 0;
1117 : else
1118 1058 : slash_idx++;
1119 1058 : filename = filename.substr (slash_idx);
1120 :
1121 1058 : std::string subdir;
1122 1058 : if (get_file_subdir (filename, subdir))
1123 1045 : default_path = subdir + file_separator + name.as_string ();
1124 1058 : }
1125 :
1126 1479 : std::string module_path_name
1127 : = extract_module_path (inner_attrs, outer_attrs, default_path);
1128 1479 : InlineModuleStackScope scope (*this, std::move (module_path_name));
1129 :
1130 : // parse items
1131 1479 : std::vector<std::unique_ptr<AST::Item>> items;
1132 1479 : const_TokenPtr tok = lexer.peek_token ();
1133 6987 : while (tok->get_id () != RIGHT_CURLY)
1134 : {
1135 5508 : auto item = parse_item (false);
1136 5508 : 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 5507 : items.push_back (std::move (item.value ()));
1146 :
1147 5507 : tok = lexer.peek_token ();
1148 : }
1149 :
1150 1478 : if (!skip_token (RIGHT_CURLY))
1151 : {
1152 : // skip somewhere?
1153 0 : return nullptr;
1154 : }
1155 :
1156 : return std::unique_ptr<AST::Module> (
1157 1478 : new AST::Module (std::move (name), locus, std::move (items),
1158 : std::move (vis), safety, std::move (inner_attrs),
1159 1478 : std::move (outer_attrs))); // module name?
1160 1479 : }
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 1814 : }
1171 :
1172 : // Parses an extern crate declaration (dependency on external crate)
1173 : template <typename ManagedTokenSource>
1174 : std::unique_ptr<AST::ExternCrate>
1175 70 : Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
1176 : AST::AttrVec outer_attrs)
1177 : {
1178 70 : location_t locus = lexer.peek_token ()->get_locus ();
1179 70 : if (!skip_token (EXTERN_KW))
1180 : {
1181 0 : skip_after_semicolon ();
1182 0 : return nullptr;
1183 : }
1184 :
1185 70 : 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 70 : const_TokenPtr crate_name_tok = lexer.peek_token ();
1194 70 : std::string crate_name;
1195 :
1196 70 : switch (crate_name_tok->get_id ())
1197 : {
1198 69 : case IDENTIFIER:
1199 69 : crate_name = crate_name_tok->get_str ();
1200 69 : lexer.skip_token ();
1201 69 : 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 140 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1218 : {
1219 61 : lexer.skip_token ();
1220 :
1221 : return std::unique_ptr<AST::ExternCrate> (
1222 61 : new AST::ExternCrate (std::move (crate_name), std::move (vis),
1223 61 : 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 158 : }
1267 :
1268 : // Parses a use declaration.
1269 : template <typename ManagedTokenSource>
1270 : std::unique_ptr<AST::UseDeclaration>
1271 2049 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
1272 : AST::AttrVec outer_attrs)
1273 : {
1274 2049 : location_t locus = lexer.peek_token ()->get_locus ();
1275 2049 : if (!skip_token (USE))
1276 : {
1277 0 : skip_after_semicolon ();
1278 0 : return nullptr;
1279 : }
1280 :
1281 : // parse use tree, which is required
1282 2049 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1283 2049 : 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 2048 : if (!skip_token (SEMICOLON))
1294 : {
1295 0 : skip_after_semicolon ();
1296 0 : return nullptr;
1297 : }
1298 :
1299 : return std::unique_ptr<AST::UseDeclaration> (
1300 2048 : new AST::UseDeclaration (std::move (use_tree), std::move (vis),
1301 2048 : std::move (outer_attrs), locus));
1302 2049 : }
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 3933 : 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 3933 : location_t locus = lexer.peek_token ()->get_locus ();
1335 :
1336 : // bool has_path = false;
1337 3933 : auto path = parse_simple_path ();
1338 :
1339 3933 : if (!path)
1340 : {
1341 : // has no path, so must be glob or nested tree UseTree type
1342 :
1343 6 : bool is_global = false;
1344 :
1345 : // check for global scope resolution operator
1346 12 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
1347 : {
1348 1 : lexer.skip_token ();
1349 1 : is_global = true;
1350 : }
1351 :
1352 6 : const_TokenPtr t = lexer.peek_token ();
1353 6 : switch (t->get_id ())
1354 : {
1355 4 : case ASTERISK:
1356 : // glob UseTree type
1357 4 : lexer.skip_token ();
1358 :
1359 4 : 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 3 : return std::unique_ptr<AST::UseTreeGlob> (
1365 6 : new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
1366 9 : 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 6 : }
1430 : else
1431 : {
1432 3927 : const_TokenPtr t = lexer.peek_token ();
1433 :
1434 3927 : switch (t->get_id ())
1435 : {
1436 23 : case AS:
1437 : {
1438 : // rebind UseTree type
1439 23 : lexer.skip_token ();
1440 :
1441 23 : const_TokenPtr t = lexer.peek_token ();
1442 23 : switch (t->get_id ())
1443 : {
1444 21 : case IDENTIFIER:
1445 : // skip lexer token
1446 21 : lexer.skip_token ();
1447 :
1448 21 : return std::unique_ptr<AST::UseTreeRebind> (
1449 63 : new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
1450 63 : 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 23 : }
1471 3077 : 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 3077 : return std::unique_ptr<AST::UseTreeRebind> (
1480 9231 : new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
1481 3077 : 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 826 : skip_token ();
1493 826 : t = lexer.peek_token ();
1494 :
1495 826 : switch (t->get_id ())
1496 : {
1497 241 : case ASTERISK:
1498 : // glob UseTree type
1499 241 : lexer.skip_token ();
1500 :
1501 241 : return std::unique_ptr<AST::UseTreeGlob> (
1502 723 : new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
1503 241 : std::move (path.value ()), locus));
1504 585 : case LEFT_CURLY:
1505 : {
1506 : // nested tree UseTree type
1507 585 : lexer.skip_token ();
1508 :
1509 585 : std::vector<std::unique_ptr<AST::UseTree>> use_trees;
1510 :
1511 : // TODO: think of better control structure
1512 585 : const_TokenPtr t = lexer.peek_token ();
1513 2466 : while (t->get_id () != RIGHT_CURLY)
1514 : {
1515 1881 : std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
1516 1881 : if (use_tree == nullptr)
1517 : {
1518 : break;
1519 : }
1520 :
1521 1881 : use_trees.push_back (std::move (use_tree));
1522 :
1523 3762 : if (lexer.peek_token ()->get_id () != COMMA)
1524 : break;
1525 :
1526 1333 : lexer.skip_token ();
1527 1333 : t = lexer.peek_token ();
1528 : }
1529 :
1530 : // skip end curly delimiter
1531 585 : if (!skip_token (RIGHT_CURLY))
1532 : {
1533 : // skip after somewhere?
1534 0 : return nullptr;
1535 : }
1536 :
1537 585 : return std::unique_ptr<AST::UseTreeList> (
1538 1170 : new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
1539 585 : std::move (path.value ()),
1540 585 : std::move (use_trees), locus));
1541 585 : }
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 3927 : }
1551 3933 : }
1552 :
1553 : // Parses a function (not a method).
1554 : template <typename ManagedTokenSource>
1555 : std::unique_ptr<AST::Function>
1556 17986 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
1557 : AST::AttrVec outer_attrs,
1558 : bool is_external)
1559 : {
1560 17986 : location_t locus = lexer.peek_token ()->get_locus ();
1561 : // Get qualifiers for function if they exist
1562 17986 : auto qualifiers = parse_function_qualifiers ();
1563 17986 : if (!qualifiers)
1564 1 : return nullptr;
1565 :
1566 17985 : skip_token (FN_KW);
1567 :
1568 : // Save function name token
1569 17985 : const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
1570 17985 : if (function_name_tok == nullptr)
1571 : {
1572 0 : skip_after_next_block ();
1573 0 : return nullptr;
1574 : }
1575 35970 : Identifier function_name{function_name_tok};
1576 :
1577 : // parse generic params - if exist
1578 17985 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1579 : = parse_generic_params_in_angles ();
1580 :
1581 17985 : 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 17985 : auto initial_param = parse_self_param ();
1593 :
1594 17985 : if (!initial_param.has_value ()
1595 17985 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
1596 0 : return nullptr;
1597 :
1598 20837 : if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
1599 1696 : skip_token ();
1600 :
1601 : // parse function parameters (only if next token isn't right paren)
1602 17985 : std::vector<std::unique_ptr<AST::Param>> function_params;
1603 :
1604 35970 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
1605 : function_params
1606 8942 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
1607 :
1608 17985 : if (initial_param.has_value ())
1609 2852 : function_params.insert (function_params.begin (),
1610 2852 : std::move (*initial_param));
1611 :
1612 17985 : 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 17984 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
1625 :
1626 : // parse where clause - if exists
1627 17984 : AST::WhereClause where_clause = parse_where_clause ();
1628 :
1629 17984 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
1630 35968 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1631 5713 : lexer.skip_token ();
1632 : else
1633 : {
1634 12271 : auto block_expr = parse_block_expr ();
1635 12271 : if (!block_expr)
1636 30 : return nullptr;
1637 12241 : body = std::move (block_expr.value ());
1638 12271 : }
1639 :
1640 48149 : return std::unique_ptr<AST::Function> (new AST::Function (
1641 17954 : 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 17954 : std::move (vis), std::move (outer_attrs), locus, is_external));
1645 53955 : }
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 36333 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
1651 : {
1652 36333 : location_t locus = lexer.peek_token ()->get_locus ();
1653 :
1654 36333 : auto parsed = parse_function_qualifiers_raw (locus);
1655 36333 : if (!parsed)
1656 3 : return tl::unexpected<Parse::Error::Node> (parsed.error ());
1657 :
1658 72660 : return function_qualifiers_from_keywords (locus, std::move (parsed->first),
1659 72660 : std::move (parsed->second));
1660 36333 : }
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 36330 : Parser<ManagedTokenSource>::function_qualifiers_from_keywords (
1670 : location_t locus, const std::vector<TokenId> keywords, std::string abi)
1671 : {
1672 36330 : Default default_status = Default::No;
1673 36330 : Async async_status = Async::No;
1674 36330 : Const const_status = Const::No;
1675 36330 : Unsafety unsafe_status = Unsafety::Normal;
1676 36330 : bool has_extern = false;
1677 :
1678 44342 : for (auto qualifier : keywords)
1679 : {
1680 8012 : switch (qualifier)
1681 : {
1682 74 : case IDENTIFIER:
1683 : // only "default" is valid in this context
1684 74 : default_status = Default::Yes;
1685 74 : continue;
1686 2398 : case CONST:
1687 2398 : const_status = Const::Yes;
1688 2398 : continue;
1689 11 : case ASYNC:
1690 11 : async_status = Async::Yes;
1691 11 : continue;
1692 4775 : case UNSAFE:
1693 4775 : unsafe_status = Unsafety::Unsafe;
1694 4775 : continue;
1695 754 : case EXTERN_KW:
1696 754 : has_extern = true;
1697 754 : continue;
1698 0 : default:
1699 : // non-qualifier token in input
1700 0 : rust_unreachable ();
1701 : }
1702 : }
1703 :
1704 72660 : return AST::FunctionQualifiers (locus, default_status, async_status,
1705 : const_status, unsafe_status, has_extern,
1706 36330 : 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 36333 : Parser<ManagedTokenSource>::parse_function_qualifiers_raw (location_t locus)
1714 : {
1715 36333 : std::vector<TokenId> found_order;
1716 36333 : std::string abi;
1717 :
1718 : // this will terminate on duplicates or the first non-qualifier token
1719 8022 : while (true)
1720 : {
1721 44354 : auto token = lexer.peek_token ();
1722 44354 : const TokenId token_id = token->get_id ();
1723 44354 : location_t locus = lexer.peek_token ()->get_locus ();
1724 :
1725 44354 : switch (token_id)
1726 : {
1727 76 : case IDENTIFIER:
1728 76 : 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 7267 : found_order.push_back (token_id);
1739 7267 : lexer.skip_token ();
1740 7267 : break;
1741 755 : case EXTERN_KW:
1742 : {
1743 755 : found_order.push_back (token_id);
1744 755 : lexer.skip_token ();
1745 :
1746 : // detect optional abi name
1747 755 : const_TokenPtr next_tok = lexer.peek_token ();
1748 755 : if (next_tok->get_id () == STRING_LITERAL)
1749 : {
1750 755 : abi = next_tok->get_str ();
1751 755 : lexer.skip_token ();
1752 : }
1753 755 : }
1754 755 : break;
1755 36332 : default:
1756 : // non-qualifier keyword
1757 36332 : goto done;
1758 : }
1759 :
1760 16044 : 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 36332 : done:
1772 :
1773 36332 : if (!ensure_function_qualifier_order (locus, found_order))
1774 2 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1775 :
1776 72660 : return make_pair (found_order, abi);
1777 36333 : }
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 36332 : 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 8019 : auto token_priority = [] (const TokenId id) {
1792 8019 : switch (id)
1793 : {
1794 : case IDENTIFIER: // "default"; the only "weak" keyword considered here
1795 : return 1;
1796 2399 : case CONST:
1797 2399 : return 2;
1798 12 : case ASYNC:
1799 12 : return 3;
1800 4777 : case UNSAFE:
1801 4777 : return 4;
1802 755 : case EXTERN_KW:
1803 755 : return 5;
1804 0 : default:
1805 0 : rust_unreachable ();
1806 : };
1807 : };
1808 :
1809 36332 : size_t last_priority = 0;
1810 44349 : for (auto token_id : found_order)
1811 : {
1812 8019 : const size_t priority = token_priority (token_id);
1813 8019 : if (priority <= last_priority)
1814 : {
1815 2 : emit_function_qualifier_order_error_msg (locus, found_order);
1816 2 : return false;
1817 : }
1818 :
1819 8017 : 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 62148 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
1880 : {
1881 124296 : if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
1882 : {
1883 : // seems to be no generic params, so exit with empty vector
1884 52595 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
1885 : }
1886 9553 : lexer.skip_token ();
1887 :
1888 : // DEBUG:
1889 9553 : rust_debug ("skipped left angle in generic param");
1890 :
1891 9553 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1892 : = parse_generic_params (Parse::Utils::is_right_angle_tok);
1893 :
1894 : // DEBUG:
1895 9553 : rust_debug ("finished parsing actual generic params (i.e. inside angles)");
1896 :
1897 9553 : 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 9552 : return generic_params;
1907 9553 : }
1908 :
1909 : template <typename ManagedTokenSource>
1910 : template <typename EndTokenPred>
1911 : std::unique_ptr<AST::GenericParam>
1912 15596 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
1913 : {
1914 15596 : auto outer_attrs = parse_outer_attributes ();
1915 15596 : std::unique_ptr<AST::GenericParam> param;
1916 15596 : auto token = lexer.peek_token ();
1917 :
1918 15596 : switch (token->get_id ())
1919 : {
1920 1696 : case LIFETIME:
1921 : {
1922 1696 : auto lifetime = parse_lifetime (false);
1923 1696 : 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 1696 : std::vector<AST::Lifetime> lifetime_bounds;
1933 3392 : if (lexer.peek_token ()->get_id () == COLON)
1934 : {
1935 25 : lexer.skip_token ();
1936 : // parse required bounds
1937 : lifetime_bounds
1938 25 : = parse_lifetime_bounds ([is_end_token] (TokenId id) {
1939 26 : return is_end_token (id) || id == COMMA;
1940 : });
1941 : }
1942 :
1943 3392 : param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
1944 1696 : std::move (lifetime.value ()), std::move (lifetime_bounds),
1945 1696 : std::move (outer_attrs), token->get_locus ()));
1946 : break;
1947 3392 : }
1948 13696 : case IDENTIFIER:
1949 : {
1950 13696 : auto type_ident = token->get_str ();
1951 13696 : lexer.skip_token ();
1952 :
1953 13696 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
1954 27392 : if (lexer.peek_token ()->get_id () == COLON)
1955 : {
1956 3122 : lexer.skip_token ();
1957 :
1958 : // parse optional type param bounds
1959 3122 : type_param_bounds = parse_type_param_bounds ();
1960 : }
1961 :
1962 13696 : std::unique_ptr<AST::Type> type = nullptr;
1963 27392 : if (lexer.peek_token ()->get_id () == EQUAL)
1964 : {
1965 441 : lexer.skip_token ();
1966 :
1967 : // parse required type
1968 441 : type = parse_type ();
1969 441 : 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 13696 : param = std::unique_ptr<AST::TypeParam> (
1981 41088 : new AST::TypeParam (std::move (type_ident), token->get_locus (),
1982 : std::move (type_param_bounds), std::move (type),
1983 13696 : std::move (outer_attrs)));
1984 : break;
1985 13696 : }
1986 203 : case CONST:
1987 : {
1988 203 : lexer.skip_token ();
1989 :
1990 203 : auto name_token = expect_token (IDENTIFIER);
1991 :
1992 406 : if (!name_token || !expect_token (COLON))
1993 1 : return nullptr;
1994 :
1995 202 : auto type = parse_type ();
1996 202 : if (!type)
1997 1 : return nullptr;
1998 :
1999 : // optional default value
2000 201 : tl::optional<AST::GenericArg> default_expr = tl::nullopt;
2001 402 : 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 200 : param = std::unique_ptr<AST::ConstGenericParam> (
2037 822 : new AST::ConstGenericParam (name_token->get_str (), std::move (type),
2038 : default_expr, std::move (outer_attrs),
2039 200 : token->get_locus ()));
2040 :
2041 : break;
2042 405 : }
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 15592 : return param;
2054 15596 : }
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 9553 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
2062 : {
2063 9553 : 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 9553 : AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
2071 :
2072 : // Did we parse a generic type param yet
2073 9553 : auto type_seen = false;
2074 : // Did we parse a const param with a default value yet
2075 9553 : auto const_with_default_seen = false;
2076 : // Did the user write a lifetime parameter after a type one
2077 9553 : auto order_error = false;
2078 : // Did the user write a const param with a default value after a type one
2079 9553 : auto const_with_default_order_error = false;
2080 :
2081 : // parse lifetime params
2082 65886 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2083 : {
2084 15596 : auto param = parse_generic_param (is_end_token);
2085 15596 : if (param)
2086 : {
2087 15592 : if (param->get_kind () == AST::GenericParam::Kind::Type)
2088 : {
2089 13696 : type_seen = true;
2090 13696 : if (const_with_default_seen)
2091 15592 : const_with_default_order_error = true;
2092 : }
2093 1896 : else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
2094 1896 : && 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 1894 : else if (param->get_kind () == AST::GenericParam::Kind::Const)
2101 : {
2102 200 : type_seen = true;
2103 : AST::ConstGenericParam *const_param
2104 200 : = static_cast<AST::ConstGenericParam *> (param.get ());
2105 200 : if (const_param->has_default_value ())
2106 : const_with_default_seen = true;
2107 178 : else if (const_with_default_seen)
2108 15592 : const_with_default_order_error = true;
2109 : }
2110 :
2111 15592 : generic_params.emplace_back (std::move (param));
2112 15592 : maybe_skip_token (COMMA);
2113 : }
2114 : else
2115 : break;
2116 : }
2117 :
2118 : // FIXME: Add reordering hint
2119 9553 : 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 9553 : 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 9553 : generic_params.shrink_to_fit ();
2135 9553 : return generic_params;
2136 9553 : }
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 23273 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
2488 : {
2489 23273 : std::vector<std::unique_ptr<AST::Param>> params;
2490 :
2491 46546 : if (is_end_token (lexer.peek_token ()->get_id ()))
2492 2097 : return params;
2493 :
2494 21176 : auto initial_param = parse_function_param ();
2495 :
2496 : // Return empty parameter list if no parameter there
2497 21176 : if (initial_param == nullptr)
2498 : {
2499 : // TODO: is this an error?
2500 1 : return params;
2501 : }
2502 :
2503 21175 : 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 21175 : const_TokenPtr t = lexer.peek_token ();
2509 28630 : while (t->get_id () == COMMA)
2510 : {
2511 : // skip comma if applies
2512 7778 : lexer.skip_token ();
2513 :
2514 : // TODO: strictly speaking, shouldn't there be no trailing comma?
2515 15556 : if (is_end_token (lexer.peek_token ()->get_id ()))
2516 : break;
2517 :
2518 : // now, as right paren would break, function param is required
2519 7455 : auto param = parse_function_param ();
2520 7455 : 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 7455 : params.push_back (std::move (param));
2531 :
2532 7455 : t = lexer.peek_token ();
2533 : }
2534 :
2535 21175 : params.shrink_to_fit ();
2536 21175 : return params;
2537 23273 : }
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 28631 : Parser<ManagedTokenSource>::parse_function_param ()
2544 : {
2545 : // parse outer attributes if they exist
2546 28631 : AST::AttrVec outer_attrs = parse_outer_attributes ();
2547 :
2548 : // TODO: should saved location be at start of outer attributes or pattern?
2549 28631 : location_t locus = lexer.peek_token ()->get_locus ();
2550 :
2551 57262 : if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
2552 : {
2553 887 : lexer.skip_token (); // Skip ellipsis
2554 887 : return std::make_unique<AST::VariadicParam> (
2555 1774 : AST::VariadicParam (std::move (outer_attrs), locus));
2556 : }
2557 :
2558 27744 : std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
2559 :
2560 : // create error function param if it doesn't exist
2561 27744 : if (param_pattern == nullptr)
2562 : {
2563 : // skip after something
2564 1 : return nullptr;
2565 : }
2566 :
2567 27743 : if (!skip_token (COLON))
2568 : {
2569 : // skip after something
2570 0 : return nullptr;
2571 : }
2572 :
2573 55486 : 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 27732 : std::unique_ptr<AST::Type> param_type = parse_type ();
2583 27732 : if (param_type == nullptr)
2584 : {
2585 0 : return nullptr;
2586 : }
2587 27732 : return std::make_unique<AST::FunctionParam> (
2588 55464 : AST::FunctionParam (std::move (param_pattern), std::move (param_type),
2589 27732 : std::move (outer_attrs), locus));
2590 27732 : }
2591 28631 : }
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 36232 : Parser<ManagedTokenSource>::parse_function_return_type ()
2598 : {
2599 72464 : if (lexer.peek_token ()->get_id () != RETURN_TYPE)
2600 9589 : return nullptr;
2601 :
2602 : // skip return type, as it now obviously exists
2603 26643 : lexer.skip_token ();
2604 :
2605 26643 : std::unique_ptr<AST::Type> type = parse_type ();
2606 :
2607 26643 : return type;
2608 26643 : }
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 62125 : Parser<ManagedTokenSource>::parse_where_clause ()
2617 : {
2618 62125 : const_TokenPtr where_tok = lexer.peek_token ();
2619 62125 : if (where_tok->get_id () != WHERE)
2620 : {
2621 : // where clause doesn't exist, so create empty one
2622 60825 : return AST::WhereClause::create_empty ();
2623 : }
2624 :
2625 1300 : 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 1300 : std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
2630 :
2631 1300 : std::vector<AST::LifetimeParam> for_lifetimes;
2632 2600 : 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 1300 : const_TokenPtr t = lexer.peek_token ();
2638 2957 : while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
2639 2763 : && t->get_id () != EQUAL)
2640 : {
2641 1657 : std::unique_ptr<AST::WhereClauseItem> where_clause_item
2642 : = parse_where_clause_item (for_lifetimes);
2643 :
2644 1657 : 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 1657 : where_clause_items.push_back (std::move (where_clause_item));
2653 :
2654 : // also skip comma if it exists
2655 3314 : if (lexer.peek_token ()->get_id () != COMMA)
2656 : break;
2657 :
2658 1463 : lexer.skip_token ();
2659 1463 : t = lexer.peek_token ();
2660 : }
2661 :
2662 1300 : where_clause_items.shrink_to_fit ();
2663 1300 : return AST::WhereClause (std::move (where_clause_items));
2664 1300 : }
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 1657 : 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 1657 : const_TokenPtr t = lexer.peek_token ();
2676 :
2677 1657 : if (t->get_id () == LIFETIME)
2678 3 : return parse_lifetime_where_clause_item ();
2679 : else
2680 1654 : return parse_type_bound_where_clause_item (outer_for_lifetimes);
2681 1657 : }
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 1654 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
2716 : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
2717 : {
2718 1654 : std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
2719 :
2720 1654 : std::unique_ptr<AST::Type> type = parse_type ();
2721 1654 : if (type == nullptr)
2722 : {
2723 0 : return nullptr;
2724 : }
2725 :
2726 1654 : if (!skip_token (COLON))
2727 : {
2728 : // TODO: skip after somewhere
2729 0 : return nullptr;
2730 : }
2731 :
2732 3308 : 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 1654 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
2741 : = parse_type_param_bounds ();
2742 :
2743 1654 : location_t locus = lexer.peek_token ()->get_locus ();
2744 :
2745 : return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
2746 1654 : new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
2747 : std::move (type),
2748 1654 : std::move (type_param_bounds), locus));
2749 1654 : }
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 : 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 4869 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
2793 : {
2794 4869 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2795 :
2796 4869 : std::unique_ptr<AST::TypeParamBound> initial_bound
2797 : = parse_type_param_bound ();
2798 :
2799 : // quick exit if null
2800 4869 : 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 4869 : type_param_bounds.push_back (std::move (initial_bound));
2807 :
2808 10460 : while (lexer.peek_token ()->get_id () == PLUS)
2809 : {
2810 361 : lexer.skip_token ();
2811 :
2812 361 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
2813 361 : 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 361 : type_param_bounds.push_back (std::move (bound));
2821 : }
2822 :
2823 4869 : type_param_bounds.shrink_to_fit ();
2824 : return type_param_bounds;
2825 4869 : }
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 729 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
2833 : {
2834 729 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2835 :
2836 729 : std::unique_ptr<AST::TypeParamBound> initial_bound
2837 : = parse_type_param_bound ();
2838 :
2839 : // quick exit if null
2840 729 : 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 729 : type_param_bounds.push_back (std::move (initial_bound));
2847 :
2848 1668 : while (lexer.peek_token ()->get_id () == PLUS)
2849 : {
2850 105 : lexer.skip_token ();
2851 :
2852 : // break if end token character
2853 210 : if (is_end_token (lexer.peek_token ()->get_id ()))
2854 : break;
2855 :
2856 105 : std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
2857 105 : 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 105 : type_param_bounds.push_back (std::move (bound));
2868 : }
2869 :
2870 729 : type_param_bounds.shrink_to_fit ();
2871 729 : return type_param_bounds;
2872 729 : }
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 6136 : Parser<ManagedTokenSource>::parse_type_param_bound ()
2879 : {
2880 : // shitty cheat way of determining lifetime or trait bound - test for
2881 : // lifetime
2882 6136 : const_TokenPtr t = lexer.peek_token ();
2883 6136 : switch (t->get_id ())
2884 : {
2885 290 : case LIFETIME:
2886 290 : return std::unique_ptr<AST::Lifetime> (
2887 580 : new AST::Lifetime (parse_lifetime (false).value ()));
2888 5846 : 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 5846 : return parse_trait_bound ();
2899 0 : default:
2900 : // don't error - assume this is fine TODO
2901 0 : return nullptr;
2902 : }
2903 6136 : }
2904 :
2905 : // Parses a trait bound type param bound.
2906 : template <typename ManagedTokenSource>
2907 : std::unique_ptr<AST::TraitBound>
2908 6394 : Parser<ManagedTokenSource>::parse_trait_bound ()
2909 : {
2910 6394 : bool has_parens = false;
2911 6394 : bool has_question_mark = false;
2912 :
2913 6394 : location_t locus = lexer.peek_token ()->get_locus ();
2914 :
2915 : /* parse optional `for lifetimes`. */
2916 6394 : std::vector<AST::LifetimeParam> for_lifetimes;
2917 12788 : if (lexer.peek_token ()->get_id () == FOR)
2918 7 : for_lifetimes = parse_for_lifetimes ();
2919 :
2920 : // handle trait bound being in parentheses
2921 12788 : 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 12788 : if (lexer.peek_token ()->get_id () == QUESTION_MARK)
2929 : {
2930 944 : has_question_mark = true;
2931 944 : lexer.skip_token ();
2932 : }
2933 :
2934 : // handle TypePath
2935 6394 : AST::TypePath type_path = parse_type_path ();
2936 6394 : if (type_path.is_error ())
2937 2 : return nullptr;
2938 :
2939 : // handle closing parentheses
2940 6392 : 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 6392 : new AST::TraitBound (std::move (type_path), locus, has_parens,
2950 6392 : has_question_mark, std::move (for_lifetimes)));
2951 6394 : }
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 25 : Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
2987 : {
2988 25 : std::vector<AST::Lifetime> lifetime_bounds;
2989 :
2990 103 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2991 : {
2992 26 : auto lifetime = parse_lifetime (false);
2993 :
2994 26 : 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 26 : 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 52 : if (lexer.peek_token ()->get_id () != PLUS)
3010 : break;
3011 :
3012 1 : lexer.skip_token ();
3013 : }
3014 :
3015 25 : lifetime_bounds.shrink_to_fit ();
3016 25 : return lifetime_bounds;
3017 25 : }
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 27801 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
3024 : {
3025 27801 : const_TokenPtr lifetime_tok = lexer.peek_token ();
3026 27801 : if (lifetime_tok->get_id () != LIFETIME)
3027 : {
3028 21572 : if (allow_elided)
3029 : {
3030 0 : return AST::Lifetime::elided ();
3031 : }
3032 : else
3033 : {
3034 21572 : return tl::make_unexpected<Parse::Error::Lifetime> ({});
3035 : }
3036 : }
3037 6229 : lexer.skip_token ();
3038 :
3039 12458 : return lifetime_from_token (lifetime_tok);
3040 27801 : }
3041 :
3042 : template <typename ManagedTokenSource>
3043 : AST::Lifetime
3044 6290 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
3045 : {
3046 6290 : location_t locus = tok->get_locus ();
3047 6290 : std::string lifetime_ident = tok->get_str ();
3048 :
3049 6290 : if (lifetime_ident == "static")
3050 : {
3051 136 : return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
3052 : }
3053 6154 : else if (lifetime_ident == "_")
3054 : {
3055 : // Explicitly and implicitly elided lifetimes follow the same rules.
3056 1058 : return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
3057 : }
3058 : else
3059 : {
3060 10192 : return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
3061 5096 : locus);
3062 : }
3063 6290 : }
3064 :
3065 : template <typename ManagedTokenSource>
3066 : std::unique_ptr<AST::ExternalTypeItem>
3067 8 : Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
3068 : AST::AttrVec outer_attrs)
3069 : {
3070 8 : location_t locus = lexer.peek_token ()->get_locus ();
3071 8 : skip_token (TYPE);
3072 :
3073 8 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
3074 8 : 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 8 : if (!skip_token (SEMICOLON))
3085 1 : return nullptr;
3086 :
3087 : return std::unique_ptr<AST::ExternalTypeItem> (
3088 21 : new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
3089 7 : std::move (outer_attrs), std::move (locus)));
3090 8 : }
3091 :
3092 : // Parses a "type alias" (typedef) item.
3093 : template <typename ManagedTokenSource>
3094 : std::unique_ptr<AST::TypeAlias>
3095 4350 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
3096 : AST::AttrVec outer_attrs)
3097 : {
3098 4350 : location_t locus = lexer.peek_token ()->get_locus ();
3099 4350 : skip_token (TYPE);
3100 :
3101 : // TODO: use this token for identifier when finished that
3102 4350 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
3103 4350 : 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 8700 : Identifier alias_name{alias_name_tok};
3113 :
3114 : // parse generic params, which may not exist
3115 4350 : 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 4350 : AST::WhereClause where_clause = parse_where_clause ();
3120 :
3121 4350 : if (!skip_token (EQUAL))
3122 : {
3123 0 : skip_after_semicolon ();
3124 0 : return nullptr;
3125 : }
3126 :
3127 4350 : std::unique_ptr<AST::Type> type_to_alias = parse_type ();
3128 :
3129 4350 : 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 4350 : new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
3137 : std::move (where_clause), std::move (type_to_alias),
3138 4350 : std::move (vis), std::move (outer_attrs), locus));
3139 8700 : }
3140 :
3141 : // Parse a struct item AST node.
3142 : template <typename ManagedTokenSource>
3143 : std::unique_ptr<AST::Struct>
3144 3821 : 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 3821 : location_t locus = lexer.peek_token ()->get_locus ();
3159 3821 : skip_token (STRUCT_KW);
3160 :
3161 : // parse struct name
3162 3821 : const_TokenPtr name_tok = expect_token (IDENTIFIER);
3163 3821 : if (name_tok == nullptr)
3164 : {
3165 : // skip after somewhere?
3166 1 : return nullptr;
3167 : }
3168 7640 : Identifier struct_name{name_tok};
3169 :
3170 : // parse generic params, which may or may not exist
3171 3820 : 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 7640 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
3176 : {
3177 : // tuple struct
3178 :
3179 : // skip left parenthesis
3180 1173 : lexer.skip_token ();
3181 :
3182 : // parse tuple fields
3183 1173 : std::vector<AST::TupleField> tuple_fields;
3184 : // Might be empty tuple for unit tuple struct.
3185 2346 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3186 23 : tuple_fields = std::vector<AST::TupleField> ();
3187 : else
3188 1150 : tuple_fields = parse_tuple_fields ();
3189 :
3190 : // tuple parameters must have closing parenthesis
3191 1173 : 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 1172 : AST::WhereClause where_clause = parse_where_clause ();
3199 :
3200 1172 : 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 1172 : return std::unique_ptr<AST::TupleStruct> (
3207 1172 : 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 1172 : std::move (outer_attrs), locus));
3211 1173 : }
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 2647 : AST::WhereClause where_clause = parse_where_clause ();
3218 :
3219 : // branch on next token - determines whether struct is a unit struct
3220 2647 : const_TokenPtr t = lexer.peek_token ();
3221 2647 : switch (t->get_id ())
3222 : {
3223 1415 : case LEFT_CURLY:
3224 : {
3225 : // struct with body
3226 :
3227 : // skip curly bracket
3228 1415 : lexer.skip_token ();
3229 :
3230 : // parse struct fields, if any
3231 1415 : std::vector<AST::StructField> struct_fields
3232 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3233 :
3234 1415 : if (!skip_token (RIGHT_CURLY))
3235 : {
3236 : // skip somewhere?
3237 0 : return nullptr;
3238 : }
3239 :
3240 1415 : 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 1415 : std::move (vis), std::move (outer_attrs), locus));
3244 1415 : }
3245 1231 : case SEMICOLON:
3246 : // unit struct declaration
3247 :
3248 1231 : lexer.skip_token ();
3249 :
3250 1231 : return std::unique_ptr<AST::StructStruct> (
3251 2462 : new AST::StructStruct (std::move (struct_name),
3252 : std::move (generic_params),
3253 : std::move (where_clause), std::move (vis),
3254 1231 : 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 3820 : }
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 1631 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
3305 : {
3306 1631 : std::vector<AST::StructField> fields;
3307 :
3308 1631 : AST::StructField initial_field = parse_struct_field ();
3309 :
3310 : // Return empty field list if no field there
3311 1631 : if (initial_field.is_error ())
3312 57 : return fields;
3313 :
3314 1574 : fields.push_back (std::move (initial_field));
3315 :
3316 6302 : while (lexer.peek_token ()->get_id () == COMMA)
3317 : {
3318 2951 : lexer.skip_token ();
3319 :
3320 5902 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3321 : break;
3322 :
3323 1577 : AST::StructField field = parse_struct_field ();
3324 1577 : 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 1577 : fields.push_back (std::move (field));
3336 : }
3337 :
3338 1574 : fields.shrink_to_fit ();
3339 1574 : return fields;
3340 : // TODO: template if possible (parse_non_ptr_seq)
3341 1631 : }
3342 :
3343 : // Parses a single struct field (in a struct definition). Does not parse
3344 : // commas.
3345 : template <typename ManagedTokenSource>
3346 : AST::StructField
3347 3208 : Parser<ManagedTokenSource>::parse_struct_field ()
3348 : {
3349 : // parse outer attributes, if they exist
3350 3208 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3351 :
3352 : // parse visibility, if it exists
3353 3208 : auto vis = parse_visibility ();
3354 3208 : if (!vis)
3355 0 : return AST::StructField::create_error ();
3356 :
3357 3208 : location_t locus = lexer.peek_token ()->get_locus ();
3358 :
3359 : // parse field name
3360 3208 : const_TokenPtr field_name_tok = lexer.peek_token ();
3361 3208 : 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 57 : return AST::StructField::create_error ();
3366 : }
3367 6302 : Identifier field_name{field_name_tok};
3368 3151 : lexer.skip_token ();
3369 :
3370 3151 : 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 3151 : std::unique_ptr<AST::Type> field_type = parse_type ();
3378 3151 : 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 6302 : return AST::StructField (std::move (field_name), std::move (field_type),
3389 3151 : std::move (vis.value ()), locus,
3390 3151 : std::move (outer_attrs));
3391 12718 : }
3392 :
3393 : // Parses tuple fields in tuple/tuple struct declarations.
3394 : template <typename ManagedTokenSource>
3395 : std::vector<AST::TupleField>
3396 1667 : Parser<ManagedTokenSource>::parse_tuple_fields ()
3397 : {
3398 1667 : std::vector<AST::TupleField> fields;
3399 :
3400 1667 : AST::TupleField initial_field = parse_tuple_field ();
3401 :
3402 : // Return empty field list if no field there
3403 1667 : if (initial_field.is_error ())
3404 : {
3405 1 : return fields;
3406 : }
3407 :
3408 1666 : 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 1666 : const_TokenPtr t = lexer.peek_token ();
3415 2890 : while (t->get_id () == COMMA)
3416 : {
3417 : // skip comma if applies - e.g. trailing comma
3418 1227 : lexer.skip_token ();
3419 :
3420 : // break out due to right paren if it exists
3421 2454 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3422 : {
3423 : break;
3424 : }
3425 :
3426 1224 : AST::TupleField field = parse_tuple_field ();
3427 1224 : 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 1224 : fields.push_back (std::move (field));
3437 :
3438 1224 : t = lexer.peek_token ();
3439 : }
3440 :
3441 1666 : fields.shrink_to_fit ();
3442 1666 : return fields;
3443 :
3444 : // TODO: this shares basically all code with function params and struct
3445 : // fields
3446 : // - templates?
3447 1667 : }
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 2891 : Parser<ManagedTokenSource>::parse_tuple_field ()
3454 : {
3455 : // parse outer attributes if they exist
3456 2891 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3457 :
3458 : // parse visibility if it exists
3459 2891 : auto visibility = parse_visibility ();
3460 2891 : if (!visibility)
3461 0 : return AST::TupleField::create_error ();
3462 :
3463 2891 : location_t locus = lexer.peek_token ()->get_locus ();
3464 :
3465 : // parse type, which is required
3466 2891 : std::unique_ptr<AST::Type> field_type = parse_type ();
3467 2891 : 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 2890 : return AST::TupleField (std::move (field_type),
3479 2890 : std::move (visibility.value ()), locus,
3480 2890 : std::move (outer_attrs));
3481 5782 : }
3482 :
3483 : // Parses a Rust "enum" tagged union item definition.
3484 : template <typename ManagedTokenSource>
3485 : std::unique_ptr<AST::Enum>
3486 656 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
3487 : AST::AttrVec outer_attrs)
3488 : {
3489 656 : location_t locus = lexer.peek_token ()->get_locus ();
3490 656 : skip_token (ENUM_KW);
3491 :
3492 : // parse enum name
3493 656 : const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
3494 656 : if (enum_name_tok == nullptr)
3495 1 : return nullptr;
3496 :
3497 1310 : Identifier enum_name = {enum_name_tok};
3498 :
3499 : // parse generic params (of enum container, not enum variants) if they exist
3500 655 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3501 : = parse_generic_params_in_angles ();
3502 :
3503 : // parse where clause if it exists
3504 655 : AST::WhereClause where_clause = parse_where_clause ();
3505 :
3506 655 : 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 655 : std::vector<std::unique_ptr<AST::EnumItem>> enum_items
3514 : = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
3515 :
3516 655 : 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 654 : new AST::Enum (std::move (enum_name), std::move (vis),
3524 : std::move (generic_params), std::move (where_clause),
3525 654 : std::move (enum_items), std::move (outer_attrs), locus));
3526 1310 : }
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 655 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
3568 : {
3569 655 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3570 :
3571 655 : auto initial_item = parse_enum_item ();
3572 :
3573 : // Return empty item list if no field there
3574 655 : if (!initial_item)
3575 27 : return items;
3576 :
3577 628 : items.push_back (std::move (initial_item.value ()));
3578 :
3579 3028 : while (lexer.peek_token ()->get_id () == COMMA)
3580 : {
3581 1488 : lexer.skip_token ();
3582 :
3583 2976 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3584 : break;
3585 :
3586 886 : auto item = parse_enum_item ();
3587 886 : 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 886 : items.push_back (std::move (item.value ()));
3599 : }
3600 :
3601 628 : items.shrink_to_fit ();
3602 628 : return items;
3603 :
3604 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3605 655 : }
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 1541 : Parser<ManagedTokenSource>::parse_enum_item ()
3612 : {
3613 : // parse outer attributes if they exist
3614 1541 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3615 :
3616 : // parse visibility, which may or may not exist
3617 1541 : auto vis_res = parse_visibility ();
3618 1541 : if (!vis_res)
3619 0 : return Parse::Error::EnumVariant::make_child_error ();
3620 1541 : auto vis = vis_res.value ();
3621 :
3622 : // parse name for enum item, which is required
3623 1541 : const_TokenPtr item_name_tok = lexer.peek_token ();
3624 1541 : 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 54 : return Parse::Error::EnumVariant::make_not_identifier (item_name_tok);
3628 : }
3629 1514 : lexer.skip_token ();
3630 3028 : Identifier item_name{item_name_tok};
3631 :
3632 : // branch based on next token
3633 1514 : const_TokenPtr t = lexer.peek_token ();
3634 1514 : switch (t->get_id ())
3635 : {
3636 535 : case LEFT_PAREN:
3637 : {
3638 : // tuple enum item
3639 535 : lexer.skip_token ();
3640 :
3641 535 : std::vector<AST::TupleField> tuple_fields;
3642 : // Might be empty tuple for unit tuple enum variant.
3643 1070 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3644 18 : tuple_fields = std::vector<AST::TupleField> ();
3645 : else
3646 517 : tuple_fields = parse_tuple_fields ();
3647 :
3648 535 : if (!skip_token (RIGHT_PAREN))
3649 : {
3650 : // skip after somewhere
3651 0 : return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
3652 : }
3653 :
3654 535 : return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
3655 : std::move (item_name), std::move (vis), std::move (tuple_fields),
3656 535 : std::move (outer_attrs), item_name_tok->get_locus ()));
3657 535 : }
3658 100 : case LEFT_CURLY:
3659 : {
3660 : // struct enum item
3661 100 : lexer.skip_token ();
3662 :
3663 100 : std::vector<AST::StructField> struct_fields
3664 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3665 :
3666 100 : if (!skip_token (RIGHT_CURLY))
3667 : {
3668 : // skip after somewhere
3669 0 : return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
3670 : }
3671 :
3672 100 : return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
3673 : std::move (item_name), std::move (vis), std::move (struct_fields),
3674 100 : std::move (outer_attrs), item_name_tok->get_locus ()));
3675 100 : }
3676 296 : case EQUAL:
3677 : {
3678 : // discriminant enum item
3679 296 : lexer.skip_token ();
3680 :
3681 296 : auto discriminant_expr = parse_expr ();
3682 296 : if (!discriminant_expr)
3683 0 : return Parse::Error::EnumVariant::make_child_error ();
3684 :
3685 296 : return std::make_unique<AST::EnumItemDiscriminant> (
3686 : std::move (item_name), std::move (vis),
3687 296 : std::move (discriminant_expr.value ()), std::move (outer_attrs),
3688 592 : item_name_tok->get_locus ());
3689 296 : }
3690 583 : default:
3691 : // regular enum with just an identifier
3692 583 : return std::make_unique<AST::EnumItem> (std::move (item_name),
3693 : std::move (vis),
3694 : std::move (outer_attrs),
3695 583 : item_name_tok->get_locus ());
3696 : }
3697 4596 : }
3698 :
3699 : // Parses a C-style (and C-compat) untagged union declaration.
3700 : template <typename ManagedTokenSource>
3701 : std::unique_ptr<AST::Union>
3702 116 : 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 116 : const_TokenPtr union_keyword = expect_token (IDENTIFIER);
3708 116 : rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
3709 116 : location_t locus = union_keyword->get_locus ();
3710 :
3711 : // parse actual union name
3712 116 : const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
3713 116 : if (union_name_tok == nullptr)
3714 : {
3715 0 : skip_after_next_block ();
3716 0 : return nullptr;
3717 : }
3718 232 : Identifier union_name{union_name_tok};
3719 :
3720 : // parse optional generic parameters
3721 116 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3722 : = parse_generic_params_in_angles ();
3723 :
3724 : // parse optional where clause
3725 116 : AST::WhereClause where_clause = parse_where_clause ();
3726 :
3727 116 : 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 116 : std::vector<AST::StructField> union_fields
3736 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3737 :
3738 116 : if (!skip_token (RIGHT_CURLY))
3739 : {
3740 : // skip after somewhere
3741 0 : return nullptr;
3742 : }
3743 :
3744 : return std::unique_ptr<AST::Union> (
3745 116 : new AST::Union (std::move (union_name), std::move (vis),
3746 : std::move (generic_params), std::move (where_clause),
3747 116 : std::move (union_fields), std::move (outer_attrs), locus));
3748 348 : }
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 1295 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
3755 : AST::AttrVec outer_attrs)
3756 : {
3757 1295 : location_t locus = lexer.peek_token ()->get_locus ();
3758 1295 : skip_token (CONST);
3759 :
3760 : /* get constant identifier - this is either a proper identifier or the _
3761 : * wildcard */
3762 1295 : const_TokenPtr ident_tok = lexer.peek_token ();
3763 : // make default identifier the underscore wildcard one
3764 1295 : std::string ident (Values::Keywords::UNDERSCORE);
3765 1295 : switch (ident_tok->get_id ())
3766 : {
3767 1288 : case IDENTIFIER:
3768 1288 : ident = ident_tok->get_str ();
3769 1288 : lexer.skip_token ();
3770 1288 : 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 1295 : if (!skip_token (COLON))
3787 : {
3788 0 : skip_after_semicolon ();
3789 0 : return nullptr;
3790 : }
3791 :
3792 : // parse constant type (required)
3793 1295 : std::unique_ptr<AST::Type> type = parse_type ();
3794 :
3795 : // A const with no given expression value
3796 2590 : 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 1291 : if (!skip_token (EQUAL))
3806 : {
3807 0 : skip_after_semicolon ();
3808 0 : return nullptr;
3809 : }
3810 :
3811 : // parse constant expression (required)
3812 1291 : auto expr = parse_expr ();
3813 1291 : if (!expr)
3814 1 : return nullptr;
3815 :
3816 1290 : if (!skip_token (SEMICOLON))
3817 : {
3818 : // skip somewhere?
3819 0 : return nullptr;
3820 : }
3821 :
3822 : return std::unique_ptr<AST::ConstantItem> (
3823 2580 : new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
3824 1290 : std::move (expr.value ()), std::move (outer_attrs),
3825 1290 : locus));
3826 2590 : }
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 4502 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
3887 : AST::AttrVec outer_attrs)
3888 : {
3889 4502 : location_t locus = lexer.peek_token ()->get_locus ();
3890 4502 : bool is_unsafe = false;
3891 4502 : bool is_auto_trait = false;
3892 :
3893 9004 : if (lexer.peek_token ()->get_id () == UNSAFE)
3894 : {
3895 84 : is_unsafe = true;
3896 84 : lexer.skip_token ();
3897 : }
3898 :
3899 9004 : if (lexer.peek_token ()->get_id () == AUTO)
3900 : {
3901 30 : is_auto_trait = true;
3902 30 : lexer.skip_token ();
3903 : }
3904 :
3905 4502 : skip_token (TRAIT);
3906 :
3907 : // parse trait name
3908 4502 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3909 4502 : if (ident_tok == nullptr)
3910 0 : return nullptr;
3911 :
3912 9004 : Identifier ident{ident_tok};
3913 :
3914 : // parse generic parameters (if they exist)
3915 4502 : 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 4502 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3920 :
3921 : // parse type param bounds (if they exist)
3922 9004 : if (lexer.peek_token ()->get_id () == COLON)
3923 : {
3924 664 : lexer.skip_token ();
3925 :
3926 664 : type_param_bounds = parse_type_param_bounds (
3927 95 : [] (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 4502 : AST::WhereClause where_clause = parse_where_clause ();
3933 :
3934 4502 : 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 4502 : AST::AttrVec inner_attrs = parse_inner_attributes ();
3942 :
3943 : // parse trait items
3944 4502 : std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
3945 :
3946 4502 : const_TokenPtr t = lexer.peek_token ();
3947 8719 : while (t->get_id () != RIGHT_CURLY)
3948 : {
3949 4217 : std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
3950 :
3951 4217 : 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 4217 : trait_items.push_back (std::move (trait_item));
3960 :
3961 4217 : t = lexer.peek_token ();
3962 : }
3963 :
3964 4502 : if (!skip_token (RIGHT_CURLY))
3965 : {
3966 : // skip after something
3967 0 : return nullptr;
3968 : }
3969 :
3970 4502 : trait_items.shrink_to_fit ();
3971 : return std::unique_ptr<AST::Trait> (
3972 4502 : 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 4502 : std::move (inner_attrs), locus));
3977 9004 : }
3978 :
3979 : // Parses a trait item used inside traits (not trait, the Item).
3980 : template <typename ManagedTokenSource>
3981 : std::unique_ptr<AST::AssociatedItem>
3982 4219 : Parser<ManagedTokenSource>::parse_trait_item ()
3983 : {
3984 : // parse outer attributes (if they exist)
3985 4219 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3986 :
3987 4219 : auto vis_res = parse_visibility ();
3988 4219 : if (!vis_res)
3989 0 : return nullptr;
3990 :
3991 4219 : auto vis = vis_res.value ();
3992 :
3993 : // lookahead to determine what type of trait item to parse
3994 4219 : const_TokenPtr tok = lexer.peek_token ();
3995 4219 : 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 890 : case TYPE:
4010 890 : return parse_trait_type (std::move (outer_attrs), vis);
4011 62 : case CONST:
4012 : // disambiguate with function qualifier
4013 124 : if (lexer.peek_token (1)->get_id () == IDENTIFIER)
4014 : {
4015 122 : 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 6534 : 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 8438 : }
4034 :
4035 : // Parse a typedef trait item.
4036 : template <typename ManagedTokenSource>
4037 : std::unique_ptr<AST::TraitItemType>
4038 890 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
4039 : AST::Visibility vis)
4040 : {
4041 890 : location_t locus = lexer.peek_token ()->get_locus ();
4042 890 : skip_token (TYPE);
4043 :
4044 890 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4045 890 : if (ident_tok == nullptr)
4046 0 : return nullptr;
4047 :
4048 1780 : Identifier ident{ident_tok};
4049 :
4050 : // Parse optional generic parameters for GATs (Generic Associated Types)
4051 890 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
4052 1780 : if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
4053 : {
4054 17 : generic_params = parse_generic_params_in_angles ();
4055 : }
4056 :
4057 890 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
4058 :
4059 : // parse optional colon
4060 1780 : if (lexer.peek_token ()->get_id () == COLON)
4061 : {
4062 65 : lexer.skip_token ();
4063 :
4064 : // parse optional type param bounds
4065 : bounds
4066 65 : = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
4067 : // bounds = parse_type_param_bounds ();
4068 : }
4069 :
4070 890 : if (!skip_token (SEMICOLON))
4071 : {
4072 : // skip?
4073 0 : return nullptr;
4074 : }
4075 :
4076 : return std::unique_ptr<AST::TraitItemType> (
4077 890 : new AST::TraitItemType (std::move (ident), std::move (generic_params),
4078 : std::move (bounds), std::move (outer_attrs), vis,
4079 890 : locus));
4080 890 : }
4081 :
4082 : // Parses a constant trait item.
4083 : template <typename ManagedTokenSource>
4084 : std::unique_ptr<AST::ConstantItem>
4085 61 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
4086 : {
4087 61 : location_t locus = lexer.peek_token ()->get_locus ();
4088 61 : skip_token (CONST);
4089 :
4090 : // parse constant item name
4091 61 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4092 61 : if (ident_tok == nullptr)
4093 0 : return nullptr;
4094 :
4095 122 : Identifier ident{ident_tok};
4096 :
4097 61 : if (!skip_token (COLON))
4098 : {
4099 0 : skip_after_semicolon ();
4100 0 : return nullptr;
4101 : }
4102 :
4103 : // parse constant trait item type
4104 61 : std::unique_ptr<AST::Type> type = parse_type ();
4105 :
4106 : // parse constant trait body expression, if it exists
4107 61 : std::unique_ptr<AST::Expr> const_body = nullptr;
4108 122 : 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 61 : if (!skip_token (SEMICOLON))
4120 : {
4121 : // skip after something?
4122 0 : return nullptr;
4123 : }
4124 :
4125 183 : return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
4126 122 : std::move (ident), AST::Visibility::create_private (), std::move (type),
4127 61 : std::move (const_body), std::move (outer_attrs), locus));
4128 122 : }
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 13065 : 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 13065 : location_t locus = lexer.peek_token ()->get_locus ();
4141 13065 : bool is_unsafe = false;
4142 26130 : if (lexer.peek_token ()->get_id () == UNSAFE)
4143 : {
4144 296 : lexer.skip_token ();
4145 296 : is_unsafe = true;
4146 : }
4147 :
4148 13065 : 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 13065 : 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 13065 : bool has_exclam = false;
4161 26130 : if (lexer.peek_token ()->get_id () == EXCLAM)
4162 : {
4163 26 : lexer.skip_token ();
4164 26 : 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 13065 : AST::TypePath type_path = parse_type_path ();
4170 25892 : 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 1559 : std::unique_ptr<AST::Type> type = nullptr;
4177 1559 : if (!type_path.is_error ())
4178 1321 : type = std::unique_ptr<AST::TypePath> (
4179 1321 : new AST::TypePath (std::move (type_path)));
4180 : else
4181 238 : type = parse_type ();
4182 :
4183 : // Type is required, so error if null
4184 1559 : 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 1558 : AST::WhereClause where_clause = parse_where_clause ();
4196 :
4197 1558 : 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 1558 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4206 :
4207 : // parse inherent impl items
4208 1558 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4209 :
4210 1558 : const_TokenPtr t = lexer.peek_token ();
4211 6773 : while (t->get_id () != RIGHT_CURLY)
4212 : {
4213 5225 : std::unique_ptr<AST::AssociatedItem> impl_item
4214 : = parse_inherent_impl_item ();
4215 :
4216 5225 : 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 5215 : impl_items.push_back (std::move (impl_item));
4227 :
4228 5215 : t = lexer.peek_token ();
4229 : }
4230 :
4231 1548 : if (!skip_token (RIGHT_CURLY))
4232 : {
4233 : // skip somewhere
4234 0 : return nullptr;
4235 : }
4236 :
4237 : // DEBUG
4238 1548 : rust_debug ("successfully parsed inherent impl");
4239 :
4240 1548 : impl_items.shrink_to_fit ();
4241 :
4242 1548 : 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 1548 : std::move (outer_attrs), locus));
4246 1559 : }
4247 : else
4248 : {
4249 : // type path must both be valid and next token is for, so trait impl
4250 11506 : if (!skip_token (FOR))
4251 : {
4252 0 : skip_after_next_block ();
4253 0 : return nullptr;
4254 : }
4255 :
4256 : // parse type
4257 11506 : std::unique_ptr<AST::Type> type = parse_type ();
4258 : // ensure type is included as it is required
4259 11506 : 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 11506 : AST::WhereClause where_clause = parse_where_clause ();
4271 :
4272 11506 : 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 11506 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4281 :
4282 : // parse trait impl items
4283 11506 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4284 :
4285 11506 : const_TokenPtr t = lexer.peek_token ();
4286 27290 : while (t->get_id () != RIGHT_CURLY)
4287 : {
4288 15787 : std::unique_ptr<AST::AssociatedItem> impl_item
4289 : = parse_trait_impl_item ();
4290 :
4291 15787 : 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 15784 : impl_items.push_back (std::move (impl_item));
4301 :
4302 15784 : t = lexer.peek_token ();
4303 :
4304 : // DEBUG
4305 15784 : rust_debug ("successfully parsed a trait impl item");
4306 : }
4307 : // DEBUG
4308 11503 : rust_debug ("successfully finished trait impl items");
4309 :
4310 11503 : if (!skip_token (RIGHT_CURLY))
4311 : {
4312 : // skip somewhere
4313 0 : return nullptr;
4314 : }
4315 :
4316 : // DEBUG
4317 11503 : rust_debug ("successfully parsed trait impl");
4318 :
4319 11503 : impl_items.shrink_to_fit ();
4320 :
4321 11503 : return std::unique_ptr<AST::TraitImpl> (
4322 23006 : 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 11503 : std::move (outer_attrs), locus));
4327 11506 : }
4328 13065 : }
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 7231 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
4334 : {
4335 : // parse outer attributes (if they exist)
4336 7231 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4337 :
4338 : // TODO: cleanup - currently an unreadable mess
4339 :
4340 : // branch on next token:
4341 7231 : const_TokenPtr t = lexer.peek_token ();
4342 7231 : 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 5262 : 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 5262 : auto vis_res = parse_visibility ();
4355 5262 : if (!vis_res)
4356 0 : return nullptr;
4357 5262 : auto vis = vis_res.value ();
4358 :
4359 : // TODO: is a recursive call to parse_inherent_impl_item better?
4360 10524 : switch (lexer.peek_token ()->get_id ())
4361 : {
4362 2900 : case EXTERN_KW:
4363 : case UNSAFE:
4364 : case FN_KW:
4365 : // function or method
4366 5800 : return parse_inherent_impl_function_or_method (std::move (vis),
4367 : std::move (
4368 2900 : outer_attrs));
4369 2362 : case CONST:
4370 : // lookahead to resolve production - could be function/method or
4371 : // const item
4372 2362 : t = lexer.peek_token (1);
4373 :
4374 2362 : switch (t->get_id ())
4375 : {
4376 102 : case IDENTIFIER:
4377 : case UNDERSCORE:
4378 204 : return parse_const_item (std::move (vis),
4379 102 : std::move (outer_attrs));
4380 2260 : case UNSAFE:
4381 : case EXTERN_KW:
4382 : case FN_KW:
4383 4520 : return parse_inherent_impl_function_or_method (std::move (vis),
4384 : std::move (
4385 2260 : 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 10524 : }
4404 823 : case ASYNC:
4405 : case EXTERN_KW:
4406 : case UNSAFE:
4407 : case FN_KW:
4408 : // function or method
4409 823 : return parse_inherent_impl_function_or_method (
4410 823 : AST::Visibility::create_private (), std::move (outer_attrs));
4411 55 : case CONST:
4412 : /* lookahead to resolve production - could be function/method or const
4413 : * item */
4414 55 : t = lexer.peek_token (1);
4415 :
4416 55 : switch (t->get_id ())
4417 : {
4418 43 : case IDENTIFIER:
4419 : case UNDERSCORE:
4420 86 : return parse_const_item (AST::Visibility::create_private (),
4421 43 : 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 7231 : }
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 5995 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
4456 : AST::Visibility vis, AST::AttrVec outer_attrs)
4457 : {
4458 5995 : location_t locus = lexer.peek_token ()->get_locus ();
4459 : // parse function or method qualifiers
4460 5995 : auto qualifiers = parse_function_qualifiers ();
4461 5995 : if (!qualifiers)
4462 0 : return nullptr;
4463 :
4464 5995 : skip_token (FN_KW);
4465 :
4466 : // parse function or method name
4467 5995 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4468 5995 : if (ident_tok == nullptr)
4469 7 : return nullptr;
4470 :
4471 11976 : Identifier ident{ident_tok};
4472 :
4473 : // parse generic params
4474 5988 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4475 : = parse_generic_params_in_angles ();
4476 :
4477 5988 : 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 5988 : auto initial_param = parse_self_param ();
4486 :
4487 5988 : if (!initial_param.has_value ()
4488 5988 : && 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 5985 : bool is_method = false;
4495 5985 : if (initial_param.has_value ())
4496 : {
4497 4428 : 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 8856 : if (lexer.peek_token ()->get_id () == COMMA)
4503 2586 : lexer.skip_token ();
4504 : }
4505 :
4506 : // parse trait function params
4507 5985 : std::vector<std::unique_ptr<AST::Param>> function_params
4508 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4509 :
4510 5985 : if (initial_param.has_value ())
4511 4428 : function_params.insert (function_params.begin (),
4512 4428 : std::move (*initial_param));
4513 :
4514 5985 : if (!skip_token (RIGHT_PAREN))
4515 : {
4516 0 : skip_after_end_block ();
4517 0 : return nullptr;
4518 : }
4519 :
4520 : // parse return type (optional)
4521 5985 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4522 :
4523 : // parse where clause (optional)
4524 5985 : AST::WhereClause where_clause = parse_where_clause ();
4525 :
4526 5985 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4527 11970 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4528 2 : lexer.skip_token ();
4529 : else
4530 : {
4531 5983 : auto result = parse_block_expr ();
4532 :
4533 5983 : 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 5983 : body = std::move (result.value ());
4545 5983 : }
4546 :
4547 5985 : return std::unique_ptr<AST::Function> (
4548 23938 : 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 5985 : std::move (outer_attrs), locus));
4553 17968 : }
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 16040 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
4559 : {
4560 : // parse outer attributes (if they exist)
4561 16040 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4562 :
4563 16040 : auto vis_res = parse_visibility ();
4564 16040 : if (!vis_res)
4565 0 : return nullptr;
4566 16040 : auto visibility = vis_res.value ();
4567 :
4568 : // branch on next token:
4569 16040 : const_TokenPtr t = lexer.peek_token ();
4570 16040 : 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 147 : case IDENTIFIER:
4580 294 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
4581 148 : return parse_trait_impl_function_or_method (visibility,
4582 74 : std::move (outer_attrs));
4583 : else
4584 146 : return parse_macro_invocation_semi (std::move (outer_attrs));
4585 4239 : case TYPE:
4586 8478 : return parse_type_alias (visibility, std::move (outer_attrs));
4587 11577 : case EXTERN_KW:
4588 : case UNSAFE:
4589 : case FN_KW:
4590 : // function or method
4591 23154 : return parse_trait_impl_function_or_method (visibility,
4592 11577 : std::move (outer_attrs));
4593 1 : case ASYNC:
4594 2 : return parse_async_item (visibility, std::move (outer_attrs));
4595 76 : case CONST:
4596 : // lookahead to resolve production - could be function/method or const
4597 : // item
4598 76 : t = lexer.peek_token (1);
4599 :
4600 76 : switch (t->get_id ())
4601 : {
4602 75 : case IDENTIFIER:
4603 : case UNDERSCORE:
4604 150 : 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 32080 : }
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 11652 : 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 11652 : location_t locus = lexer.peek_token ()->get_locus ();
4643 :
4644 : // parse function or method qualifiers
4645 11652 : auto qualifiers = parse_function_qualifiers ();
4646 11652 : if (!qualifiers)
4647 2 : return nullptr;
4648 :
4649 11650 : skip_token (FN_KW);
4650 :
4651 : // parse function or method name
4652 11650 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4653 11650 : if (ident_tok == nullptr)
4654 : {
4655 0 : return nullptr;
4656 : }
4657 23300 : Identifier ident{ident_tok};
4658 :
4659 : // DEBUG:
4660 11650 : rust_debug (
4661 : "about to start parsing generic params in trait impl function or method");
4662 :
4663 : // parse generic params
4664 11650 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4665 : = parse_generic_params_in_angles ();
4666 :
4667 : // DEBUG:
4668 11650 : rust_debug (
4669 : "finished parsing generic params in trait impl function or method");
4670 :
4671 11650 : 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 11650 : auto initial_param = parse_self_param ();
4680 :
4681 11650 : if (!initial_param.has_value ()
4682 11650 : && 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 11650 : bool is_method = false;
4688 11650 : if (initial_param.has_value ())
4689 : {
4690 10491 : 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 20982 : if (lexer.peek_token ()->get_id () == COMMA)
4696 : {
4697 7429 : lexer.skip_token ();
4698 : }
4699 :
4700 : // DEBUG
4701 10491 : rust_debug ("successfully parsed self param in method trait impl item");
4702 : }
4703 :
4704 : // DEBUG
4705 11650 : 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 11650 : std::vector<std::unique_ptr<AST::Param>> function_params;
4710 23300 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
4711 : {
4712 : function_params
4713 8346 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4714 :
4715 8346 : 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 11650 : if (initial_param.has_value ())
4729 10491 : function_params.insert (function_params.begin (),
4730 10491 : std::move (*initial_param));
4731 :
4732 : // DEBUG
4733 11650 : rust_debug ("successfully parsed function params in function or method "
4734 : "trait impl item");
4735 :
4736 11650 : if (!skip_token (RIGHT_PAREN))
4737 : {
4738 0 : skip_after_next_block ();
4739 0 : return nullptr;
4740 : }
4741 :
4742 : // parse return type (optional)
4743 11650 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4744 :
4745 : // DEBUG
4746 11650 : rust_debug (
4747 : "successfully parsed return type in function or method trait impl item");
4748 :
4749 : // parse where clause (optional)
4750 11650 : AST::WhereClause where_clause = parse_where_clause ();
4751 :
4752 : // DEBUG
4753 11650 : 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 11650 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4758 :
4759 23300 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4760 1 : lexer.skip_token ();
4761 : else
4762 : {
4763 11649 : auto result = parse_block_expr ();
4764 11649 : 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 11648 : body = std::move (result.value ());
4775 11649 : }
4776 :
4777 11649 : return std::unique_ptr<AST::Function> (
4778 46595 : 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 11649 : std::move (outer_attrs), locus));
4783 34950 : }
4784 :
4785 : // Parses an extern block of declarations.
4786 : template <typename ManagedTokenSource>
4787 : std::unique_ptr<AST::ExternBlock>
4788 1777 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
4789 : AST::AttrVec outer_attrs)
4790 : {
4791 1777 : location_t locus = lexer.peek_token ()->get_locus ();
4792 1777 : skip_token (EXTERN_KW);
4793 :
4794 : // detect optional abi name
4795 1777 : std::string abi;
4796 1777 : const_TokenPtr next_tok = lexer.peek_token ();
4797 1777 : if (next_tok->get_id () == STRING_LITERAL)
4798 : {
4799 1776 : lexer.skip_token ();
4800 1776 : abi = next_tok->get_str ();
4801 : }
4802 :
4803 1777 : if (!skip_token (LEFT_CURLY))
4804 : {
4805 0 : skip_after_end_block ();
4806 0 : return nullptr;
4807 : }
4808 :
4809 1777 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4810 :
4811 : // parse declarations inside extern block
4812 1777 : std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
4813 :
4814 1777 : const_TokenPtr t = lexer.peek_token ();
4815 5312 : while (t->get_id () != RIGHT_CURLY)
4816 : {
4817 3536 : std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
4818 :
4819 3536 : 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 3535 : extern_items.push_back (std::move (extern_item));
4830 :
4831 3535 : t = lexer.peek_token ();
4832 : }
4833 :
4834 1776 : if (!skip_token (RIGHT_CURLY))
4835 : {
4836 : // skip somewhere
4837 0 : return nullptr;
4838 : }
4839 :
4840 1776 : extern_items.shrink_to_fit ();
4841 :
4842 : return std::unique_ptr<AST::ExternBlock> (
4843 1776 : new AST::ExternBlock (std::move (abi), std::move (extern_items),
4844 : std::move (vis), std::move (inner_attrs),
4845 1776 : std::move (outer_attrs), locus));
4846 3554 : }
4847 :
4848 : // Parses a single extern block item (static or function declaration).
4849 : template <typename ManagedTokenSource>
4850 : std::unique_ptr<AST::ExternalItem>
4851 3539 : Parser<ManagedTokenSource>::parse_external_item ()
4852 : {
4853 : // parse optional outer attributes
4854 3539 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4855 :
4856 3539 : location_t locus = lexer.peek_token ()->get_locus ();
4857 :
4858 : // parse optional visibility
4859 3539 : auto vis_res = parse_visibility ();
4860 3539 : if (!vis_res)
4861 0 : return nullptr;
4862 3539 : auto vis = vis_res.value ();
4863 :
4864 3539 : const_TokenPtr t = lexer.peek_token ();
4865 3539 : 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 3528 : case FN_KW:
4921 7056 : return parse_function (std::move (vis), std::move (outer_attrs), true);
4922 :
4923 8 : case TYPE:
4924 8 : return parse_external_type_item (std::move (vis),
4925 8 : 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 7078 : }
4937 :
4938 : // Parses a statement (will further disambiguate any statement).
4939 : template <typename ManagedTokenSource>
4940 : std::unique_ptr<AST::Stmt>
4941 1087 : 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 1087 : const_TokenPtr t = lexer.peek_token ();
4946 1087 : 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 1057 : 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 1057 : t = lexer.peek_token ();
4962 1057 : switch (t->get_id ())
4963 : {
4964 227 : case LET:
4965 : // let statement
4966 227 : 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 267 : case IDENTIFIER:
5001 267 : if (t->get_str () == Values::WeakKeywords::UNION
5002 267 : && 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 534 : 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 642 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
5017 : break;
5018 : }
5019 1057 : }
5020 :
5021 : // Parses a let statement.
5022 : template <typename ManagedTokenSource>
5023 : std::unique_ptr<AST::LetStmt>
5024 24656 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
5025 : ParseRestrictions restrictions)
5026 : {
5027 24656 : location_t locus = lexer.peek_token ()->get_locus ();
5028 24656 : skip_token (LET);
5029 :
5030 : // parse pattern (required)
5031 24656 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
5032 24656 : 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 24656 : std::unique_ptr<AST::Type> type = nullptr;
5044 49312 : if (lexer.peek_token ()->get_id () == COLON)
5045 : {
5046 : // must have a type declaration
5047 2701 : lexer.skip_token ();
5048 :
5049 2701 : type = parse_type ();
5050 2701 : 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 24656 : std::unique_ptr<AST::Expr> expr = nullptr;
5063 49312 : if (lexer.peek_token ()->get_id () == EQUAL)
5064 : {
5065 : // must have an expression
5066 23523 : lexer.skip_token ();
5067 :
5068 23523 : auto expr_res = parse_expr ();
5069 23523 : if (!expr_res)
5070 : {
5071 22 : skip_after_semicolon ();
5072 22 : return nullptr;
5073 : }
5074 23501 : expr = std::move (expr_res.value ());
5075 23523 : }
5076 :
5077 24634 : tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
5078 24634 : 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 24634 : 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 24489 : if (restrictions.allow_close_after_expr_stmt)
5095 82 : maybe_skip_token (SEMICOLON);
5096 24407 : else if (!skip_token (SEMICOLON))
5097 1 : return nullptr;
5098 : }
5099 :
5100 : return std::unique_ptr<AST::LetStmt> (
5101 49271 : new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
5102 24633 : std::move (else_expr), std::move (outer_attrs), locus));
5103 24656 : }
5104 :
5105 : template <typename ManagedTokenSource>
5106 : tl::optional<AST::GenericArg>
5107 23166 : Parser<ManagedTokenSource>::parse_generic_arg ()
5108 : {
5109 23166 : auto tok = lexer.peek_token ();
5110 23166 : std::unique_ptr<AST::Expr> expr = nullptr;
5111 :
5112 23166 : switch (tok->get_id ())
5113 : {
5114 17797 : 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 17797 : auto next_tok = lexer.peek_token (1);
5120 17797 : if (next_tok->get_id () == LEFT_ANGLE
5121 16694 : || next_tok->get_id () == SCOPE_RESOLUTION
5122 34041 : || next_tok->get_id () == EXCLAM)
5123 : {
5124 1561 : auto type = parse_type ();
5125 1561 : if (type)
5126 1561 : return AST::GenericArg::create_type (std::move (type));
5127 : else
5128 0 : return tl::nullopt;
5129 1561 : }
5130 16236 : else if (next_tok->get_id () == COLON)
5131 : {
5132 0 : lexer.skip_token (); // skip ident
5133 0 : lexer.skip_token (); // skip colon
5134 :
5135 0 : auto tok = lexer.peek_token ();
5136 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5137 : = parse_type_param_bounds ();
5138 :
5139 0 : auto type = std::unique_ptr<AST::TraitObjectType> (
5140 0 : new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
5141 : false));
5142 0 : if (type)
5143 0 : return AST::GenericArg::create_type (std::move (type));
5144 : else
5145 : return tl::nullopt;
5146 0 : }
5147 16236 : lexer.skip_token ();
5148 64944 : return AST::GenericArg::create_ambiguous (tok->get_str (),
5149 16236 : tok->get_locus ());
5150 19967 : }
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 5254 : default:
5178 : {
5179 5254 : auto type = parse_type ();
5180 : // FIXME: Find a better way to do this?
5181 5254 : if (type)
5182 5253 : return AST::GenericArg::create_type (std::move (type));
5183 : else
5184 1 : return tl::nullopt;
5185 5254 : }
5186 : }
5187 :
5188 115 : if (!expr)
5189 0 : return tl::nullopt;
5190 :
5191 115 : return AST::GenericArg::create_const (std::move (expr));
5192 23166 : }
5193 :
5194 : // Parses the generic arguments in each path segment.
5195 : template <typename ManagedTokenSource>
5196 : AST::GenericArgs
5197 22543 : Parser<ManagedTokenSource>::parse_path_generic_args ()
5198 : {
5199 45086 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
5200 21 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
5201 :
5202 22543 : 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 22543 : std::vector<AST::Lifetime> lifetime_args;
5213 :
5214 22543 : const_TokenPtr t = lexer.peek_token ();
5215 22543 : location_t locus = t->get_locus ();
5216 45990 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5217 : {
5218 23447 : auto lifetime = parse_lifetime (false);
5219 23447 : if (!lifetime)
5220 : {
5221 : // not necessarily an error
5222 : break;
5223 : }
5224 :
5225 2011 : lifetime_args.push_back (std::move (lifetime.value ()));
5226 :
5227 : // if next token isn't comma, then it must be end of list
5228 4022 : if (lexer.peek_token ()->get_id () != COMMA)
5229 : {
5230 : break;
5231 : }
5232 : // skip comma
5233 905 : lexer.skip_token ();
5234 :
5235 905 : t = lexer.peek_token ();
5236 : }
5237 :
5238 : // try to parse types and const generics second
5239 22543 : std::vector<AST::GenericArg> generic_args;
5240 :
5241 : // TODO: think of better control structure
5242 22543 : t = lexer.peek_token ();
5243 46187 : 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 23644 : if (t->get_id () == IDENTIFIER
5250 47288 : && (lexer.peek_token (1)->get_id () == EQUAL
5251 41532 : || lexer.peek_token (1)->get_id () == COLON))
5252 : break;
5253 :
5254 23142 : auto arg = parse_generic_arg ();
5255 23142 : if (arg)
5256 : {
5257 23142 : generic_args.emplace_back (std::move (arg.value ()));
5258 : }
5259 :
5260 : // FIXME: Do we need to break if we encounter an error?
5261 :
5262 : // if next token isn't comma, then it must be end of list
5263 46284 : if (lexer.peek_token ()->get_id () != COMMA)
5264 : break;
5265 :
5266 : // skip comma
5267 2217 : lexer.skip_token ();
5268 2217 : t = lexer.peek_token ();
5269 : }
5270 :
5271 : // try to parse bindings third
5272 22543 : std::vector<AST::GenericArgsBinding> binding_args;
5273 :
5274 : // TODO: think of better control structure
5275 22543 : t = lexer.peek_token ();
5276 23054 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5277 : {
5278 511 : AST::GenericArgsBinding binding = parse_generic_args_binding ();
5279 511 : if (binding.is_error ())
5280 : {
5281 : // not necessarily an error
5282 : break;
5283 : }
5284 :
5285 511 : binding_args.push_back (std::move (binding));
5286 :
5287 : // if next token isn't comma, then it must be end of list
5288 1022 : if (lexer.peek_token ()->get_id () != COMMA)
5289 : {
5290 : break;
5291 : }
5292 : // skip comma
5293 9 : lexer.skip_token ();
5294 :
5295 9 : t = lexer.peek_token ();
5296 : }
5297 :
5298 : // skip any trailing commas
5299 45086 : if (lexer.peek_token ()->get_id () == COMMA)
5300 0 : lexer.skip_token ();
5301 :
5302 22543 : if (!skip_generics_right_angle ())
5303 0 : return AST::GenericArgs::create_empty ();
5304 :
5305 22543 : lifetime_args.shrink_to_fit ();
5306 22543 : generic_args.shrink_to_fit ();
5307 22543 : binding_args.shrink_to_fit ();
5308 :
5309 22543 : return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
5310 22543 : std::move (binding_args), locus);
5311 45086 : }
5312 :
5313 : // Parses a binding in a generic args path segment.
5314 : template <typename ManagedTokenSource>
5315 : AST::GenericArgsBinding
5316 511 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
5317 : {
5318 511 : const_TokenPtr ident_tok = lexer.peek_token ();
5319 511 : if (ident_tok->get_id () != IDENTIFIER)
5320 : {
5321 : // allow non error-inducing use
5322 : // skip somewhere?
5323 0 : return AST::GenericArgsBinding::create_error ();
5324 : }
5325 511 : lexer.skip_token ();
5326 1022 : Identifier ident{ident_tok};
5327 :
5328 1022 : if (lexer.peek_token ()->get_id () == COLON)
5329 : {
5330 93 : lexer.skip_token ();
5331 93 : auto bounds_locus = lexer.peek_token ()->get_locus ();
5332 93 : auto bounds = parse_type_param_bounds ();
5333 93 : auto type = std::unique_ptr<AST::Type> (
5334 93 : new AST::ImplTraitType (std::move (bounds), bounds_locus));
5335 186 : return AST::GenericArgsBinding (
5336 : std::move (ident), std::move (type), ident_tok->get_locus (),
5337 186 : AST::GenericArgsBinding::Kind::Constraint);
5338 93 : }
5339 :
5340 418 : if (!skip_token (EQUAL))
5341 0 : return AST::GenericArgsBinding::create_error ();
5342 :
5343 : // parse type (required)
5344 418 : std::unique_ptr<AST::Type> type = parse_type ();
5345 418 : if (type == nullptr)
5346 : {
5347 : // skip somewhere?
5348 0 : return AST::GenericArgsBinding::create_error ();
5349 : }
5350 :
5351 836 : return AST::GenericArgsBinding (std::move (ident), std::move (type),
5352 836 : ident_tok->get_locus ());
5353 929 : }
5354 :
5355 : // Parses a self param. Also handles self param not existing.
5356 : template <typename ManagedTokenSource>
5357 : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
5358 35623 : Parser<ManagedTokenSource>::parse_self_param ()
5359 : {
5360 35623 : bool has_reference = false;
5361 35623 : AST::Lifetime lifetime = AST::Lifetime::elided ();
5362 :
5363 35623 : location_t locus = lexer.peek_token ()->get_locus ();
5364 :
5365 : // TODO: Feels off, find a better way to clearly express this
5366 142492 : std::vector<std::vector<TokenId>> ptrs
5367 : = {{ASTERISK, SELF} /* *self */,
5368 : {ASTERISK, CONST, SELF} /* *const self */,
5369 : {ASTERISK, MUT, SELF} /* *mut self */};
5370 :
5371 142486 : for (auto &s : ptrs)
5372 : {
5373 : size_t i = 0;
5374 106877 : for (i = 0; i < s.size (); i++)
5375 213748 : if (lexer.peek_token (i)->get_id () != s[i])
5376 : break;
5377 106866 : if (i == s.size ())
5378 : {
5379 3 : Error error (lexer.peek_token ()->get_locus (),
5380 : "cannot pass %<self%> by raw pointer");
5381 3 : add_error (std::move (error));
5382 3 : return Parse::Error::Self::make_self_raw_pointer ();
5383 3 : }
5384 : }
5385 :
5386 : // Trying to find those patterns:
5387 : //
5388 : // &'lifetime mut self
5389 : // &'lifetime self
5390 : // & mut self
5391 : // & self
5392 : // mut self
5393 : // self
5394 : //
5395 : // If not found, it is probably a function, exit and let function parsing
5396 : // handle it.
5397 : bool is_self = false;
5398 213720 : for (size_t i = 0; i < 5; i++)
5399 356200 : if (lexer.peek_token (i)->get_id () == SELF)
5400 17780 : is_self = true;
5401 :
5402 35620 : if (!is_self)
5403 17845 : return Parse::Error::Self::make_not_self ();
5404 :
5405 : // test if self is a reference parameter
5406 35550 : if (lexer.peek_token ()->get_id () == AMP)
5407 : {
5408 9906 : has_reference = true;
5409 9906 : lexer.skip_token ();
5410 :
5411 : // now test whether it has a lifetime
5412 19812 : if (lexer.peek_token ()->get_id () == LIFETIME)
5413 : {
5414 : // something went wrong somehow
5415 106 : if (auto parsed_lifetime = parse_lifetime (true))
5416 : {
5417 53 : lifetime = parsed_lifetime.value ();
5418 : }
5419 : else
5420 : {
5421 0 : Error error (lexer.peek_token ()->get_locus (),
5422 : "failed to parse lifetime in self param");
5423 0 : add_error (std::move (error));
5424 :
5425 : // skip after somewhere?
5426 0 : return Parse::Error::Self::make_parsing_error ();
5427 0 : }
5428 : }
5429 : }
5430 :
5431 : // test for mut
5432 17775 : bool has_mut = false;
5433 35550 : if (lexer.peek_token ()->get_id () == MUT)
5434 : {
5435 2866 : has_mut = true;
5436 2866 : lexer.skip_token ();
5437 : }
5438 :
5439 : // skip self token
5440 17775 : const_TokenPtr self_tok = lexer.peek_token ();
5441 17775 : if (self_tok->get_id () != SELF)
5442 : {
5443 : // skip after somewhere?
5444 4 : return Parse::Error::Self::make_not_self ();
5445 : }
5446 17771 : lexer.skip_token ();
5447 :
5448 : // parse optional type
5449 17771 : std::unique_ptr<AST::Type> type = nullptr;
5450 35542 : if (lexer.peek_token ()->get_id () == COLON)
5451 : {
5452 28 : lexer.skip_token ();
5453 :
5454 : // type is now required
5455 28 : type = parse_type ();
5456 28 : if (type == nullptr)
5457 : {
5458 0 : Error error (lexer.peek_token ()->get_locus (),
5459 : "could not parse type in self param");
5460 0 : add_error (std::move (error));
5461 :
5462 : // skip after somewhere?
5463 0 : return Parse::Error::Self::make_parsing_error ();
5464 0 : }
5465 : }
5466 :
5467 : // ensure that cannot have both type and reference
5468 17771 : if (type && has_reference)
5469 : {
5470 0 : Error error (
5471 0 : lexer.peek_token ()->get_locus (),
5472 : "cannot have both a reference and a type specified in a self param");
5473 0 : add_error (std::move (error));
5474 :
5475 : // skip after somewhere?
5476 0 : return Parse::Error::Self::make_parsing_error ();
5477 0 : }
5478 :
5479 17771 : if (has_reference)
5480 : {
5481 9906 : return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
5482 9906 : locus);
5483 : }
5484 : else
5485 : {
5486 : // note that type may be nullptr here and that's fine
5487 7865 : return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
5488 7865 : locus);
5489 : }
5490 53394 : }
5491 :
5492 : /* Parses an expression or macro statement. */
5493 : template <typename ManagedTokenSource>
5494 : std::unique_ptr<AST::Stmt>
5495 643 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
5496 : ParseRestrictions restrictions)
5497 : {
5498 643 : location_t locus = lexer.peek_token ()->get_locus ();
5499 :
5500 643 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
5501 :
5502 1286 : switch (lexer.peek_token ()->get_id ())
5503 : {
5504 271 : case IDENTIFIER:
5505 : case CRATE:
5506 : case SUPER:
5507 : case SELF:
5508 : case SELF_ALIAS:
5509 : case DOLLAR_SIGN:
5510 : case SCOPE_RESOLUTION:
5511 : {
5512 271 : AST::PathInExpression path = parse_path_in_expression ();
5513 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
5514 271 : null_denotation;
5515 :
5516 542 : if (lexer.peek_token ()->get_id () == EXCLAM)
5517 : {
5518 61 : std::unique_ptr<AST::MacroInvocation> invoc
5519 122 : = parse_macro_invocation_partial (std::move (path),
5520 : std::move (outer_attrs));
5521 :
5522 61 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
5523 : {
5524 59 : invoc->add_semicolon ();
5525 : // Macro invocation with semicolon.
5526 59 : return invoc;
5527 : }
5528 :
5529 2 : TokenId after_macro = lexer.peek_token ()->get_id ();
5530 :
5531 2 : if (restrictions.allow_close_after_expr_stmt
5532 2 : && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
5533 : || after_macro == RIGHT_SQUARE))
5534 2 : return invoc;
5535 :
5536 0 : if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
5537 : == AST::CURLY
5538 0 : && after_macro != DOT && after_macro != QUESTION_MARK)
5539 : {
5540 0 : rust_debug ("braced macro statement");
5541 0 : return invoc;
5542 : }
5543 :
5544 0 : null_denotation = std::move (invoc);
5545 61 : }
5546 : else
5547 : {
5548 : null_denotation
5549 420 : = null_denotation_path (std::move (path), {}, restrictions);
5550 : }
5551 :
5552 840 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
5553 : std::move (outer_attrs), restrictions);
5554 : break;
5555 271 : }
5556 372 : default:
5557 372 : restrictions.expr_can_be_stmt = true;
5558 744 : expr = parse_expr (std::move (outer_attrs), restrictions);
5559 372 : break;
5560 : }
5561 :
5562 582 : if (!expr)
5563 : {
5564 : // expr is required, error
5565 0 : Error error (lexer.peek_token ()->get_locus (),
5566 : "failed to parse expr in expr statement");
5567 0 : add_error (std::move (error));
5568 :
5569 0 : skip_after_semicolon ();
5570 0 : return nullptr;
5571 0 : }
5572 :
5573 582 : bool has_semi = false;
5574 :
5575 582 : if (restrictions.consume_semi)
5576 : {
5577 566 : if (maybe_skip_token (SEMICOLON))
5578 : {
5579 166 : has_semi = true;
5580 : }
5581 400 : else if (expr.value ()->is_expr_without_block ())
5582 : {
5583 34 : if (restrictions.allow_close_after_expr_stmt)
5584 : {
5585 34 : TokenId id = lexer.peek_token ()->get_id ();
5586 34 : if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
5587 : {
5588 3 : expect_token (SEMICOLON);
5589 3 : return nullptr;
5590 : }
5591 : }
5592 : else
5593 : {
5594 0 : expect_token (SEMICOLON);
5595 0 : return nullptr;
5596 : }
5597 : }
5598 : }
5599 :
5600 579 : return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
5601 579 : has_semi);
5602 643 : }
5603 :
5604 : // Parses a loop label used in loop expressions.
5605 : template <typename ManagedTokenSource>
5606 : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
5607 61 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
5608 : {
5609 : // parse lifetime - if doesn't exist, assume no label
5610 61 : if (tok->get_id () != LIFETIME)
5611 : {
5612 : // not necessarily an error
5613 0 : return Parse::Error::LoopLabel::make_not_loop_label ();
5614 : }
5615 : /* FIXME: check for named lifetime requirement here? or check in semantic
5616 : * analysis phase? */
5617 122 : AST::Lifetime label = lifetime_from_token (tok);
5618 :
5619 61 : if (!skip_token (COLON))
5620 : {
5621 : // skip somewhere?
5622 61 : Parse::Error::LoopLabel::make_missing_colon ();
5623 : }
5624 :
5625 : return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
5626 61 : AST::LoopLabel (std::move (label), tok->get_locus ()));
5627 61 : }
5628 :
5629 : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
5630 : template <typename ManagedTokenSource>
5631 : AST::MatchArm
5632 50363 : Parser<ManagedTokenSource>::parse_match_arm ()
5633 : {
5634 : // parse optional outer attributes
5635 50363 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5636 :
5637 : // DEBUG
5638 50363 : rust_debug ("about to start parsing match arm patterns");
5639 :
5640 : // break early if find right curly
5641 100726 : if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
5642 : {
5643 : // not an error
5644 0 : return AST::MatchArm::create_error ();
5645 : }
5646 :
5647 : // parse match arm patterns - at least 1 is required
5648 50363 : std::unique_ptr<AST::Pattern> match_arm_pattern
5649 : = parse_match_arm_pattern (RIGHT_CURLY);
5650 50363 : if (match_arm_pattern == nullptr)
5651 : {
5652 0 : Error error (lexer.peek_token ()->get_locus (),
5653 : "failed to parse any patterns in match arm");
5654 0 : add_error (std::move (error));
5655 :
5656 : // skip somewhere?
5657 0 : return AST::MatchArm::create_error ();
5658 0 : }
5659 :
5660 : // DEBUG
5661 50363 : rust_debug ("successfully parsed match arm patterns");
5662 :
5663 : // parse match arm guard expr if it exists
5664 50363 : std::unique_ptr<AST::Expr> guard_expr = nullptr;
5665 100726 : if (lexer.peek_token ()->get_id () == IF)
5666 : {
5667 43 : lexer.skip_token ();
5668 :
5669 43 : auto guard_expr_res = parse_expr ();
5670 43 : if (!guard_expr_res)
5671 : {
5672 0 : Error error (lexer.peek_token ()->get_locus (),
5673 : "failed to parse guard expression in match arm");
5674 0 : add_error (std::move (error));
5675 :
5676 : // skip somewhere?
5677 0 : return AST::MatchArm::create_error ();
5678 0 : }
5679 43 : guard_expr = std::move (guard_expr_res.value ());
5680 43 : }
5681 :
5682 : // DEBUG
5683 50363 : rust_debug ("successfully parsed match arm");
5684 :
5685 100726 : return AST::MatchArm (std::move (match_arm_pattern),
5686 100726 : lexer.peek_token ()->get_locus (),
5687 50363 : std::move (guard_expr), std::move (outer_attrs));
5688 50363 : }
5689 :
5690 : /* Parses the patterns used in a match arm. End token id is the id of the
5691 : * token that would exist after the patterns are done (e.g. '}' for match
5692 : * expr, '=' for if let and while let). */
5693 : template <typename ManagedTokenSource>
5694 : std::unique_ptr<AST::Pattern>
5695 50578 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
5696 : {
5697 : // skip optional leading '|'
5698 101156 : if (lexer.peek_token ()->get_id () == PIPE)
5699 0 : lexer.skip_token ();
5700 : /* TODO: do I even need to store the result of this? can't be used.
5701 : * If semantically different, I need a wrapped "match arm patterns" object
5702 : * for this. */
5703 :
5704 50578 : std::unique_ptr<AST::Pattern> pattern;
5705 :
5706 : // quick break out if end_token_id
5707 101156 : if (lexer.peek_token ()->get_id () == end_token_id)
5708 1 : return pattern;
5709 :
5710 : // parse required pattern - if doesn't exist, return empty
5711 50577 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
5712 50577 : if (initial_pattern == nullptr)
5713 : {
5714 : // FIXME: should this be an error?
5715 0 : return pattern;
5716 : }
5717 :
5718 50577 : return initial_pattern;
5719 50578 : }
5720 :
5721 : // Parses a single parameter used in a closure definition.
5722 : template <typename ManagedTokenSource>
5723 : AST::ClosureParam
5724 611 : Parser<ManagedTokenSource>::parse_closure_param ()
5725 : {
5726 611 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5727 :
5728 : // parse pattern (which is required)
5729 611 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
5730 611 : if (pattern == nullptr)
5731 : {
5732 : // not necessarily an error
5733 0 : return AST::ClosureParam::create_error ();
5734 : }
5735 :
5736 : // parse optional type of param
5737 611 : std::unique_ptr<AST::Type> type = nullptr;
5738 1222 : if (lexer.peek_token ()->get_id () == COLON)
5739 : {
5740 88 : lexer.skip_token ();
5741 :
5742 : // parse type, which is now required
5743 88 : type = parse_type ();
5744 88 : if (type == nullptr)
5745 : {
5746 0 : Error error (lexer.peek_token ()->get_locus (),
5747 : "failed to parse type in closure parameter");
5748 0 : add_error (std::move (error));
5749 :
5750 : // skip somewhere?
5751 0 : return AST::ClosureParam::create_error ();
5752 0 : }
5753 : }
5754 :
5755 611 : location_t loc = pattern->get_locus ();
5756 611 : return AST::ClosureParam (std::move (pattern), loc, std::move (type),
5757 611 : std::move (outer_attrs));
5758 611 : }
5759 :
5760 : // Parses a type (will further disambiguate any type).
5761 : template <typename ManagedTokenSource>
5762 : std::unique_ptr<AST::Type>
5763 117542 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
5764 : {
5765 : /* rules for all types:
5766 : * NeverType: '!'
5767 : * SliceType: '[' Type ']'
5768 : * InferredType: '_'
5769 : * MacroInvocation: SimplePath '!' DelimTokenTree
5770 : * ParenthesisedType: '(' Type ')'
5771 : * ImplTraitType: 'impl' TypeParamBounds
5772 : * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
5773 : * TypeParamBound Lifetime | TraitBound
5774 : * ImplTraitTypeOneBound: 'impl' TraitBound
5775 : * TraitObjectType: 'dyn'? TypeParamBounds
5776 : * TraitObjectTypeOneBound: 'dyn'? TraitBound
5777 : * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
5778 : * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
5779 : * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
5780 : * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
5781 : * 'unsafe'?
5782 : * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
5783 : * (
5784 : * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
5785 : * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
5786 : * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
5787 : * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
5788 : * TupleType: '(' Type etc. - regular tuple stuff. Also
5789 : * regular tuple vs parenthesised precedence
5790 : *
5791 : * Disambiguate between macro and type path via type path being parsed, and
5792 : * then if '!' found, convert type path to simple path for macro. Usual
5793 : * disambiguation for tuple vs parenthesised. For ImplTraitType and
5794 : * TraitObjectType individual disambiguations, they seem more like "special
5795 : * cases", so probably just try to parse the more general ImplTraitType or
5796 : * TraitObjectType and return OneBound versions if they satisfy those
5797 : * criteria. */
5798 :
5799 117542 : const_TokenPtr t = lexer.peek_token ();
5800 117542 : switch (t->get_id ())
5801 : {
5802 257 : case EXCLAM:
5803 : // never type - can't be macro as no path beforehand
5804 257 : lexer.skip_token ();
5805 257 : return std::unique_ptr<AST::NeverType> (
5806 257 : new AST::NeverType (t->get_locus ()));
5807 1526 : case LEFT_SQUARE:
5808 : // slice type or array type - requires further disambiguation
5809 1526 : return parse_slice_or_array_type ();
5810 3555 : case LEFT_SHIFT:
5811 : case LEFT_ANGLE:
5812 : {
5813 : // qualified path in type
5814 3555 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
5815 3555 : if (path.is_error ())
5816 : {
5817 0 : if (save_errors)
5818 : {
5819 0 : Error error (t->get_locus (),
5820 : "failed to parse qualified path in type");
5821 0 : add_error (std::move (error));
5822 0 : }
5823 :
5824 0 : return nullptr;
5825 : }
5826 3555 : return std::unique_ptr<AST::QualifiedPathInType> (
5827 3555 : new AST::QualifiedPathInType (std::move (path)));
5828 3555 : }
5829 337 : case UNDERSCORE:
5830 : // inferred type
5831 337 : lexer.skip_token ();
5832 337 : return std::unique_ptr<AST::InferredType> (
5833 337 : new AST::InferredType (t->get_locus ()));
5834 3873 : case ASTERISK:
5835 : // raw pointer type
5836 3873 : return parse_raw_pointer_type ();
5837 12932 : case AMP: // does this also include AMP_AMP?
5838 : case LOGICAL_AND:
5839 : // reference type
5840 12932 : return parse_reference_type ();
5841 0 : case LIFETIME:
5842 : {
5843 : /* probably a lifetime bound, so probably type param bounds in
5844 : * TraitObjectType */
5845 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5846 : = parse_type_param_bounds ();
5847 :
5848 0 : return std::unique_ptr<AST::TraitObjectType> (
5849 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5850 0 : false));
5851 0 : }
5852 92704 : case IDENTIFIER:
5853 : case SUPER:
5854 : case SELF:
5855 : case SELF_ALIAS:
5856 : case CRATE:
5857 : case DOLLAR_SIGN:
5858 : case SCOPE_RESOLUTION:
5859 : {
5860 : // macro invocation or type path - requires further disambiguation.
5861 : /* for parsing path component of each rule, perhaps parse it as a
5862 : * typepath and attempt conversion to simplepath if a trailing '!' is
5863 : * found */
5864 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
5865 : * with it, it is exactly the same as a TypePath syntactically, so
5866 : * this is a syntactical ambiguity. As such, the parser will parse it
5867 : * as a TypePath. This, however, does not prevent TraitObjectType from
5868 : * starting with a typepath. */
5869 :
5870 : // parse path as type path
5871 92704 : AST::TypePath path = parse_type_path ();
5872 92704 : if (path.is_error ())
5873 : {
5874 0 : if (save_errors)
5875 : {
5876 0 : Error error (t->get_locus (),
5877 : "failed to parse path as first component of type");
5878 0 : add_error (std::move (error));
5879 0 : }
5880 :
5881 0 : return nullptr;
5882 : }
5883 92704 : location_t locus = path.get_locus ();
5884 :
5885 : // branch on next token
5886 92704 : t = lexer.peek_token ();
5887 92704 : switch (t->get_id ())
5888 : {
5889 497 : case EXCLAM:
5890 : {
5891 : // macro invocation
5892 : // convert to simple path
5893 497 : AST::SimplePath macro_path = path.as_simple_path ();
5894 497 : if (macro_path.is_empty ())
5895 : {
5896 0 : if (save_errors)
5897 : {
5898 0 : Error error (t->get_locus (),
5899 : "failed to parse simple path in macro "
5900 : "invocation (for type)");
5901 0 : add_error (std::move (error));
5902 0 : }
5903 :
5904 0 : return nullptr;
5905 : }
5906 :
5907 497 : lexer.skip_token ();
5908 :
5909 497 : auto tok_tree = parse_delim_token_tree ();
5910 497 : if (!tok_tree)
5911 0 : return nullptr;
5912 :
5913 994 : return AST::MacroInvocation::Regular (
5914 994 : AST::MacroInvocData (std::move (macro_path),
5915 497 : std::move (tok_tree.value ())),
5916 497 : {}, locus);
5917 994 : }
5918 29 : case PLUS:
5919 : {
5920 : // type param bounds
5921 29 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5922 :
5923 : // convert type path to trait bound
5924 29 : std::unique_ptr<AST::TraitBound> path_bound (
5925 29 : new AST::TraitBound (std::move (path), locus, false, false));
5926 29 : bounds.push_back (std::move (path_bound));
5927 :
5928 : /* parse rest of bounds - FIXME: better way to find when to stop
5929 : * parsing */
5930 58 : while (t->get_id () == PLUS)
5931 : {
5932 29 : lexer.skip_token ();
5933 :
5934 : // parse bound if it exists - if not, assume end of sequence
5935 29 : std::unique_ptr<AST::TypeParamBound> bound
5936 : = parse_type_param_bound ();
5937 29 : if (bound == nullptr)
5938 : {
5939 : break;
5940 : }
5941 29 : bounds.push_back (std::move (bound));
5942 :
5943 29 : t = lexer.peek_token ();
5944 : }
5945 :
5946 29 : return std::unique_ptr<AST::TraitObjectType> (
5947 29 : new AST::TraitObjectType (std::move (bounds), locus, false));
5948 29 : }
5949 92178 : default:
5950 : // assume that this is a type path and not an error
5951 92178 : return std::unique_ptr<AST::TypePath> (
5952 92178 : new AST::TypePath (std::move (path)));
5953 : }
5954 92704 : }
5955 1342 : case LEFT_PAREN:
5956 : /* tuple type or parenthesised type - requires further disambiguation
5957 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
5958 : * could be TraitObjectTypeOneBound or TraitObjectType */
5959 1342 : return parse_paren_prefixed_type ();
5960 5 : case FOR:
5961 : // TraitObjectTypeOneBound or BareFunctionType
5962 5 : return parse_for_prefixed_type ();
5963 694 : case ASYNC:
5964 : case CONST:
5965 : case UNSAFE:
5966 : case EXTERN_KW:
5967 : case FN_KW:
5968 : // bare function type (with no for lifetimes)
5969 694 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
5970 241 : case IMPL:
5971 241 : lexer.skip_token ();
5972 482 : if (lexer.peek_token ()->get_id () == LIFETIME)
5973 : {
5974 : /* cannot be one bound because lifetime prevents it from being
5975 : * traitbound */
5976 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5977 : = parse_type_param_bounds ();
5978 :
5979 0 : return std::unique_ptr<AST::ImplTraitType> (
5980 0 : new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
5981 0 : }
5982 : else
5983 : {
5984 : // should be trait bound, so parse trait bound
5985 241 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
5986 241 : if (initial_bound == nullptr)
5987 : {
5988 0 : if (save_errors)
5989 : {
5990 0 : Error error (lexer.peek_token ()->get_locus (),
5991 : "failed to parse ImplTraitType initial bound");
5992 0 : add_error (std::move (error));
5993 0 : }
5994 :
5995 0 : return nullptr;
5996 : }
5997 :
5998 241 : location_t locus = t->get_locus ();
5999 :
6000 : // short cut if next token isn't '+'
6001 241 : t = lexer.peek_token ();
6002 241 : if (t->get_id () != PLUS)
6003 : {
6004 239 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6005 239 : new AST::ImplTraitTypeOneBound (std::move (initial_bound),
6006 239 : locus));
6007 : }
6008 :
6009 : // parse additional type param bounds
6010 2 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6011 2 : bounds.push_back (std::move (initial_bound));
6012 4 : while (t->get_id () == PLUS)
6013 : {
6014 2 : lexer.skip_token ();
6015 :
6016 : // parse bound if it exists
6017 2 : std::unique_ptr<AST::TypeParamBound> bound
6018 : = parse_type_param_bound ();
6019 2 : if (bound == nullptr)
6020 : {
6021 : // not an error as trailing plus may exist
6022 : break;
6023 : }
6024 2 : bounds.push_back (std::move (bound));
6025 :
6026 2 : t = lexer.peek_token ();
6027 : }
6028 :
6029 2 : return std::unique_ptr<AST::ImplTraitType> (
6030 2 : new AST::ImplTraitType (std::move (bounds), locus));
6031 241 : }
6032 60 : case DYN:
6033 : case QUESTION_MARK:
6034 : {
6035 : // either TraitObjectType or TraitObjectTypeOneBound
6036 60 : bool has_dyn = false;
6037 60 : if (t->get_id () == DYN)
6038 : {
6039 60 : lexer.skip_token ();
6040 60 : has_dyn = true;
6041 : }
6042 :
6043 120 : if (lexer.peek_token ()->get_id () == LIFETIME)
6044 : {
6045 : /* cannot be one bound because lifetime prevents it from being
6046 : * traitbound */
6047 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
6048 : = parse_type_param_bounds ();
6049 :
6050 0 : return std::unique_ptr<AST::TraitObjectType> (
6051 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
6052 0 : has_dyn));
6053 0 : }
6054 : else
6055 : {
6056 : // should be trait bound, so parse trait bound
6057 60 : std::unique_ptr<AST::TraitBound> initial_bound
6058 : = parse_trait_bound ();
6059 60 : if (initial_bound == nullptr)
6060 : {
6061 2 : if (save_errors)
6062 : {
6063 2 : Error error (
6064 2 : lexer.peek_token ()->get_locus (),
6065 : "failed to parse TraitObjectType initial bound");
6066 2 : add_error (std::move (error));
6067 2 : }
6068 :
6069 2 : return nullptr;
6070 : }
6071 :
6072 : // short cut if next token isn't '+'
6073 58 : t = lexer.peek_token ();
6074 58 : if (t->get_id () != PLUS)
6075 : {
6076 : // convert trait bound to value object
6077 27 : AST::TraitBound value_bound (*initial_bound);
6078 :
6079 : // DEBUG: removed as unique ptr, so should auto delete
6080 : // delete initial_bound;
6081 :
6082 27 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6083 54 : new AST::TraitObjectTypeOneBound (std::move (value_bound),
6084 27 : t->get_locus (), has_dyn));
6085 27 : }
6086 :
6087 : // parse additional type param bounds
6088 31 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6089 31 : bounds.push_back (std::move (initial_bound));
6090 72 : while (t->get_id () == PLUS)
6091 : {
6092 41 : lexer.skip_token ();
6093 :
6094 : // parse bound if it exists
6095 41 : std::unique_ptr<AST::TypeParamBound> bound
6096 : = parse_type_param_bound ();
6097 41 : if (bound == nullptr)
6098 : {
6099 : // not an error as trailing plus may exist
6100 : break;
6101 : }
6102 41 : bounds.push_back (std::move (bound));
6103 :
6104 41 : t = lexer.peek_token ();
6105 : }
6106 :
6107 31 : return std::unique_ptr<AST::TraitObjectType> (
6108 31 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
6109 31 : has_dyn));
6110 60 : }
6111 : }
6112 16 : default:
6113 16 : if (save_errors)
6114 16 : add_error (Error (t->get_locus (), "unrecognised token %qs in type",
6115 : t->get_token_description ()));
6116 :
6117 16 : return nullptr;
6118 : }
6119 117542 : }
6120 :
6121 : /* Parses a type that has '(' as its first character. Returns a tuple type,
6122 : * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
6123 : * on following characters. */
6124 : template <typename ManagedTokenSource>
6125 : std::unique_ptr<AST::Type>
6126 1342 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
6127 : {
6128 : /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
6129 : * a trait bound, not a parenthesised type, so that it can still be used in
6130 : * type param bounds. */
6131 :
6132 : /* NOTE: this implementation is really shit but I couldn't think of a better
6133 : * one. It requires essentially breaking polymorphism and downcasting via
6134 : * virtual method abuse, as it was copied from the rustc implementation (in
6135 : * which types are reified due to tagged union), after a more OOP attempt by
6136 : * me failed. */
6137 1342 : location_t left_delim_locus = lexer.peek_token ()->get_locus ();
6138 :
6139 : // skip left delim
6140 1342 : lexer.skip_token ();
6141 : /* while next token isn't close delim, parse comma-separated types, saving
6142 : * whether trailing comma happens */
6143 1342 : const_TokenPtr t = lexer.peek_token ();
6144 1342 : bool trailing_comma = true;
6145 1342 : std::vector<std::unique_ptr<AST::Type>> types;
6146 :
6147 3049 : while (t->get_id () != RIGHT_PAREN)
6148 : {
6149 2658 : std::unique_ptr<AST::Type> type = parse_type ();
6150 2658 : if (type == nullptr)
6151 : {
6152 0 : Error error (t->get_locus (),
6153 : "failed to parse type inside parentheses (probably "
6154 : "tuple or parenthesised)");
6155 0 : add_error (std::move (error));
6156 :
6157 0 : return nullptr;
6158 0 : }
6159 2658 : types.push_back (std::move (type));
6160 :
6161 2658 : t = lexer.peek_token ();
6162 2658 : if (t->get_id () != COMMA)
6163 : {
6164 951 : trailing_comma = false;
6165 : break;
6166 : }
6167 1707 : lexer.skip_token ();
6168 :
6169 1707 : t = lexer.peek_token ();
6170 : }
6171 :
6172 1342 : if (!skip_token (RIGHT_PAREN))
6173 : {
6174 0 : return nullptr;
6175 : }
6176 :
6177 : // if only one type and no trailing comma, then not a tuple type
6178 1342 : if (types.size () == 1 && !trailing_comma)
6179 : {
6180 : // must be a TraitObjectType (with more than one bound)
6181 10 : if (lexer.peek_token ()->get_id () == PLUS)
6182 : {
6183 : // create type param bounds vector
6184 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6185 :
6186 : // HACK: convert type to traitbound and add to bounds
6187 0 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6188 0 : std::unique_ptr<AST::TraitBound> converted_bound (
6189 0 : released_ptr->to_trait_bound (true));
6190 0 : if (converted_bound == nullptr)
6191 : {
6192 0 : Error error (
6193 0 : lexer.peek_token ()->get_locus (),
6194 : "failed to hackily converted parsed type to trait bound");
6195 0 : add_error (std::move (error));
6196 :
6197 0 : return nullptr;
6198 0 : }
6199 0 : bounds.push_back (std::move (converted_bound));
6200 :
6201 0 : t = lexer.peek_token ();
6202 0 : while (t->get_id () == PLUS)
6203 : {
6204 0 : lexer.skip_token ();
6205 :
6206 : // attempt to parse typeparambound
6207 0 : std::unique_ptr<AST::TypeParamBound> bound
6208 : = parse_type_param_bound ();
6209 0 : if (bound == nullptr)
6210 : {
6211 : // not an error if null
6212 : break;
6213 : }
6214 0 : bounds.push_back (std::move (bound));
6215 :
6216 0 : t = lexer.peek_token ();
6217 : }
6218 :
6219 0 : return std::unique_ptr<AST::TraitObjectType> (
6220 0 : new AST::TraitObjectType (std::move (bounds), left_delim_locus,
6221 0 : false));
6222 0 : }
6223 : else
6224 : {
6225 : // release vector pointer
6226 5 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6227 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6228 : * type */
6229 5 : std::unique_ptr<AST::TraitBound> converted_bound (
6230 5 : released_ptr->to_trait_bound (true));
6231 5 : if (converted_bound == nullptr)
6232 : {
6233 : // parenthesised type
6234 5 : return std::unique_ptr<AST::ParenthesisedType> (
6235 5 : new AST::ParenthesisedType (std::move (released_ptr),
6236 5 : left_delim_locus));
6237 : }
6238 : else
6239 : {
6240 : // trait object type (one bound)
6241 :
6242 : // get value semantics trait bound
6243 0 : AST::TraitBound value_bound (*converted_bound);
6244 :
6245 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6246 0 : new AST::TraitObjectTypeOneBound (value_bound,
6247 0 : left_delim_locus));
6248 0 : }
6249 5 : }
6250 : }
6251 : else
6252 : {
6253 1337 : return std::unique_ptr<AST::TupleType> (
6254 1337 : new AST::TupleType (std::move (types), left_delim_locus));
6255 : }
6256 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6257 : * lost somehow */
6258 1342 : }
6259 :
6260 : /* Parses a type that has 'for' as its first character. This means it has a
6261 : * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
6262 : * TraitObjectTypeOneBound depending on following characters. */
6263 : template <typename ManagedTokenSource>
6264 : std::unique_ptr<AST::Type>
6265 5 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
6266 : {
6267 5 : location_t for_locus = lexer.peek_token ()->get_locus ();
6268 : // parse for lifetimes in type
6269 5 : std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
6270 :
6271 : // branch on next token - either function or a trait type
6272 5 : const_TokenPtr t = lexer.peek_token ();
6273 5 : switch (t->get_id ())
6274 : {
6275 4 : case ASYNC:
6276 : case CONST:
6277 : case UNSAFE:
6278 : case EXTERN_KW:
6279 : case FN_KW:
6280 4 : return parse_bare_function_type (std::move (for_lifetimes));
6281 1 : case SCOPE_RESOLUTION:
6282 : case IDENTIFIER:
6283 : case SUPER:
6284 : case SELF:
6285 : case SELF_ALIAS:
6286 : case CRATE:
6287 : case DOLLAR_SIGN:
6288 : {
6289 : // path, so trait type
6290 :
6291 : // parse type path to finish parsing trait bound
6292 1 : AST::TypePath path = parse_type_path ();
6293 :
6294 1 : t = lexer.peek_token ();
6295 1 : if (t->get_id () != PLUS)
6296 : {
6297 : // must be one-bound trait type
6298 : // create trait bound value object
6299 1 : AST::TraitBound bound (std::move (path), for_locus, false, false,
6300 : std::move (for_lifetimes));
6301 :
6302 1 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6303 2 : new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
6304 1 : }
6305 :
6306 : /* more than one bound trait type (or at least parsed as it - could be
6307 : * trailing '+') create trait bound pointer and bounds */
6308 0 : std::unique_ptr<AST::TraitBound> initial_bound (
6309 0 : new AST::TraitBound (std::move (path), for_locus, false, false,
6310 : std::move (for_lifetimes)));
6311 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6312 0 : bounds.push_back (std::move (initial_bound));
6313 :
6314 0 : while (t->get_id () == PLUS)
6315 : {
6316 0 : lexer.skip_token ();
6317 :
6318 : // parse type param bound if it exists
6319 0 : std::unique_ptr<AST::TypeParamBound> bound
6320 : = parse_type_param_bound ();
6321 0 : if (bound == nullptr)
6322 : {
6323 : // not an error - e.g. trailing plus
6324 0 : return nullptr;
6325 : }
6326 0 : bounds.push_back (std::move (bound));
6327 :
6328 0 : t = lexer.peek_token ();
6329 : }
6330 :
6331 0 : return std::unique_ptr<AST::TraitObjectType> (
6332 0 : new AST::TraitObjectType (std::move (bounds), for_locus, false));
6333 1 : }
6334 0 : default:
6335 : // error
6336 0 : add_error (Error (t->get_locus (),
6337 : "unrecognised token %qs in bare function type or trait "
6338 : "object type or trait object type one bound",
6339 : t->get_token_description ()));
6340 :
6341 0 : return nullptr;
6342 : }
6343 5 : }
6344 :
6345 : // Parses a maybe named param used in bare function types.
6346 : template <typename ManagedTokenSource>
6347 : AST::MaybeNamedParam
6348 3823 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
6349 : {
6350 : /* Basically guess that param is named if first token is identifier or
6351 : * underscore and second token is semicolon. This should probably have no
6352 : * exceptions. rustc uses backtracking to parse these, but at the time of
6353 : * writing gccrs has no backtracking capabilities. */
6354 3823 : const_TokenPtr current = lexer.peek_token ();
6355 3823 : const_TokenPtr next = lexer.peek_token (1);
6356 :
6357 3823 : Identifier name;
6358 3823 : AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
6359 :
6360 3823 : if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
6361 : {
6362 : // named param
6363 1 : name = {current};
6364 1 : kind = AST::MaybeNamedParam::IDENTIFIER;
6365 1 : lexer.skip_token (1);
6366 : }
6367 3822 : else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
6368 : {
6369 : // wildcard param
6370 12 : name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
6371 6 : kind = AST::MaybeNamedParam::WILDCARD;
6372 6 : lexer.skip_token (1);
6373 : }
6374 :
6375 : // parse type (required)
6376 3823 : std::unique_ptr<AST::Type> type = parse_type ();
6377 3823 : if (type == nullptr)
6378 : {
6379 0 : Error error (lexer.peek_token ()->get_locus (),
6380 : "failed to parse type in maybe named param");
6381 0 : add_error (std::move (error));
6382 :
6383 0 : return AST::MaybeNamedParam::create_error ();
6384 0 : }
6385 :
6386 7646 : return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
6387 3823 : std::move (outer_attrs), current->get_locus ());
6388 7646 : }
6389 :
6390 : /* Parses a bare function type (with the given for lifetimes for convenience -
6391 : * does not parse them itself). */
6392 : template <typename ManagedTokenSource>
6393 : std::unique_ptr<AST::BareFunctionType>
6394 700 : Parser<ManagedTokenSource>::parse_bare_function_type (
6395 : std::vector<AST::LifetimeParam> for_lifetimes)
6396 : {
6397 : // TODO: pass in for lifetime location as param
6398 700 : location_t best_try_locus = lexer.peek_token ()->get_locus ();
6399 :
6400 700 : auto qualifiers = parse_function_qualifiers ();
6401 700 : if (!qualifiers)
6402 0 : return nullptr;
6403 :
6404 700 : if (!skip_token (FN_KW))
6405 0 : return nullptr;
6406 :
6407 700 : if (!skip_token (LEFT_PAREN))
6408 0 : return nullptr;
6409 :
6410 : // parse function params, if they exist
6411 700 : std::vector<AST::MaybeNamedParam> params;
6412 700 : bool is_variadic = false;
6413 700 : AST::AttrVec variadic_attrs;
6414 :
6415 700 : const_TokenPtr t = lexer.peek_token ();
6416 8087 : while (t->get_id () != RIGHT_PAREN)
6417 : {
6418 4015 : AST::AttrVec temp_attrs = parse_outer_attributes ();
6419 :
6420 8030 : if (lexer.peek_token ()->get_id () == ELLIPSIS)
6421 : {
6422 192 : lexer.skip_token ();
6423 192 : is_variadic = true;
6424 192 : variadic_attrs = std::move (temp_attrs);
6425 :
6426 192 : t = lexer.peek_token ();
6427 :
6428 192 : if (t->get_id () != RIGHT_PAREN)
6429 : {
6430 0 : Error error (t->get_locus (),
6431 : "expected right parentheses after variadic in maybe "
6432 : "named function "
6433 : "parameters, found %qs",
6434 : t->get_token_description ());
6435 0 : add_error (std::move (error));
6436 :
6437 0 : return nullptr;
6438 0 : }
6439 :
6440 : break;
6441 : }
6442 :
6443 3823 : AST::MaybeNamedParam param
6444 3823 : = parse_maybe_named_param (std::move (temp_attrs));
6445 3823 : if (param.is_error ())
6446 : {
6447 0 : Error error (
6448 0 : lexer.peek_token ()->get_locus (),
6449 : "failed to parse maybe named param in bare function type");
6450 0 : add_error (std::move (error));
6451 :
6452 0 : return nullptr;
6453 0 : }
6454 3823 : params.push_back (std::move (param));
6455 :
6456 7646 : if (lexer.peek_token ()->get_id () != COMMA)
6457 : break;
6458 :
6459 3372 : lexer.skip_token ();
6460 3372 : t = lexer.peek_token ();
6461 : }
6462 :
6463 700 : if (!skip_token (RIGHT_PAREN))
6464 0 : return nullptr;
6465 :
6466 : // bare function return type, if exists
6467 700 : std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
6468 1400 : if (lexer.peek_token ()->get_id () == RETURN_TYPE)
6469 : {
6470 671 : lexer.skip_token ();
6471 :
6472 : // parse required TypeNoBounds
6473 671 : return_type = parse_type_no_bounds ();
6474 671 : if (return_type == nullptr)
6475 : {
6476 0 : Error error (lexer.peek_token ()->get_locus (),
6477 : "failed to parse return type (type no bounds) in bare "
6478 : "function type");
6479 0 : add_error (std::move (error));
6480 :
6481 0 : return nullptr;
6482 0 : }
6483 : }
6484 :
6485 700 : return std::unique_ptr<AST::BareFunctionType> (new AST::BareFunctionType (
6486 700 : std::move (for_lifetimes), std::move (qualifiers.value ()),
6487 : std::move (params), is_variadic, std::move (variadic_attrs),
6488 700 : std::move (return_type), best_try_locus));
6489 1400 : }
6490 :
6491 : template <typename ManagedTokenSource>
6492 : std::unique_ptr<AST::ReferenceType>
6493 13008 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
6494 : {
6495 : // parse optional lifetime
6496 13008 : AST::Lifetime lifetime = AST::Lifetime::elided ();
6497 26016 : if (lexer.peek_token ()->get_id () == LIFETIME)
6498 : {
6499 2096 : auto parsed_lifetime = parse_lifetime (true);
6500 2096 : if (parsed_lifetime)
6501 : {
6502 2096 : lifetime = parsed_lifetime.value ();
6503 : }
6504 : else
6505 : {
6506 0 : Error error (lexer.peek_token ()->get_locus (),
6507 : "failed to parse lifetime in reference type");
6508 0 : add_error (std::move (error));
6509 :
6510 0 : return nullptr;
6511 0 : }
6512 2096 : }
6513 :
6514 13008 : bool is_mut = false;
6515 26016 : if (lexer.peek_token ()->get_id () == MUT)
6516 : {
6517 1961 : lexer.skip_token ();
6518 1961 : is_mut = true;
6519 : }
6520 :
6521 : // parse type no bounds, which is required
6522 13008 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6523 13008 : if (type == nullptr)
6524 : {
6525 0 : Error error (lexer.peek_token ()->get_locus (),
6526 : "failed to parse referenced type in reference type");
6527 0 : add_error (std::move (error));
6528 :
6529 0 : return nullptr;
6530 0 : }
6531 :
6532 : return std::unique_ptr<AST::ReferenceType> (
6533 39024 : new AST::ReferenceType (is_mut, std::move (type), locus,
6534 13008 : std::move (lifetime)));
6535 13008 : }
6536 :
6537 : // Parses a reference type (mutable or immutable, with given lifetime).
6538 : template <typename ManagedTokenSource>
6539 : std::unique_ptr<AST::ReferenceType>
6540 13008 : Parser<ManagedTokenSource>::parse_reference_type ()
6541 : {
6542 13008 : auto t = lexer.peek_token ();
6543 13008 : auto locus = t->get_locus ();
6544 :
6545 13008 : switch (t->get_id ())
6546 : {
6547 12960 : case AMP:
6548 12960 : skip_token (AMP);
6549 12960 : return parse_reference_type_inner (locus);
6550 48 : case LOGICAL_AND:
6551 48 : skip_token (LOGICAL_AND);
6552 : return std::unique_ptr<AST::ReferenceType> (
6553 144 : new AST::ReferenceType (false, parse_reference_type_inner (locus),
6554 48 : locus));
6555 0 : default:
6556 0 : rust_unreachable ();
6557 : }
6558 13008 : }
6559 :
6560 : // Parses a raw (unsafe) pointer type.
6561 : template <typename ManagedTokenSource>
6562 : std::unique_ptr<AST::RawPointerType>
6563 8764 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
6564 : {
6565 8764 : location_t locus = lexer.peek_token ()->get_locus ();
6566 8764 : skip_token (ASTERISK);
6567 :
6568 8764 : AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
6569 :
6570 : // branch on next token for pointer kind info
6571 8764 : const_TokenPtr t = lexer.peek_token ();
6572 8764 : switch (t->get_id ())
6573 : {
6574 1717 : case MUT:
6575 1717 : kind = AST::RawPointerType::MUT;
6576 1717 : lexer.skip_token ();
6577 1717 : break;
6578 7047 : case CONST:
6579 7047 : kind = AST::RawPointerType::CONST;
6580 7047 : lexer.skip_token ();
6581 7047 : break;
6582 0 : default:
6583 0 : add_error (Error (t->get_locus (),
6584 : "unrecognised token %qs in raw pointer type",
6585 : t->get_token_description ()));
6586 :
6587 0 : return nullptr;
6588 : }
6589 :
6590 : // parse type no bounds (required)
6591 8764 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6592 8764 : if (type == nullptr)
6593 : {
6594 0 : Error error (lexer.peek_token ()->get_locus (),
6595 : "failed to parse pointed type of raw pointer type");
6596 0 : add_error (std::move (error));
6597 :
6598 0 : return nullptr;
6599 0 : }
6600 :
6601 : return std::unique_ptr<AST::RawPointerType> (
6602 8764 : new AST::RawPointerType (kind, std::move (type), locus));
6603 8764 : }
6604 :
6605 : /* Parses a slice or array type, depending on following arguments (as
6606 : * lookahead is not possible). */
6607 : template <typename ManagedTokenSource>
6608 : std::unique_ptr<AST::TypeNoBounds>
6609 2979 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
6610 : {
6611 2979 : location_t locus = lexer.peek_token ()->get_locus ();
6612 2979 : skip_token (LEFT_SQUARE);
6613 :
6614 : // parse inner type (required)
6615 2979 : std::unique_ptr<AST::Type> inner_type = parse_type ();
6616 2979 : if (inner_type == nullptr)
6617 : {
6618 0 : Error error (lexer.peek_token ()->get_locus (),
6619 : "failed to parse inner type in slice or array type");
6620 0 : add_error (std::move (error));
6621 :
6622 0 : return nullptr;
6623 0 : }
6624 :
6625 : // branch on next token
6626 2979 : const_TokenPtr t = lexer.peek_token ();
6627 2979 : switch (t->get_id ())
6628 : {
6629 1796 : case RIGHT_SQUARE:
6630 : // slice type
6631 1796 : lexer.skip_token ();
6632 :
6633 1796 : return std::unique_ptr<AST::SliceType> (
6634 1796 : new AST::SliceType (std::move (inner_type), locus));
6635 1183 : case SEMICOLON:
6636 : {
6637 : // array type
6638 1183 : lexer.skip_token ();
6639 :
6640 : // parse required array size expression
6641 1183 : auto size = parse_anon_const ();
6642 :
6643 1183 : if (!size)
6644 : {
6645 1 : Error error (lexer.peek_token ()->get_locus (),
6646 : "failed to parse size expression in array type");
6647 1 : add_error (std::move (error));
6648 :
6649 1 : return nullptr;
6650 1 : }
6651 :
6652 1182 : if (!skip_token (RIGHT_SQUARE))
6653 : {
6654 0 : return nullptr;
6655 : }
6656 :
6657 1182 : return std::unique_ptr<AST::ArrayType> (
6658 2351 : new AST::ArrayType (std::move (inner_type), std::move (*size),
6659 1182 : locus));
6660 1183 : }
6661 0 : default:
6662 : // error
6663 0 : add_error (
6664 0 : Error (t->get_locus (),
6665 : "unrecognised token %qs in slice or array type after inner type",
6666 : t->get_token_description ()));
6667 :
6668 0 : return nullptr;
6669 : }
6670 2979 : }
6671 :
6672 : // Parses a type, taking into account type boundary disambiguation.
6673 : template <typename ManagedTokenSource>
6674 : std::unique_ptr<AST::TypeNoBounds>
6675 32187 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
6676 : {
6677 32187 : const_TokenPtr t = lexer.peek_token ();
6678 32187 : switch (t->get_id ())
6679 : {
6680 4 : case EXCLAM:
6681 : // never type - can't be macro as no path beforehand
6682 4 : lexer.skip_token ();
6683 4 : return std::unique_ptr<AST::NeverType> (
6684 4 : new AST::NeverType (t->get_locus ()));
6685 1453 : case LEFT_SQUARE:
6686 : // slice type or array type - requires further disambiguation
6687 1453 : return parse_slice_or_array_type ();
6688 26 : case LEFT_SHIFT:
6689 : case LEFT_ANGLE:
6690 : {
6691 : // qualified path in type
6692 26 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
6693 26 : if (path.is_error ())
6694 : {
6695 0 : Error error (t->get_locus (),
6696 : "failed to parse qualified path in type");
6697 0 : add_error (std::move (error));
6698 :
6699 0 : return nullptr;
6700 0 : }
6701 26 : return std::unique_ptr<AST::QualifiedPathInType> (
6702 26 : new AST::QualifiedPathInType (std::move (path)));
6703 26 : }
6704 225 : case UNDERSCORE:
6705 : // inferred type
6706 225 : lexer.skip_token ();
6707 225 : return std::unique_ptr<AST::InferredType> (
6708 225 : new AST::InferredType (t->get_locus ()));
6709 4891 : case ASTERISK:
6710 : // raw pointer type
6711 4891 : return parse_raw_pointer_type ();
6712 76 : case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
6713 : case LOGICAL_AND:
6714 : // reference type
6715 76 : return parse_reference_type ();
6716 0 : case LIFETIME:
6717 : /* probably a lifetime bound, so probably type param bounds in
6718 : * TraitObjectType. this is not allowed, but detection here for error
6719 : * message */
6720 0 : add_error (Error (t->get_locus (),
6721 : "lifetime bounds (i.e. in type param bounds, in "
6722 : "TraitObjectType) are not allowed as TypeNoBounds"));
6723 :
6724 0 : return nullptr;
6725 24934 : case IDENTIFIER:
6726 : case SUPER:
6727 : case SELF:
6728 : case SELF_ALIAS:
6729 : case CRATE:
6730 : case DOLLAR_SIGN:
6731 : case SCOPE_RESOLUTION:
6732 : {
6733 : // macro invocation or type path - requires further disambiguation.
6734 : /* for parsing path component of each rule, perhaps parse it as a
6735 : * typepath and attempt conversion to simplepath if a trailing '!' is
6736 : * found */
6737 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
6738 : * with it, it is exactly the same as a TypePath syntactically, so
6739 : * this is a syntactical ambiguity. As such, the parser will parse it
6740 : * as a TypePath. This, however, does not prevent TraitObjectType from
6741 : * starting with a typepath. */
6742 :
6743 : // parse path as type path
6744 24934 : AST::TypePath path = parse_type_path ();
6745 24934 : if (path.is_error ())
6746 : {
6747 0 : Error error (
6748 : t->get_locus (),
6749 : "failed to parse path as first component of type no bounds");
6750 0 : add_error (std::move (error));
6751 :
6752 0 : return nullptr;
6753 0 : }
6754 24934 : location_t locus = path.get_locus ();
6755 :
6756 : // branch on next token
6757 24934 : t = lexer.peek_token ();
6758 24934 : switch (t->get_id ())
6759 : {
6760 1 : case EXCLAM:
6761 : {
6762 : // macro invocation
6763 : // convert to simple path
6764 1 : AST::SimplePath macro_path = path.as_simple_path ();
6765 1 : if (macro_path.is_empty ())
6766 : {
6767 0 : Error error (t->get_locus (),
6768 : "failed to parse simple path in macro "
6769 : "invocation (for type)");
6770 0 : add_error (std::move (error));
6771 :
6772 0 : return nullptr;
6773 0 : }
6774 :
6775 1 : lexer.skip_token ();
6776 :
6777 1 : auto tok_tree = parse_delim_token_tree ();
6778 1 : if (!tok_tree)
6779 0 : return nullptr;
6780 :
6781 2 : return AST::MacroInvocation::Regular (
6782 2 : AST::MacroInvocData (std::move (macro_path),
6783 1 : std::move (tok_tree.value ())),
6784 1 : {}, locus);
6785 2 : }
6786 24933 : default:
6787 : // assume that this is a type path and not an error
6788 24933 : return std::unique_ptr<AST::TypePath> (
6789 24933 : new AST::TypePath (std::move (path)));
6790 : }
6791 24934 : }
6792 329 : case LEFT_PAREN:
6793 : /* tuple type or parenthesised type - requires further disambiguation
6794 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
6795 : * could be TraitObjectTypeOneBound */
6796 329 : return parse_paren_prefixed_type_no_bounds ();
6797 2 : case FOR:
6798 : case ASYNC:
6799 : case CONST:
6800 : case UNSAFE:
6801 : case EXTERN_KW:
6802 : case FN_KW:
6803 : // bare function type (with no for lifetimes)
6804 2 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
6805 30 : case IMPL:
6806 30 : lexer.skip_token ();
6807 60 : if (lexer.peek_token ()->get_id () == LIFETIME)
6808 : {
6809 : /* cannot be one bound because lifetime prevents it from being
6810 : * traitbound not allowed as type no bounds, only here for error
6811 : * message */
6812 0 : Error error (
6813 0 : lexer.peek_token ()->get_locus (),
6814 : "lifetime (probably lifetime bound, in type param "
6815 : "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
6816 0 : add_error (std::move (error));
6817 :
6818 0 : return nullptr;
6819 0 : }
6820 : else
6821 : {
6822 : // should be trait bound, so parse trait bound
6823 30 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6824 30 : if (initial_bound == nullptr)
6825 : {
6826 0 : Error error (lexer.peek_token ()->get_locus (),
6827 : "failed to parse ImplTraitTypeOneBound bound");
6828 0 : add_error (std::move (error));
6829 :
6830 0 : return nullptr;
6831 0 : }
6832 :
6833 30 : location_t locus = t->get_locus ();
6834 :
6835 : // ensure not a trait with multiple bounds
6836 30 : t = lexer.peek_token ();
6837 30 : if (t->get_id () == PLUS)
6838 : {
6839 0 : Error error (t->get_locus (),
6840 : "plus after trait bound means an ImplTraitType, "
6841 : "which is not allowed as a TypeNoBounds");
6842 0 : add_error (std::move (error));
6843 :
6844 0 : return nullptr;
6845 0 : }
6846 :
6847 30 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6848 30 : new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
6849 30 : }
6850 217 : case DYN:
6851 : case QUESTION_MARK:
6852 : {
6853 : // either TraitObjectTypeOneBound
6854 217 : bool has_dyn = false;
6855 217 : if (t->get_id () == DYN)
6856 : {
6857 217 : lexer.skip_token ();
6858 217 : has_dyn = true;
6859 : }
6860 :
6861 434 : if (lexer.peek_token ()->get_id () == LIFETIME)
6862 : {
6863 : /* means that cannot be TraitObjectTypeOneBound - so here for
6864 : * error message */
6865 0 : Error error (lexer.peek_token ()->get_locus (),
6866 : "lifetime as bound in TraitObjectTypeOneBound "
6867 : "is not allowed, so cannot be TypeNoBounds");
6868 0 : add_error (std::move (error));
6869 :
6870 0 : return nullptr;
6871 0 : }
6872 :
6873 : // should be trait bound, so parse trait bound
6874 217 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6875 217 : if (initial_bound == nullptr)
6876 : {
6877 0 : Error error (
6878 0 : lexer.peek_token ()->get_locus (),
6879 : "failed to parse TraitObjectTypeOneBound initial bound");
6880 0 : add_error (std::move (error));
6881 :
6882 0 : return nullptr;
6883 0 : }
6884 :
6885 217 : location_t locus = t->get_locus ();
6886 :
6887 : // detect error with plus as next token
6888 217 : t = lexer.peek_token ();
6889 217 : if (t->get_id () == PLUS)
6890 : {
6891 0 : Error error (t->get_locus (),
6892 : "plus after trait bound means a TraitObjectType, "
6893 : "which is not allowed as a TypeNoBounds");
6894 0 : add_error (std::move (error));
6895 :
6896 0 : return nullptr;
6897 0 : }
6898 :
6899 : // convert trait bound to value object
6900 217 : AST::TraitBound value_bound (*initial_bound);
6901 :
6902 217 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6903 434 : new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
6904 217 : has_dyn));
6905 217 : }
6906 0 : default:
6907 0 : add_error (Error (t->get_locus (),
6908 : "unrecognised token %qs in type no bounds",
6909 : t->get_token_description ()));
6910 :
6911 0 : return nullptr;
6912 : }
6913 32187 : }
6914 :
6915 : // Parses a type no bounds beginning with '('.
6916 : template <typename ManagedTokenSource>
6917 : std::unique_ptr<AST::TypeNoBounds>
6918 329 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
6919 : {
6920 : /* NOTE: this could probably be parsed without the HACK solution of
6921 : * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
6922 :
6923 : /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
6924 : * considered a trait bound, not a parenthesised type, so that it can still
6925 : * be used in type param bounds. */
6926 :
6927 329 : location_t left_paren_locus = lexer.peek_token ()->get_locus ();
6928 :
6929 : // skip left delim
6930 329 : lexer.skip_token ();
6931 : /* while next token isn't close delim, parse comma-separated types, saving
6932 : * whether trailing comma happens */
6933 329 : const_TokenPtr t = lexer.peek_token ();
6934 329 : bool trailing_comma = true;
6935 329 : std::vector<std::unique_ptr<AST::Type>> types;
6936 :
6937 964 : while (t->get_id () != RIGHT_PAREN)
6938 : {
6939 659 : std::unique_ptr<AST::Type> type = parse_type ();
6940 659 : if (type == nullptr)
6941 : {
6942 0 : Error error (t->get_locus (),
6943 : "failed to parse type inside parentheses (probably "
6944 : "tuple or parenthesised)");
6945 0 : add_error (std::move (error));
6946 :
6947 0 : return nullptr;
6948 0 : }
6949 659 : types.push_back (std::move (type));
6950 :
6951 659 : t = lexer.peek_token ();
6952 659 : if (t->get_id () != COMMA)
6953 : {
6954 24 : trailing_comma = false;
6955 : break;
6956 : }
6957 635 : lexer.skip_token ();
6958 :
6959 635 : t = lexer.peek_token ();
6960 : }
6961 :
6962 329 : if (!skip_token (RIGHT_PAREN))
6963 : {
6964 0 : return nullptr;
6965 : }
6966 :
6967 : // if only one type and no trailing comma, then not a tuple type
6968 329 : if (types.size () == 1 && !trailing_comma)
6969 : {
6970 : // must be a TraitObjectType (with more than one bound)
6971 26 : if (lexer.peek_token ()->get_id () == PLUS)
6972 : {
6973 : // error - this is not allowed for type no bounds
6974 0 : Error error (lexer.peek_token ()->get_locus (),
6975 : "plus (implying TraitObjectType as type param "
6976 : "bounds) is not allowed in type no bounds");
6977 0 : add_error (std::move (error));
6978 :
6979 0 : return nullptr;
6980 0 : }
6981 : else
6982 : {
6983 : // release vector pointer
6984 13 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6985 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6986 : * type */
6987 13 : std::unique_ptr<AST::TraitBound> converted_bound (
6988 13 : released_ptr->to_trait_bound (true));
6989 13 : if (converted_bound == nullptr)
6990 : {
6991 : // parenthesised type
6992 13 : return std::unique_ptr<AST::ParenthesisedType> (
6993 13 : new AST::ParenthesisedType (std::move (released_ptr),
6994 13 : left_paren_locus));
6995 : }
6996 : else
6997 : {
6998 : // trait object type (one bound)
6999 :
7000 : // get value semantics trait bound
7001 0 : AST::TraitBound value_bound (*converted_bound);
7002 :
7003 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
7004 0 : new AST::TraitObjectTypeOneBound (value_bound,
7005 0 : left_paren_locus));
7006 0 : }
7007 13 : }
7008 : }
7009 : else
7010 : {
7011 316 : return std::unique_ptr<AST::TupleType> (
7012 316 : new AST::TupleType (std::move (types), left_paren_locus));
7013 : }
7014 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
7015 : * lost somehow */
7016 329 : }
7017 :
7018 : // Parses tuple struct items if they exist. Does not parse parentheses.
7019 : template <typename ManagedTokenSource>
7020 : std::unique_ptr<AST::TupleStructItems>
7021 2021 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
7022 : {
7023 2021 : std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
7024 :
7025 : // DEBUG
7026 2021 : rust_debug ("started parsing tuple struct items");
7027 :
7028 : // check for '..' at front
7029 4042 : if (lexer.peek_token ()->get_id () == DOT_DOT)
7030 : {
7031 : // only parse upper patterns
7032 25 : lexer.skip_token ();
7033 :
7034 : // DEBUG
7035 25 : rust_debug ("'..' at front in tuple struct items detected");
7036 :
7037 25 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
7038 :
7039 25 : const_TokenPtr t = lexer.peek_token ();
7040 42 : while (t->get_id () == COMMA)
7041 : {
7042 17 : lexer.skip_token ();
7043 :
7044 : // break if right paren
7045 34 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
7046 : break;
7047 :
7048 : // parse pattern, which is now required
7049 17 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7050 17 : if (pattern == nullptr)
7051 : {
7052 0 : Error error (lexer.peek_token ()->get_locus (),
7053 : "failed to parse pattern in tuple struct items");
7054 0 : add_error (std::move (error));
7055 :
7056 0 : return nullptr;
7057 0 : }
7058 17 : upper_patterns.push_back (std::move (pattern));
7059 :
7060 17 : t = lexer.peek_token ();
7061 : }
7062 :
7063 : // DEBUG
7064 25 : rust_debug (
7065 : "finished parsing tuple struct items ranged (upper/none only)");
7066 :
7067 25 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
7068 25 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
7069 25 : std::move (upper_patterns)));
7070 25 : }
7071 :
7072 : // has at least some lower patterns
7073 1996 : const_TokenPtr t = lexer.peek_token ();
7074 2126 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
7075 : {
7076 : // DEBUG
7077 2074 : rust_debug ("about to parse pattern in tuple struct items");
7078 :
7079 : // parse pattern, which is required
7080 2074 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7081 2074 : if (pattern == nullptr)
7082 : {
7083 0 : Error error (t->get_locus (),
7084 : "failed to parse pattern in tuple struct items");
7085 0 : add_error (std::move (error));
7086 :
7087 0 : return nullptr;
7088 0 : }
7089 2074 : lower_patterns.push_back (std::move (pattern));
7090 :
7091 : // DEBUG
7092 2074 : rust_debug ("successfully parsed pattern in tuple struct items");
7093 :
7094 4148 : if (lexer.peek_token ()->get_id () != COMMA)
7095 : {
7096 : // DEBUG
7097 1944 : rust_debug ("broke out of parsing patterns in tuple struct "
7098 : "items as no comma");
7099 :
7100 : break;
7101 : }
7102 130 : lexer.skip_token ();
7103 130 : t = lexer.peek_token ();
7104 : }
7105 :
7106 : // branch on next token
7107 1996 : t = lexer.peek_token ();
7108 1996 : switch (t->get_id ())
7109 : {
7110 1966 : case RIGHT_PAREN:
7111 1966 : return std::unique_ptr<AST::TupleStructItemsNoRest> (
7112 1966 : new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
7113 29 : case DOT_DOT:
7114 : {
7115 : // has an upper range that must be parsed separately
7116 29 : lexer.skip_token ();
7117 :
7118 29 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
7119 :
7120 29 : t = lexer.peek_token ();
7121 35 : while (t->get_id () == COMMA)
7122 : {
7123 6 : lexer.skip_token ();
7124 :
7125 : // break if next token is right paren
7126 12 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
7127 : break;
7128 :
7129 : // parse pattern, which is required
7130 6 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7131 6 : if (pattern == nullptr)
7132 : {
7133 0 : Error error (lexer.peek_token ()->get_locus (),
7134 : "failed to parse pattern in tuple struct items");
7135 0 : add_error (std::move (error));
7136 :
7137 0 : return nullptr;
7138 0 : }
7139 6 : upper_patterns.push_back (std::move (pattern));
7140 :
7141 6 : t = lexer.peek_token ();
7142 : }
7143 :
7144 29 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
7145 29 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
7146 29 : std::move (upper_patterns)));
7147 29 : }
7148 1 : default:
7149 : // error
7150 1 : add_error (Error (t->get_locus (),
7151 : "unexpected token %qs in tuple struct items",
7152 : t->get_token_description ()));
7153 :
7154 1 : return nullptr;
7155 : }
7156 2021 : }
7157 :
7158 : /* Parses a statement or expression (depending on whether a trailing semicolon
7159 : * exists). Useful for block expressions where it cannot be determined through
7160 : * lookahead whether it is a statement or expression to be parsed. */
7161 : template <typename ManagedTokenSource>
7162 : tl::expected<ExprOrStmt, Parse::Error::Node>
7163 80483 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
7164 : {
7165 : // quick exit for empty statement
7166 80483 : const_TokenPtr t = lexer.peek_token ();
7167 80483 : if (t->get_id () == SEMICOLON)
7168 : {
7169 18 : lexer.skip_token ();
7170 18 : std::unique_ptr<AST::EmptyStmt> stmt (
7171 18 : new AST::EmptyStmt (t->get_locus ()));
7172 36 : return ExprOrStmt (std::move (stmt));
7173 18 : }
7174 :
7175 : // parse outer attributes
7176 80465 : AST::AttrVec outer_attrs = parse_outer_attributes ();
7177 80465 : ParseRestrictions restrictions;
7178 80465 : restrictions.expr_can_be_stmt = true;
7179 :
7180 : // Defered child error checking: we need to check for a semicolon
7181 80465 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
7182 :
7183 : // parsing this will be annoying because of the many different possibilities
7184 : /* best may be just to copy paste in parse_item switch, and failing that try
7185 : * to parse outer attributes, and then pass them in to either a let
7186 : * statement or (fallback) expression statement. */
7187 : // FIXME: think of a way to do this without such a large switch?
7188 :
7189 : /* FIXME: for expressions at least, the only way that they can really be
7190 : * parsed properly in this way is if they don't support operators on them.
7191 : * They must be pratt-parsed otherwise. As such due to composability, only
7192 : * explicit statements will have special cases here. This should roughly
7193 : * correspond to "expr-with-block", but this warning is here in case it
7194 : * isn't the case. */
7195 80465 : t = lexer.peek_token ();
7196 80465 : switch (t->get_id ())
7197 : {
7198 24429 : case LET:
7199 : {
7200 : // let statement
7201 24429 : std::unique_ptr<AST::LetStmt> stmt (
7202 24429 : parse_let_stmt (std::move (outer_attrs)));
7203 48858 : return ExprOrStmt (std::move (stmt));
7204 24429 : }
7205 966 : case PUB:
7206 : case MOD:
7207 : case EXTERN_KW:
7208 : case USE:
7209 : case FN_KW:
7210 : case TYPE:
7211 : case STRUCT_KW:
7212 : case ENUM_KW:
7213 : case CONST:
7214 : case STATIC_KW:
7215 : case AUTO:
7216 : case TRAIT:
7217 : case IMPL:
7218 : {
7219 966 : std::unique_ptr<AST::VisItem> item (
7220 966 : parse_vis_item (std::move (outer_attrs)));
7221 1932 : return ExprOrStmt (std::move (item));
7222 966 : }
7223 : /* TODO: implement union keyword but not really because of
7224 : * context-dependence crappy hack way to parse a union written below to
7225 : * separate it from the good code. */
7226 : // case UNION:
7227 4692 : case UNSAFE:
7228 : { // maybe - unsafe traits are a thing
7229 : /* if any of these (should be all possible VisItem prefixes), parse a
7230 : * VisItem - can't parse item because would require reparsing outer
7231 : * attributes */
7232 4692 : const_TokenPtr t2 = lexer.peek_token (1);
7233 4692 : switch (t2->get_id ())
7234 : {
7235 4669 : case LEFT_CURLY:
7236 : {
7237 : // unsafe block: parse as expression
7238 9338 : expr = parse_expr (std::move (outer_attrs), restrictions);
7239 : break;
7240 : }
7241 0 : case AUTO:
7242 : case TRAIT:
7243 : {
7244 : // unsafe trait
7245 0 : std::unique_ptr<AST::VisItem> item (
7246 0 : parse_vis_item (std::move (outer_attrs)));
7247 0 : return ExprOrStmt (std::move (item));
7248 0 : }
7249 23 : case EXTERN_KW:
7250 : case FN_KW:
7251 : {
7252 : // unsafe function
7253 23 : std::unique_ptr<AST::VisItem> item (
7254 23 : parse_vis_item (std::move (outer_attrs)));
7255 46 : return ExprOrStmt (std::move (item));
7256 23 : }
7257 0 : case IMPL:
7258 : {
7259 : // unsafe trait impl
7260 0 : std::unique_ptr<AST::VisItem> item (
7261 0 : parse_vis_item (std::move (outer_attrs)));
7262 0 : return ExprOrStmt (std::move (item));
7263 0 : }
7264 0 : default:
7265 0 : add_error (Error (t2->get_locus (),
7266 : "unrecognised token %qs after parsing unsafe - "
7267 : "expected beginning of expression or statement",
7268 : t->get_token_description ()));
7269 :
7270 : // skip somewhere?
7271 : return tl::unexpected<Parse::Error::Node> (
7272 0 : Parse::Error::Node::MALFORMED);
7273 : }
7274 : break;
7275 62320 : }
7276 : /* FIXME: this is either a macro invocation or macro invocation semi.
7277 : * start parsing to determine which one it is. */
7278 : // FIXME: old code there
7279 :
7280 : // crappy hack to do union "keyword"
7281 28903 : case IDENTIFIER:
7282 28903 : if (t->get_str () == Values::WeakKeywords::UNION
7283 28939 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
7284 : {
7285 1 : std::unique_ptr<AST::VisItem> item (
7286 1 : parse_vis_item (std::move (outer_attrs)));
7287 2 : return ExprOrStmt (std::move (item));
7288 : // or should this go straight to parsing union?
7289 1 : }
7290 28902 : else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
7291 29419 : && lexer.peek_token (1)->get_id () == EXCLAM)
7292 : {
7293 : // macro_rules! macro item
7294 517 : std::unique_ptr<AST::Item> item (
7295 517 : parse_macro_rules_def (std::move (outer_attrs)));
7296 1034 : return ExprOrStmt (std::move (item));
7297 517 : }
7298 : gcc_fallthrough ();
7299 : case SUPER:
7300 : case SELF:
7301 : case SELF_ALIAS:
7302 : case CRATE:
7303 : case SCOPE_RESOLUTION:
7304 : case DOLLAR_SIGN:
7305 : {
7306 34834 : AST::PathInExpression path = parse_path_in_expression ();
7307 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
7308 34834 : null_denotation;
7309 :
7310 69668 : if (lexer.peek_token ()->get_id () == EXCLAM)
7311 : {
7312 2704 : std::unique_ptr<AST::MacroInvocation> invoc
7313 5408 : = parse_macro_invocation_partial (std::move (path),
7314 : std::move (outer_attrs));
7315 2704 : if (invoc == nullptr)
7316 : return tl::unexpected<Parse::Error::Node> (
7317 0 : Parse::Error::Node::CHILD_ERROR);
7318 :
7319 2704 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7320 : {
7321 1516 : invoc->add_semicolon ();
7322 : // Macro invocation with semicolon.
7323 1516 : return ExprOrStmt (
7324 3032 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7325 : }
7326 :
7327 2376 : TokenId after_macro = lexer.peek_token ()->get_id ();
7328 :
7329 1188 : AST::DelimType delim_type = invoc->get_invoc_data ()
7330 1188 : .get_delim_tok_tree ()
7331 1188 : .get_delim_type ();
7332 :
7333 1188 : if (delim_type == AST::CURLY && after_macro != DOT
7334 20 : && after_macro != QUESTION_MARK)
7335 : {
7336 20 : rust_debug ("braced macro statement");
7337 20 : return ExprOrStmt (
7338 40 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7339 : }
7340 :
7341 1168 : null_denotation = std::move (invoc);
7342 2704 : }
7343 : else
7344 : {
7345 : null_denotation
7346 64259 : = null_denotation_path (std::move (path), {}, restrictions);
7347 : }
7348 :
7349 133186 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7350 : std::move (outer_attrs), restrictions);
7351 : break;
7352 34834 : }
7353 15026 : default:
7354 : /* expression statement or expression itself - parse
7355 : * expression then make it statement if semi afterwards */
7356 30022 : expr = parse_expr (std::move (outer_attrs), restrictions);
7357 15026 : break;
7358 : }
7359 :
7360 52993 : const_TokenPtr after_expr = lexer.peek_token ();
7361 52993 : if (after_expr->get_id () == SEMICOLON)
7362 : {
7363 : // must be expression statement
7364 14704 : lexer.skip_token ();
7365 :
7366 14704 : if (expr)
7367 : {
7368 14703 : return ExprOrStmt (
7369 29406 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7370 44109 : t->get_locus (), true));
7371 : }
7372 : else
7373 : {
7374 : return tl::unexpected<Parse::Error::Node> (
7375 1 : Parse::Error::Node::CHILD_ERROR);
7376 : }
7377 : }
7378 :
7379 38289 : if (expr)
7380 : {
7381 : // block expression statement.
7382 38257 : if (!expr.value ()->is_expr_without_block ()
7383 38257 : && after_expr->get_id () != RIGHT_CURLY)
7384 3536 : return ExprOrStmt (
7385 7072 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7386 10608 : t->get_locus (), false));
7387 :
7388 : // Check if expr_without_block is properly terminated
7389 34721 : if (expr.value ()->is_expr_without_block ()
7390 34721 : && after_expr->get_id () != RIGHT_CURLY)
7391 : {
7392 : // expr_without_block must be followed by ';' or '}'
7393 1 : Error error (after_expr->get_locus (),
7394 : "expected %<;%> or %<}%> after expression, found %qs",
7395 : after_expr->get_token_description ());
7396 1 : add_error (std::move (error));
7397 : return tl::unexpected<Parse::Error::Node> (
7398 1 : Parse::Error::Node::MALFORMED);
7399 1 : }
7400 : }
7401 :
7402 : // return expression
7403 34752 : if (expr)
7404 69440 : return ExprOrStmt (std::move (expr.value ()));
7405 : else
7406 32 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
7407 133458 : }
7408 :
7409 : } // namespace Rust
7410 :
7411 : #include "rust-parse-impl-utils.hxx"
7412 : #include "rust-parse-impl-attribute.hxx"
7413 : #include "rust-parse-impl-ttree.hxx"
7414 : #include "rust-parse-impl-macro.hxx"
7415 : #include "rust-parse-impl-path.hxx"
7416 : #include "rust-parse-impl-pattern.hxx"
7417 : #include "rust-parse-impl-expr.hxx"
|